Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

strtotime() considered harmful?

It seems like a lot of people struggle with date/time issues in PHP, and inevitably, many of the accepted answers tend to be "Use strtotime in this way."

Is this really the best way to direct people dealing with date problems? I'm beginning to feel like strtotime is sort of a nifty trick that shouldn't necessarily be relied on for important date/time calculations, and by the nature of it taking arbitrary strings, it seems like a potential source of buggy, hard-to-predict behavior. Its inability to differentiate between MM/DD/YYYY and DD/MM/YYYY is sort of a big deal, no?

StackOverflow is usually very good at promoting good practices (I rarely see a mysql_real_escape_string conversation that doesn't have someone say "Use PDO instead.")

But there doesn't seem to be an accepted norm around date issues in PHP, with a lot of people falling back on the crutch that is strtotime.

So, what should we be doing about this, if anything at all? Is there a better norm we should be enforcing for people asking questions like "How do I add 1 week to X", or "How do I convert this date format to this other date format?"

What is the best, most reliable way to deal with Date/Time issues like strtotime tries to, but too often fails to?

like image 566
Yahel Avatar asked Mar 13 '11 03:03

Yahel


3 Answers

I'll start off by saying that I am a big advocate for using the DateTime object, which allows you to use the DateTime::createFromFormat() function. The DateTime object makes the code much more readable and avoids the need to do the whole Unix timestamp modification using 60 * 60 * 24 to advance the date days.

That being said, the arbitrary string that strtotime() takes is not very hard to predict. Supported Date and Time Formats lists the formats that are supported.

As per your example of not being able to differentiate between MM/DD/YYYY and DD/MM/YYYY it does differentiate based on the Date Formats. Dates that use slashes are always read as American format. So a date in the format 00/00/0000 will always be read as MM/DD/YYYY. Alternatively using dashes or periods will be DMY. e.g. 00-00-0000 will always be read as DD-MM-YYYY.

Here are some examples:

<?php
$dates = array(
    // MM DD YYYY
    '11/12/2013' => strtotime('2013-11-12'),
    // Using 0 goes to the previous month
    '0/12/2013' => strtotime('2012-12-12'), 
    // 31st of November (30 days) goes to 1st December
    '11/31/2013' => strtotime('2013-12-01'), 
    // There isn't a 25th month... expect false
    '25/12/2013' => false,

    // DD MM YYYY
    '11-12-2013' => strtotime('2013-12-11'),
    '11.12.2013' => strtotime('2013-12-11'),
    '31.12.2013' => strtotime('2013-12-31'),
    // There isn't a 25th month expect false
    '12.25.2013' => false,
);

foreach($dates as $date => $expected) {
    assert(strtotime($date) == $expected);
}

As you can see a couple of key examples are 25/12/2013 and 12.25.2013 which would both be valid if read the with the opposite format, however they return false as they are invalid according the the Suported Date and Time Formats...

So as you can see the behaviour is quite predictable. As always if you are receiving a date from use input you should be validating that input first. No method will work if you are not validating the input first.

If you want to be very specific about the date being read, or the format you are being given isn't a supported format, then I recommend using DateTime::createFromFormat().

like image 120
Jacob Avatar answered Nov 16 '22 20:11

Jacob


strtotime() is suggested because it's been in PHP since the v4.x days, so is basically guaranteed to be available. Availability trumps the odd time (no pun intended) that it'll turn around and bite you in the butt with a mis-parsed date.

The current "proper" way to do date math would be using the DateTime/DateInterval objects, but those are more recent additions to PHP (5.2/5.3, I think) and therefore not always available - there's plenty of hosts out there still on 4.x.

like image 8
Marc B Avatar answered Nov 16 '22 19:11

Marc B


I use strtotime() frequently. Thing is, you shouldn't use it as a crutch, but you should be aware of its limitations.

If you wanted to enforce a standard, then I suppose you should go with the c-based mktime(). For instance, to get 1 week later:

date('Y-m-d', mktime(0, 0, 0, date('n'), date('j') + 7);
like image 2
Explosion Pills Avatar answered Nov 16 '22 18:11

Explosion Pills