123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799 |
- <?php
- /**
- * sfDateFormat class file.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the BSD License.
- *
- * Copyright(c) 2004 by Qiang Xue. All rights reserved.
- *
- * To contact the author write to {@link mailto:qiang.xue@gmail.com Qiang Xue}
- * The latest version of PRADO can be obtained from:
- * {@link http://prado.sourceforge.net/}
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id: sfDateFormat.class.php 9128 2008-05-21 00:58:19Z Carl.Vondrick $
- * @package symfony
- * @subpackage i18n
- */
- /**
- * sfDateFormat class.
- *
- * The sfDateFormat class allows you to format dates and times with
- * predefined styles in a locale-sensitive manner. Formatting times
- * with the sfDateFormat class is similar to formatting dates.
- *
- * Formatting dates with the sfDateFormat class is a two-step process.
- * First, you create a formatter with the getDateInstance method.
- * Second, you invoke the format method, which returns a string containing
- * the formatted date.
- *
- * DateTime values are formatted using standard or custom patterns stored
- * in the properties of a DateTimeFormatInfo.
- *
- * @author Xiang Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version v1.0, last update on Sat Dec 04 14:10:49 EST 2004
- * @package symfony
- * @subpackage i18n
- */
- class sfDateFormat
- {
- /**
- * A list of tokens and their function call.
- * @var array
- */
- protected $tokens = array(
- 'G' => 'Era',
- 'y' => 'year',
- 'M' => 'mon',
- 'd' => 'mday',
- 'h' => 'Hour12',
- 'H' => 'hours',
- 'm' => 'minutes',
- 's' => 'seconds',
- 'E' => 'wday',
- 'D' => 'yday',
- 'F' => 'DayInMonth',
- 'w' => 'WeekInYear',
- 'W' => 'WeekInMonth',
- 'a' => 'AMPM',
- 'k' => 'HourInDay',
- 'K' => 'HourInAMPM',
- 'z' => 'TimeZone'
- );
- /**
- * A list of methods, to be used by the token function calls.
- * @var array
- */
- protected $methods = array();
- /**
- * The sfDateTimeFormatInfo, containing culture specific patterns and names.
- * @var sfDateTimeFormatInfo
- */
- protected $formatInfo;
- /**
- * Initializes a new sfDateFormat.
- *
- * @param mixed $forrmatInfo either, null, a sfCultureInfo instance, a DateTimeFormatInfo instance, or a locale.
- * @return sfDateFormat instance
- */
- function __construct($formatInfo = null)
- {
- if (is_null($formatInfo))
- {
- $this->formatInfo = sfDateTimeFormatInfo::getInvariantInfo();
- }
- else if ($formatInfo instanceof sfCultureInfo)
- {
- $this->formatInfo = $formatInfo->DateTimeFormat;
- }
- else if ($formatInfo instanceof sfDateTimeFormatInfo)
- {
- $this->formatInfo = $formatInfo;
- }
- else
- {
- $this->formatInfo = sfDateTimeFormatInfo::getInstance($formatInfo);
- }
- $this->methods = get_class_methods($this);
- }
- /**
- * Guesses a date without calling strtotime.
- *
- * @author Olivier Verdier <Olivier.Verdier@gmail.com>
- * @param mixed $time the time as integer or string in strtotime format.
- * @param string $pattern the input pattern; default is sql date or timestamp
- * @return array same array as the getdate function
- */
- public function getDate($time, $pattern = null)
- {
- if (is_null($time))
- {
- return null;
- }
- // if the type is not a php timestamp
- $isString = (string) $time !== (string) (int) $time;
- if ($isString)
- {
- if (!$pattern)
- {
- if (strlen($time) == 10)
- {
- $pattern = 'i';
- }
- else // otherwise, default:
- {
- $pattern = 'I';
- }
- }
- $pattern = $this->getPattern($pattern);
- $tokens = $this->getTokens($pattern);
- $pregPattern = '';
- $matchNames = array();
- foreach ($tokens as $token)
- {
- if ($matchName = $this->getFunctionName($token))
- {
- $pregPattern .= '(\d+)';
- $matchNames[] = $matchName;
- }
- else
- {
- $pregPattern .= '[^\d]+';
- }
- }
- preg_match('@'.$pregPattern.'@', $time, $matches);
- array_shift($matches);
- if (count($matchNames) == count($matches))
- {
- $date = array_combine($matchNames, $matches);
- // guess the date if input with two digits
- if (strlen($date['year']) == 2)
- {
- $date['year'] = date('Y', mktime(0, 0, 0, 1, 1, $date['year']));
- }
- $date = array_map('intval', $date);
- }
- }
- // the last attempt has failed we fall back on the default method
- if (!isset($date))
- {
- if ($isString)
- {
- $numericalTime = @strtotime($time);
- if ($numericalTime === false)
- {
- throw new sfException(sprintf('Impossible to parse date "%s" with format "%s".', $time, $pattern));
- }
- }
- else
- {
- $numericalTime = $time;
- }
- $date = @getdate($numericalTime);
- }
- // we set default values for the time
- foreach (array('hours', 'minutes', 'seconds') as $timeDiv)
- {
- if (!isset($date[$timeDiv]))
- {
- $date[$timeDiv] = 0;
- }
- }
- return $date;
- }
- /**
- * Formats a date according to the pattern.
- *
- * @param mixed $time the time as integer or string in strtotime format.
- * @param string $pattern the pattern
- * @param string $inputPattern the input pattern
- * @param string $charset the charset
- * @return string formatted date time.
- */
- public function format($time, $pattern = 'F', $inputPattern = null, $charset = 'UTF-8')
- {
- $date = $this->getDate($time, $inputPattern);
- if (is_null($pattern))
- {
- $pattern = 'F';
- }
- $pattern = $this->getPattern($pattern);
- $tokens = $this->getTokens($pattern);
- for ($i = 0, $max = count($tokens); $i < $max; $i++)
- {
- $pattern = $tokens[$i];
- if ($pattern{0} == "'" && $pattern{strlen($pattern) - 1} == "'")
- {
- $tokens[$i] = str_replace('``````', '\'', preg_replace('/(^\')|(\'$)/', '', $pattern));
- }
- else if ($pattern == '``````')
- {
- $tokens[$i] = '\'';
- }
- else
- {
- $function = ucfirst($this->getFunctionName($pattern));
- if ($function != null)
- {
- $fName = 'get'.$function;
- if (in_array($fName, $this->methods))
- {
- $tokens[$i] = $this->$fName($date, $pattern);
- }
- else
- {
- throw new sfException(sprintf('Function %s not found.', $function));
- }
- }
- }
- }
- return sfToolkit::I18N_toEncoding(implode('', $tokens), $charset);
- }
- /**
- * For a particular token, get the corresponding function to call.
- *
- * @param string $token token
- * @return mixed the function if good token, null otherwise.
- */
- protected function getFunctionName($token)
- {
- if (isset($this->tokens[$token{0}]))
- {
- return $this->tokens[$token{0}];
- }
- }
- /**
- * Gets the pattern from DateTimeFormatInfo or some predefined patterns.
- * If the $pattern parameter is an array of 2 element, it will assume
- * that the first element is the date, and second the time
- * and try to find an appropriate pattern and apply
- * DateTimeFormatInfo::formatDateTime
- * See the tutorial documentation for futher details on the patterns.
- *
- * @param mixed $pattern a pattern.
- * @return string a pattern.
- * @see DateTimeFormatInfo::formatDateTime()
- */
- public function getPattern($pattern)
- {
- if (is_array($pattern) && count($pattern) == 2)
- {
- return $this->formatInfo->formatDateTime($this->getPattern($pattern[0]), $this->getPattern($pattern[1]));
- }
- switch ($pattern)
- {
- case 'd':
- return $this->formatInfo->ShortDatePattern;
- break;
- case 'D':
- return $this->formatInfo->LongDatePattern;
- break;
- case 'p':
- return $this->formatInfo->MediumDatePattern;
- break;
- case 'P':
- return $this->formatInfo->FullDatePattern;
- break;
- case 't':
- return $this->formatInfo->ShortTimePattern;
- break;
- case 'T':
- return $this->formatInfo->LongTimePattern;
- break;
- case 'q':
- return $this->formatInfo->MediumTimePattern;
- break;
- case 'Q':
- return $this->formatInfo->FullTimePattern;
- break;
- case 'f':
- return $this->formatInfo->formatDateTime($this->formatInfo->LongDatePattern, $this->formatInfo->ShortTimePattern);
- break;
- case 'F':
- return $this->formatInfo->formatDateTime($this->formatInfo->LongDatePattern, $this->formatInfo->LongTimePattern);
- break;
- case 'g':
- return $this->formatInfo->formatDateTime($this->formatInfo->ShortDatePattern, $this->formatInfo->ShortTimePattern);
- break;
- case 'G':
- return $this->formatInfo->formatDateTime($this->formatInfo->ShortDatePattern, $this->formatInfo->LongTimePattern);
- break;
- case 'i':
- return 'yyyy-MM-dd';
- break;
- case 'I':
- return 'yyyy-MM-dd HH:mm:ss';
- break;
- case 'M':
- case 'm':
- return 'MMMM dd';
- break;
- case 'R':
- case 'r':
- return 'EEE, dd MMM yyyy HH:mm:ss';
- break;
- case 's':
- return 'yyyy-MM-ddTHH:mm:ss';
- break;
- case 'u':
- return 'yyyy-MM-dd HH:mm:ss z';
- break;
- case 'U':
- return 'EEEE dd MMMM yyyy HH:mm:ss';
- break;
- case 'Y':
- case 'y':
- return 'yyyy MMMM';
- break;
- default :
- return $pattern;
- }
- }
- /**
- * Returns an easy to parse input pattern
- * yy is replaced by yyyy and h by H
- *
- * @param string $pattern pattern.
- * @return string input pattern
- */
- public function getInputPattern($pattern)
- {
- $pattern = $this->getPattern($pattern);
-
- $pattern = strtr($pattern, array('yyyy' => 'Y', 'h'=>'H', 'z'=>'', 'a'=>''));
- $pattern = strtr($pattern, array('yy'=>'yyyy', 'Y'=>'yyyy'));
-
- return trim($pattern);
- }
- /**
- * Tokenizes the pattern. The tokens are delimited by group of
- * similar characters, e.g. 'aabb' will form 2 tokens of 'aa' and 'bb'.
- * Any substrings, starting and ending with a single quote (')
- * will be treated as a single token.
- *
- * @param string $pattern pattern.
- * @return array string tokens in an array.
- */
- protected function getTokens($pattern)
- {
- $char = null;
- $tokens = array();
- $token = null;
- $text = false;
- for ($i = 0, $max = strlen($pattern); $i < $max; $i++)
- {
- if ($char == null || $pattern{$i} == $char || $text)
- {
- $token .= $pattern{$i};
- }
- else
- {
- $tokens[] = str_replace("''", "'", $token);
- $token = $pattern{$i};
- }
- if ($pattern{$i} == "'" && $text == false)
- {
- $text = true;
- }
- else if ($text && $pattern{$i} == "'" && $char == "'")
- {
- $text = true;
- }
- else if ($text && $char != "'" && $pattern{$i} == "'")
- {
- $text = false;
- }
- $char = $pattern{$i};
- }
- $tokens[] = $token;
- return $tokens;
- }
-
- // makes a unix date from our incomplete $date array
- protected function getUnixDate($date)
- {
- return getdate(mktime($date['hours'], $date['minutes'], $date['seconds'], $date['mon'], $date['mday'], $date['year']));
- }
- /**
- * Gets the year.
- * "yy" will return the last two digits of year.
- * "yyyy" will return the full integer year.
- *
- * @param array $dat getdate format.
- * @param string $pattern a pattern.
- * @return string year
- */
- protected function getYear($date, $pattern = 'yyyy')
- {
- $year = $date['year'];
- switch ($pattern)
- {
- case 'yy':
- return substr($year, 2);
- case 'yyyy':
- return $year;
- default:
- throw new sfException('The pattern for year is either "yy" or "yyyy".');
- }
- }
- /**
- * Gets the month.
- * "M" will return integer 1 through 12
- * "MM" will return the narrow month name, e.g. "J"
- * "MMM" will return the abrreviated month name, e.g. "Jan"
- * "MMMM" will return the month name, e.g. "January"
- *
- * @param array $date getdate format.
- * @param string $pattern a pattern.
- * @return string month name
- */
- protected function getMon($date, $pattern = 'M')
- {
- $month = $date['mon'];
- switch ($pattern)
- {
- case 'M':
- return $month;
- case 'MM':
- return str_pad($month, 2, '0', STR_PAD_LEFT);
- case 'MMM':
- return $this->formatInfo->AbbreviatedMonthNames[$month - 1];
- break;
- case 'MMMM':
- return $this->formatInfo->MonthNames[$month - 1];
- default:
- throw new sfException('The pattern for month is "M", "MM", "MMM", or "MMMM".');
- }
- }
- /**
- * Gets the day of the week.
- * "E" will return integer 0 (for Sunday) through 6 (for Saturday).
- * "EE" will return the narrow day of the week, e.g. "M"
- * "EEE" will return the abrreviated day of the week, e.g. "Mon"
- * "EEEE" will return the day of the week, e.g. "Monday"
- *
- * @param array $date getdate format.
- * @param string $pattern a pattern.
- * @return string day of the week.
- */
- protected function getWday($date, $pattern = 'EEEE')
- {
- // if the $date comes from our home-made get date
- if (!isset($date['wday']))
- {
- $date = $this->getUnixDate($date);
- }
- $day = $date['wday'];
- switch ($pattern)
- {
- case 'E':
- return $day;
- break;
- case 'EE':
- return $this->formatInfo->NarrowDayNames[$day];
- case 'EEE':
- return $this->formatInfo->AbbreviatedDayNames[$day];
- break;
- case 'EEEE':
- return $this->formatInfo->DayNames[$day];
- break;
- default:
- throw new sfException('The pattern for day of the week is "E", "EE", "EEE", or "EEEE".');
- }
- }
- /**
- * Gets the day of the month.
- * "d" for non-padding, "dd" will always return 2 characters.
- *
- * @param array $date getdate format.
- * @param string $pattern a pattern.
- * @return string day of the month
- */
- protected function getMday($date, $pattern = 'd')
- {
- $day = $date['mday'];
- switch ($pattern)
- {
- case 'd':
- return $day;
- case 'dd':
- return str_pad($day, 2, '0', STR_PAD_LEFT);
- case 'dddd':
- return $this->getWday($date);
- default:
- throw new sfException('The pattern for day of the month is "d", "dd" or "dddd".');
- }
- }
- /**
- * Gets the era. i.e. in gregorian, year > 0 is AD, else BC.
- *
- * @todo How to support multiple Eras?, e.g. Japanese.
- * @param array $date getdate format.
- * @param string $pattern a pattern.
- * @return string era
- */
- protected function getEra($date, $pattern = 'G')
- {
- if ($pattern != 'G')
- {
- throw new sfException('The pattern for era is "G".');
- }
- return $this->formatInfo->getEra($date['year'] > 0 ? 1 : 0);
- }
- /**
- * Gets the hours in 24 hour format, i.e. [0-23].
- * "H" for non-padding, "HH" will always return 2 characters.
- *
- * @param array $date getdate format.
- * @param string $pattern a pattern.
- * @return string hours in 24 hour format.
- */
- protected function getHours($date, $pattern = 'H')
- {
- $hour = $date['hours'];
- switch ($pattern)
- {
- case 'H':
- return $hour;
- case 'HH':
- return str_pad($hour, 2, '0', STR_PAD_LEFT);
- default:
- throw new sfException('The pattern for 24 hour format is "H" or "HH".');
- }
- }
- /**
- * Get the AM/PM designator, 12 noon is PM, 12 midnight is AM.
- *
- * @param array $date getdate format.
- * @param string $pattern a pattern.
- * @return string AM or PM designator
- */
- protected function getAMPM($date, $pattern = 'a')
- {
- if ($pattern != 'a')
- {
- throw new sfException('The pattern for AM/PM marker is "a".');
- }
- return $this->formatInfo->AMPMMarkers[intval($date['hours'] / 12)];
- }
- /**
- * Gets the hours in 12 hour format.
- * "h" for non-padding, "hh" will always return 2 characters.
- *
- * @param array $date getdate format.
- * @param string $pattern a pattern.
- * @return string hours in 12 hour format.
- */
- protected function getHour12($date, $pattern = 'h')
- {
- $hour = $date['hours'];
- $hour = ($hour == 12 | $hour == 0) ? 12 : $hour % 12;
- switch ($pattern)
- {
- case 'h':
- return $hour;
- case 'hh':
- return str_pad($hour, 2, '0', STR_PAD_LEFT);
- default:
- throw new sfException('The pattern for 24 hour format is "H" or "HH".');
- }
- }
- /**
- * Gets the minutes.
- * "m" for non-padding, "mm" will always return 2 characters.
- *
- * @param array $date getdate format.
- * @param string $pattern a pattern.
- * @return string minutes.
- */
- protected function getMinutes($date, $pattern = 'm')
- {
- $minutes = $date['minutes'];
- switch ($pattern)
- {
- case 'm':
- return $minutes;
- case 'mm':
- return str_pad($minutes, 2, '0', STR_PAD_LEFT);
- default:
- throw new sfException('The pattern for minutes is "m" or "mm".');
- }
- }
- /**
- * Gets the seconds.
- * "s" for non-padding, "ss" will always return 2 characters.
- *
- * @param array $date getdate format.
- * @param string $pattern a pattern.
- * @return string seconds
- */
- protected function getSeconds($date, $pattern = 's')
- {
- $seconds = $date['seconds'];
- switch ($pattern)
- {
- case 's':
- return $seconds;
- case 'ss':
- return str_pad($seconds, 2, '0', STR_PAD_LEFT);
- default:
- throw new sfException('The pattern for seconds is "s" or "ss".');
- }
- }
- /**
- * Gets the timezone from the server machine.
- *
- * @todo How to get the timezone for a different region?
- * @param array $date getdate format.
- * @param string $pattern a pattern.
- * @return string time zone
- */
- protected function getTimeZone($date, $pattern = 'z')
- {
- if ($pattern != 'z')
- {
- throw new sfException('The pattern for time zone is "z".');
- }
- return @date('T', @mktime($date['hours'], $date['minutes'], $date['seconds'], $date['mon'], $date['mday'], $date['year']));
- }
- /**
- * Gets the day in the year, e.g. [1-366]
- *
- * @param array $date getdate format.
- * @param string $pattern a pattern.
- * @return int hours in AM/PM format.
- */
- protected function getYday($date, $pattern = 'D')
- {
- if ($pattern != 'D')
- {
- throw new sfException('The pattern for day in year is "D".');
- }
- return $date['yday'];
- }
- /**
- * Gets day in the month.
- *
- * @param array $date getdate format.
- * @param string $pattern a pattern.
- * @return int day in month
- */
- protected function getDayInMonth($date, $pattern = 'FF')
- {
- switch ($pattern)
- {
- case 'F':
- return @date('j', @mktime(0, 0, 0, $date['mon'], $date['mday'], $date['year']));
- break;
- case 'FF':
- return @date('d', @mktime(0, 0, 0, $date['mon'], $date['mday'], $date['year']));
- break;
- default:
- throw new sfException('The pattern for day in month is "F" or "FF".');
- }
- }
- /**
- * Gets the week in the year.
- *
- * @param array $date getdate format.
- * @param string $pattern a pattern.
- * @return int week in year
- */
- protected function getWeekInYear($date, $pattern = 'w')
- {
- if ($pattern != 'w')
- {
- throw new sfException('The pattern for week in year is "w".');
- }
- return @date('W', @mktime(0, 0, 0, $date['mon'], $date['mday'], $date['year']));
- }
- /**
- * Gets week in the month.
- *
- * @param array $date getdate format.
- * @param string $pattern a pattern
- * @return int week in month
- */
- protected function getWeekInMonth($date, $pattern = 'W')
- {
- if ($pattern != 'W')
- {
- throw new sfException('The pattern for week in month is "W".');
- }
- return @date('W', @mktime(0, 0, 0, $date['mon'], $date['mday'], $date['year'])) - date('W', mktime(0, 0, 0, $date['mon'], 1, $date['year']));
- }
- /**
- * Gets the hours [1-24].
- *
- * @param array $date getdate format.
- * @param string $pattern a pattern.
- * @return int hours [1-24]
- */
- protected function getHourInDay($date, $pattern = 'k')
- {
- if ($pattern != 'k')
- {
- throw new sfException('The pattern for hour in day is "k".');
- }
- return $date['hours'] + 1;
- }
- /**
- * Gets the hours in AM/PM format, e.g [1-12]
- *
- * @param array $date getdate format.
- * @param string $pattern a pattern.
- * @return int hours in AM/PM format.
- */
- protected function getHourInAMPM($date, $pattern = 'K')
- {
- if ($pattern != 'K')
- {
- throw new sfException('The pattern for hour in AM/PM is "K".');
- }
- return ($date['hours'] + 1) % 12;
- }
- }
|