Negative hours value in DateInterval::format() - php

i need to convert number of seconds to date, and then show time difference as days, hours and seconds.
But for some reason after some number of days, in last hour before next full day I get negative hours value. Right now this problem occures if date is greater then 38 days (it's before 1st November). Maybe tomorrow this value will be different, I'm not sure.
Code:
$s = 84600; // 23.5 h in seconds
$s += (60*60*24)*38; // add 38 days in seconds
$d = (new \DateTime())->modify("-".$s."seconds");
echo (new \DateTime())->diff($d)->format("%a days %h:%I");
// shows: 38 days -1:30
Same code with 1 day of difference:
$s = 84600; // 23.5 h in seconds
$s += (60*60*24)*37; // add 37 days in seconds
$d = (new \DateTime())->modify("-".$s."seconds");
echo (new \DateTime())->diff($d)->format("%a days %h:%I");
// shows: 37 days 23:30
PHP version 5.6.2. Tested on localhost, server and http://sandbox.onlinephpfunctions.com/ with same result.

Not sure if you looking for this kind of work around
<?php
$s= 84600;
$ts= strtotime('38 day 30 second', 0);
$difference=$ts-$s;
$days = floor($difference / 86400);
$hours = floor(($difference - $days * 86400) / 3600);
$minutes = floor(($difference - $days * 86400 - $hours * 3600) / 60);
$seconds = floor($difference - $days * 86400 - $hours * 3600 - $minutes * 60);
echo "{$days} days {$hours} hours {$minutes} minutes {$seconds} seconds";
?>
//Output 37 days 0 hours 30 minutes 30 seconds

Related

PHP Time difference only display when not zero

I'm calculating the difference between two dates (the current date and a date in the database). I want to display the difference in days and hours between the dates, but when the day-difference is 0 I don't want to display it. This is my code:
<?php
$to_time = new \DateTime($database_time);
$from_time = new \DateTime();
echo $from_time->diff($to_time)->format("%d %H");
?>
Output should be, for example:
> 50 days and 4 hours
> 1 day and 7 hours //and not 1 dayS
> 6 hours //and not 0 days and 6 hours
There are two issues with my own code: the first one is that it always display the number of days. The second one is that it is just a format. For example when the difference is 2 months, 6 days and 2 hours it displays: 6 days and 2 hours. But it should be 68 days and 2 hours (because of the two months).
Can't get it work with other codes I found. Thanks in advance!
Try this..
$seconds = strtotime("2012-10-10 02:40:03") - strtotime("2010-12-25 05:15:02");
echo $days = floor($seconds / 86400);
echo "</br>";
echo $hours = floor(($seconds - ($days * 86400)) / 3600);
echo "</br>";
echo $minutes = floor(($seconds - ($days * 86400) - ($hours * 3600))/60);
echo "</br>";
echo $seconds = floor(($seconds - ($days * 86400) - ($hours * 3600) - ($minutes*60)));

Converting minutes to hours issue in php

I have this code:
$total_days = 0;
$minutes = 1200;
echo date('H:i', mktime(0, $minutes));
This return me 20 hours, which means two 8 hours + 4 hours working day. It means that in the $total_days will have 2 days + 4 h. How can I divide the 1200 minutes to get 2 days and 4 hours ?
Calculate it manually -
$minutes = 1200;
$total_hours = $minutes / 60;
echo floor($total_hours / 8). ' days ' . ($total_hours % 8). ' hours';
Output
2 days 4 hours
$total_hours contains fractinal value then the calculation should be changed accordingly.

Make a timer reset every 30 days?

I currently have code that changes the month number and MYSQL table every month automatically but the timer it displays still resets every 24 hours. I need to make it so the timer resets every month instead of every 24 hours. I am not thinking straight and need some help solving this.
Basically I need it so that $month_end_time counts down from 30 days, 0 hours, 0 minutes 0 seconds down to 0 days, 0 hours, 0 minutes 0 seconds and then resets back to the 30 days. Currently it counts down from 30 days to 29 days then resets as it is from a script that resets every 24 hours and I am porting it to monthly.
Credits to #ElmoVanKielmo for the original snippet.
Thanks in advance.
define("FIRST_DAY_STRING", "2014-4-6");
define("SHIFT_DAYS", 'P30D');
define("TIME_SUFFIX", " 0:00:00 GMT+11:00");
$today = new DateTime();
$first_day = new DateTime(FIRST_DAY_STRING);
$interval = $first_day->diff($today);
$days = $interval->format('%R%a days');
$end_date = $today->add(new DateInterval(SHIFT_DAYS));
$month_number = floor(intval($days) / 30 + 1);
$txid = "tx$month_number";
$month_end_time = $end_date->format('Y-n-j');
$month_end_time .= TIME_SUFFIX;
I suspect you're possibly overthinking this, since it includes "dates". When moving around months, it can be tricky, since (as Raptor notes), months have differing number of days between each other.
However, based on your comments, you're actually looking for the number of 30-day periods between one date and another. This can be accomplished with basic math and Unix timestamps:
$start = strtotime('2012-04-12 00:00:00 GMT');
$today = strtotime('00:00:00 GMT');
$days = ($today - $start) / 60 / 60 / 24;
$months = $days / 30;
echo "<pre>
Days: $days
Months: $months
";
This will give:
Days: 723
Months: 24.1
http://codepad.viper-7.com/KBVfqq
And if you're trying to figure out how many days:
$start = strtotime('2012-04-12 00:00:00 GMT');
$today = strtotime('00:00:00 GMT');
$days = ($today - $start) / 60 / 60 / 24;
$months = $days / 30;
$months_days = floor($months) . " months, " . ($days - (floor($months) * 30)) . " days";
echo "<pre>
Days: $days
Months: $months
Months and Days: $months_days
";
Giving:
Days: 723
Months: 24.1
Months and Days: 24 months, 3 days
http://codepad.viper-7.com/AdnFsu
Which means that between the start and today's date, there have been 24 full 30-day periods, and we are currently in the 25th period (ceil($months)). This seems sufficient for what you are after, although the specific use of the period value may require better explanation.

PHP Count Down Expiry Button or Link

I'm trying to create a button or link that will expire after 1 hour.
I'm setting the time the visitor hit the page with a cookie.
Most of the code examples I have seen only give the time that has passed and not the time left.
example: Link will expire in 0 hours, 30, mins and 34 seconds
This is just some rough code :
//Setting cookie example
setcookie('previous_time', time(), time()+3600*1);
$current_time = time();
$previous_time = $_COOKIE['previous_time'];
$time_diff = $current_time-$previous_time;
This is where I'm stuck, I have no idea how to convert the $time_diff timestamp
into a format like "expire in 0 hours, 30, mins and 34 seconds"
Many thanks.
To format your time difference, just do some math, since your $time_diff is just the number of seconds between the two times:
$hours = floor( $time_diff / 3600);
$minutes = floor( ($time_diff / 60) % 60);
$seconds = $time_diff % 60;
echo "$hours hours, $minutes minutes, $seconds seconds\n";
So, a value of 20712 would produce :
5 hours, 45 minutes, 12 seconds
Using your formula comparing timestamps, the difference is in seconds.
So, $time_diff / 60 gets you minutes; divide by another 60 to get hours; etc.
I agree with nickb that cookie based is tamper-able, but saying you mark the first visit somehow for an hour ahead when the link will expire:
// set when we are counting down to
setcookie('expires_at', time()+3600, time()+3600);
// we are counting down not up (for "expires in" not "valid since" logic)
$time_diff = $_COOKIE['expires_at'] - time();
$minutes = floor($time_diff / 60);
$seconds = floor($time_diff % 60);
// zero hours since the link will only be valid for one hour max
echo sprintf('expire in 0 hours, %d mins and %d seconds', $minutes, $seconds);
Then you can do:
if($time_diff > 0){
echo '...';
}

Is there something built into PHP to convert seconds to days, hours, mins?

For example if I have:
$seconds = 3744000; // i want to output: 43 days, 8 hours, 0 minutes
Do I have to create a function to convert this? Or does PHP already have something built in to do this like date()?
function secondsToWords($seconds)
{
$ret = "";
/*** get the days ***/
$days = intval(intval($seconds) / (3600*24));
if($days> 0)
{
$ret .= "$days days ";
}
/*** get the hours ***/
$hours = (intval($seconds) / 3600) % 24;
if($hours > 0)
{
$ret .= "$hours hours ";
}
/*** get the minutes ***/
$minutes = (intval($seconds) / 60) % 60;
if($minutes > 0)
{
$ret .= "$minutes minutes ";
}
/*** get the seconds ***/
$seconds = intval($seconds) % 60;
if ($seconds > 0) {
$ret .= "$seconds seconds";
}
return $ret;
}
print secondsToWords(3744000);
This is very simple and easy to find days , hours, minute and second in core php :
$dbDate = strtotime("".$yourdbtime."");
$endDate = time();
$diff = $endDate - $dbDate;
$days = floor($diff/86400);
$hours = floor(($diff-$days*86400)/(60 * 60));
$min = floor(($diff-($days*86400+$hours*3600))/60);
$second = $diff - ($days*86400+$hours*3600+$min*60);
if($days > 0) echo $days." Days ago";
elseif($hours > 0) echo $hours." Hours ago";
elseif($min > 0) echo $min." Minutes ago";
else echo "Just now";
An easy way to accomplish this nowadays is using DateTimeImmutable, DateInterval and PHP 5.5.0 or higher:
$seconds = 3744000;
$interval = new DateInterval("PT{$seconds}S");
$now = new DateTimeImmutable('now', new DateTimeZone('utc'));
$difference = $now->diff($now->add($interval))->format('%a days, %h hours, %i minutes');
The result will be:
43 days, 8 hours, 0 minutes
The code adds the seconds to a date and calculates the difference to it. Like this, the seconds are transformed into the specified days, hours and minutes.
Warning 1: Working without UTC - Clock changes
You may not specify the DateTimeZone in the constructor of the DateTimeImmutable object to UTC.
$now = new DateTimeImmutable();
There are regions in this world, where the clock changes on specific days of the year. Most countries in the EU change between a summer- and winter-time for example.
If your date interval overlaps the day on that a clock change occurs and your server is set to the related region for that clock change, the result might change as well. This is best shown with the following example:
$twentyFourHours = new DateInterval('PT24H');
$twentyFiveHours = new DateInterval('PT25H');
//Pacific time changed from summer- to winter-time on that day
$summerToWinter = new DateTimeImmutable('2018-11-04');
If you add 24 hours to the $summerToWinter date, you will get the following result:
$extra24Hours = $summerToWinter->add($twentyFourHours);
echo $summerToWinter->format('y-m-d H:i');
echo $extra24Hours->format('y-m-d H:i');
echo $summerToWinter->diff($extra24Hours)->format('%a days, %h hours, %i minutes');
18-11-04 00:00
18-11-04 23:00
0 days, 24 hours, 0 minutes
As you can see, between 00:00 and 23:00 on that day lay 24 hours, which is technically correct. Because of the clock change the timelap between 02:00 and 03:00 occured twice on that day.
Adding 25 hours will result in this:
$extra25Hours = $summerToWinter->add($twentyFiveHours);
echo $summerToWinter->format('y-m-d H:i');
echo $extra25Hours->format('y-m-d H:i');
echo $summerToWinter->diff($extra25Hours)->format('%a days, %h hours, %i minutes');
18-11-04 00:00
18-11-05 00:00
1 days, 0 hours, 0 minutes
As we can see, 1 day elapsed, that has had 25 hours. If this is applied for the 3744000 seconds from the original question, the result would show:
43 days, 7 hours, 0 minutes
The information, that an elapsed day has had 25 hours, is not shown though.
Also, I was not able to recreate the same effect for a day that changes the clock from winter to summer time, that should only elapse 23 hours.
Warning 2: Working with the raw DateInterval object
Using this code without DateTimeImmutable will cause the wrong output:
$seconds = 3744000;
$interval = new DateInterval("PT{$seconds}S");
$difference = $interval->format('%a days, %h hours, %i minutes, %s seconds');
Now, only the seconds are set in the DateInterval object. $difference would be:
(unknown) days, 0 hours, 0 minutes, 3744000 seconds
I like Ian Gregory's answer the most and upvoted it but thought i'd just simplify it a little bit :
function secondsToWords($seconds)
{
$days = intval(intval($seconds) / (3600*24));
$hours = (intval($seconds) / 3600) % 24;
$minutes = (intval($seconds) / 60) % 60;
$seconds = intval($seconds) % 60;
$days = $days ? $days . ' days' : '';
$hours = $hours ? $hours . ' hours' : '';
$minutes = $minutes ? $minutes . ' minutes' : '';
$seconds = $seconds ? $seconds . ' seconds' : '';
return $days . $hours . $minutes . $seconds;
}

Categories