PHP: Calculate Real Differences Between Two Dates or Timestamps

I was using simple function to calculate difference between two dates and timestamps until I noticed, it’s not working correctly in long intervals. It’s very easy to calculate difference between two timestamps in seconds, but it’s much more complicated print difference in human readable format. The Internet can be found in a wide range of ways to do this thing, but as a rule they use a fixed amount of seconds for the year and the month. So if we calculate year with using 365 or 365.25 days and month using 30 or 31 then the difference is not accurate, because of leap years, DST (Daylight Saving Time) and so on.

Because of this problem, I decided to make a function (at least in the short testing) to return the right kind of differences between the UNIX timestamps and dates in human readable format. This function uses PHP strtotime function to calculate real differences and can handle leap years and DST. This function can also return Twitter like about texts with precision parameter.

PHP dateDiff function for calculating real differences between dates and UNIX timestamps

<?php
 
  // Set timezone
  date_default_timezone_set("UTC");
 
  // Time format is UNIX timestamp or
  // PHP strtotime compatible strings
  function dateDiff($time1, $time2, $precision = 6) {
    // If not numeric then convert texts to unix timestamps
    if (!is_int($time1)) {
      $time1 = strtotime($time1);
    }
    if (!is_int($time2)) {
      $time2 = strtotime($time2);
    }
 
    // If time1 is bigger than time2
    // Then swap time1 and time2
    if ($time1 > $time2) {
      $ttime = $time1;
      $time1 = $time2;
      $time2 = $ttime;
    }
 
    // Set up intervals and diffs arrays
    $intervals = array('year','month','day','hour','minute','second');
    $diffs = array();
 
    // Loop thru all intervals
    foreach ($intervals as $interval) {
      // Create temp time from time1 and interval
      $ttime = strtotime('+1 ' . $interval, $time1);
      // Set initial values
      $add = 1;
      $looped = 0;
      // Loop until temp time is smaller than time2
      while ($time2 >= $ttime) {
        // Create new temp time from time1 and interval
        $add++;
        $ttime = strtotime("+" . $add . " " . $interval, $time1);
        $looped++;
      }
 
      $time1 = strtotime("+" . $looped . " " . $interval, $time1);
      $diffs[$interval] = $looped;
    }
 
    $count = 0;
    $times = array();
    // Loop thru all diffs
    foreach ($diffs as $interval => $value) {
      // Break if we have needed precission
      if ($count >= $precision) {
	break;
      }
      // Add value and interval 
      // if value is bigger than 0
      if ($value > 0) {
	// Add s if value is not 1
	if ($value != 1) {
	  $interval .= "s";
	}
	// Add value and interval to times array
	$times[] = $value . " " . $interval;
	$count++;
      }
    }
 
    // Return string with times
    return implode(", ", $times);
  }
 
?>

dateDiff function example usage

strtotime examples:

echo dateDiff("2010-01-26", "2004-01-26") . "\n";
echo dateDiff("2006-04-12 12:30:00", "1987-04-12 12:30:01") . "\n";
echo dateDiff("now", "now +2 months") . "\n";
echo dateDiff("now", "now -6 year -2 months -10 days") . "\n";
echo dateDiff("2009-01-26", "2004-01-26 15:38:11") . "\n";

Output:

6 years
18 years, 11 months, 30 days, 23 hours, 59 minutes, 59 seconds
2 months
6 years, 2 months, 10 days
4 years, 11 months, 30 days, 8 hours, 21 minutes, 49 seconds

UNIX timestamp and precision examples

echo dateDiff(time(), time()-1000000, 1) . "\n";
echo dateDiff(time(), time()-1000000, 3) . "\n";
echo dateDiff(time(), time()-1000000, 6) . "\n";

Output:

11 days
11 days, 13 hours, 46 minutes
11 days, 13 hours, 46 minutes, 40 seconds

Converting text format back to UNIX timestamp example

$time1 = time();
$time2 = $time1-10000000;
echo $diff = dateDiff($time1, $time2) . "\n";
echo $time1 . "\n";
echo strtotime(" +".$diff, $time2) . "\n";

Output:

3 months, 23 days, 17 hours, 46 minutes, 40 seconds
1264514564
1264514564
Follow If Not True Then False Updates!

193 Comments

  1. Hi JR, I able to set the code inside my system. The difference between 2 times display correctly in a table. But the total return the total hour only without ‘days or minute’.. Could you help me figure it out?

    • In a row, the time difference output is ok, but when I total it up outside the while loop it calculate the total difference but not presenting in a correct way, example.

      row 1 = 46 hours, 32 minutes
      row 2 = 32 hours, 28 minutes

      Total = 78

      TQ

      • Hi FM,

        Could you post your code, how you calculate that total value?

        • class TimestampCalc {
          	private $total_seconds;
           
          	public function __construct() {
          		$this->resetTotal();
          	}
           
          	// Reset total time
          	public function resetTotal() {
          		$this->total_seconds = 0;
          	}
           
          	// Time format is UNIX timestamp or
          	// PHP strtotime compatible strings
          	// Returns formatted time
          	public function addTimeDiff($time1, $time2) {
          		// If not numeric then convert texts to unix timestamps
          		if (!is_int($time1)) {
          			$time1 = strtotime($time1);
          		}
          		if (!is_int($time2)) {
          			$time2 = strtotime($time2);
          		}
           
          		// If time1 is bigger than time2
          		// Then swap time1 and time2
          		if ($time1 &gt; $time2) {
          			$ttime = $time1;
          			$time1 = $time2;
          			$time2 = $ttime;
          		}
           
          		$time = ($time2 - $time1);
           
          		$this->total_seconds += $time;
           
          		return $this->formatTime($time);
          	}
           
          	// Returns plain total time
          	public function getPlainTotal() {
          		return $this->total_seconds;
          	}
           
          	// Returns formatted total time
          	public function getFormattedTotal() {
          		return $this->formatTime($this->total_seconds);
          	}
           
          	private function formatTime($total_seconds) {
          		$diffs = array();
          		$diffs['hour'] =  floor ($total_seconds / (60 * 60));
          		// extract minutes
          		$minutes = $total_seconds % (60 * 60);
          		$diffs['minute'] = floor ($minutes / 60);
          		// extract seconds
          		$seconds = $minutes % 60;
              	$diffs['second'] = $seconds % 60;
           
          		$count = 0;
          		$times = array();
          		// Loop thru all diffs
          		foreach ($diffs as $interval => $value) {
          			// Add value and interval 
          			// if value is bigger than 0
          			if ($value &gt; 0) {
          				// Add s if value is not 1
          				if ($value != 1) {
          					$interval .= "s";
          				}
          				// Add value and interval to times array
          				$times[] = $value . " " . $interval;
          				$count++;
          			}
          		}
          		// Return string with times
          		return implode(", ", $times);
          	}
          }
           
          $start = $row['course_in'];
          $end = $row['course_out'];
           
          $tc = new TimestampCalc();
          $formattedTime = $tc->addTimeDiff($start, $end);
           
           
          $total = $total+$formattedTime;
          • Hi FM,

            If you try to get sum of “46 hours, 32 minutes” + “32 hours, 28 minutes” then you get 78, but actually you should calculate total sum first without time formatting and then format time.

            • Hi JR. Thanks for the info. Yes I able to do that.

              • Hi FM,

                You are welcome! Nice to hear that you got it working!

  2. I was finding This type of Date Calculation function using PHP from a Long Time…Thanks A lot for this…

  3. Using the first code the difference between 01/01/2013 and 31/12/2012 shows 43 years

    • Hi Rageesh.PK,

      Date format 31/12/2012 is wrong. Following note from PHP strtotime manual:
      Note:

      Dates in the m/d/y or d-m-y formats are disambiguated by looking at the separator between the various components: if the separator is a slash (/), then the American m/d/y is assumed; whereas if the separator is a dash (-) or a dot (.), then the European d-m-y format is assumed.

      To avoid potential ambiguity, it’s best to use ISO 8601 (YYYY-MM-DD) dates or DateTime::createFromFormat() when possible.

      So you can use following:

      // ISO 8601
      echo dateDiff("2013-01-01", "2012-12-31") . "\n";
       
      // European d-m-y format is assumed
      echo dateDiff("01-01-2013", "31-12-2012") . "\n";
      echo dateDiff("01.01.2013", "31.12.2012") . "\n";
       
      // American m/d/y is assumed
      echo dateDiff("01/01/2013", "12/31/2012") . "\n";

      So 31/12/2012 is not valid date here.

  4. Hi, thanks for share, how can return total days number (2 months+3days = 63days)

    thanks ;)

    • Hi paskuale,

      You are welcome!

      If you can use fixed values then just multiply months with 30 and years with 12 * 30 and so on. If you want exact values then you have to use timestamps / dates (from – to) and this function to get exact values.

  5. I would like to limit the output from this (2 days, 18 hours, 42 minutes, 24 seconds) to only outputting the two longest times. So in the example given, when I echo dateDiff() I would only get 2 day, 18 hours. Once we are down to less than 1 day, then (18 hours, 42 minutes) would be output.

    Is there an easy way to do this in your function?

    • Hi John,

      Actually you can use this dateDiff function directly, when you set precision = 2, like:

        echo dateDiff(time(), time()-39671, 2) . "\n";
        echo dateDiff(time(), time()-111611, 2) . "\n";
        echo dateDiff(time(), time()-3628811, 2) . "\n";
        echo dateDiff(time(), time()-36288011, 2) . "\n";

      Output:

      11 hours, 1 minute
      1 day, 7 hours
      1 month, 11 days
      1 year, 1 month
      

      One additional thing to note, if you test following example:

      echo dateDiff(time(), time()-259201, 2) . "\n";

      Output:

      3 days, 1 second
      

      If you want remove seconds completely then modify intervals array:

      $intervals = array('year','month','day','hour','minute','second');

      To

      $intervals = array('year','month','day','hour','minute');
  6. This is such a useful function! Many thanks :)

  7. hello JR,
    i would like to ask you that how can i use these date functions so that i can use them for my articles publishing .
    like “posted ___ seconds/hours/days/years ago”
    i tried a code but it isn’t working for me.
    plz help me out

    • Hi Shiv,

      This code should work just as you want. So could you tell more about your problem?

      • Hi Mate,I am having an exam in PHP next week.there was a sample question that might come to exam if you can show me how to do that that will be great,
        every time the client submit a number the page will tell them the different between it and the previous number they entered and how many seconds it has been since they submitted the previous number.

        many thanks.

        • Hi sabri,

          Here is one possible solution using text file as data store. This is not polished code, just quickly written ugly code. :)

          <?php
                  $old;
                  $diff_value = null;
                  $diff_seconds = null;
                  $current_time;
           
                  if (isset($_POST['number']) && is_numeric($_POST['number'])) {
                          $file = "/tmp/data.txt";
                          $current_time = time();
                          $old = explode(':', file_get_contents($file));
                          if ($old[0] != "") {
                                  $diff_value = $old[0] - $_POST['number'];
                                  $diff_seconds = $current_time - $old[1];
                          }
                          $str = $_POST['number'] . ":" . $current_time;
           
                          file_put_contents($file, $str);
                  }
          ?>
          <html>
                  <head><title>Show diff</title></head>
                  <body>
                          <form action="" method="post">
                                  <input name="number" type="text" size="12" />
                                  <input name="submit" type="submit" value="Send" />
                          </form>
                          <div style="margin-top:25px;">
                                  <strong>Difference (value):</strong><br />
                                  <?php if ($diff_value !== null) echo $old[0], " - ", $_POST['number'], " = ", $diff_value; ?>
                                  <br /><br />
                                  <strong>Difference (sencods):</strong><br />
                                  <?php if ($diff_seconds !== null) echo $current_time, " - ", $old[1], " = ", $diff_seconds; ?>
                          </div>
                  </body>
          </html>

          If you are using Linux or Mac, then this should work without any modifications, but if you use Windows then check $file location. So copy paste this code somefilename.php and run from your web server.

          • Thank you very much..you save my life

            • You are welcome! :)

              • Hi JR,
                Can you please help me to do this codding,
                Form a page name “numbers,php” which uses sessions to calculate the different between numbers.

                <form name="numbers" method="post" action="numbers"
                enter a number;

                every time the client submit a number the page will tell them the difference between it and the previous
                number they entered and how many seconds it has been since they sumbmittde the previous number.
                write the php code which goes below the form on this page in order to implement the functionality described.

                *check if a session variable named”time”exists and if it doesnt then,
                -create a session”time”and give it a value of the current unix timestamp
                -create $-session [number]and give it a value of 0.

                Locking forward to see your answer.
                thanks

  8. i was wondering how can i write the interval array in norwegian, i tryed it but then my site goes bananas (loading all the time and freezes) :/

    • Hi Kris,

      You have to create separate array for norwegian intervals, because this function uses those english intervals with strtotime function.

      I recommend you to do full mapping with interval names (singular and plural), like:

      $intervals_no['second'] = 'your text';
      $intervals_no['seconds'] = 'your text';
      ...
      $intervals_no['hour'] = 'your text';
      $intervals_no['hours'] = 'your text';
      ...

      Then simply replace following:

      $times[] = $value . " " . $interval;

      with:

      $times[] = $value . " " . $intervals_no[$interval];
  9. I need output below like this way 2013.02.07 8:25:36 how do i do this.

    • Hi Mahesh,

      You can’t display difference between two dates in this format? Or could you explain what you try to do?

  10. I am not getting correct months and days using this function when the start date is 29, 30 or 31 of any month and the end date is 31 May 2013.
    I tried with following dates
    Start: 2012-09-29 End: 2013-05-31 Output: 7 months, 30 days
    Start: 2012-09-30 End: 2013-05-31 Output: 7 months, 29 days
    Start: 2012-09-31 End: 2013-05-31 Output: 7 months, 30 days

    • Hi San,

      If you checked your start dates, then you see that 2012-09-31 is not real date, right?

      And output of 2012-09-29 and 2012-09-30 looks good?

      • Ok, 2012-09-31 is not real date but you see the output is not correct with 2012-09-29 and 2012-09-30.

        Correct output should be following

        Start: 2012-09-28 End: 2013-05-31 Output: 8 months, 3 days //Correct
        Start: 2012-09-29 End: 2013-05-31 Output: 7 months, 30 days //Incorrect
        Correct output should be 8 months 2 days
        Start: 2012-09-30 End: 2013-05-31 Output: 7 months, 29 days //Incorrect
        Correct output should be 8 months 1 day

        • Hi San,

          It take a while to figure out whats happening, but you are exactly right. It’s hard to say that is this even PHP bug, but I can explain you this. If you try following code you will see something interesting:

          <?php
           
          $init_time = strtotime('2012-09-30');
          $time = $init_time;
          for ($i = 1; $i <= 8;$i++) {
                  $time = strtotime("+1 month", $time);
                  echo date('Y-m-d', $time) . "\n";
          }
           
          echo "\n";
           
          $time = $init_time;
          for ($i = 1; $i <= 8;$i++) {
                  $time = mktime(0, 0, 0, date('m', $time)+1, date('d', $time), date('Y', $time));
                  echo date('Y-m-d', $time) . "\n";
          }
           
           
          echo "\n" . date('Y-m-d', strtotime("+8 month", $init_time));
          echo date('Y-m-d', mktime(0, 0, 0, date('m', $init_time)+8, date('d', $init_time), date('Y', $init_time)));

          So both PHP functions strtotime and mktime shows different final values if you add 8 months once or if you add 8 times one month, which is really strange to me, but yes this is the case.

          So I made quickly following replace to interval loop:

              ...
           
              // Loop thru all intervals
              foreach ($intervals as $interval) {
                // Create temp time from time1 and interval
                $ttime = strtotime('+1 ' . $interval, $time1);
                // Set initial values
                $add = 1;
                $looped = 0;
                // Loop until temp time is smaller than time2
                while ($time2 >= $ttime) {
                  // Create new temp time from time1 and interval
                  $add++;
                  $ttime = strtotime("+" . $add . " " . $interval, $time1);
                  $looped++;
                }
           
                $time1 = strtotime("+" . $looped . " " . $interval, $time1);
                $diffs[$interval] = $looped;
              }
           
              ...

          This actually tries every interval until $ttime is more than $time2, and then add needed value to $time1 and move to the next interval and do same thing etc. So if we think your case, this version add 8 months once (when it first try 1,2,3,4,5,6,7) instead adding 8 times one month.

          If you replace “// Loop thru all intervals” loop with this, is it working then as expected? :)

          • Thanks, it seems to be working fine with this change. I am going through a lot more date comparisons at the moment and will come back to you if I notice anything wrong.

  11. Very nice work JR

  12. Nice work…

    But maybe consider making the possibility to get the result in days only, or hours only ….

  13. Hi, I really like this code, it is really good, the only thing I would like to do is to display text when date reached, like for countdown to christmas, when reached display merry christmas. Rather then counting backwards too. Is this possible with this code somehow?

  14. Thank you……for very useful code….:)

  15. I have noticed if you use this class and use two dates that are the same it does not reply correctly. for example.
    $firsttimestamp = ‘1395229055’;
    $secondtimestamp =’1395231544′;

    $date = date(“Y-m-d”, $firsttimestamp) ;
    $time = date(“g:i a”, $firsttimestamp) ;

    $end_date = date(“Y-m-d”,$secondtimestamp) ;
    $end_time = date(“g:i a”,$secondtimestamp) ;

    • Hi Jamie,

      So this function returns 41 minutes, 29 seconds, which is exactly what it should be?

      Difference in seconds 1395231544 – 1395229055 = 2489 seconds.

      41 * 60 = 2460

      2489 – 2460 = 29

      So it’s 41 minutes 29 seconds?

  16. i need output in the format: 0 years, 0 months, 0 days, 15 hours, 0 minutes, 12 seconds
    that is aal the parameters with their values,if their is no value then it should be 0 and the interval name.
    Thanks.

Leave a Comment

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Trackbacks/Pingbacks

  1. php date difference accurate multiformat input and output ideas for design, code and seo - [...] recently came across a very simple solution detailed on the following site, PHP: Calculate Real Differences Between Two Dates …