Here's what I've got so far:
/**
* Parse a duration between 2 date/times in seconds
* and to convert that duration into a formatted string
*
* @param integer $time_start start time in seconds
* @param integer $time_end end time in seconds
* @param string $format like the php strftime formatting uses %y %m %w %d %h or %i.
* @param boolean $chop chop off sections that have 0 values
*/
public static function FormatDateDiff($time_start = 0, $time_end = 0, $format = "%s", $chop = false) {
if($time_start > $time_end) list($time_start, $time_end) = array($time_end, $time_start);
list($year_start,$month_start,$day_start) = explode('-',date('Y-m-d',$time_start));
list($year_end,$month_end,$day_end) = explode('-',date('Y-m-d',$time_end));
$years = $year_end - $year_start;
$months = $month_end - $month_start;
$days = $day_start - $day_end;
$weeks = 0;
$hours = 0;
$mins = 0;
$secs = 0;
if(mktime(0,0,0,$month_end,$day_end) < mktime(0,0,0,$month_start,$day_start)) {
$years -= 1;
}
if($days < 0) {
$months -= 1;
$days += 30; // this is an approximation...not sure how to figure this out
}
if($months < 0) $months += 12;
if(strpos($format, '%y')===false) {
$months += $years * 12;
}
if(strpos($format, '%w')!==false) {
$weeks = floor($days/7);
$days %= 7;
}
echo date('Y-m-d',$time_start).' to '.date('Y-m-d',$time_end).": {$years}y {$months}m {$weeks}w {$days}d<br/>";
}
(It's incomplete and inaccurate)
I can't seem to get the math right. Naively dividing it out won't work because of leap years and differing lengths of months.
The logic also needs to change depending on the format string. For example, passing 04-Feb-2010 to 28-Jun-2011 (as unix timestamps) with format string %y year %m month %d day
should output 1 year 4 month 24 day
but if %y year
is omitted then it needs to add 12 months to the month, i.e., output should be 16 month 24 day
.
Should handle times too...but I haven't got to that yet.
None of these date_diff solutions handle weeks. And I don't know how I could hack it into date_diff
, so that's not really a solution for me.
Furthermore, $diff->format
doesn't do what I asked...to give the total months and days if "bigger units" are omitted. Example:
>>> $start = new DateTime('04-Feb-2010')
>>> $end = new DateTime('28-Jun-2011')
>>> $diff = $start->diff($end)
>>> $diff->format('%m months, %d days')
'4 months, 24 days'
Should be 16 months, 24 days
, as I stated earlier. Please stop being so quick to close my question as a dupe before you understand it fully. If the solutions to other questions can be tweaked to solve this, fine, but please explain how, because I don't get it.
To be clear,
%y
is omitted, years should be rolled in the months%m
is omitted, months should be rolled into the days%w
is omitted, weeks should be rolled into the days%h
is omitted, hours should be rolled into minutes%m
is omitted, minutes should be rolled into secondsIf "smaller units" are omitted, the next biggest unit can be rounded or floored where it makes sense.
We can use compareTo() function from Date class to compare the two dates. compareTo() function returns: 0 if both dates are equal. 1 if date1 comes after date2.
Use the strptime(date_str, format) function to convert a date string into a datetime object as per the corresponding format . To get the difference between two dates, subtract date2 from date1.
To find the difference between dates, use the DATEDIFF(datepart, startdate, enddate) function. The datepart argument defines the part of the date/datetime in which you'd like to express the difference. Its value can be year , quarter , month , day , minute , etc.
I don't expect an accepted answer, but here is how to get date_diff to do weeks.
<?php
$january = new DateTime('2010-01-01');
$february = new DateTime('2011-02-20 3:35:28');
$interval = $february->diff($january);
$parts = $interval->format('%y %m %d %h %i %s %a');
$weeks = 0;
list($years, $months, $days, $hours, $minutes, $seconds, $total_days) = explode(' ', $parts);
if ($days >= 7) {
$weeks = (int)($days / 7);
$days %= 7;
}
echo "$years years, $months months, $weeks weeks, $days days, $hours hours, $minutes minutes $seconds seconds";
// 1 years, 1 months, 2 weeks, 5 days, 3 hours, 35 minutes 28 seconds
Maybe with that you can integrate it into your function to do the rolling over and handling the user given format.
If the bigger units aren't given, you can start from the largest unit and apply them back to the next smaller unit. (i.e. 1 year 1 month with no years should add 12 back to months). If "month" isn't included in the format, then you can use the total days to handle the fact that months have different numbers of days.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With