6

I'm trying to understand the following behavior of the date function strtotime():

  • strtotime(1420066800) returns false, as expected.
  • strtotime(1451602800) returns 26197048320! But expected false as 1451602800 is not a valid date and time format. (same thing with new DateTime(1451602800) as well)

I read the whole Supported Date and Time Formats page, but didn't find any match for this input.

By the way, these are timestamps of 2015-01-01 and 2016-01-01 relatively.

Any insights will be appreciated.

Update:
Different versions test results:

PHP 5.1.6  => false
PHP 5.2.17 => 26197048320
PHP 5.3.29 => 26197048320
PHP 5.4.34 => 26197048320
PHP 5.5.18 => 26197048320
PHP 5.6.2  => 26197048320
PHP 5.6.17 => 26197048320
PHP 7.0.2  => 26197048320

Running on Mac OS X 10.11.3

Slavik Meltser
  • 9,712
  • 3
  • 47
  • 48
  • 2
    both return `false` for me – Guiroux Feb 25 '16 at 16:23
  • Tested with PHP v7.0.2 – Slavik Meltser Feb 25 '16 at 16:24
  • If you use PHP 7 why not use OOP ? You have `DateTime` class to this purposes, and you don't need to use never more the procedural functions – Marcos Pérez Gude Feb 25 '16 at 16:41
  • Great question and great answers. I tested too on 7.0.2 and get the same result what OP get. – Alive to die - Anant Feb 25 '16 at 16:42
  • 1
    @MarcosPérezGude the `DateTime` class internally uses the same code as `strtotime()` to [parse the string](http://php.net/manual/en/datetime.formats.php) provided as first argument to its constructor. The problem and the outcome is the same. – axiac Feb 25 '16 at 16:48
  • @axiac I'm not agree while I can't see the proof of what you said. Where did you see the same code of the parser? I think that `This section describes all the different formats that the strtotime(), DateTime and date_create() parser understands.` doesn't means that's the same code. However, it's better to use classes instead of functions if you start to coding in PHP 7. PHP people wants to improve the language image, to avoid java developers said php is a crap (due this kind of reasons) – Marcos Pérez Gude Feb 25 '16 at 17:07
  • 1
    @MarcosPérezGude First of all, JAVA sucks! :-) Second, I agree with you that using OOP is better practice, but this particular script is not a part of an application, but something small and dirty. In this case, I can say that's why I like PHP, because I can write fast and dirty script and in most of the cases it will be reliable and fast. But when I write an application, I have strict rules of "law and order" and also apply the best of Design Patterns as possible. – Slavik Meltser Feb 25 '16 at 17:15
  • Ok, @SlavikMe I agree with you in all your comment's said. And java sucks it's a reality but don't tell that to a java developer, he can make a java toy gun and trigger a toy bullet in your head. Be carefull!! LOL (I work with lots of java developers that make jokes with me because I'm php/javascript developer. I laugh when a tomcat doesn't start due a missing semicolon, or the performance of a webpage with one form that loads in 15 seconds. I love php for the easy-to-learn and fast-to-run) – Marcos Pérez Gude Feb 25 '16 at 17:24
  • 2
    @MarcosPérezGude It doesn't make much sense to write a different parser for `DateTime` that supports the same formats as `strtotime()` supports, don't you think? If you need a solid proof then feel free to check the [source code of PHP](https://github.com/php/php-src). Search for function `timelib_strtotime()` (it implements the parsing) in file [`ext/date/php_date.c`](https://github.com/php/php-src/blob/master/ext/date/php_date.c). You will find it called by `strtotime()`, indirectly by `DateTime::__construct()`, by `date_parse()`, by `DateInterval::createFromDateString()` and some others. – axiac Feb 25 '16 at 17:34
  • @axiac that's a big great explanation. Now I'm trust in you sightless :) Thank you!! – Marcos Pérez Gude Feb 25 '16 at 17:36

2 Answers2

6

Let's start with the right way to do it. If you want to pass a timestamp to strtotime you have to prefix it with '@'. It is explained on the Compound Formats page, under "Localized notations" -> "Unix Timestamp".

echo(date('r', strtotime('@1420066800'))."\n");
echo(date('r', strtotime('@1451602800'))."\n");

The output is:

Thu, 01 Jan 2015 01:00:00 +0200
Fri, 01 Jan 2016 01:00:00 +0200

Now, why strtotime() returns false for 1420066800 and 26197048320 for 1451602800?

It expects to receive a string and if it receives a number it doesn't care and converts it to string first. Then it follows some rules and tries to identify the date components into the string. Because neither '1420066800' nor '1451602800' contains any separator for components, it probably tries to guess the order of components.

Today, 2016-02-25, strtotime('1451602800') produces a timestamp that, converted to a printable date looks like: 'Fri, 25 Feb 2800 14:52:00 +0200'

It makes me think it interprets the input string as follows: 14:51:60 is the time, 2800 is the year, the other components (day, month) are initialized from the current time.

The documentation says:

The function expects to be given a string containing an English date format and will try to parse that format into a Unix timestamp (the number of seconds since January 1 1970 00:00:00 UTC), relative to the timestamp given in $now, or the current time if $now is not supplied.

Since the "date" you provide doesn't follow any valid date-time format, strtotime() is free to return any value. It is called "garbage in, garbage out".

axiac
  • 68,258
  • 9
  • 99
  • 134
  • Thanks for the explanation. I didn't try to parse the value as a timestamp, but expected to receive an error in order to handle it differently. – Slavik Meltser Feb 25 '16 at 16:48
  • How do you explain the version difference? on PHP 5.1.6 it returns `false` as expected. – Slavik Meltser Feb 25 '16 at 16:49
  • @SlavikMe I don't know, they probably added more formats and attempts to extract something from the given input. See the [changelog](http://php.net/manual/en/function.strtotime.php#refsect1-function.strtotime-changelog) of the function; its behaviour changed a lot, there were bugs and fixes because of code additions and improvements between PHP 5.0 and PHP 5.3. I remember the `DateTime` class also had a lot of improvements, behaviour changes and bug fixes in the same interval of versions. – axiac Feb 25 '16 at 16:58
  • @SlavikMe regarding the error you expect, I think you can use [`is_numeric()`](http://php.net/manual/en/function.is-numeric.php) to make a first decision about how to handle the value. A non-numeric value is probably a date; pass it to `strtotime()` and hope it will parse it correctly. A numeric value is probably a timestamp. Either compare it with a hardcoded timestamp or convert it to a date (using `DateTime` f.e.) then check its value against an interval of valid dates; pick the way that suits your application better. – axiac Feb 25 '16 at 17:02
  • @axiac that is exactly what I've done, I just wanted to improve it a bit, and found out this strange bug. Anyway, thanks for the help! – Slavik Meltser Feb 25 '16 at 17:12
4

1451602800 gives a timestamp of 2800-02-25 14:52:00; and is being interpreted as:

1451602800
------
  ^
14:51:60 (or 14:52) time

today in the year

1451602800
      ----
       ^
      2800

but only on 64-bit systems that can handle that date range

Mark Baker
  • 209,507
  • 32
  • 346
  • 385
  • If you are right, then it should have been able to convert the `strtotime(1420066800)` same way to date `6800-02-25 14:20:06`, but it didn't. How do you explain it? IMHO it's a bug rather than a feature. – Slavik Meltser Feb 25 '16 at 16:51
  • 1
    The year 6800 is likely to be outside the year range.... and yes, it almost certainly is a bug rather than a feature – Mark Baker Feb 25 '16 at 16:52