I've been using PHP's strtotime() method to accept a date field on a form. I love how powerful it is, in how it will accept "Tomorrow", "Next Thursday", or (supposedly) any date representation and convert it to the Unix timestamp.
It's been working great -- until yesterday. Someone entered "2-4-10" and instead of logging Feb 4th, 2010, it logged April 10, 2002! So it expected Y-M-D instead of M-D-Y.
I thought maybe the problem was just using a 2-digit year, so we tried again with "2-4-2010". That logged April 2nd, 2010! At that point I just don't understand what strtotime() is doing. PHP.net says it expects a US English date format. Why then would it assume D-M-Y?
Is there a way around this? Or do I have to stop using strtotime()?
Note: I just now did a test. When you use slashes instead of hyphen/dashes, it works fine, even with 2/4/10. Why on earth does that matter? And if that's all it is, should I just run str_replace("-", "/", $input) on the form input before passing it to strtotime()?
The - indicates an ISO Date:
03-02-01 => 1. february 2003 (ISO)
01.02.03 => 1. february 2003 (European)
02/01/03 => 1. february 2003 (US)
The behavior of strtotime() is based largely on the GNU date input formats spec. But as powerful as it is, it shouldn't be expected to read minds. Allowing free-form user date input is asking for perpetual trouble.
I had this problem and solved it by doing exactly what you suggested - do a str_replace on the user-entered date to replace the dashes with slashes. This prevents strtotime from using an ISO date and solves the problem.
strtotime is by its very nature fuzzy, so you can't assume that it will always do what you want. If you enter 2010-04-02 then you would expect that to return 2nd April 2010, which is what strottime is trying to do. Running an str_replace from hyphens to slashes might mean that people entering in that format get the wrong date.
If you're running PHP 5.3 or above, consider date_parse_from_format() or for PHP 5.1 and above on Unix consider strptime(). Both functions take a format, so remove potential ambiguity (if you tell users what format you are expecting - if you're running an international site and have a text box labelled date which the user enters 2/4/2010 into then there is no way to know what their intended date is).
Related
Goal: Convert any local date to the according ISO date
My Approach: http://codepad.viper-7.com/XEmnst
strftime("%Y-%m-%d",strtotime($date))";
Upside: Converts a lot of formats really well
Downside / Problem: Converts strings and numbers that are obviously not a date. E.g.
strftime("%Y-%m-%d",strtotime("A")) => 2012-10-29
strftime("%Y-%m-%d",strtotime("1")) => 1970-01-01
Questions:
Is there a better way to identify and convert dates to ISO dates?
Do you know of any library / regex that is capable of do so in php?
PHP's strtotime() function already does a best-effort attempt at taking an arbitrary string and working out what date format it is.
I dislike this function for a number of reasons, but it does do a reasonable job of working things out, given a string of unknown date format as input.
However, even strtotime()'s best efforts can never be enough, because arbitrary date formats are ambiguous.
There is no way to tell whether 05-06-07 is meant to be the 5th of June 2007 or the 6th of May 2007. Or even the 7th June 2005 (yes, some people do write dates like that).
Simple plain truth: It's impossible.
If you want your dates to be reliable in any meaningfuly way, you must abandon the idea that you'll be able to accept arbitrary input formats.
[EDIT]
You say in the comments that the input is coming from a variety of Excel and CSV files.
The only hope you have is if each of those files is consistent in itself. If you know that a file from a given source will have a given input format, you can write a custom wrapper for each file type that you import, and process it for that format. This is a solution I've used myself in the past, and it does work as long as you can predict the format for the file you're processing.
However, if individual files contain unpredictable or ambiguous dates, then you are out of luck: You have an impossible task. The only way you'll avoid having bad data is to kick back to the suppliers of the files and ask them to fix their data.
I think the problems will really arise when faced with dates such as 5-6-2012 when it is unclear whether you are dealing with 5th June, or 6th May and you could be taking input from European countries where DD MM YYYY is the norm.
If you are analyzing just one input field, then you might have a chance of detecting the delimeters and splitting the string up looking for what might look like a real date.
In this case the PHP function checkdate might come in handy as a last ditch double check.
Be aware also that Mysql (if this is where the data is heading) is also quite lenient about what it will put into a DATE field, the delimeters, the absence of leading zeros etc. But still, you have to get the Y M D order correct for it to have a chance.
I suppose the ultimate answer is to disallow free-text input for dates, but give them pickers - but of course you may not be in a position to influence the incoming date ...
I'm creating a mobile version of a website. On the normal version we just use a jquery date picker to select the date. I haven't added anything like this yet on the mobile version because It seemed my Iphone was smart enough to realise it was a date field and give you date scrollers.
But after I've selected the date it's coming up at 7 Aug 2012 which raises a few questions for me... is this standard? or am I going to have to code for different date formats coming from different phones?
Would it be best to use a jquery date picker? (I'm not sure this would be very tidy).
What's the best way to convert a date like this into a format that php and my database can handle. I have done a bit of looking around google but haven't found much as of yet.
Try this
<?php
$today = date('Y-m-d', strtotime('7 Aug 2012'));
echo $today;
?>
gives 2012-08-07
You can change its output by altering Y-m-d in date()
Refer this!
$date = DateTime::createFromFormat('j M Y', '7 Aug 2012'); is the most robust way to do it if you know the format. strtotime guesses which isn't necessarily a good thing, and you won't be informed (i.e. an exception won't be thrown) if the date is in a bad format.
See the manual here: http://www.php.net/manual/en/datetime.createfromformat.php
I don't think the date format is standard. It is very probable that it is affected by the user settings (eg. locale). Eg. if the user defines a Portuguese locale I think the date would be a little bit different.
Using jquery date picker you have the advantage of being able to specify your desired format (applying the dateFormat option). Then you could safely write a PHP script that reads the date in your defined format. You can use PHP's date() function as specified by #Bhuvan Rikka.
Good evŠµning!
echo date('r', strtotime('10.01.11'));
Prints: Sun, 05 Feb 2012 10:01:11
Expected: Mon, 10 Jan 2011 00:00:00
How do I force strtotime() to parse the input string as a date only? I have to convert a bunch of dates in different format. DateTime::format is not an option since I don't know all the formats the script will run into, and it's not even installed on the server (and i don't have privileges to do it).
Tried
strtotime('day 10.01.11'),
strtotime('10.01.11 00:00:00'),
strtotime('10.01.11 midnight')
- nothing worked.
Any help is much appreciated
How do I force strtotime() to parse the input string as a date only?
You don't. strtotime uses very well-defined parsing formats. What it generates will depend entirely on what you give it.
'10.01.11' is parsed as a time format, as it will always interpret three pairs of digits separated by periods as a time. It will recognize dates when separated by dashes, slashes or spaces. Annoyingly, there's an example there on the date format page that uses dots, but there doesn't seem to be a sure-fire way to force date parsing instead of time parsing. Sigh, PHP.
If you need that specific format to be interpreted as a date instead of a time, you have two options.
First, you can use a different date parsing method. If the expected format never changed, you could use DateTime::createFromFormat() or the horrifying strptime. You've indicated in comments that the format will vary and your PHP version is old enough not to have DateTime, so this might not work for you.
Second, you can pre-process the data. At least in this example, a conversion of . to / may do the trick, though 10/01/11 can be ambiguous as a date to humans. There's nothing wrong with a little regex sniffing to determine how to best process data.
There's also a third option: if you're getting this information from users, make your application begin forcing users to enter dates in a normal, consistent, parseable format. It may take some time to train your users to use YYYY-MM-DD, but it's probably the most sane long-term bet.
Is modifying the input an option for you?
$str = '10.01.11';
$str = str_replace('.', '/', $str);
echo date('r', strtotime($str));
However, this will still output Sat, 01 Oct 2011 00:00:00, according to the MM.DD.YY pattern (US standard).
EDIT: Depending on you usage, you might consider creating a list of regex patterns and parse the date accordingly. It is very hard to make a code like this to be open to all possibilities.
Tested, this works:
$date = DateTime::createFromFormat('d.m.y', '10.01.11');
echo $date->format('r');
http://codepad.viper-7.com/OH7Kyn
why don't you add the time set to 00:00:00 by default?
e.g.
echo date('D, d M Y H:i:s', strtotime('10.01.11'));
also strtotime uses the american date format so this will be translated into 1st of october 2011. it's easier to use the iso date format
I don't think strtotime knows how to parse those dates. To avoid potential ambiguity, it's best to use ISO 8601 (YYYY-MM-DD) dates.
I've got a website where users can potentially type in their own dates before they're sent to the server. So I obviously need to parse what they give me and get it into a standard format before actually using it. So I used PHP's strtotime() function, which is pretty forgiving about what it will accept as input.
But I'm also using date.js on the site and its parse() function is pretty good, too. Should I use that on the user input before sending it to the server? Which one is better?
I'll keep strtotime() on the back end for safety, but if date.js is better I'll add that to the client.
(To clarify, I'm expecting mostly American date formats. But should that change, anything that eases that transition is preferred.)
As long as you feel strtotime() is meeting your needs, there isn't a great reason to change it on the client side. However, strtotime() makes a couple of assumptions which you need to stay on top of:
From the strtotime() documentation:
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.
If you are allowing your client to send the date in any format they choose, the above could be a source of confusion. I just tested the dates 5/1/12 and 5-1-12 in date.js, and both were parsed as May 1st, 2012. PHP would interpret the two as May 1st 2012 and Jan 12th 2005(!!) respectively.
echo date("Y-M-n", strtotime("5/1/12"));
// 2012-May-5
echo date("Y-M-n", strtotime("5-1-12"));
// 2005-Jan-1 (whoops!)
However, pre-formatting the date has the obvious benefit of some insurance that the entered date is valid. Keeping strtotime() on the backend also ensures that you don't need a JavaScript-enabled client to send requests. Your PHP could still be called as a web service, etc, without the client needing to be a web browser.
Both.
You absolutely do need to validate the date in PHP, because one or more of your users may have disabled Javascript.
Javascript validation is nice because you can have a date entered in an input control, validate it in the onblur handler, and write the validated date back to the control. So after the user types the date of birth 2/5/01 and leaves the control, the date changes to 2 May 2001 and not only does the user knows that the date is interpreted correctly, but strtotime() also gets an unambiguous value.
You can also use much better validation feedback, from a UX point of view. Javascript can do the following (which is probably well known but it took a bit of searching for me to find it). Put an element in the page, like
<div id="DobReply"></div>;
Then the function which validates the Date of Birth can do
document.getElementById("DobReply").innerHTML = "Current age is "+age;
where age is a variable calculated from the entered date of birth, and today's date. As soon as the user leaves the control, the calculated age pops up, and if the user entered the current year (it happens) then she might spot the error immediately.
So I wouldn't get rid of datejs validation either. But all of this is lost if Javascript is disabled, you can get invalid dates, dates in weird formats, or anything. So if you can only have one, keep the strtotime().
I have a script which is fed dates in numerous different formats.
I want to save these dates as timestamps so they can easily be manipulated/ordered.
When i try an convert a mm-dd-yyyy type date to a timestamp, it fails.
When the script runs, it does not know what format it will be fed, and as such this cannot be specified. Near all other formats of date seem to be converted fine.
Could anyone advise how to fix this, or alternatively an alternative way that all date formats can be converted to an orderable, consistent format that can be manipulated?
Many Thanks
It sees strings with - in them as dd-mm-yyyy and / as mm/dd/yyyy.
See also this question and the comments on the documentation.
Possible solutions / workarounds:
on php 5.3, use date_create_from_format
on older php and not on windows, use strptime
if neither can be used, either replace the - to / when necessary, or use one of the regexes suggested you can find through the linked question.
Note however that at some time you do need to know what the format is to start with. Computers are not mindreaders. They can't, and never will be able to, distinguish between mm-dd-yyyy and dd-mm-yyyy in the overlap ranges (both mm and dd <= 12) if you don't provide the distinction.