PageRenderTime 49ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/yii/framework/i18n/CDateFormatter.php

https://github.com/ashie1287/headfirst
PHP | 538 lines | 468 code | 8 blank | 62 comment | 31 complexity | e526fbca9c1dd0a552c54d4b1c4676aa MD5 | raw file
Possible License(s): BSD-2-Clause, BSD-3-Clause, LGPL-2.1
  1. <?php
  2. /**
  3. * CDateFormatter class file.
  4. *
  5. * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
  6. * @author Qiang Xue <qiang.xue@gmail.com>
  7. * @link http://www.yiiframework.com/
  8. * @copyright Copyright &copy; 2008-2010 Yii Software LLC
  9. * @license http://www.yiiframework.com/license/
  10. */
  11. /**
  12. * CDateFormatter provides date/time localization functionalities.
  13. *
  14. * CDateFormatter allows you to format dates and times in a locale-sensitive manner.
  15. * Patterns are interpretted in the locale that the CDateFormatter instance
  16. * is associated with. For example, month names and weekday names may vary
  17. * under different locales, which yields different formatting results.
  18. * The patterns that CDateFormatter recognizes are as defined in
  19. * {@link http://www.unicode.org/reports/tr35/#Date_Format_Patterns CLDR}.
  20. *
  21. * CDateFormatter supports predefined patterns as well as customized ones:
  22. * <ul>
  23. * <li>The method {@link formatDateTime()} formats date or time or both using
  24. * predefined patterns which include 'full', 'long', 'medium' (default) and 'short'.</li>
  25. * <li>The method {@link format()} formats datetime using the specified pattern.
  26. * See {@link http://www.unicode.org/reports/tr35/#Date_Format_Patterns} for
  27. * details about the recognized pattern characters.</li>
  28. * </ul>
  29. *
  30. * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
  31. * @author Qiang Xue <qiang.xue@gmail.com>
  32. * @version $Id: CDateFormatter.php 2408 2010-09-01 18:45:30Z qiang.xue $
  33. * @package system.i18n
  34. * @since 1.0
  35. */
  36. class CDateFormatter extends CComponent
  37. {
  38. /**
  39. * @var array pattern characters mapping to the corresponding translator methods
  40. */
  41. private static $_formatters=array(
  42. 'G'=>'formatEra',
  43. 'y'=>'formatYear',
  44. 'M'=>'formatMonth',
  45. 'L'=>'formatMonth',
  46. 'd'=>'formatDay',
  47. 'h'=>'formatHour12',
  48. 'H'=>'formatHour24',
  49. 'm'=>'formatMinutes',
  50. 's'=>'formatSeconds',
  51. 'E'=>'formatDayInWeek',
  52. 'c'=>'formatDayInWeek',
  53. 'e'=>'formatDayInWeek',
  54. 'D'=>'formatDayInYear',
  55. 'F'=>'formatDayInMonth',
  56. 'w'=>'formatWeekInYear',
  57. 'W'=>'formatWeekInMonth',
  58. 'a'=>'formatPeriod',
  59. 'k'=>'formatHourInDay',
  60. 'K'=>'formatHourInPeriod',
  61. 'z'=>'formatTimeZone',
  62. 'Z'=>'formatTimeZone',
  63. 'v'=>'formatTimeZone',
  64. );
  65. private $_locale;
  66. /**
  67. * Constructor.
  68. * @param mixed locale ID (string) or CLocale instance
  69. */
  70. public function __construct($locale)
  71. {
  72. if(is_string($locale))
  73. $this->_locale=CLocale::getInstance($locale);
  74. else
  75. $this->_locale=$locale;
  76. }
  77. /**
  78. * Formats a date according to a customized pattern.
  79. * @param string the pattern (See {@link http://www.unicode.org/reports/tr35/#Date_Format_Patterns})
  80. * @param mixed UNIX timestamp or a string in strtotime format
  81. * @return string formatted date time.
  82. */
  83. public function format($pattern,$time)
  84. {
  85. if(is_string($time))
  86. {
  87. if(ctype_digit($time))
  88. $time=(int)$time;
  89. else
  90. $time=strtotime($time);
  91. }
  92. $date=CTimestamp::getDate($time,false,false);
  93. $tokens=$this->parseFormat($pattern);
  94. foreach($tokens as &$token)
  95. {
  96. if(is_array($token)) // a callback: method name, sub-pattern
  97. $token=$this->{$token[0]}($token[1],$date);
  98. }
  99. return implode('',$tokens);
  100. }
  101. /**
  102. * Formats a date according to a predefined pattern.
  103. * The predefined pattern is determined based on the date pattern width and time pattern width.
  104. * @param mixed UNIX timestamp or a string in strtotime format
  105. * @param string width of the date pattern. It can be 'full', 'long', 'medium' and 'short'.
  106. * If null, it means the date portion will NOT appear in the formatting result
  107. * @param string width of the time pattern. It can be 'full', 'long', 'medium' and 'short'.
  108. * If null, it means the time portion will NOT appear in the formatting result
  109. * @return string formatted date time.
  110. */
  111. public function formatDateTime($timestamp,$dateWidth='medium',$timeWidth='medium')
  112. {
  113. if(!empty($dateWidth))
  114. $date=$this->format($this->_locale->getDateFormat($dateWidth),$timestamp);
  115. if(!empty($timeWidth))
  116. $time=$this->format($this->_locale->getTimeFormat($timeWidth),$timestamp);
  117. if(isset($date) && isset($time))
  118. {
  119. $dateTimePattern=$this->_locale->getDateTimeFormat();
  120. return strtr($dateTimePattern,array('{0}'=>$time,'{1}'=>$date));
  121. }
  122. else if(isset($date))
  123. return $date;
  124. else if(isset($time))
  125. return $time;
  126. }
  127. /**
  128. * Parses the datetime format pattern.
  129. * @param string the pattern to be parsed
  130. * @return array tokenized parsing result
  131. */
  132. protected function parseFormat($pattern)
  133. {
  134. static $formats=array(); // cache
  135. if(isset($formats[$pattern]))
  136. return $formats[$pattern];
  137. $tokens=array();
  138. $n=strlen($pattern);
  139. $isLiteral=false;
  140. $literal='';
  141. for($i=0;$i<$n;++$i)
  142. {
  143. $c=$pattern[$i];
  144. if($c==="'")
  145. {
  146. if($i<$n-1 && $pattern[$i+1]==="'")
  147. {
  148. $tokens[]="'";
  149. $i++;
  150. }
  151. else if($isLiteral)
  152. {
  153. $tokens[]=$literal;
  154. $literal='';
  155. $isLiteral=false;
  156. }
  157. else
  158. {
  159. $isLiteral=true;
  160. $literal='';
  161. }
  162. }
  163. else if($isLiteral)
  164. $literal.=$c;
  165. else
  166. {
  167. for($j=$i+1;$j<$n;++$j)
  168. {
  169. if($pattern[$j]!==$c)
  170. break;
  171. }
  172. $p=str_repeat($c,$j-$i);
  173. if(isset(self::$_formatters[$c]))
  174. $tokens[]=array(self::$_formatters[$c],$p);
  175. else
  176. $tokens[]=$p;
  177. $i=$j-1;
  178. }
  179. }
  180. if($literal!=='')
  181. $tokens[]=$literal;
  182. return $formats[$pattern]=$tokens;
  183. }
  184. /**
  185. * Get the year.
  186. * "yy" will return the last two digits of year.
  187. * "y...y" will pad the year with 0 in the front, e.g. "yyyyy" will generate "02008" for year 2008.
  188. * @param string a pattern.
  189. * @param array result of {@link CTimestamp::getdate}.
  190. * @return string formatted year
  191. */
  192. protected function formatYear($pattern,$date)
  193. {
  194. $year=$date['year'];
  195. if($pattern==='yy')
  196. return str_pad($year%100,2,'0',STR_PAD_LEFT);
  197. else
  198. return str_pad($year,strlen($pattern),'0',STR_PAD_LEFT);
  199. }
  200. /**
  201. * Get the month.
  202. * "M" will return integer 1 through 12;
  203. * "MM" will return two digits month number with necessary zero padding, e.g. 05;
  204. * "MMM" will return the abrreviated month name, e.g. "Jan";
  205. * "MMMM" will return the full month name, e.g. "January";
  206. * "MMMMM" will return the narrow month name, e.g. "J";
  207. * @param string a pattern.
  208. * @param array result of {@link CTimestamp::getdate}.
  209. * @return string month name
  210. */
  211. protected function formatMonth($pattern,$date)
  212. {
  213. $month=$date['mon'];
  214. switch($pattern)
  215. {
  216. case 'M':
  217. return $month;
  218. case 'MM':
  219. return str_pad($month,2,'0',STR_PAD_LEFT);
  220. case 'MMM':
  221. return $this->_locale->getMonthName($month,'abbreviated');
  222. case 'MMMM':
  223. return $this->_locale->getMonthName($month,'wide');
  224. case 'MMMMM':
  225. return $this->_locale->getMonthName($month,'narrow');
  226. case 'L':
  227. return $month;
  228. case 'LL':
  229. return str_pad($month,2,'0',STR_PAD_LEFT);
  230. case 'LLL':
  231. return $this->_locale->getMonthName($month,'abbreviated', true);
  232. case 'LLLL':
  233. return $this->_locale->getMonthName($month,'wide', true);
  234. case 'LLLLL':
  235. return $this->_locale->getMonthName($month,'narrow', true);
  236. default:
  237. throw new CException(Yii::t('yii','The pattern for month must be "M", "MM", "MMM", "MMMM", "L", "LL", "LLL" or "LLLL".'));
  238. }
  239. }
  240. /**
  241. * Get the day of the month.
  242. * "d" for non-padding, "dd" will always return 2 digits day numbers, e.g. 05.
  243. * @param string a pattern.
  244. * @param array result of {@link CTimestamp::getdate}.
  245. * @return string day of the month
  246. */
  247. protected function formatDay($pattern,$date)
  248. {
  249. $day=$date['mday'];
  250. if($pattern==='d')
  251. return $day;
  252. else if($pattern==='dd')
  253. return str_pad($day,2,'0',STR_PAD_LEFT);
  254. else
  255. throw new CException(Yii::t('yii','The pattern for day of the month must be "d" or "dd".'));
  256. }
  257. /**
  258. * Get the day in the year, e.g. [1-366]
  259. * @param string a pattern.
  260. * @param array result of {@link CTimestamp::getdate}.
  261. * @return int hours in AM/PM format.
  262. */
  263. protected function formatDayInYear($pattern,$date)
  264. {
  265. $day=$date['yday'];
  266. if(($n=strlen($pattern))<=3)
  267. return str_pad($day,$n,'0',STR_PAD_LEFT);
  268. else
  269. throw new CException(Yii::t('yii','The pattern for day in year must be "D", "DD" or "DDD".'));
  270. }
  271. /**
  272. * Get day of week in the month, e.g. 2nd Wed in July.
  273. * @param string a pattern.
  274. * @param array result of {@link CTimestamp::getdate}.
  275. * @return int day in month
  276. * @see http://www.unicode.org/reports/tr35/#Date_Format_Patterns
  277. */
  278. protected function formatDayInMonth($pattern,$date)
  279. {
  280. if($pattern==='F')
  281. return (int)(($date['mday']+6)/7);
  282. else
  283. throw new CException(Yii::t('yii','The pattern for day in month must be "F".'));
  284. }
  285. /**
  286. * Get the day of the week.
  287. * "E", "EE", "EEE" will return abbreviated week day name, e.g. "Tues";
  288. * "EEEE" will return full week day name;
  289. * "EEEEE" will return the narrow week day name, e.g. "T";
  290. * @param string a pattern.
  291. * @param array result of {@link CTimestamp::getdate}.
  292. * @return string day of the week.
  293. * @see http://www.unicode.org/reports/tr35/#Date_Format_Patterns
  294. */
  295. protected function formatDayInWeek($pattern,$date)
  296. {
  297. $day=$date['wday'];
  298. switch($pattern)
  299. {
  300. case 'E':
  301. case 'EE':
  302. case 'EEE':
  303. case 'eee':
  304. return $this->_locale->getWeekDayName($day,'abbreviated');
  305. case 'EEEE':
  306. case 'eeee':
  307. return $this->_locale->getWeekDayName($day,'wide');
  308. case 'EEEEE':
  309. case 'eeeee':
  310. return $this->_locale->getWeekDayName($day,'narrow');
  311. case 'e':
  312. case 'ee':
  313. case 'c':
  314. return $day ? $day : 7;
  315. case 'ccc':
  316. return $this->_locale->getWeekDayName($day,'abbreviated',true);
  317. case 'cccc':
  318. return $this->_locale->getWeekDayName($day,'wide',true);
  319. case 'ccccc':
  320. return $this->_locale->getWeekDayName($day,'narrow',true);
  321. default:
  322. throw new CException(Yii::t('yii','The pattern for day of the week must be "E", "EE", "EEE", "EEEE", "EEEEE", "e", "ee", "eee", "eeee", "eeeee", "c", "cccc" or "ccccc".'));
  323. }
  324. }
  325. /**
  326. * Get the AM/PM designator, 12 noon is PM, 12 midnight is AM.
  327. * @param string a pattern.
  328. * @param array result of {@link CTimestamp::getdate}.
  329. * @return string AM or PM designator
  330. */
  331. protected function formatPeriod($pattern,$date)
  332. {
  333. if($pattern==='a')
  334. {
  335. if(intval($date['hours']/12))
  336. return $this->_locale->getPMName();
  337. else
  338. return $this->_locale->getAMName();
  339. }
  340. else
  341. throw new CException(Yii::t('yii','The pattern for AM/PM marker must be "a".'));
  342. }
  343. /**
  344. * Get the hours in 24 hour format, i.e. [0-23].
  345. * "H" for non-padding, "HH" will always return 2 characters.
  346. * @param string a pattern.
  347. * @param array result of {@link CTimestamp::getdate}.
  348. * @return string hours in 24 hour format.
  349. */
  350. protected function formatHour24($pattern,$date)
  351. {
  352. $hour=$date['hours'];
  353. if($pattern==='H')
  354. return $hour;
  355. else if($pattern==='HH')
  356. return str_pad($hour,2,'0',STR_PAD_LEFT);
  357. else
  358. throw new CException(Yii::t('yii','The pattern for 24 hour format must be "H" or "HH".'));
  359. }
  360. /**
  361. * Get the hours in 12 hour format, i.e., [1-12]
  362. * "h" for non-padding, "hh" will always return 2 characters.
  363. * @param string a pattern.
  364. * @param array result of {@link CTimestamp::getdate}.
  365. * @return string hours in 12 hour format.
  366. */
  367. protected function formatHour12($pattern,$date)
  368. {
  369. $hour=$date['hours'];
  370. $hour=($hour==12|$hour==0)?12:($hour)%12;
  371. if($pattern==='h')
  372. return $hour;
  373. else if($pattern==='hh')
  374. return str_pad($hour,2,'0',STR_PAD_LEFT);
  375. else
  376. throw new CException(Yii::t('yii','The pattern for 12 hour format must be "h" or "hh".'));
  377. }
  378. /**
  379. * Get the hours [1-24].
  380. * 'k' for non-padding, and 'kk' with 2 characters padding.
  381. * @param string a pattern.
  382. * @param array result of {@link CTimestamp::getdate}.
  383. * @return int hours [1-24]
  384. */
  385. protected function formatHourInDay($pattern,$date)
  386. {
  387. $hour=$date['hours']==0?24:$date['hours'];
  388. if($pattern==='k')
  389. return $hour;
  390. else if($pattern==='kk')
  391. return str_pad($hour,2,'0',STR_PAD_LEFT);
  392. else
  393. throw new CException(Yii::t('yii','The pattern for hour in day must be "k" or "kk".'));
  394. }
  395. /**
  396. * Get the hours in AM/PM format, e.g [0-11]
  397. * "K" for non-padding, "KK" will always return 2 characters.
  398. * @param string a pattern.
  399. * @param array result of {@link CTimestamp::getdate}.
  400. * @return int hours in AM/PM format.
  401. */
  402. protected function formatHourInPeriod($pattern,$date)
  403. {
  404. $hour=$date['hours']%12;
  405. if($pattern==='K')
  406. return $hour;
  407. else if($pattern==='KK')
  408. return str_pad($hour,2,'0',STR_PAD_LEFT);
  409. else
  410. throw new CException(Yii::t('yii','The pattern for hour in AM/PM must be "K" or "KK".'));
  411. }
  412. /**
  413. * Get the minutes.
  414. * "m" for non-padding, "mm" will always return 2 characters.
  415. * @param string a pattern.
  416. * @param array result of {@link CTimestamp::getdate}.
  417. * @return string minutes.
  418. */
  419. protected function formatMinutes($pattern,$date)
  420. {
  421. $minutes=$date['minutes'];
  422. if($pattern==='m')
  423. return $minutes;
  424. else if($pattern==='mm')
  425. return str_pad($minutes,2,'0',STR_PAD_LEFT);
  426. else
  427. throw new CException(Yii::t('yii','The pattern for minutes must be "m" or "mm".'));
  428. }
  429. /**
  430. * Get the seconds.
  431. * "s" for non-padding, "ss" will always return 2 characters.
  432. * @param string a pattern.
  433. * @param array result of {@link CTimestamp::getdate}.
  434. * @return string seconds
  435. */
  436. protected function formatSeconds($pattern,$date)
  437. {
  438. $seconds=$date['seconds'];
  439. if($pattern==='s')
  440. return $seconds;
  441. else if($pattern==='ss')
  442. return str_pad($seconds,2,'0',STR_PAD_LEFT);
  443. else
  444. throw new CException(Yii::t('yii','The pattern for seconds must be "s" or "ss".'));
  445. }
  446. /**
  447. * Get the week in the year.
  448. * @param string a pattern.
  449. * @param array result of {@link CTimestamp::getdate}.
  450. * @return int week in year
  451. */
  452. protected function formatWeekInYear($pattern,$date)
  453. {
  454. if($pattern==='w')
  455. return @date('W',@mktime(0,0,0,$date['mon'],$date['mday'],$date['year']));
  456. else
  457. throw new CException(Yii::t('yii','The pattern for week in year must be "w".'));
  458. }
  459. /**
  460. * Get week in the month.
  461. * @param array result of {@link CTimestamp::getdate}.
  462. * @param string a pattern.
  463. * @return int week in month
  464. */
  465. protected function formatWeekInMonth($pattern,$date)
  466. {
  467. if($pattern==='W')
  468. return @date('W',@mktime(0,0,0,$date['mon'], $date['mday'],$date['year']))-date('W', mktime(0,0,0,$date['mon'],1,$date['year']))+1;
  469. else
  470. throw new CException(Yii::t('yii','The pattern for week in month must be "W".'));
  471. }
  472. /**
  473. * Get the timezone of the server machine.
  474. * @param string a pattern.
  475. * @param array result of {@link CTimestamp::getdate}.
  476. * @return string time zone
  477. * @todo How to get the timezone for a different region?
  478. */
  479. protected function formatTimeZone($pattern,$date)
  480. {
  481. if($pattern[0]==='z' || $pattern[0]==='v')
  482. return @date('T', @mktime($date['hours'], $date['minutes'], $date['seconds'], $date['mon'], $date['mday'], $date['year']));
  483. elseif($pattern[0]==='Z')
  484. return @date('O', @mktime($date['hours'], $date['minutes'], $date['seconds'], $date['mon'], $date['mday'], $date['year']));
  485. else
  486. throw new CException(Yii::t('yii','The pattern for time zone must be "z" or "v".'));
  487. }
  488. /**
  489. * Get the era. i.e. in gregorian, year > 0 is AD, else BC.
  490. * @param string a pattern.
  491. * @param array result of {@link CTimestamp::getdate}.
  492. * @return string era
  493. * @todo How to support multiple Eras?, e.g. Japanese.
  494. */
  495. protected function formatEra($pattern,$date)
  496. {
  497. $era=$date['year']>0 ? 1 : 0;
  498. switch($pattern)
  499. {
  500. case 'G':
  501. case 'GG':
  502. case 'GGG':
  503. return $this->_locale->getEraName($era,'abbreviated');
  504. case 'GGGG':
  505. return $this->_locale->getEraName($era,'wide');
  506. case 'GGGGG':
  507. return $this->_locale->getEraName($era,'narrow');
  508. default:
  509. throw new CException(Yii::t('yii','The pattern for era must be "G", "GG", "GGG", "GGGG" or "GGGGG".'));
  510. }
  511. }
  512. }