Say I have the following 2 dates, a start date and end date:
Year-Month-Day Hours:Minutes:Seconds
Start Date: 2010-12-03 14:04:41
Expiry Date: 2010-12-06 12:59:59
How could I, using PHP subtract the two dates and be left with something like:
Difference: -3 days, 2 minutes and 18 seconds (If expiry date is past 3 days for example).
http://www.php.net/manual/en/datetime.diff.php
<?php
$datetime1 = date_create('2009-10-11');
$datetime2 = date_create('2009-10-13');
$interval = date_diff($datetime1, $datetime2);
echo $interval->format('%R%d days');
//result will be +2 days
?>
I hope that is what you are looking for.
This is based on numerous online examples; you'll see similar code all around if you get your google on.
function timeSince($dateFrom, $dateTo) {
// array of time period chunks
$chunks = array(
array(60 * 60 * 24 * 365 , 'year'),
array(60 * 60 * 24 * 30 , 'month'),
array(60 * 60 * 24 * 7, 'week'),
array(60 * 60 * 24 , 'day'),
array(60 * 60 , 'hour'),
array(60 , 'minute'),
);
$original = strtotime($dateFrom);
$now = strtotime($dateTo);
$since = $now - $original;
$message = ($now < $original) ? '-' : null;
// If the difference is less than 60, we will show the seconds difference as well
if ($since < 60) {
$chunks[] = array(1 , 'second');
}
// $j saves performing the count function each time around the loop
for ($i = 0, $j = count($chunks); $i < $j; $i++) {
$seconds = $chunks[$i][0];
$name = $chunks[$i][1];
// finding the biggest chunk (if the chunk fits, break)
if (($count = floor($since / $seconds)) != 0) {
break;
}
}
$print = ($count == 1) ? '1 ' . $name : $count . ' ' . $name . 's';
if ($i + 1 < $j) {
// now getting the second item
$seconds2 = $chunks[$i + 1][0];
$name2 = $chunks[$i + 1][1];
// add second item if it's greater than 0
if (($count2 = floor(($since - ($seconds * $count)) / $seconds2)) != 0) {
$print .= ($count2 == 1) ? ', 1 ' . $name2 : ', ' . $count2 . ' ' . $name2 . 's';
}
}
return $message . $print;
}
It was intended to show the difference between a given time and the current time, but I've made slight changes to show the difference between two times instead. You may wish to change the output from a postfix of ' ago' to a prefix of 'Difference: '.
Related
I want to get a user registered date, count the days since registration and show max days left to given days and show message after period ends.
What I got so far works:
$regDatestr = '2020-04-09 19:38:10';
$regDate = strtotime($regDatestr);
$regSince = time() - $regDate;
$days = round ($regSince / ( 60 * 60 * 24 ));
$maxDays = 20;
$maxDaysstr = strtotime("-$maxDays days");
$maxReg = ($regSince + $maxDaysstr);
$daysleft = time() - $maxReg;
$restDays = round ($daysleft / ( 60 * 60 * 24 ));
if ($regdate <= $maxDaysstr) :
echo 'period ended'
else :
echo 'Registered since' . $days . ' .days . Rest days ' . $restDays . '
endif;
$daysleft and days gives me the right days. But the period doesnt end exact after 20 days.
What I need is max 20 days since registration date. So when
'2020-04-09 19:38:10';
plus 20 days should end the period at
'2020-04-29 19:38:10';
but it seems my if condition doesnt work as expected. So Im getting "Registered since 21 days. Rest days 0".
Why is that so?
Because you have an typo in with your variable names
if ($regdate <= $maxDaysstr)
should be
if ($regDate <= $maxDaysstr)
and your code could be shorter
$regDatestr = '2020-04-01 19:38:10';
$regDate = new DateTime($regDatestr);
$diffToday = $regDate->diff(new DateTime());
$maxDays = 10;
$diffMax = $regDate->diff(new DateTime("-$maxDays days"));
if ($diffMax->invert == 0) :
echo 'period ended';
else :
echo 'Registered since ' . $diffToday->days . ' .days . Rest days ' . $diffMax->days;
endif;
This question already has answers here:
How do I find the hour difference between two dates in PHP?
(10 answers)
Closed 5 years ago.
I have datetimes in the following format:
Start: 2017-07-16 20:00
End: 2017-07-16 23:30
Start: 2017-07-18 21:30
End: 2017-07-19 00:30
I need to tell from these intervals how many hours (in 0,5 increments) are spent between 18:00-22:00 and 22:00-06:00 in total for a month.
Thanks in advance for any hint.
The current code I have is this, but I'm not sure if it is covering all timeframe possibilities:
<?php
date_default_timezone_set("UTC");
$start = array(
"2017-07-16 21:30:00",
"2017-07-16 18:00:00"
);
$end = array(
"2017-07-17 00:30:00",
"2017-07-16 18:30:00"
);
$amount_low = 0;
$amount_high = 0;
for($i = 0; $i < sizeof($start); $i++) {
$start_time = date("H:i:s", strtotime($start[$i]));
$end_time = date("H:i:s", strtotime($end[$i]));
$start_date = date("Ymd", strtotime($start[$i]));
$end_date = date("Ymd", strtotime($end[$i]));
// getting chunk before 22:00 if
if(
(strtotime($start[$i]) >= strtotime($start_date . " 18:00") && strtotime($start[$i]) < strtotime($start_date . " 22:00"))
&&
$start_date < $end_date
) {
$interval_low = strtotime($start_date . " 22:00") - strtotime($start[$i]);
$amount_low += ceil($interval_low / 1800) / 2;
}
//amount_high
if(strtotime($start[$i]) > strtotime($start_date . " 22:00") && strtotime($start[$i]) < strtotime($start_date . " 06:00")) {
$interval_high = strtotime($end[$i]) - strtotime($start[$i]); //needs further things
$amount_high += ceil($interval_high / 1800) / 2;
} elseif (strtotime($start[$i]) < strtotime($start_date . " 22:00") && strtotime($end[$i]) > strtotime($start_date . " 22:00")) {
$interval_high = strtotime($end[$i]) - strtotime($start_date . " 22:00");
$amount_high += ceil($interval_high / 1800) / 2;
} else {
$interval_low = strtotime($end[$i]) - strtotime($start[$i]);
$amount_low += ceil($interval_low / 1800) / 2;
}
}
echo $amount_low;
echo "\n$amount_high";
?>
Would this work for you?
$start = strtotime('2017-07-16 20:00');
$end = strtotime('2017-07-16 23:30');
$interval = $end - $start;
$hours = floor($interval / 1800)/2;
echo($hours);
This will display the total hours (in 0,5 increments) between the two dates (rounding down, so if it's 55 minutes, it's 0,5 hours; replace 'floor' with 'ceil' for the opposite).
I believe a part of your solution is found here from Aillyn
You can convert them to timestamps and go from there:
$hourdiff = round((strtotime($time1) - strtotime($time2))/3600, 1);
Dividing by 3600 because there are 3600 seconds in one hour and using round()
to avoid having a lot of decimal places.
$hourdiff = round((strtotime($time1) - strtotime($time2))/3600, 1);
This will give you a rounded hour difference between the two times. You could do something similar, just apply it for each interval for which ever month and adjust your math. There's not really going to be a single PHP function you can call to solve this.
I am trying to create a duration time.
I have a user option to enter a time duration in any of these formats: 0.5, 1, 1.5, 2, 2.5 ect.
I have a WordPress post date (used as a start time) and the finish time is calculated with the above user inputs. Together they build a duration time.
Example:
A user enters 1 - Example Out: Duration: 16:30 - 17:30
Problem:
This currently cannot output the correct end time if a user enters anything other then a whole number.
So, 1,2,3 ect would work fine, but 0.5, 1.5, 2.5 will all error and show the wrong end time.
I am need of a second pair of eyes, I cannot see the error of my ways.
// Get user duration option - 0.5, 1, 1.5, 2 ect
$course_hours = floatval(get_field('hours'));
$course_minutes = ($course_hours % 1) * 60;
$end_hour = intval(get_the_date('H'));
$end_minute = intval(get_the_date('i'));
$end_ampm = get_the_date('a');
if($course_minutes != 0 && $course_minutes + $end_minute <= 59){
$end_minute += $course_minutes;
$end_hour += floor($course_hours);
}
elseif($course_minutes != 0 && $course_minutes + $end_minute > 59){
$end_minute = ($course_minutes + $end_minute) % 60;
$end_hour += floor($course_hours) + 1;
}
elseif($course_minutes == 0){
$end_hour += floor($course_hours);
if ($end_minute == 0){$end_minute = '00';}
}
$end_time = $end_hour.':'.$end_minute;
$safe_post_status = get_post_status();
//Demo output
echo the_date('d F Y G:i');
echo ' - '.$end_time;
Thanks!
Writing logic for your question. Change the date format as per your requirement.
seems like you are using wordpress.
$course_hours = (get_field('hours'));
$course_minutes = ($course_hours) * 60;
$formatter = [];
$increment = 0.5;
$h = $increment * 60;
while ($h < $course_minutes ) {
$key = date('H:i', strtotime(date('Y-m-d') . ' + ' . $h . ' minutes'));
$value = date('h:i', strtotime(date('Y-m-d') . ' + ' . $h . ' minutes'));
$formatter[$key] = $value;
$h = $h + ($increment * 60 );
}
echo $output = implode(" - ",$formatter);
// 12:30 - 01:00 - 01:30 - 02:00
I have a database which contains posts that have both a creation date(unix timestamp) and a publication date(unix timestamp). I want to calculate the average time it takes a post to be published after its created. I guess im way off, but this is what i got so far:
$times = array();
foreach($posts as $post) {
$timeBetween = $post->publicationDate - $post->creationDate;
array_push($times, $timeBetween);
}
$average = array_sum($times) / count($times);
echo date("H:m:s",mktime(0,0,$average,0,0,0));
My optimal output would be something like: 1 day, 12 hours, 13 second..
Anyone?
Appreciate any help!
date() is not the correct tool for this job. date() doesn't understand a period of time like 2D 3H 27M, it only understands points in time.
In your code $average will contain a number of seconds, so you should finish with something like:-
$h = floor($average/3600);
$average -= $h*3600;
$m = floor($average/60);
$average -= $m*60;
$s = floor($average);
echo "$h:$m:$s";
Why don't you use the foreach-loop like this:
$time = 0;
foreach ( $posts as $post ) {
$time += $post->publicationDate - $post->creationDate;
}
$average = $time / count( $posts );
This way you don't need to use an array, and you got the same result.
If you want to show it like 2 days, 4 hours, 43 minutes and 2 seconds you can calculate it like this:
// 1 day = 24 hours * 60 minutes * 60 seconds = 86400 seconds
$days = floor( $average / 86400 );
$hours = floor( ( $average % 86400 ) / 3600 );
$minutes = floor( ( $average % 3600 ) / 60 );
$seconds = $average % 60;
echo $days . ' day' . ( $days > 0 ? 's' : '' ) . ', ';
echo $hours . ' hour' . ( $hours > 0 ? 's' : '' ) . ', ';
echo $minutes . ' minute' . ( $minutes > 0 ? 's' : '' ) . ', ';
echo $seconds . ' second' . ( $seconds > 0 ? 's' : '' );
I'm attempting to convert 7500 seconds to minutes, and then the minutes to hours. If it comes out to 2 hours and 5 minutes, as in this example, I'd like to display it as "2 hours and 5 minutes". If its 2 hours even, I just want it to display "2 hours".
7500 divided by 60 divided by 60 comes out to 2.083 (3 repeated). Why does the % return 0? How can I determine if its hours exactly, or if there are minutes to display?
die("Test: " . ((7500 / 60) / 60) % 1);
For conversion, you can use:
function secondsToWords($seconds)
{
/*** return value ***/
$ret = "";
/*** get the hours ***/
$hours = intval(intval($seconds) / 3600);
if($hours > 0)
{
$ret .= "$hours hours ";
}
/*** get the minutes ***/
$minutes = bcmod((intval($seconds) / 60),60);
if($hours > 0 || $minutes > 0)
{
$ret .= "$minutes minutes ";
}
/*** get the seconds ***/
$seconds = bcmod(intval($seconds),60);
$ret .= "$seconds seconds";
return $ret;
}
echo secondsToWords(7500);
Because that is the modulus operator, which gives the remainder of the division.
You want to use /, the division operator, that returns a float. See here
I've created a nice function for that a while ago. It also does years and months (and anything you'd like) if you want.
Source + examples: http://hotblocks.nl/tests/time_ago.php
Function:
<?php
function time_ago( $f_seconds, $f_size = 2, $f_factor = 1.6 ) {
$units = array(
86400*365.25 => array(' year', ' years'),
86400*30 => array(' month', ' months'),
86400*7 => array(' week', ' weeks'),
86400 => array(' day', ' days'),
3600 => array(' hour', ' hours'),
60 => array(' minute', ' minutes'),
1 => array(' second', ' seconds'),
);
if ( isset($GLOBALS['g_units']) && is_array($GLOBALS['g_units']) ) {
$units = $GLOBALS['g_units'];
}
$timeAgo = array();
$seconds = (int)$f_seconds;
foreach ( $units AS $range => $unit ) {
if ( 1 == $range || $seconds >= $range * $f_factor ) {
is_array($unit) || $unit = array($unit, $unit);
$last = count($timeAgo) == $f_size-1;
$round = $last ? 'round' : 'floor';
$num = $round($seconds / $range);
$timeAgo[] = $num . $unit[(int)(1 != $num)];
if ( $last ) {
break;
}
$seconds -= $num * $range;
}
}
$separator = isset($GLOBALS['g_separator']) ? $GLOBALS['g_separator'] : ', ';
return implode($separator, $timeAgo);
}
?>
That's the way the mod (%) operator works. Every integer is divisible by 1, so
n % 1 = 0
for all integral n.
What are you trying to do with the % operator?
Whatever it is, you probably want to apply it on an integral value, like the number of seconds. It doesn't work for non-integral values; they are promoted to int values before the operator is applied.