PHP strtotime Limitation

September 20, 2005 | 5 Comments

I have been relying very heavily on strtotime() in PHP in just about everything I write. For those not entirely familiar with this function, strtotime() will "parse about any English textual datetime description into a Unix timestamp." The ones I get most excited about are the MySQL date format: 2005-10-21 or the more common us representation of 3/22/05. Another great use is to put stuff in like "-3 days" or "yesterday".

Why create Unix timestamps you may wonder? Well, there are all kinds of things that happily take timestamps and do fun things with them. My favorite example is the date() function. The first parameter to date is the format you want results in, the second is optionally a Unix timestamp. A call to date like date('m/d/Y'); will generate a reasonably nice US representation of today's date. However, if you did date('m/d/Y',strtotime('3 weeks ago')); you can get the nice readable format provided by date, but for some arbitrary date you are deciding upon with strtotime. Also, knowing strtotime happily accepts the MySQL date format, when you get data back from a table and want to display it to the end user nicely, the same chaining example I just did works again: date('m/d/Y',strtotime($row['date_field']));. For a complete list of the available date formats, visit PHP.net.

Ok, so the title of this makes reference to a limitation... on to that. On some operating systems when running PHP versions < 5.1, a date like 1956-07-11 makes strtotime return -1, which is an error. Unix timestamps start at the epoch, which is January 1, 1970 (1970-01-01). A '-1' passed along to the date function will get you back December 31, 1969 (at 23:59:59) because you are saying 1 second before midnight of the Unix Epoch. (Note: you may also see the date of 1969-12-31 in a case where you have an empty MySQL date of 0000-00-00, which is very common). This is hugely frustrating, but thankfully is resolved in 5.1.

In the meantime, Ed Lecky-Thompson wrote a very useful safestrtotime() function and shared it on PHP.net. I'm reproducing it here for my convenience, altered to match the code formatting I prefer.

PHP:
  1. <?php
  2.  
  3. function safestrtotime($strInput)
  4. {
  5.     $iVal = -1;
  6.     for ($i=1900; $i<=1969; $i++)
  7.     {
  8.         // Check for this year string in date
  9.         $strYear = (string)$i;
  10.         if (!(strpos($strInput, $strYear)===false))
  11.         {
  12.             $replYear = $strYear;
  13.             $yearSkew = 1970 - $i;
  14.             $strInput = str_replace($strYear, '1970', $strInput);
  15.         }
  16.     }
  17.     $iVal = strtotime($strInput);
  18.     if ($yearSkew> 0)
  19.     {
  20.         $numSecs = (60 * 60 * 24 * 365 * $yearSkew);
  21.         $iVal = $iVal - $numSecs;
  22.         $numLeapYears = 0// determine number of leap years in period
  23.         for ($j=$replYear; $j<=1969; $j++)
  24.         {
  25.             $thisYear = $j;
  26.             $isLeapYear = false;
  27.             // Is div by 4?
  28.             if (($thisYear % 4) == 0)
  29.             {
  30.                 $isLeapYear = true;
  31.             }
  32.             // Is div by 100?
  33.             if (($thisYear % 100) == 0)
  34.             {
  35.                 $isLeapYear = false;
  36.             }
  37.             // Is div by 1000?
  38.             if (($thisYear % 1000) == 0)
  39.             {
  40.                 $isLeapYear = true;
  41.             }
  42.             if ($isLeapYear == true)
  43.             {
  44.                 $numLeapYears++;
  45.             }
  46.         }
  47.         $iVal = $iVal - (60 * 60 * 24 * $numLeapYears);
  48.     }
  49.     return $iVal;
  50. }
  51. ?>

1970-01-01, date format, datetime, ed lecky-thompson, epoch, function, mysql, operating systems, php.net, timestamp, timestamps, unix epoch, unix timestamp

Tags: , , , , , , , , , , , ,

Related: