Skip Navigation

PHP DateDiff Function

 
Please note: This script was written some time ago and does have quirks and bugs. Several improved versions can be found in the comments on this post.

VBScript's "DateDiff" function is very useful, allowing you to quickly determine time intervals between customer dates. PHP, unfortunately, had no function to perform the same task. Instead, you must rely on a combination of the date() function and it's power and timestamps - not always the most effective way to handle dates and times.

With this in mind, the PHP DateDiff function below is intended to allow you to very quickly make the most of the power of PHP, and give you quick access to time interval functions. It is based upon the VBScript function of the same name, with a couple of small changes.

To use the below, call it like a normal function. There are four arguments. The first determines what you want to measure the date difference in - years, months, quarters, etc - and the allowed values of this are listed in the first few lines of the function. The next two are the dates themselves. Any valid date should work just fine. You can also use timestamps as dates, although if you do, you must set the last of the four arguments to "true". You can call it like so:

echo datediff('w', '9 July 2003', '4 March 2004', false);
Which will tell you the number of weekdays between the 9th July 2003 and the 4th of March 2004.

<?php

function datediff($interval, $datefrom, $dateto, $using_timestamps = false) {
/*
$interval can be:
yyyy - Number of full years
q - Number of full quarters
m - Number of full months
y - Difference between day numbers
(eg 1st Jan 2004 is "1", the first day. 2nd Feb 2003 is "33". The datediff is "-32".)
d - Number of full days
w - Number of full weekdays
ww - Number of full weeks
h - Number of full hours
n - Number of full minutes
s - Number of full seconds (default)
*/

if (!$using_timestamps) {
$datefrom = strtotime($datefrom, 0);
$dateto = strtotime($dateto, 0);
}
$difference = $dateto - $datefrom; // Difference in seconds

switch($interval) {

case 'yyyy': // Number of full years

$years_difference = floor($difference / 31536000);
if (mktime(date("H", $datefrom), date("i", $datefrom), date("s", $datefrom), date("n", $datefrom), date("j", $datefrom), date("Y", $datefrom)+$years_difference) > $dateto) {
$years_difference--;
}
if (mktime(date("H", $dateto), date("i", $dateto), date("s", $dateto), date("n", $dateto), date("j", $dateto), date("Y", $dateto)-($years_difference+1)) > $datefrom) {
$years_difference++;
}
$datediff = $years_difference;
break;

case "q": // Number of full quarters

$quarters_difference = floor($difference / 8035200);
while (mktime(date("H", $datefrom), date("i", $datefrom), date("s", $datefrom), date("n", $datefrom)+($quarters_difference*3), date("j", $dateto), date("Y", $datefrom)) < $dateto) {
$months_difference++;
}
$quarters_difference--;
$datediff = $quarters_difference;
break;

case "m": // Number of full months

$months_difference = floor($difference / 2678400);
while (mktime(date("H", $datefrom), date("i", $datefrom), date("s", $datefrom), date("n", $datefrom)+($months_difference), date("j", $dateto), date("Y", $datefrom)) < $dateto) {
$months_difference++;
}
$months_difference--;
$datediff = $months_difference;
break;

case 'y': // Difference between day numbers

$datediff = date("z", $dateto) - date("z", $datefrom);
break;

case "d": // Number of full days

$datediff = floor($difference / 86400);
break;

case "w": // Number of full weekdays

$days_difference = floor($difference / 86400);
$weeks_difference = floor($days_difference / 7); // Complete weeks
$first_day = date("w", $datefrom);
$days_remainder = floor($days_difference % 7);
$odd_days = $first_day + $days_remainder; // Do we have a Saturday or Sunday in the remainder?
if ($odd_days > 7) { // Sunday
$days_remainder--;
}
if ($odd_days > 6) { // Saturday
$days_remainder--;
}
$datediff = ($weeks_difference * 5) + $days_remainder;
break;

case "ww": // Number of full weeks

$datediff = floor($difference / 604800);
break;

case "h": // Number of full hours

$datediff = floor($difference / 3600);
break;

case "n": // Number of full minutes

$datediff = floor($difference / 60);
break;

default: // Number of full seconds (default)

$datediff = $difference;
break;
}

return $datediff;

}

?>

 

Syndication

If you like this post, subscribe to my full feed or partial feed.

 

51 comments (Add Yours)

You can keep up to date with this discussion by subscribing to the RSS or Atom feed.
 
case "d": // Number of full days
$datediff = floor($difference / 86400);

Very buggy implementation, since day IS NOT a 24 hours (can be also 23 and 25 due to daylight savings).
Using this function can cause +-1 day error.

PEAR::DATE and ADODB::TIME libs have, instead, correct handling of days differences
P.S. The same with weeks/months/quarters/years
mario
Austria #3: October 13, 2004
Your script produces a parse error!
Hmmm, it worked fine for me. What did the error say?
Euth
United States #5: November 1, 2004
I'm having problems with case "w". I am gaining and losing days. Ex:
1 Feb 2004 -> 28 Feb 2004 = 21 weekdays
1 Feb 2004 -> 29 Feb 2004 = 20 weekdays.
The correct answer is actually 20 weekdays for both examples. Very buggy, but I am unsure how to fix it.
Euth
United States #6: November 2, 2004
I wrote my own script for finding weekdays in the current month. It's very straight forward. Not hard to modify to plug in your own dates.

&lt;?
$month = date("M");
$year = date("Y");
$numdays = date("t");
$startdate = "1 ". $month." ".$year;
$enddate = $numdays." ". $month." ".$year;

$start = strtotime($startdate);
$end = strtotime($enddate);

$weekdays = "0";

while ($start &lt;= ($end+3600)) {
if (date("D", $start) != "Sat" &amp;&amp; date("D", $start) != "Sun") {
$weekdays++;
}
$start = ($start+86400);
}
?&gt;
Kipp
United States #7: November 8, 2004
I am having problems getting case 'n' to work. For the datefrom I use something like this (2004-11-08 13:10:04) and for dateto I use something like this (2004-11-08 13:45:37). I have tried using the timestamp set to true and set to false, but all I get returned is 0 (zero). I am just looking for the minute difference. Any suggestions, thanks!
if there would be a function some thing like getting "2 Years 5 Months 3 Days" kind of output, if some one get this function please mail me on this id 'vijaydchauhan@hotmail.com'
ap0c
United Kingdom #9: March 9, 2005
Good code but it does not display differences as negatives. If it did i could use this.
Reginos
United Kingdom #10: March 12, 2005
I am making a booking system for a hotel.Can anyone guide me how to use(if is possible) this function to fit my needs?
Or to give my any other advise...

Thanks
I am using this on another site to calculate ages (peoples) so I only needed the month and year calculations.

One change I made was to use only one date() call for each mktime() call, the functions previously used 6 date() calls per mktime().

eg. for quarters:

$df = explode(',', date("H,i,s,n,j,Y", $datefrom));
while (mktime($df[0], $df[1], $df[2], $df[3] + ($quarters_difference*3), $df[4], $df[5]) < $dateto) {
$months_difference++;
}

Should speed it up a little...
Simon
Australia #12: April 27, 2005
GREAT! Been looking everywhere for a script that can take two dates of the mySQL format [YYYY-MM-DD HH:MM:SS] and return the difference, in whole seconds. Your script seems to work beautifully for me - although I have not tested it for bugs mentioned, such as leapyear stuff, which I don't think apply to me anyways.

Thanks for your code - and for all the other great resources on your site.

I love beer :)
thanks; I was starting to write this bitch for myself and I thought "man, this thing I'm carving looks suspiciously like a wheel."
Osiris
Brazil #14: May 28, 2005
Thanks for posting this function. I have been annoyed by my ISP moving backwards on my MySQL date and I lost DATEDIFF() function in MySQL 4.1.1, so this fits the bill perfectly!
Stefan
Switzerland #15: September 22, 2005
There is a Bug in the "Number of full quarters" calculation.

In the while clause you increment the variable $months_difference. But you should increment $quarters_difference.

Anyway, very nice script.
Thanks so much this helped alot!
kirk
United States #17: November 3, 2005
This implementation is very wrong, especially as someone mentioned with regard to daylight savings time but especially with the difference between dates as shown in months. He used 31 days as the average days per month (='2678400', which itself is wrong since the average per year is 30.5); however, you need to calculate difference in months based on the same date of month to the same date of the next month. For dates whose variance is greater than a few years, this script will produce errors.
Anonymous
United States #18: January 5, 2006
terrible script, there are only 60 seconds in a minute. DO NOT USE THIS SCRIPT.
I might be missing something, but how many seconds would you prefer in a minute?

On a serious note, folks, this script does need updating as there are some problems with it - notably daylight savings and leap years. An update is coming.
NiƱo
Philippines #20: January 19, 2006
Actually I'm going to use it for my simple web application which doesn't take into account DST and leap years :) Hope to make this work. Thanks Dave Child!
Phany
India #21: April 4, 2006
How to find out the minutes difference on same date?
Ex: $datefrom = "Tue Apr 4";
$dateto = "Tue Apr 4";
Hi,

If you just want to count days between 2 unixtime stamps then why not use this:

<?php
function datediff ($start_date, $finish_date)
{
return date ("j", $finish_date) - date("j", $start_date);
}
?>

Thanks.
Karl
Argentina #23: June 12, 2006
Dave: did you finished the last version of this function updated?
I would like to use it, but not sure if it still have any bugs...
Thanks.
Very nice code :D thanks.
Matt Wynn
United Kingdom #25: June 27, 2006
Great code - just what i needed

Thanks!
Nacho
Argentina #26: August 7, 2006
Nice, this is what i was looking for!
Thanks! your site is awesome, great stuff.

Nacho.
I can't believe people are still raving about this buggy script. I guess what they don't know won't hurt them. Right? .... wrong.
Dante
Indonesia #28: November 11, 2006
Thanks for this function. It's very useful for my recent project. I appreciate it so much!

Cheers
Bruce Leister
Australia #29: November 14, 2006
If you make this change, then the daylight saving problems of your local timezone goes away.

$datefrom = strtotime($datefrom.' GMT');
$dateto = strtotime($dateto.' GMT');
Isnt it just a simple thing? Why sounds so complicated!!!
Thank. Your function help-me.
Rod
United States #32: December 14, 2006
good stuff.. thnks! Rod
Sergey Chitalov
Russian Federation #33: January 23, 2007
misprint in a month case (may be in a quarter case too - not tested):
in "while" date("j", $dateto) instead date("j", $datefrom)
working code is:
case "m": // Number of full months
$months_difference = floor($difference / 2678400);
while (mktime(date("H", $datefrom), date("i", $datefrom), date("s", $datefrom), date("n", $datefrom)+($months_difference), date("j", $datefrom), date("Y", $datefrom)) < $dateto)
$months_difference++;
$months_difference--;
$datediff = $months_difference;
break;
Oxygen
Unknown #34: January 25, 2007
This code does NOT copy properly (IE 6). The carriage returns do not copy and must be manually reinserted upon copying into a text editor.
Paula
Unknown #35: January 26, 2007
I'd like to be able to use this code somehow and insert into a calendar all the days inbetween two dates.. for example, the beginning of X week and the end.. so I can fill out every day into the database.. Any clues?
Matt
United States #36: February 7, 2007
This code is unpasteable... probably because the background markup looks ridiculous!
this function works great for me. i just need the seconds feature to create a unique long-id. it also works for my hidden countdown timer, too. thanks!
Oh, great! I've been looking for this function a long time. Thanks for it. Congratulations!
Thanks for this wonderful function. It really helps to find the difference between 2 days. This is a great web site
Ryan D. Hatch
United States #40: April 25, 2007
Please post the most recent version!

I don't have the knowledge or time to read through every comment / code snipet and piece my own function together.

Where can I find the latest (and correct) DateDiff function?

Ryan
prodigel
Romania #41: May 24, 2007
Just do a sql query and capture the result. As you said, why reinvent the wheel
Hi

Looks good! Very useful, good stuff. Good resources here. Thanks much!


G'night
eval
Australia #43: July 19, 2007
This is what exactly i needed!! Thank you very much for sharing it
looking for this script for some time. I found another script here.

http://tinyurl.com/392hn4

but this script just calculate in days.
Tom
Unknown #45: July 27, 2007
would someone be able to apply all of the needed updates and re-release it or just post it in a comment? it would be very helpful
Wreckman
France #46: September 19, 2007
I found the mistake in the number of weekdays case :

It's written :
$weeks_difference = floor($days_difference / 7);

Replace with :
If(abs($days_difference) >= 7) {
$weeks_difference = floor($days_difference / 7);
}
Else {
$weeks_difference = 0;
}
Huu, you don't find somethig more complicated ???
Super Mike
United States #48: February 15, 2008
You know, I don't see why this has to be so complicated. I mean, lest we forget that the strtotime function has the ability to add or subtract any interval of time you want with its first optional parameter. So you could compare differences between dates quite easily with it.

http://us2.php.net/manual/en/function.strtotime.php

It doesn't involve parsing the dates, which consumes precious processor time, and the function runs at C-level for things you would be running at PHP-level with a function like the one used here at ilovejackdaniels.com.
Super Mike
United States #49: February 15, 2008
Check this bad boy out:

function DateComp($sDateA, $sDateB_ForInterval, $sInterval, $bUseTimeStamps = FALSE) {
$sFormat = ($bUseTimeStamps) ? 'Y-m-d H:i:s' : 'Y-m-d';
$sDateA = (($sDateA == '') || (empty($sDateA))) ? gmdate($sFormat) : $sDateA;
$dDateA = strtotime(date($sFormat, strtotime($sDateA)));
$sDateB = $sDateB_ForInterval;
$sDateB = (($sDateB == '') || (empty($sDateB))) ? gmdate($sFormat) : $sDateB;
$dDateB = strtotime(date($sFormat, strtotime($sDateB)));
$dTempDate = strtotime($sInterval, $dDateB);
return ($dTempDate > $dDateA);
}

/*

// USAGE OF DateComp:
$sDBDate = '2007-10-15 23:16:28';
$sCurrDate = gmdate('Y-m-d');
if (DateComp($sDBDate, $sCurrDate, '- 4 months')) {
echo "DB date value is older than 4 months past current date.";
} else {
echo "DB date value is newer than 4 months past current date.";
}
*/
Super Mike
United States #50: February 15, 2008
Meant the previous post to read "4 months prior to current date", not "past current date". But you get the point.
Job
Malaysia #51: May 1, 2008
So long already yet no latest update?

 

Post Your Comment

 
Only the name and comment fields are required.
 

Live Comment Preview

 United States #52: 1 minute ago

Web Design, Development and Marketing