"Fossies" - the Fresh Open Source Software Archive

Member "yii-1.1.22.bf1d26/framework/utils/CDateTimeParser.php" (16 Jan 2020, 11324 Bytes) of package /linux/www/yii-1.1.22.bf1d26.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) PHP source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "CDateTimeParser.php" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.1.21.733ac5_vs_1.1.22.bf1d26.

    1 <?php
    2 /**
    3  * CDateTimeParser class file
    4  *
    5  * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
    6  * @author Qiang Xue <qiang.xue@gmail.com>
    7  * @author Tomasz Suchanek <tomasz[dot]suchanek[at]gmail[dot]com>
    8  * @link http://www.yiiframework.com/
    9  * @copyright 2008-2013 Yii Software LLC
   10  * @license http://www.yiiframework.com/license/
   11  */
   12 
   13 /**
   14  * CDateTimeParser converts a date/time string to a UNIX timestamp according to the specified pattern.
   15  *
   16  * The following pattern characters are recognized:
   17  * <pre>
   18  * Pattern |      Description
   19  * ----------------------------------------------------
   20  * d       | Day of month 1 to 31, no padding
   21  * dd      | Day of month 01 to 31, zero leading
   22  * M       | Month digit 1 to 12, no padding
   23  * MM      | Month digit 01 to 12, zero leading
   24  * MMM     | Abbreviation representation of month (available since 1.1.11; locale aware since 1.1.13)
   25  * MMMM    | Full name representation (available since 1.1.13; locale aware)
   26  * y       | 4 year digit, e.g., 2005 (available since 1.1.16)
   27  * yy      | 2 year digit, e.g., 96, 05
   28  * yyyy    | 4 year digit, e.g., 2005
   29  * h       | Hour in 0 to 12, no padding
   30  * hh      | Hour in 00 to 12, zero leading
   31  * H       | Hour in 0 to 23, no padding
   32  * HH      | Hour in 00 to 23, zero leading
   33  * m       | Minutes in 0 to 59, no padding
   34  * mm      | Minutes in 00 to 59, zero leading
   35  * s       | Seconds in 0 to 59, no padding
   36  * ss      | Seconds in 00 to 59, zero leading
   37  * a       | AM or PM, case-insensitive (since version 1.1.5)
   38  * ?       | matches any character (wildcard) (since version 1.1.11)
   39  * ----------------------------------------------------
   40  * </pre>
   41  * All other characters must appear in the date string at the corresponding positions.
   42  *
   43  * For example, to parse a date string '21/10/2008', use the following:
   44  * <pre>
   45  * $timestamp=CDateTimeParser::parse('21/10/2008','dd/MM/yyyy');
   46  * </pre>
   47  *
   48  * Locale specific patterns such as MMM and MMMM uses {@link CLocale} for retrieving needed information.
   49  *
   50  * To format a timestamp to a date string, please use {@link CDateFormatter}.
   51  *
   52  * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
   53  * @author Qiang Xue <qiang.xue@gmail.com>
   54  * @package system.utils
   55  * @since 1.0
   56  */
   57 class CDateTimeParser
   58 {
   59     /**
   60      * @var boolean whether 'mbstring' PHP extension available. This static property introduced for
   61      * the better overall performance of the class functionality. Checking 'mbstring' availability
   62      * through static property with predefined status value is much faster than direct calling
   63      * of function_exists('...').
   64      * Intended for internal use only.
   65      * @since 1.1.13
   66      */
   67     private static $_mbstringAvailable;
   68 
   69     /**
   70      * Converts a date string to a timestamp.
   71      * @param string $value the date string to be parsed
   72      * @param string $pattern the pattern that the date string is following
   73      * @param array $defaults the default values for year, month, day, hour, minute and second.
   74      * The default values will be used in case when the pattern doesn't specify the
   75      * corresponding fields. For example, if the pattern is 'MM/dd/yyyy' and this
   76      * parameter is array('minute'=>0, 'second'=>0), then the actual minute and second
   77      * for the parsing result will take value 0, while the actual hour value will be
   78      * the current hour obtained by date('H'). This parameter has been available since version 1.1.5.
   79      * @return integer timestamp for the date string. False if parsing fails.
   80      */
   81     public static function parse($value,$pattern='MM/dd/yyyy',$defaults=array())
   82     {
   83         if(self::$_mbstringAvailable===null)
   84             self::$_mbstringAvailable=extension_loaded('mbstring');
   85 
   86         $tokens=self::tokenize($pattern);
   87         $i=0;
   88         $n=self::$_mbstringAvailable ? mb_strlen($value,Yii::app()->charset) : strlen($value);
   89         foreach($tokens as $token)
   90         {
   91             switch($token)
   92             {
   93                 case 'yyyy':
   94                 case 'y':
   95                 {
   96                     if(($year=self::parseInteger($value,$i,4,4))===false)
   97                         return false;
   98                     $i+=4;
   99                     break;
  100                 }
  101                 case 'yy':
  102                 {
  103                     if(($year=self::parseInteger($value,$i,1,2))===false)
  104                         return false;
  105                     $i+=strlen($year);
  106                     break;
  107                 }
  108                 case 'MMMM':
  109                 {
  110                     $monthName='';
  111                     if(($month=self::parseMonth($value,$i,'wide',$monthName))===false)
  112                         return false;
  113                     $i+=self::$_mbstringAvailable ? mb_strlen($monthName,Yii::app()->charset) : strlen($monthName);
  114                     break;
  115                 }
  116                 case 'MMM':
  117                 {
  118                     $monthName='';
  119                     if(($month=self::parseMonth($value,$i,'abbreviated',$monthName))===false)
  120                         return false;
  121                     $i+=self::$_mbstringAvailable ? mb_strlen($monthName,Yii::app()->charset) : strlen($monthName);
  122                     break;
  123                 }
  124                 case 'MM':
  125                 {
  126                     if(($month=self::parseInteger($value,$i,2,2))===false)
  127                         return false;
  128                     $i+=2;
  129                     break;
  130                 }
  131                 case 'M':
  132                 {
  133                     if(($month=self::parseInteger($value,$i,1,2))===false)
  134                         return false;
  135                     $i+=strlen($month);
  136                     break;
  137                 }
  138                 case 'dd':
  139                 {
  140                     if(($day=self::parseInteger($value,$i,2,2))===false)
  141                         return false;
  142                     $i+=2;
  143                     break;
  144                 }
  145                 case 'd':
  146                 {
  147                     if(($day=self::parseInteger($value,$i,1,2))===false)
  148                         return false;
  149                     $i+=strlen($day);
  150                     break;
  151                 }
  152                 case 'h':
  153                 case 'H':
  154                 {
  155                     if(($hour=self::parseInteger($value,$i,1,2))===false)
  156                         return false;
  157                     $i+=strlen($hour);
  158                     break;
  159                 }
  160                 case 'hh':
  161                 case 'HH':
  162                 {
  163                     if(($hour=self::parseInteger($value,$i,2,2))===false)
  164                         return false;
  165                     $i+=2;
  166                     break;
  167                 }
  168                 case 'm':
  169                 {
  170                     if(($minute=self::parseInteger($value,$i,1,2))===false)
  171                         return false;
  172                     $i+=strlen($minute);
  173                     break;
  174                 }
  175                 case 'mm':
  176                 {
  177                     if(($minute=self::parseInteger($value,$i,2,2))===false)
  178                         return false;
  179                     $i+=2;
  180                     break;
  181                 }
  182                 case 's':
  183                 {
  184                     if(($second=self::parseInteger($value,$i,1,2))===false)
  185                         return false;
  186                     $i+=strlen($second);
  187                     break;
  188                 }
  189                 case 'ss':
  190                 {
  191                     if(($second=self::parseInteger($value,$i,2,2))===false)
  192                         return false;
  193                     $i+=2;
  194                     break;
  195                 }
  196                 case 'a':
  197                 {
  198                     if(($ampm=self::parseAmPm($value,$i))===false)
  199                         return false;
  200                     if(isset($hour))
  201                     {
  202                         if($hour==12 && $ampm==='am')
  203                             $hour=0;
  204                         elseif($hour<12 && $ampm==='pm')
  205                             $hour+=12;
  206                     }
  207                     $i+=2;
  208                     break;
  209                 }
  210                 default:
  211                 {
  212                     $tn=self::$_mbstringAvailable ? mb_strlen($token,Yii::app()->charset) : strlen($token);
  213                     if($i>=$n || ($token[0]!='?' && (self::$_mbstringAvailable ? mb_substr($value,$i,$tn,Yii::app()->charset) : substr($value,$i,$tn))!==$token))
  214                         return false;
  215                     $i+=$tn;
  216                     break;
  217                 }
  218             }
  219         }
  220         if($i<$n)
  221             return false;
  222 
  223         if(!isset($year))
  224             $year=isset($defaults['year']) ? $defaults['year'] : date('Y');
  225         if(!isset($month))
  226             $month=isset($defaults['month']) ? $defaults['month'] : date('n');
  227         if(!isset($day))
  228             $day=isset($defaults['day']) ? $defaults['day'] : date('j');
  229 
  230         if(strlen($year)===2)
  231         {
  232             if($year>=70)
  233                 $year+=1900;
  234             else
  235                 $year+=2000;
  236         }
  237         $year=(int)$year;
  238         $month=(int)$month;
  239         $day=(int)$day;
  240 
  241         if(
  242             !isset($hour) && !isset($minute) && !isset($second)
  243             && !isset($defaults['hour']) && !isset($defaults['minute']) && !isset($defaults['second'])
  244         )
  245             $hour=$minute=$second=0;
  246         else
  247         {
  248             if(!isset($hour))
  249                 $hour=isset($defaults['hour']) ? $defaults['hour'] : date('H');
  250             if(!isset($minute))
  251                 $minute=isset($defaults['minute']) ? $defaults['minute'] : date('i');
  252             if(!isset($second))
  253                 $second=isset($defaults['second']) ? $defaults['second'] : date('s');
  254             $hour=(int)$hour;
  255             $minute=(int)$minute;
  256             $second=(int)$second;
  257         }
  258 
  259         if(CTimestamp::isValidDate($year,$month,$day) && CTimestamp::isValidTime($hour,$minute,$second))
  260             return CTimestamp::getTimestamp($hour,$minute,$second,$month,$day,$year);
  261         else
  262             return false;
  263     }
  264 
  265     /*
  266      * @param string $pattern the pattern that the date string is following
  267      */
  268     private static function tokenize($pattern)
  269     {
  270         if(!($n=self::$_mbstringAvailable ? mb_strlen($pattern,Yii::app()->charset) : strlen($pattern)))
  271             return array();
  272         $tokens=array();
  273         $c0=self::$_mbstringAvailable ? mb_substr($pattern,0,1,Yii::app()->charset) : substr($pattern,0,1);
  274 
  275         for($start=0,$i=1;$i<$n;++$i)
  276         {
  277             $c=self::$_mbstringAvailable ? mb_substr($pattern,$i,1,Yii::app()->charset) : substr($pattern,$i,1);
  278             if($c!==$c0)
  279             {
  280                 $tokens[]=self::$_mbstringAvailable ? mb_substr($pattern,$start,$i-$start,Yii::app()->charset) : substr($pattern,$start,$i-$start);
  281                 $c0=$c;
  282                 $start=$i;
  283             }
  284         }
  285         $tokens[]=self::$_mbstringAvailable ? mb_substr($pattern,$start,$n-$start,Yii::app()->charset) : substr($pattern,$start,$n-$start);
  286         return $tokens;
  287     }
  288 
  289     /**
  290      * @param string $value the date string to be parsed
  291      * @param integer $offset starting offset
  292      * @param integer $minLength minimum length
  293      * @param integer $maxLength maximum length
  294      * @return string parsed integer value
  295      */
  296     protected static function parseInteger($value,$offset,$minLength,$maxLength)
  297     {
  298         for($len=$maxLength;$len>=$minLength;--$len)
  299         {
  300             $v=self::$_mbstringAvailable ? mb_substr($value,$offset,$len,Yii::app()->charset) : substr($value,$offset,$len);
  301             if(ctype_digit($v) && (self::$_mbstringAvailable ? mb_strlen($v,Yii::app()->charset) : strlen($v))>=$minLength)
  302                 return $v;
  303         }
  304         return false;
  305     }
  306 
  307     /**
  308      * @param string $value the date string to be parsed
  309      * @param integer $offset starting offset
  310      * @return string parsed day period value
  311      */
  312     protected static function parseAmPm($value, $offset)
  313     {
  314         $v=strtolower(self::$_mbstringAvailable ? mb_substr($value,$offset,2,Yii::app()->charset) : substr($value,$offset,2));
  315         return $v==='am' || $v==='pm' ? $v : false;
  316     }
  317 
  318     /**
  319      * @param string $value the date string to be parsed.
  320      * @param integer $offset starting offset.
  321      * @param string $width month name width. It can be 'wide', 'abbreviated' or 'narrow'.
  322      * @param string $monthName extracted month name. Passed by reference.
  323      * @return string parsed month name.
  324      * @since 1.1.13
  325      */
  326     protected static function parseMonth($value,$offset,$width,&$monthName)
  327     {
  328         $valueLength=self::$_mbstringAvailable ? mb_strlen($value,Yii::app()->charset) : strlen($value);
  329         for($len=1; $offset+$len<=$valueLength; $len++)
  330         {
  331             $monthName=self::$_mbstringAvailable ? mb_substr($value,$offset,$len,Yii::app()->charset) : substr($value,$offset,$len);
  332             if(!preg_match('/^[\p{L}\p{M}]+$/u',$monthName)) // unicode aware replacement for ctype_alpha($monthName)
  333             {
  334                 $monthName=self::$_mbstringAvailable ? mb_substr($monthName,0,-1,Yii::app()->charset) : substr($monthName,0,-1);
  335                 break;
  336             }
  337         }
  338         $monthName=self::$_mbstringAvailable ? mb_strtolower($monthName,Yii::app()->charset) : strtolower($monthName);
  339 
  340         $monthNames=Yii::app()->getLocale()->getMonthNames($width,false);
  341         foreach($monthNames as $k=>$v)
  342             $monthNames[$k]=rtrim(self::$_mbstringAvailable ? mb_strtolower($v,Yii::app()->charset) : strtolower($v),'.');
  343 
  344         $monthNamesStandAlone=Yii::app()->getLocale()->getMonthNames($width,true);
  345         foreach($monthNamesStandAlone as $k=>$v)
  346             $monthNamesStandAlone[$k]=rtrim(self::$_mbstringAvailable ? mb_strtolower($v,Yii::app()->charset) : strtolower($v),'.');
  347 
  348         if(($v=array_search($monthName,$monthNames))===false && ($v=array_search($monthName,$monthNamesStandAlone))===false)
  349             return false;
  350         return $v;
  351     }
  352 }