PageRenderTime 48ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/symphony/lib/core/class.datetimeobj.php

http://github.com/symphonycms/symphony-2
PHP | 582 lines | 235 code | 59 blank | 288 comment | 34 complexity | a9c689da854d67bcb8f9fc5818369d44 MD5 | raw file
  1. <?php
  2. /**
  3. * @package core
  4. */
  5. /**
  6. * The DateTimeObj provides static functions regarding dates in Symphony.
  7. * Symphony will set the default timezone of the system using the value from
  8. * the Configuration values. Alternatively a new settings can be set using the
  9. * `setSettings` function. Symphony parses all input dates against the Configuration
  10. * date formats by default for better support with non English dates.
  11. */
  12. class DateTimeObj
  13. {
  14. /**
  15. * Holds the various settings for the formats that the `DateTimeObj` should
  16. * use when parsing input dates.
  17. *
  18. * @since Symphony 2.7.0 it contains default values to prevent the case where
  19. * no settings are set
  20. * @since Symphony 2.2.4
  21. * @var array
  22. */
  23. private static $settings = array(
  24. 'time_format' => 'g:i a',
  25. 'date_format' => 'm/d/Y',
  26. );
  27. /**
  28. * Mapping PHP to Moment date formats.
  29. */
  30. protected static $date_mappings = array(
  31. 'Y/m/d' => 'YYYY/MM/DD', // e. g. 2014/01/02
  32. 'd/m/Y' => 'DD/MM/YYYY', // e. g. 01/02/2014
  33. 'm/d/Y' => 'MM/DD/YYYY', // e. g. 01/02/2014
  34. 'm/d/y' => 'MM/DD/YY', // e. g. 01/02/14
  35. 'Y-m-d' => 'YYYY-MM-DD', // e. g. 2014-01-02
  36. 'm-d-Y' => 'MM-DD-YYYY', // e. g. 01-02-2014
  37. 'm-d-y' => 'MM-DD-YY', // e. g. 01-02-14
  38. 'j.n.Y' => 'D.M.YYYY', // e. g. 2.1.2014 - no leading zeros
  39. 'j.n.y' => 'D.M.YY', // e. g. 2.1.14 - no leading zeros
  40. 'd.m.Y' => 'DD.MM.YYYY', // e. g. 02.01.2014
  41. 'd.m.y' => 'DD.MM.YYYY', // e. g. 02.01.14
  42. 'd F Y' => 'DD MMMM YYYY', // e. g. 02 January 2014
  43. 'd. F Y' => 'DD. MMMM YYYY', // e. g. 02. January 2014
  44. 'd M Y' => 'DD MMM YYYY', // e. g. 02 Jan 2014
  45. 'd. M Y' => 'DD. MMM. YYYY', // e. g. 02. Jan 2014
  46. 'j. F Y' => 'D. MMMM YYYY', // e. g. 2. January 2014 - no leading zeros
  47. 'j. M. Y' => 'D. MMM. YYYY', // e. g. 2. Jan. 2014 - no leading zeros
  48. );
  49. /**
  50. * Mapping PHP to Moment time formats.
  51. */
  52. protected static $time_mappings = array(
  53. 'H:i:s' => 'HH:mm:ss', // e. g. 20:45:32
  54. 'H:i' => 'HH:mm', // e. g. 20:45
  55. 'g:i:s a' => 'h:mm:ss a', // e. g. 8:45:32 pm
  56. 'g:i a' => 'h:mm a', // e. g. 8:45 pm
  57. );
  58. /**
  59. * This function takes an array of settings for `DateTimeObj` to use when parsing
  60. * input dates. The following settings are supported, `time_format`, `date_format`,
  61. * `datetime_separator` and `timezone`. This equates to Symphony's default `region`
  62. * group set in the `Configuration` class. If any of these values are not provided
  63. * the class will fallback to existing `self::$settings` values
  64. *
  65. * @since Symphony 2.2.4
  66. * @param array $settings
  67. * An associative array of formats for this class to use to format
  68. * dates
  69. */
  70. public static function setSettings(array $settings = array())
  71. {
  72. // Date format
  73. if (isset($settings['date_format'])) {
  74. self::$settings['date_format'] = $settings['date_format'];
  75. }
  76. // Time format
  77. if (isset($settings['time_format'])) {
  78. self::$settings['time_format'] = $settings['time_format'];
  79. }
  80. // Datetime separator
  81. if (isset($settings['datetime_separator'])) {
  82. self::$settings['datetime_separator'] = $settings['datetime_separator'];
  83. } elseif (!isset(self::$settings['datetime_separator'])) {
  84. self::$settings['datetime_separator'] = ' ';
  85. }
  86. // Datetime format
  87. if (isset($settings['datetime_format'])) {
  88. self::$settings['datetime_format'] = $settings['datetime_format'];
  89. } elseif (!isset(self::$settings['datetime_format'])) {
  90. self::$settings['datetime_format'] = self::$settings['date_format'] . self::$settings['datetime_separator'] . self::$settings['time_format'];
  91. }
  92. // Timezone
  93. if (isset($settings['timezone']) && !empty($settings['timezone'])) {
  94. self::$settings['timezone'] = $settings['timezone'];
  95. self::setDefaultTimezone($settings['timezone']);
  96. } elseif (!isset(self::$settings['timezone'])) {
  97. self::$settings['timezone'] = ini_get('date.timezone');
  98. if (empty(self::$settings['timezone'])) {
  99. self::$settings['timezone'] = 'UTC';
  100. }
  101. }
  102. }
  103. /**
  104. * Accessor function for the settings of the DateTimeObj. Currently
  105. * the available settings are `time_format`, `date_format`,
  106. * `datetime_format` and `datetime_separator`. If `$name` is not
  107. * provided, the entire `$settings` array is returned.
  108. *
  109. * @since Symphony 2.2.4
  110. * @param string $name
  111. * @return array|string|null
  112. * If `$name` is omitted this function returns array.
  113. * If `$name` is not set, this fucntion returns `null`
  114. * If `$name` is set, this function returns string
  115. */
  116. public static function getSetting($name = null)
  117. {
  118. if (is_null($name)) {
  119. return self::$settings;
  120. }
  121. if (isset(self::$settings[$name])) {
  122. return self::$settings[$name];
  123. }
  124. return null;
  125. }
  126. /**
  127. * Uses PHP's date_default_timezone_set function to set the system
  128. * timezone. If the timezone provided is invalid, an exception is thrown.
  129. *
  130. * @link http://php.net/manual/en/function.date-default-timezone-set.php
  131. * @link http://www.php.net/manual/en/timezones.php
  132. * @param string $timezone
  133. * A valid timezone identifier, such as UTC or Europe/Lisbon
  134. * @throws Exception
  135. * If the timezone is not valid.
  136. */
  137. public static function setDefaultTimezone($timezone)
  138. {
  139. if (!@date_default_timezone_set($timezone)) {
  140. throw new Exception(__('Invalid timezone %s', array($timezone)));
  141. }
  142. }
  143. /**
  144. * Validate a given date and time string
  145. *
  146. * @param string $string
  147. * A date and time string or timestamp to validate
  148. * @return boolean
  149. * Returns true for valid dates, otherwise false
  150. */
  151. public static function validate($string)
  152. {
  153. try {
  154. if (is_numeric($string) && (int)$string == $string) {
  155. $date = new DateTime('@' . $string);
  156. } else {
  157. $date = self::parse($string);
  158. }
  159. } catch (Exception $ex) {
  160. return false;
  161. }
  162. // String is empty or not a valid date
  163. if (empty($string) || $date === false) {
  164. return false;
  165. // String is a valid date
  166. } else {
  167. return true;
  168. }
  169. }
  170. /**
  171. * Given a `$format`, and a `$timestamp`,
  172. * return the date in the format provided. This function is a basic
  173. * wrapper for PHP's DateTime object. If the `$timestamp` is omitted,
  174. * the current timestamp will be used. Optionally, you pass a
  175. * timezone identifier with this function to localise the output
  176. *
  177. * If you like to display a date in the backend, please make use
  178. * of `DateTimeObj::format()` which allows date and time localization
  179. *
  180. * @see class.datetimeobj.php#format()
  181. * @link http://www.php.net/manual/en/book.datetime.php
  182. * @param string $format
  183. * A valid PHP date format
  184. * @param null|string $timestamp (optional)
  185. * A unix timestamp to format. 'now' or omitting this parameter will
  186. * result in the current time being used
  187. * @param string $timezone (optional)
  188. * The timezone associated with the timestamp
  189. * @return string|boolean
  190. * The formatted date, of if the date could not be parsed, false.
  191. */
  192. public static function get($format, $timestamp = 'now', $timezone = null)
  193. {
  194. return self::format($timestamp, $format, false, $timezone);
  195. }
  196. /**
  197. * Formats the given date and time `$string` based on the given `$format`.
  198. * Optionally the result will be localized and respect a timezone differing
  199. * from the system default. The default output is ISO 8601.
  200. *
  201. * @since Symphony 2.2.1
  202. * @param string $string (optional)
  203. * A string containing date and time, defaults to the current date and time
  204. * @param string $format (optional)
  205. * A valid PHP date format, defaults to ISO 8601
  206. * @param boolean $localize (optional)
  207. * Localizes the output, if true, defaults to true
  208. * @param string $timezone (optional)
  209. * The timezone associated with the timestamp
  210. * @return string|boolean
  211. * The formatted date, or if the date could not be parsed, false.
  212. */
  213. public static function format($string = 'now', $format = DateTime::ISO8601, $localize = true, $timezone = null)
  214. {
  215. // Parse date
  216. $date = self::parse($string);
  217. if ($date === false) {
  218. return false;
  219. }
  220. // Timezone
  221. // If a timezone was given, apply it
  222. if (!is_null($timezone)) {
  223. $date->setTimezone(new DateTimeZone($timezone));
  224. // No timezone given, apply the default timezone
  225. } elseif (isset(self::$settings['timezone'])) {
  226. $date->setTimezone(new DateTimeZone(self::$settings['timezone']));
  227. }
  228. // Format date
  229. $date = $date->format($format);
  230. // Localize date
  231. // Convert date string from English back to the activated Language
  232. if ($localize === true) {
  233. $date = Lang::localizeDate($date);
  234. }
  235. // Return custom formatted date, use ISO 8601 date by default
  236. return $date;
  237. }
  238. /**
  239. * Parses the given string and returns a DateTime object.
  240. *
  241. * @since Symphony 2.3
  242. * @param string $string (optional)
  243. * A string containing date and time, defaults to the current date and time
  244. * @return DateTime|boolean
  245. * The DateTime object, or if the date could not be parsed, false.
  246. */
  247. public static function parse($string)
  248. {
  249. // Current date and time
  250. if ($string == 'now' || empty($string)) {
  251. $date = new DateTime();
  252. // Timestamp
  253. } elseif (is_numeric($string)) {
  254. $date = new DateTime('@' . $string);
  255. // Attempt to parse the date provided against the Symphony configuration setting
  256. // in an effort to better support multilingual date formats. Should this fail
  257. // this block will fallback to just passing the date to DateTime constructor,
  258. // which will parse the date assuming it's in an American format.
  259. } else {
  260. // Standardize date
  261. // Convert date string to English
  262. $string = Lang::standardizeDate($string);
  263. // PHP 5.3: Apply Symphony date format using `createFromFormat`
  264. $date = DateTime::createFromFormat(self::$settings['datetime_format'], $string);
  265. if ($date === false) {
  266. $date = DateTime::createFromFormat(self::$settings['date_format'], $string);
  267. }
  268. // Handle dates that are in a different format to Symphony's config
  269. // DateTime is much the same as `strtotime` and will handle relative
  270. // dates.
  271. if ($date === false) {
  272. try {
  273. $date = new DateTime($string);
  274. } catch (Exception $ex) {
  275. // Invalid date, it can't be parsed
  276. return false;
  277. }
  278. }
  279. // If the date is still invalid, just return false.
  280. if ($date === false || $date->format('Y') < 0) {
  281. return false;
  282. }
  283. }
  284. // Return custom formatted date, use ISO 8601 date by default
  285. return $date;
  286. }
  287. /**
  288. * A wrapper for get, this function will force the GMT timezone.
  289. *
  290. * @param string $format
  291. * A valid PHP date format
  292. * @param null|string $timestamp (optional)
  293. * A unix timestamp to format. Omitting this parameter will
  294. * result in the current time being used
  295. * @return string
  296. * The formatted date in GMT
  297. */
  298. public static function getGMT($format, $timestamp = 'now')
  299. {
  300. return self::format($timestamp, $format, false, 'GMT');
  301. }
  302. /**
  303. * This functions acts as a standard way to get the zones
  304. * available on the system.
  305. *
  306. * @since Symphony 2.3
  307. * @link http://au2.php.net/manual/en/class.datetimezone.php
  308. * @return array
  309. */
  310. public static function getZones()
  311. {
  312. $ref = new ReflectionClass('DateTimeZone');
  313. return $ref->getConstants();
  314. }
  315. /**
  316. * This functions acts as a standard way to get the timezones
  317. * regardless of PHP version. It accepts a single parameter,
  318. * zone, which returns the timezones associated with that 'zone'
  319. *
  320. * @since Symphony 2.3
  321. * @link http://au2.php.net/manual/en/class.datetimezone.php
  322. * @link http://au2.php.net/manual/en/datetimezone.listidentifiers.php
  323. * @param string $zone
  324. * The zone for the timezones the field wants. This maps to the
  325. * DateTimeZone constants
  326. * @return array
  327. */
  328. public static function getTimezones($zone = null)
  329. {
  330. return DateTimeZone::listIdentifiers(constant('DateTimeZone::' . $zone));
  331. }
  332. /**
  333. * Loads all available timezones using `getTimezones()` and builds an
  334. * array where timezones are grouped by their region (Europe/America etc.)
  335. * The options array that is returned is designed to be used with
  336. * `Widget::Select`
  337. *
  338. * @since Symphony 2.3
  339. * @see core.DateTimeObj#getTimezones()
  340. * @see core.Widget#Select()
  341. * @param string $selected
  342. * A preselected timezone, defaults to null
  343. * @return array
  344. * An associative array, for use with `Widget::Select`
  345. */
  346. public static function getTimezonesSelectOptions($selected = null)
  347. {
  348. $zones = self::getZones();
  349. $groups = array();
  350. foreach ($zones as $zone => $value) {
  351. if ($value >= 1024) {
  352. break;
  353. }
  354. $timezones = self::getTimezones($zone);
  355. $options = array();
  356. foreach ($timezones as $timezone) {
  357. $tz = new DateTime('now', new DateTimeZone($timezone));
  358. $options[] = array($timezone, ($timezone == $selected), sprintf(
  359. "%s %s",
  360. str_replace('_', ' ', substr(strrchr($timezone, '/'), 1)),
  361. $tz->format('P')
  362. ));
  363. }
  364. $groups[] = array('label' => ucwords(strtolower($zone)), 'options' => $options);
  365. }
  366. return $groups;
  367. }
  368. /**
  369. * Returns an array of PHP date formats Symphony supports mapped to
  370. * their Moment equivalent.
  371. *
  372. * @since Symphony 2.6
  373. * @return array
  374. */
  375. public static function getDateFormatMappings()
  376. {
  377. return self::$date_mappings;
  378. }
  379. /**
  380. * Returns an array of the date formats Symphony supports. These
  381. * formats are a combination of valid PHP format tokens.
  382. *
  383. * @link http://au2.php.net/manual/en/function.date.php
  384. * @since Symphony 2.3
  385. * @return array
  386. */
  387. public static function getDateFormats()
  388. {
  389. return array_keys(self::$date_mappings);
  390. }
  391. /**
  392. * Returns an array of the date formats Symphony supports. These
  393. * formats are a combination of valid Moment format tokens.
  394. *
  395. * @link http://momentjs.com/docs/#/parsing/
  396. * @since Symphony 2.6
  397. * @return array
  398. */
  399. public static function getMomentDateFormats()
  400. {
  401. return array_values(self::$date_mappings);
  402. }
  403. /**
  404. * Returns the Moment representation of a given PHP format token.
  405. *
  406. * @since Symphony 2.6
  407. * @param string $format
  408. * A valid PHP date token
  409. * @return string
  410. */
  411. public static function convertDateToMoment($format)
  412. {
  413. return self::$date_mappings[$format];
  414. }
  415. /**
  416. * Returns the PHP representation of a given Moment format token.
  417. *
  418. * @since Symphony 2.6
  419. * @param string $format
  420. * A valid Moment date token
  421. * @return string
  422. */
  423. public static function convertMomentToDate($format)
  424. {
  425. $formats = array_flip(self::$date_mappings);
  426. return $formats[$format];
  427. }
  428. /**
  429. * Returns an array of the date formats Symphony supports by applying
  430. * the format to the current datetime. The array returned is for use with
  431. * `Widget::Select()`
  432. *
  433. * @since Symphony 2.3
  434. * @see core.Widget#Select()
  435. * @param string $selected
  436. * A preselected date format, defaults to null
  437. * @return array
  438. * An associative array, for use with `Widget::Select`
  439. */
  440. public static function getDateFormatsSelectOptions($selected = null)
  441. {
  442. $formats = self::getDateFormats();
  443. $options = array();
  444. foreach ($formats as $option) {
  445. $leadingZero = '';
  446. if (strpos($option, 'j') !== false || strpos($option, 'n') !== false) {
  447. $leadingZero = ' (' . __('no leading zeros') . ')';
  448. }
  449. $options[] = array($option, $option == $selected, self::format('now', $option) . $leadingZero);
  450. }
  451. return $options;
  452. }
  453. /**
  454. * Returns an array of the time formats Symphony supports. These
  455. * formats are a combination of valid PHP format tokens.
  456. *
  457. * @link http://au2.php.net/manual/en/function.date.php
  458. * @since Symphony 2.3
  459. * @return array
  460. */
  461. public static function getTimeFormats()
  462. {
  463. return array_keys(self::$time_mappings);
  464. }
  465. /**
  466. * Returns an array of the time formats Symphony supports. These
  467. * formats are a combination of valid Moment format tokens.
  468. *
  469. * @link http://momentjs.com/docs/#/parsing/
  470. * @since Symphony 2.6
  471. * @return array
  472. */
  473. public static function getMomentTimeFormats()
  474. {
  475. return array_keys(self::$time_mappings);
  476. }
  477. /**
  478. * Returns the Moment time representation of a given PHP format token.
  479. *
  480. * @since Symphony 2.6
  481. * @param string $format
  482. * A valid PHP time token
  483. * @return string
  484. */
  485. public static function convertTimeToMoment($format)
  486. {
  487. return self::$time_mappings[$format];
  488. }
  489. /**
  490. * Returns the PHP time representation of a given Moment format token.
  491. *
  492. * @since Symphony 2.6
  493. * @param string $format
  494. * A valid Moment time token
  495. * @return string
  496. */
  497. public static function convertMomentToTime($format)
  498. {
  499. $formats = array_flip(self::$time_mappings);
  500. return $formats[$format];
  501. }
  502. /**
  503. * Returns an array of the time formats Symphony supports by applying
  504. * the format to the current datetime. The array returned is for use with
  505. * `Widget::Select()`
  506. *
  507. * @since Symphony 2.3
  508. * @see core.Widget#Select()
  509. * @param string $selected
  510. * A preselected time format, defaults to null
  511. * @return array
  512. * An associative array, for use with `Widget::Select`
  513. */
  514. public static function getTimeFormatsSelectOptions($selected = null)
  515. {
  516. $formats = self::getTimeFormats();
  517. $options = array();
  518. foreach ($formats as $option) {
  519. $options[] = array($option, $option == $selected, self::get($option));
  520. }
  521. return $options;
  522. }
  523. }