How to parse any date format - php

I'm trying to make something clever in order to parse date in any international format.
On my frontend I use jquery ui as a date picker and each languages has its specific date format.
Fr: d/m/Y
En: m/d/Y
...
OK but now on the php part I have to store those date using the same format (Mysql Y-m-d). I would like to avoid using switch case and stuff like that so I started to look for another alternative.
The best thing I've found is
http://www.php.net/manual/en/datetime.createfromformat.php That function will enable me to parse the dates if I know the format.
For example
$format = 'Y-m-d';
$date = DateTime::createFromFormat($format, '2009-02-15');
Ok so that's a good start but now I'd like to find the standard date format for the current locale.
So I found this :
http://www.php.net/manual/en/intldateformatter.getpattern.php
But I dont really know how to get it to work because I get inconstitent results:
php > $i = new IntlDateFormatter("fr_FR.utf8",IntlDateFormatter::SHORT,IntlDateFormatter::NONE);
php > echo $i->getPattern();
dd/MM/yy
/* correct ! */
but
php > $i = new IntlDateFormatter("en_US.utf8",IntlDateFormatter::SHORT,IntlDateFormatter::NONE);
php > echo $i->getPattern();
M/d/yy /* wtf */
Am I missing something ?
Thanks

There is no "universal date format symbol standard". The symbol "y" could be a 2-digit year, a 4-digit year, or even a 3-letter abbreviated month (highly unlikely), depending on the source.
The formatting symbols for IntlDateFormatter are documented here. As you can see from the documentation, for this implementation, "d" is the date without leading zeros, while "dd" contains the leading zeros. Both "M" and "MM" represent the month with leading zeros. The "yy" is the 2-digit year.
There is enough difference between this and jQuery UI's date format symbols that you'll need a data map to map the IntlDateFormatter format symbols to jQuery UI datepicker format symbols, and vice versa.
Something like this should be sufficient (untested):
// PHP => jQuery
$formatMap = array(
'dd' => 'dd',
'd' => 'd',
'MM' => 'mm',
'M' => 'mm',
'yy' => 'y'
// and so on...
);
Once you have your map set up, you can create your IntlDateFormatter based on locale, convert that format's symbols into jQuery UI date format symbols, and then send the format to the front-end.
When the user posts back the chosen date, you can do the same in reverse to get back to IntlDateFormatter symbols. At that point, you can use a combination of IntlDateFormatter::setPattern() to set the format to MySQL-style, and datefmt_format() (or equivalent) to actually format the posted date.
Hope this helps.

Related

PHP Date Formatting not working wen using date_format()

I have a date field I'm pulling from WordPress, where the default format is:
16/12/2016
Been a while since I played with PHP, but I remember the way to format dates was: echo date_format($date,"[format syntax]");
But when I do
$date = myWPField;
echo date_format($date,"F d, y");
If doesn't display the date.
What am I missing. Has this changed?
Since your date is not an acceptable format in date_create like mm/dd/yy(yy) or mm-dd-yy(yy)
Use php DateTime::createFromFormat function instead this function can detect what format you
(PHP 5 >= 5.3.0, PHP 7)
DateTime::createFromFormat -- date_create_from_format — Parses a time string according to a specified format
$date = '16/12/2016';
$show_date = DateTime::createFromFormat('d/m/Y', $date)->format('F d, y');
Demo
when create data format form string use slash format, it's in the mm/dd/yy(yy) format. So in you code your first 16 is not allowed by default, you have to specify in what format to create from the string.
Note that when you create a new date object using a format with slashes and dashes (eg 02-02-2012 or 02/02/2012) it must be in the mm/dd/yy(yy) or mm-dd-yy(yy) format (rather than british format dd/mm/yy)! Months always before years (the american style) otherwise you'll get an incorrect date and may get an error like the one above (where PHP is crashing on trying to decode a 13th month).

Convert and insert two date formats MYSQL

I'm facing an issue with managinging dates, some dates pass others dont. I want to produce an insertable date for mysql. there are two possible types of post dates
yyyy-mm-dd //should go without conversion
m/d/yyyy // should be converted
I'm using this
$date = $_REQUEST['date'];
$date_regex = '/(0[1-9]|1[012])[- \/.](0[1-9]|[12][0-9]|3[01])[- \/.](19|20)\d\d/';
if(preg_match($date_regex, $date)){
$date = DateTime::createFromFormat('m/d/Y',$date)->format('Y-m-d');}
problems
I realised this regex is failing for dates like
2/5/2013
but has been working for
12/12/2013
so I removed it BUT still
DateTime::createFromFormat('m/d/Y',$date)->format('Y-m-d');
is also failing for m/d/yyyy
This date thing has got my head spinning for the last 6 hours.
In this case, there is no need to use DateTime::createFromFormat because m/d/yyyy is one of the recognized date formats (see "American month, day and year"). Just convert it to a DateTime object and let the constructor handle the format and forget the regex:
$date = $_REQUEST['date'];
$datetime = new DateTime($date);
$datex = $datetime->format('Y-m-d');
The reason DateTime::createFromFormat('m/d/Y',$date) fails for dates like 2/5/2013 is because you are forcing it to be specifically 'm/d/Y' and that date does not fit that pattern. You can see a list of all date formats here. Specifically, m expects there to be a leading zero (like 02), so when you give it one without that, it won't recognize it. Same goes for d. In this case you would have to use n and j respectively. But, like I said, let the constructor do the hard work for you.

Convert javascript date to php date format

I'm using a jQuery datepicker where obviously the date format doesn't match php format.
How could I convert the datepicker format over to php format so that I can output date( $format ) in the same convention defined in the datepicker format. So say I put the format like dd/mm/yyyy, how could I convert that to m/d/o in php? Or if I specified it as d-m-yy, how to convert that to n-j-y?
Basically, wondering how I could convert the allowed date picker formats, regardless of what the letters or the separators are to php.
I've tried using preg_replace, but the issue there is with single and double same letters. dd becomes nn, since it's trying to replace d twice. Could something with regex be used maybe? I'm kind of lost on how the logic to convert would be done.
Edit: My Apologies for a oversight in the details. The js format is literally like dd/mm/yyyy, not the actual date output. What it is, in the CMS, the user defines the format the datepicker uses (dd/mm/yyyy or any other format sequence and separators the datepicker has). The PHP is used to output the current date using that defined format and sequence. I would love to have them define a PHP format and then convert that to the js format. But the powers that be always want things the way they want them - sigh).
Edit#2
Here's a working script up on Codepad, which shows the issue with letters in the format being treated individually and doubled up. mm becomes nn instead of just being m. The rest of the characters are being individualized as well.
http://codepad.org/lBgqVgbs
this is how would approach it:
$date = '13/06/2013';
$date = implode("-",array_reverse(explode("/",$date)));
$time = strtotime($date);
echo date("m-d-Y H:i:s",$time); // or however you want to format
explode the date by /
reverse the order of the array for proper strtotime() format
implode the pieces for our strtotime() string
You'll probably want to use DateTime::createFromFormat, which let's you define how a string is formatted. Then, use the format() function of that object to output the date in the way that you want it.
For example:
date_default_timezone_set('Europe/Berlin'); // or any other timezone - you must set a timezone though
$date = DateTime::createFromFormat('d/m/Y', '20/05/1996');
$formatted_date = $date->format('Y-m-d');
var_dump($formatted_date); // output: string(10) "1996-05-20"
You can use almost all of the same formatting letters as for the regular date() function, but if you need extra ones - for instance 'o', you can use the formatted date for that: $yet_another_date = date('m/d/o', strtotime($formatted_date));
Was actually easier than I thought it would be. I didn't know you could use #var#i. So mixing that into the two arrays and using preg_replace...
$pattern = array( '#mm#i', '#m#i', '#dd#i', '#d#i', '#yyyy#i', '#yy#i' );
$replacement = array( 'm', 'n', 'd', 'j', 'o', 'y' );
$date_format = preg_replace( $pattern, $replacement, $option_format );
Many thanks to those that provided answers to my bumbled question. My apologies.

Create empty date for specific format in PHP

I would like to get date string filled with zeros for specified date format. I want to use it in case when there is no date given by external API.
Example:
define('DATE_FORMAT', 'Y-m-d H:i:s');
[...]
$date = SomeExternalApi::get_date();
// if date is given it's simple
if(!empty($date)){
$date_obj = DateTime::createFromFormat(SomeExternalApi::SOME_DATE_FORMAT, $date_string);
return $date_obj->format(DATE_FORMAT);
}else{
// SO UGLY BELOW! :( How to use DATE_FORMAT in this case?
return '0000-00-00 00:00:00';
}
I don't want to hardcode "zero string" like in example, because when I change DATE_FORMAT I would like to get zeros formatted new way.
Probably there is no simple way to format "zero string" of date, but maybe someone from this great community has better idea? :)
The best answer for my question is: DON'T GO THIS WAY.
You will never need empty date with zeros - it's super uncommon. The only one place where you can find it is database date field - if there is no date, you will get zeros format. But this will be always the same format, so you can define it as constant and condition as string.
Zeros as I asked are BAD because if you send such zeros through some API to any client like mobile app it has no chance to parse it - it will crash the app without catching errors.
Instead of having zeros date presentation use:
[when saving] put empty string in database, you can set date field to empty string and this will become zeros, do it with UPDATE mytable SET date = "" WHERE id = 2; and mytable.date field is MySQL timestamp in this example,
[when getting] you will get zeros with SELECT date FROM mytable WHERE id = 2;, so define it in your code as constant string 0000-00-00 00:00:00 and equal with returning value from db,
[when response of API] if date is empty return false instead of zeros. Mobile app can check if it's false and try to parse it in any other case. It's the best way to keep empty date and is super simple to check in any format by any language. Lot of simpler than trying to parse some strange zeros format.
Generally if I find date by condition like in example I return false and every single client using this API is happy with it:
if(empty($date)){return false;}
Dates and times in PHP are represented with a UNIX timestamp. The range of possible dates this can represent is not capable of representing the timestamp '0000-00-00 00:00:00' on a 32-bit system (it's over 2000 years ago). Also, actually creating a DateTime representing this single timestamp is probably pretty pointless, the values it represents are unchanging.
However, you could do this by defining absolute values for every sensible format character and using strtr() to convert them to their specific values.
Short example using your example input format:
$placeholders = array(
'Y' => '0000',
'm' => '00',
'd' => '00',
'H' => '00',
'i' => '00',
's' => '00'
);
return strtr(DATE_FORMAT, $placeholders);
However, this could start to get messy when you are dealing with the format elements that represent textual elements such as D. Personally I'd probably pick a default format and use that, as your code in the question shows.

parse a date string

I have this string in a post variable
'03/21/2011'
I need to parse it via php and turn it into this format
'2011-03-21'
I am using php and i need this format so i can run this query
SELECT prospect as 'Prospect', company as 'Company', industry as 'Industry', created_at as 'Original Date Submitted', software as 'Software', warm_transfer as 'Warm Transfer', UserName as 'Sales Rep' FROM mercury_leads join user on UserID=user_id WHERE created_at BETWEEN '2011-01-01' AND '2011-03-22'
If you want to handle it in PHP, your best bet is to use the strtotime() function which converts a string into a time that can then be manipulated with the date() function.
So you'd do something like:
$dateStr = date('Y-m-d', strtotime('03/21/2011'));
The nice thing about using strtotime() is that you don't have to worry about the exact format of the string you pass in. As long as it's something semi-reasonable, it'll will convert it.
So it would handle 03/21/2011, 3-21-2011, 03-21-11 without any modifications or special cases.
You can parse it even from mysql
select str_to_date('03/21/2011','%m/%d/%Y')
$date = '03/21/2011';
$timestamp = strtotime($date);
$sqlDate = date('Y-m-d', $timestamp);
That should do what you need.
strtotime
date
$items=explode('/','03/21/2011');
$time=mktime(0,0,0,$items[0],$items[1],$items[2]);
$isodate=date('Y-m-d',$time);
While there are many ways to do this, I think the easiest to understand and apply to all date conversions is:
$date = date_create_from_format('n/d/Y', $date)->format('Y-n-d');
It is explicit and you'll never have to wonder about m/d or d/m, etc.
You can see it here
http://www.codegod.de/WebAppCodeGod/PHP-convert-string-to-date--AID597.aspx
Or use the Date class of PHP 5.3
STR_TO_DATE(created_at, '%m/%d/%Y') as 'Original Date Submitted'.
Answer 1:
You can use something like this
$dateStr = date('Y-m-d', strtotime($someDate));
Con
It is not great for code readability because it does not allow you to explicitly parse a certain format and make that obvious in the code. For instance your code will not be obvious to an outside programmer as to what format $someDate was in since strtotime parses multiple formats.
Pro
However if $someDate is subject to change and you want the code to continue to attempt to normalize various formats this is a great choice
Con
If you the data comes in a format that is not supported. For instance when trying to parse a date in a non-US date format meaning the month and day are switched but the format uses forward slashes (21/04/78) 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.
Answer 2:
To really make your code clear as to which date you are parsing and to validate that the data coming in as using the correct format, I would use date_create_from_format. Here is some code to help:
$server_date_str='06-10-2013 16:00:09';
$server_date_time = DateTime::createFromFormat('d-m-Y H:i:s',$server_date_str);
// check the format
if ( !($server_date_time instanceof DateTime) ) {
$error_array = DateTime::getLastErrors();
throw new Exception( implode(" - ",$error_array['errors']) );
}
//convert DateTime object to Unix time stamp
$server_time = strtotime($server_date_time->format('d-m-Y H:i:s'));
//convert Unix timestamp to date string of the format 2012-10-21
$dateStr = date('Y-m-d', $server_time);
This example is explained in more full detail at this link:
http://boulderapps.co/parse-a-date-by-a-specific-date-format-in-php

Categories