strtotime result makes no sense, php bug?
Asked Answered
C

3

22

The following line:

echo date('d', strtotime('First Saturday August 2015'));

prints 08, which doesn't seem to make any sense because the first occurrence of a day of the week can't be after the 7th.

Is it a php bug or a php bug or maybe even a php bug? I don't know...

php version: 5.5.19

Coorg answered 29/1, 2015 at 15:30 Comment(1)
Aug 1, 2015 is a Saturday, the first Saturday in August. Aug 8 is the second Saturday.Joliejoliet
I
45

Update #1: explained below the big difference that a simple word like "of" makes, after I investigated a little in the PHP source code.

Update #2: There actually is a documentation page on PHP manual that explains the formats of dates accepted by strftime(). I just was not aware of it until now. Thanks @Outspaced for providing the link in their answer.

For a quick and easy reading skip the section Update #1.


The initial answer:

Indeed,

echo date('Y-m-d', strtotime('First Saturday August 2015'));

prints:

2015-08-08

But

echo date('Y-m-d', strtotime('First Saturday of August 2015'));

prints the correct date:

2015-08-01

Since strtotime() tries to "understand" English, I guess you and it speak different dialects :-)

Update #1:

After some reading in the PHP source code of function strtotime(), I think that it parses First Saturday August 2015 as First Saturday followed by August 2015.

August 2015 is an absolute expression and because there is no indication about the day it produces 2015-08-01 (the 1st of August 2015) which is a reasonable guess (the only one possible, I think).

First Saturday is a relative expression. It is relative to an absolute mark provided in the string (August 2015) or as a second parameter of strtotime() and it "shifts" the timestamp of the absolute mark back or forward with some amount.

Putting them together, strtotime() interprets First Saturday August 2015 as First Saturday counting since August 1, 2015 and that is, indeed, August 8, 2015.

On the other hand, First Saturday of August 2015 is parsed using a different rule. One of next, last, previous, this or any ordinal number from first to twelfth, followed by a weekday name (full or abbreviated) and followed by of is parsed as a weekday of the provided month (or the current month if none is provided in the string).

Update #2

After I found out that the format of the string accepted by strtotime() is actually explained in the PHP documentation, the explanation became more simple. Take a look at the second "Note:" box in the documentation page.

First Saturday August 2015 is explained at item #4 in the note:

"ordinal dayname" does advance to another day.

First Saturday of August 2015 is explained at item #6 of the note:

"ordinal dayname 'of'" does not advance to another day.

The note ends with an entire block of explanation dedicated to the magical word "of".

Inductance answered 29/1, 2015 at 15:35 Comment(14)
It's interesting that echo date('Y-m-d', strtotime('Saturday August 2015')); also prints the correct date.Inductance
Well, I am not a native speaker so maybe that's the problem. ;) Thank you very much!Aardwolf
I'm not a native speaker either and the part regarding the dialect was just a joke ;-) PHP doesn't understand English, that function follows a set of rules to parse the dates. There are lots of rules, maybe that's why they are not described in the documentation.Inductance
After a quick investigation in the PHP source code of strtotime() I updated the answer with an explanation of the difference between the two expressions (with and without that troublesome of).Inductance
This is why php's strtotime is both amazing and terrible at the same timeErida
Great explanation of how the function works. Now if only someone could try to make some explanation (I don't think they can) about why someone would trust the function to resolve whatever a user gives it. As we can see by your explanation, there is already at least one case where the result of an expression is not intuitive.Vitkun
@BrianWarshaw what? No. The results are always consistent and reliable. It's very easy to make mistakes, but that's what you get for using PHP I guessErida
@Erida If the best answer for this post requires this length (and several updates), I would argue that the result was not obvious for the expression. The question becomes "what normal human being [who knows nothing of PHP or functions or magic words] would expect the given expression to produce the given output?" I'm willing to bet that the answer to that question is "very few, if any".Vitkun
@Erida and my overall point is not that one shouldn't use the function at all, but rather that the one who uses it should do some type of normalization of the input data rather than blindly feeding whatever the user types into the function.Vitkun
@BrianWarshaw php doesn't work on the user end, there's no need to think about the "normal human being". You just need to learn to use the function (or, uh, you know, stop using php altogether)Erida
@Erida I know php doesn't work on the user end. But the only possible reason that input data would/should look like it does in this question is because a user entered it that way. If the argument passed to the function isn't coming from user input, then there's no reason to use such an ambiguous format in the first place.Vitkun
@BrianWarshaw "the only possible reason [...] a user entered it" - that's a (most probably incorrect) assumption you made based on nothingErida
If the input string isn't coming from a user, why employ an algorithm that requires string parsing in the first place? At some point, after parsing the string input, it is going to have to calculate the date by translating the parts of the string to non-string data types and work through some flow control to determine which translated parts are used to calculate the parts of the date. If the programmer already knows the idea that he/she is trying to express, then why incur the cost of translating from a string intermediary in the first place?Vitkun
@BrianWarshaw (regarding "why incur the cost of translating from a string intermediary?") Because it's easier to write $date = strtotime('First Saturday of August 2015'); than $ts = mktime(0, 0, 0, 8, 1, 2015); $date = $ts + 86400 * (6 - date('w', $ts)); and furthermore, it's easier to read and understand :-) Let's recall that PHP started as a tool whose aim was to make the coding of web pages an easy task.Inductance
L
12

You need an 'of':

date('d/m/Y', strtotime('First Saturday of August 2015'))

see the manual: http://docs.php.net/manual/en/datetime.formats.relative.php

Lachish answered 29/1, 2015 at 15:34 Comment(0)
V
-3

As stated, PHP didn't quite understand your choice of dialect. If you plan on accepting varied input from your users (not a bad idea) to express a date, I suggest doing some normalization of that user input yourself so that you can submit a predictable format to strtotime.

Vitkun answered 29/1, 2015 at 15:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.