Parse and change date format in php

By | May 1, 2009

Parsing dates

Most php applications need to parse dates and convert them to timestamps for example. Parsing is also necessary to convert the date into a more standard format like yyyy-mm-dd which can be stored in a database like mysql.

Mysql database stores dates in the format yyyy-mm-dd like 2009-04-15. However humans are more used to the formats like dd-mm-yyyy or mm-dd-yyyy (e.g. 21-04-2009). So when users are filling out forms they wont enter dates in yyyy-mm-dd format, but in one of the other formats. It is the application's responsibility to convert the date into the iso format and store correctly.

For an application to parse a date correctly, it is important for it to know which format the user is entering the date in. Most good applications would give the user a configuration option to select a format to use. Here are some common examples

dd-mm-yy
dd-mm-yyyy
mm-dd-yy
mm-dd-yyyy

In place of a hyphen user may enter a dot (.) or forward slash (/) for example. So the application needs to manage that as well.

So basically that is the idea behind parsing dates. Now lets have a look at how this can be done in php.

Convert user format to yyyy-mm-dd format

strptime

The strptime function can be used to parse and extract parts of a date according to a given format. Here is a quick example

$format = '%d-%m-%Y';
$date = '25-05-2012';
$parsed = strptime($date , $format);

print_r($parsed);

In the above example the format of the date and the date string is provided and strptime parses it. The output would be an array like this

Array
(
    [tm_sec] => 0
    [tm_min] => 0
    [tm_hour] => 0
    [tm_mday] => 25
    [tm_mon] => 4
    [tm_year] => 112
    [tm_wday] => 5
    [tm_yday] => 145
    [unparsed] => 
)

tm_mday is the day of the date, tm_mon is the month of the date and tm_year is the year of the date minus 1900. So to form our date in standard format we just need to join them back.

$format = '%d-%m-%Y';
$date = '25-05-2012';
$parsed = strptime($date , $format);

if(is_array($parsed))
{
	$y = (int)$parsed['tm_year'] + 1900;
	
	$m = (int)$parsed['tm_mon'] + 1;
	$m = sprintf("%02d", $m);
	
	$d = (int)$parsed['tm_mday'];
	$d = sprintf("%02d", $d);
	
	$iso_date = "$y-$m-$d";
}

echo $iso_date; //outputs 2012-05-25

If strptime fails to parse the date (which would happen if the input date is wrong) then it would return false. This can be used to verify if the date entered by user is a valid date or not. The format used by strptime to specify the date format is similar to the format used by strftime and is different from the format used by the function date().

DateTime::createFromFormat

Php 5.3 onwards there is a useful class called DateTime which has a function createFromFormat that can be used to do the parsing of dates. It has a simpler syntax.

$format = 'd-m-Y';
$date = '25-05-2012';

$date = DateTime::createFromFormat($format , $date);
echo $date->format('Y-m-d');

Simple and quick! The DateTime class has procedural functions too

$format = 'd-m-Y';
$date = '25-05-2012';

$date = date_create_from_format($format, $date);
echo date_format($date, 'Y-m-d');

The php documentation says

Internally, this function calls the strptime() function provided by the system's C library. This function can exhibit noticeably different behaviour across different operating systems. The use of date_parse_from_format(), which does not suffer from these issues, is recommended on PHP 5.3.0 and later.

Check if date is valid

Checking the validity of a date means to check if the values are correct of day, month and year are in correct format or not. The best function to check the validity is checkdate.

The function checkdate takes care of leap years as well. Here is a quick example

list($d,$m,$y) = explode('-', $date);

if(checkdate($m, $d, $y))
{
    return true;
}

checkdate takes years in the range of 1 to 32767. The above approach however has a problem. It assumes the format of the date to be d-m-Y. The format may be different depending on user choice.

Check leap year

Here is a quick function to tell if a year is leap or not

function is_leap($year=NULL) 
{
    return checkdate(2, 29, ($year==NULL)? date('Y'):$year); // true if is a leap year
}

is_leap(); //tells if current year is leap or not
is_leap(2000); //checks if the year 2000 was leap or not

But a small issue with checkdate is that it reports a date like 01-01-2500 to be valid again (which is , as per what checkdate is supposed to do).

DateTime class

The DateTime class can be used to check if a date is valid or not. But there is a twist. The DateTime class would create a valid object of dates like 40-08-2012. For such dates, the object created has a date that matches 40 days from the beginning of the 8th month. So the trick is to convert the date into an object and format it back into the same format as specified and then compare the 2 strings.

Here is an example

/**
	Check if date is valid or not
*/
function is_valid_date($date, $format = 'd-m-Y')
{
	// string -> object -> string
	$ob = date_create_from_format($format, $date);
	$date2 = date_format($ob, $format);

	// compare the strings, if they match, then the date was valid
	if($date2 != $date)
	{
		return false;
	}

	return true;
}

var_dump(is_valid_date('25-02-1903'));
var_dump(is_valid_date('05-02-1903' , 'm-d-Y'));

So for dates like 40-08-2012 the date recreated would be something like 10-09-2012 and it would not match its previous counterpart and hence it can be said that the earlier input date was something invalid.

But the above function lacks flexibility. For example it would report 25-5-2012/d-m-Y as invalid, since the recreated date would look like 25-05-2012 which would not match with 25-5-2012 on doing string comparison.
To fix this you need to compare using multiple formats alternative formats and see if it matches any given format in a given set.

strptime/strftime

The above method of date validation can be done using strptime, strtotime, and strftime together. Here is a quick example

/**
	Check if date is valid or not by using strptime, strtotime, and strftime
*/
function is_valid_date($date, $format = '%d-%m-%Y')
{
	$p = strptime($date , $format);
	if(!$p) return false;
	
	$yyyy_mm_dd = ($p['tm_year'] + 1900) . '-' . ($p['tm_mon'] + 1) . '-' . $p['tm_mday'];
	
	//date recreated
	$date2 = strftime($format, strtotime($yyyy_mm_dd));

	if($date != $date2)
	{
		//not matching, invalid date
		return false;
	}

	//dates match, valid date
	return true;
}

var_dump(is_valid_date('25-02-1903'));	//true
var_dump(is_valid_date('05-02-1903' , '%m-%d-%Y'));	//true
var_dump(is_valid_date('aasas'));	//false

An important thing to remember regarding strtotime is that it is heavily effected by the bit-ness of the system or the integer size. So it will give different results on 32bit and 64bit machines.

Formatting dates

Formatting for mysql

Using strptime to convert a date in dd-mm-yyyy format to yyyy-mm-dd the code could be :

/*
    Convert a dd-mm-yyyy into yyyy-mm-dd for mysql
*/
function dbdate($date) 
{
    $d = strptime($date , '%d-%m-%Y'); #This is the user input format
    if($d)
    {
        $date = ($d['tm_year']+1900).'-'.($d['tm_mon']+1).'-'.$d['tm_mday'];
    }
    else
    {
        $date = '1800-01-01';
    }
    return $date;
}

The above function would convert a date in the format dd-mm-yyyy to yyyy-mm-dd.

$date = "02-04-2006";
$date = dbdate($date);    //$date is now 2006-04-02

Now $date is ready to be inserted in the mysql database

/*
    Give a dd-month-yyyy representation of mysql format yyyy-mm-dd
*/
function showdate($dbdate) 
{
    $stamp = strtotime($dbdate);
    if($stamp)
    {
        return strftime("%d-%b-%Y",$stamp); #This is the user viewing format
    }
    else
    {
        return '';
    }
}

While printing dates in a table for viewing purpose a format like 02-Mar-2010 is easily readable and the above function does the same. It converts 2010-03-02 to 02-Mar-2010.

When entering dates in forms 23-02-2010 is most preferred. The function below will convert a date in yyyy-mm-dd format to dd-mm-yyyy

/*
    Convert yyyy-mm-dd to dd-mm-yyyy
*/
function feeddate($dbdate) 
{
    $stamp = strtotime($dbdate);
    
    if($stamp)
    {
        //This is the user viewing format
        return strftime("%d-%m-%Y" , $stamp);
    }
    else
    {
        return '';
    }
}
About Silver Moon

A Tech Enthusiast, Blogger, Linux Fan and a Software Developer. Writes about Computer hardware, Linux and Open Source software and coding in Python, Php and Javascript. He can be reached at [email protected].

2 Comments

Parse and change date format in php

Leave a Reply

Your email address will not be published. Required fields are marked *