Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@tamvm
Created December 15, 2012 02:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tamvm/4290926 to your computer and use it in GitHub Desktop.
Save tamvm/4290926 to your computer and use it in GitHub Desktop.
Date parser in PHP
<?php
/**
* CDateTimeParser class file
*
* @author Wei Zhuo <weizhuo[at]gamil[dot]com>
* @author Qiang Xue <qiang.xue@gmail.com>
* @author Tomasz Suchanek <tomasz[dot]suchanek[at]gmail[dot]com>
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008-2011 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
/**
* CDateTimeParser converts a date/time string to a UNIX timestamp according to the specified pattern.
*
* The following pattern characters are recognized:
* <pre>
* Pattern | Description
* ----------------------------------------------------
* d | Day of month 1 to 31, no padding
* dd | Day of month 01 to 31, zero leading
* M | Month digit 1 to 12, no padding
* MM | Month digit 01 to 12, zero leading
* MMM | Short textual representation of month, three letters (since version 1.1.11)
* yy | 2 year digit, e.g., 96, 05
* yyyy | 4 year digit, e.g., 2005
* h | Hour in 0 to 23, no padding
* hh | Hour in 00 to 23, zero leading
* H | Hour in 0 to 23, no padding
* HH | Hour in 00 to 23, zero leading
* m | Minutes in 0 to 59, no padding
* mm | Minutes in 00 to 59, zero leading
* s | Seconds in 0 to 59, no padding
* ss | Seconds in 00 to 59, zero leading
* a | AM or PM, case-insensitive (since version 1.1.5)
* ? | matches any character (wildcard) (since version 1.1.11)
* ----------------------------------------------------
* </pre>
* All other characters must appear in the date string at the corresponding positions.
*
* For example, to parse a date string '21/10/2008', use the following:
* <pre>
* $timestamp=CDateTimeParser::parse('21/10/2008','dd/MM/yyyy');
* </pre>
*
* To format a timestamp to a date string, please use {@link CDateFormatter}.
*
* @author Wei Zhuo <weizhuo[at]gmail[dot]com>
* @author Qiang Xue <qiang.xue@gmail.com>
* @version $Id$
* @package system.utils
* @since 1.0
*/
class CDateTimeParser
{
/**
* Converts a date string to a timestamp.
* @param string $value the date string to be parsed
* @param string $pattern the pattern that the date string is following
* @param array $defaults the default values for year, month, day, hour, minute and second.
* The default values will be used in case when the pattern doesn't specify the
* corresponding fields. For example, if the pattern is 'MM/dd/yyyy' and this
* parameter is array('minute'=>0, 'second'=>0), then the actual minute and second
* for the parsing result will take value 0, while the actual hour value will be
* the current hour obtained by date('H'). This parameter has been available since version 1.1.5.
* @return integer timestamp for the date string. False if parsing fails.
*/
public static function parse($value,$pattern='MM/dd/yyyy',$defaults=array())
{
$tokens=self::tokenize($pattern);
$i=0;
$n=strlen($value);
foreach($tokens as $token)
{
switch($token)
{
case 'yyyy':
{
if(($year=self::parseInteger($value,$i,4,4))===false)
return false;
$i+=4;
break;
}
case 'yy':
{
if(($year=self::parseInteger($value,$i,1,2))===false)
return false;
$i+=strlen($year);
break;
}
case 'MMM':
{
if(($month=self::parseShortMonth($value,$i))===false)
return false;
$i+=3;
break;
}
case 'MM':
{
if(($month=self::parseInteger($value,$i,2,2))===false)
return false;
$i+=2;
break;
}
case 'M':
{
if(($month=self::parseInteger($value,$i,1,2))===false)
return false;
$i+=strlen($month);
break;
}
case 'dd':
{
if(($day=self::parseInteger($value,$i,2,2))===false)
return false;
$i+=2;
break;
}
case 'd':
{
if(($day=self::parseInteger($value,$i,1,2))===false)
return false;
$i+=strlen($day);
break;
}
case 'h':
case 'H':
{
if(($hour=self::parseInteger($value,$i,1,2))===false)
return false;
$i+=strlen($hour);
break;
}
case 'hh':
case 'HH':
{
if(($hour=self::parseInteger($value,$i,2,2))===false)
return false;
$i+=2;
break;
}
case 'm':
{
if(($minute=self::parseInteger($value,$i,1,2))===false)
return false;
$i+=strlen($minute);
break;
}
case 'mm':
{
if(($minute=self::parseInteger($value,$i,2,2))===false)
return false;
$i+=2;
break;
}
case 's':
{
if(($second=self::parseInteger($value,$i,1,2))===false)
return false;
$i+=strlen($second);
break;
}
case 'ss':
{
if(($second=self::parseInteger($value,$i,2,2))===false)
return false;
$i+=2;
break;
}
case 'a':
{
if(($ampm=self::parseAmPm($value,$i))===false)
return false;
if(isset($hour))
{
if($hour==12 && $ampm==='am')
$hour=0;
else if($hour<12 && $ampm==='pm')
$hour+=12;
}
$i+=2;
break;
}
default:
{
$tn=strlen($token);
if($i>=$n || ($token{0}!='?' && substr($value,$i,$tn)!==$token))
return false;
$i+=$tn;
break;
}
}
}
if($i<$n)
return false;
if(!isset($year))
$year=isset($defaults['year']) ? $defaults['year'] : date('Y');
if(!isset($month))
$month=isset($defaults['month']) ? $defaults['month'] : date('n');
if(!isset($day))
$day=isset($defaults['day']) ? $defaults['day'] : date('j');
if(strlen($year)===2)
{
if($year>=70)
$year+=1900;
else
$year+=2000;
}
$year=(int)$year;
$month=(int)$month;
$day=(int)$day;
if(
!isset($hour) && !isset($minute) && !isset($second)
&& !isset($defaults['hour']) && !isset($defaults['minute']) && !isset($defaults['second'])
)
$hour=$minute=$second=0;
else
{
if(!isset($hour))
$hour=isset($defaults['hour']) ? $defaults['hour'] : date('H');
if(!isset($minute))
$minute=isset($defaults['minute']) ? $defaults['minute'] : date('i');
if(!isset($second))
$second=isset($defaults['second']) ? $defaults['second'] : date('s');
$hour=(int)$hour;
$minute=(int)$minute;
$second=(int)$second;
}
if(CTimestamp::isValidDate($year,$month,$day) && CTimestamp::isValidTime($hour,$minute,$second))
return CTimestamp::getTimestamp($hour,$minute,$second,$month,$day,$year);
else
return false;
}
/*
* @param string $pattern the pattern that the date string is following
*/
private static function tokenize($pattern)
{
if(!($n=strlen($pattern)))
return array();
$tokens=array();
for($c0=$pattern[0],$start=0,$i=1;$i<$n;++$i)
{
if(($c=$pattern[$i])!==$c0)
{
$tokens[]=substr($pattern,$start,$i-$start);
$c0=$c;
$start=$i;
}
}
$tokens[]=substr($pattern,$start,$n-$start);
return $tokens;
}
/**
* @param string $value the date string to be parsed
* @param integer $offset starting offset
* @param integer $minLength minimum length
* @param integer $maxLength maximum length
*/
protected static function parseInteger($value,$offset,$minLength,$maxLength)
{
for($len=$maxLength;$len>=$minLength;--$len)
{
$v=substr($value,$offset,$len);
if(ctype_digit($v) && strlen($v)>=$minLength)
return $v;
}
return false;
}
/**
* @param string $value the date string to be parsed
* @param integer $offset starting offset
*/
protected static function parseAmPm($value, $offset)
{
$v=strtolower(substr($value,$offset,2));
return $v==='am' || $v==='pm' ? $v : false;
}
/**
* @param string $value the date string to be parsed
* @param integer $offset starting offset
* @since 1.1.11
*/
protected static function parseShortMonth($value, $offset)
{
static $titles=array('jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec');
$v=array_search(strtolower(substr($value,$offset,3)), $titles);
return $v===false ? false : $v+1;
}
}
@tamvm
Copy link
Author

tamvm commented Dec 15, 2012

From Yii

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment