PageRenderTime 50ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 1ms

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

https://bitbucket.org/Twisted/symphony-2
PHP | 516 lines | 214 code | 54 blank | 248 comment | 44 complexity | dba7185a569c3c26173717f0aaafc021 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. * Holds the various settings for the formats that the `DateTimeObj` should
  15. * use when parsing input dates.
  16. *
  17. * @since Symphony 2.2.4
  18. * @var array
  19. */
  20. private static $settings = array();
  21. /**
  22. * This function takes an array of settings for `DateTimeObj` to use when parsing
  23. * input dates. The following settings are supported, `time_format`, `date_format`,
  24. * `datetime_separator` and `timezone`. This equates to Symphony's default `region`
  25. * group set in the `Configuration` class. If any of these values are not provided
  26. * the class will fallback to existing `self::$settings` values
  27. *
  28. * @since Symphony 2.2.4
  29. * @param array $settings
  30. * An associative array of formats for this class to use to format
  31. * dates
  32. */
  33. public static function setSettings(array $settings = array()) {
  34. // Date format
  35. if(isset($settings['date_format'])) {
  36. self::$settings['date_format'] = $settings['date_format'];
  37. }
  38. // Time format
  39. if(isset($settings['time_format'])) {
  40. self::$settings['time_format'] = $settings['time_format'];
  41. }
  42. // Datetime separator
  43. if(isset($settings['datetime_separator'])) {
  44. self::$settings['datetime_separator'] = $settings['datetime_separator'];
  45. }
  46. else if (!isset(self::$settings['datetime_separator'])) {
  47. self::$settings['datetime_separator'] = ' ';
  48. }
  49. // Datetime format
  50. if(isset($settings['datetime_format'])) {
  51. self::$settings['datetime_format'] = $settings['datetime_format'];
  52. }
  53. else {
  54. self::$settings['datetime_format'] = self::$settings['date_format'] . self::$settings['datetime_separator'] . self::$settings['time_format'];
  55. }
  56. // Timezone
  57. if(isset($settings['timezone']) && !empty($settings['timezone'])) {
  58. self::$settings['timezone'] = $settings['timezone'];
  59. self::setDefaultTimezone($settings['timezone']);
  60. }
  61. }
  62. /**
  63. * Accessor function for the settings of the DateTimeObj. Currently
  64. * the available settings are `time_format`, `date_format`,
  65. * `datetime_format` and `datetime_separator`. If `$name` is not
  66. * provided, the entire `$settings` array is returned.
  67. *
  68. * @since Symphony 2.2.4
  69. * @param string $name
  70. * @return array|string|null
  71. * If `$name` is omitted this function returns array.
  72. * If `$name` is not set, this fucntion returns `null`
  73. * If `$name` is set, this function returns string
  74. */
  75. public static function getSetting($name = null) {
  76. if(is_null($name)) return self::$settings;
  77. if(isset(self::$settings[$name])) return self::$settings[$name];
  78. return null;
  79. }
  80. /**
  81. * Uses PHP's date_default_timezone_set function to set the system
  82. * timezone. If the timezone provided is invalid, a `E_USER_WARNING` will be
  83. * raised.
  84. *
  85. * @link http://php.net/manual/en/function.date-default-timezone-set.php
  86. * @link http://www.php.net/manual/en/timezones.php
  87. * @param string $timezone
  88. * A valid timezone identifier, such as UTC or Europe/Lisbon
  89. */
  90. public static function setDefaultTimezone($timezone){
  91. if(!@date_default_timezone_set($timezone)) trigger_error(__('Invalid timezone %s', array($timezone)), E_USER_WARNING);
  92. }
  93. /**
  94. * Validate a given date and time string
  95. *
  96. * @param string $string
  97. * A date and time string or timestamp to validate
  98. * @return boolean
  99. * Returns true for valid dates, otherwise false
  100. */
  101. public static function validate($string) {
  102. try {
  103. if(is_numeric($string) && (int)$string == $string) {
  104. $date = new DateTime('@' . $string);
  105. }
  106. else {
  107. $date = self::parse($string);
  108. }
  109. }
  110. catch(Exception $ex) {
  111. return false;
  112. }
  113. // String is empty or not a valid date
  114. if(empty($string) || $date === false) {
  115. return false;
  116. }
  117. // String is a valid date
  118. else {
  119. return true;
  120. }
  121. }
  122. /**
  123. * Given a `$format`, and a `$timestamp`,
  124. * return the date in the format provided. This function is a basic
  125. * wrapper for PHP's DateTime object. If the `$timestamp` is omitted,
  126. * the current timestamp will be used. Optionally, you pass a
  127. * timezone identifier with this function to localise the output
  128. *
  129. * If you like to display a date in the backend, please make use
  130. * of `DateTimeObj::format()` which allows date and time localization
  131. *
  132. * @see class.datetimeobj.php#format()
  133. * @link http://www.php.net/manual/en/book.datetime.php
  134. * @param string $format
  135. * A valid PHP date format
  136. * @param integer $timestamp (optional)
  137. * A unix timestamp to format. 'now' or omitting this parameter will
  138. * result in the current time being used
  139. * @param string $timezone (optional)
  140. * The timezone associated with the timestamp
  141. * @return string|boolean
  142. * The formatted date, of if the date could not be parsed, false.
  143. */
  144. public static function get($format, $timestamp = 'now', $timezone = null) {
  145. return self::format($timestamp, $format, false, $timezone);
  146. }
  147. /**
  148. * Formats the given date and time `$string` based on the given `$format`.
  149. * Optionally the result will be localized and respect a timezone differing
  150. * from the system default. The default output is ISO 8601.
  151. * Please note that for best compatibility with European dates it is recommended
  152. * that your site be in a PHP5.3 environment.
  153. *
  154. * @since Symphony 2.2.1
  155. * @param string $string (optional)
  156. * A string containing date and time, defaults to the current date and time
  157. * @param string $format (optional)
  158. * A valid PHP date format, defaults to ISO 8601
  159. * @param boolean $localize (optional)
  160. * Localizes the output, if true, defaults to true
  161. * @param string $timezone (optional)
  162. * The timezone associated with the timestamp
  163. * @return string|boolean
  164. * The formatted date, or if the date could not be parsed, false.
  165. */
  166. public static function format($string = 'now', $format = DateTime::ISO8601, $localize = true, $timezone = null) {
  167. // Parse date
  168. $date = self::parse($string);
  169. if($date === false) return false;
  170. // Timezone
  171. // If a timezone was given, apply it
  172. if(!is_null($timezone)) {
  173. $date->setTimezone(new DateTimeZone($timezone));
  174. }
  175. // No timezone given, apply the default timezone
  176. else if (isset(self::$settings['timezone'])) {
  177. $date->setTimezone(new DateTimeZone(self::$settings['timezone']));
  178. }
  179. // Format date
  180. $date = $date->format($format);
  181. // Localize date
  182. // Convert date string from English back to the activated Language
  183. if($localize === true) {
  184. $date = Lang::localizeDate($date);
  185. }
  186. // Return custom formatted date, use ISO 8601 date by default
  187. return $date;
  188. }
  189. /**
  190. * Parses the given string and returns a DateTime object.
  191. * Please note that for best compatibility with European dates it is recommended
  192. * that your site be in a PHP5.3 environment.
  193. *
  194. * @since Symphony 2.3
  195. * @param string $string (optional)
  196. * A string containing date and time, defaults to the current date and time
  197. * @return DateTime|boolean
  198. * The DateTime object, or if the date could not be parsed, false.
  199. */
  200. public static function parse($string) {
  201. // Current date and time
  202. if($string == 'now' || empty($string)) {
  203. $date = new DateTime();
  204. }
  205. // Timestamp
  206. elseif(is_numeric($string)) {
  207. $date = new DateTime('@' . $string);
  208. }
  209. // Attempt to parse the date provided against the Symphony configuration setting
  210. // in an effort to better support multilingual date formats. Should this fail
  211. // this block will fallback to just passing the date to DateTime constructor,
  212. // which will parse the date assuming it's in an American format.
  213. else {
  214. // Standardize date
  215. // Convert date string to English
  216. $string = Lang::standardizeDate($string);
  217. // PHP 5.3: Apply Symphony date format using `createFromFormat`
  218. if(method_exists('DateTime', 'createFromFormat')) {
  219. $date = DateTime::createFromFormat(self::$settings['datetime_format'], $string);
  220. if($date === false) {
  221. $date = DateTime::createFromFormat(self::$settings['date_format'], $string);
  222. }
  223. // Handle dates that are in a different format to Symphony's config
  224. // DateTime is much the same as `strtotime` and will handle relative
  225. // dates.
  226. if($date === false) {
  227. try {
  228. $date = new DateTime($string);
  229. }
  230. catch(Exception $ex) {
  231. // Invalid date, it can't be parsed
  232. return false;
  233. }
  234. }
  235. }
  236. // PHP 5.2: Fallback to DateTime parsing.
  237. // Note that this parsing will not respect European dates.
  238. else {
  239. try {
  240. $date = new DateTime($string);
  241. }
  242. catch(Exception $ex) {
  243. // Invalid date, it can't be parsed
  244. return false;
  245. }
  246. }
  247. // If the date is still invalid, just return false.
  248. if($date === false) {
  249. return false;
  250. }
  251. }
  252. // Return custom formatted date, use ISO 8601 date by default
  253. return $date;
  254. }
  255. /**
  256. * A wrapper for get, this function will force the GMT timezone.
  257. *
  258. * @param string $format
  259. * A valid PHP date format
  260. * @param integer $timestamp (optional)
  261. * A unix timestamp to format. Omitting this parameter will
  262. * result in the current time being used
  263. * @return string
  264. * The formatted date in GMT
  265. */
  266. public static function getGMT($format, $timestamp = 'now'){
  267. return self::format($timestamp, $format, false, 'GMT');
  268. }
  269. /**
  270. * A wrapper for get, this function will return a HTML string representing
  271. * an `<abbr>` element which contained the formatted date of now, and an
  272. * RFC 2822 formatted date (Thu, 21 Dec 2000 16:01:07 +0200) as the title
  273. * attribute. Symphony uses this in it's status messages so that it can
  274. * dynamically update how long ago the action took place using Javascript.
  275. *
  276. * @deprecated This will be removed in the next version of Symphony
  277. * @param string $format
  278. * A valid PHP date format
  279. * @return string
  280. * A HTML string of an `<abbr>` element with a class of 'timeago' and the current
  281. * date (RFC 2822) as the title element. The value is the current time as
  282. * specified by the `$format`.
  283. */
  284. public static function getTimeAgo($format = __SYM_TIME_FORMAT__){
  285. $time = Widget::Time('', $format);
  286. return $time->generate();
  287. }
  288. /**
  289. * This functions acts as a standard way to get the zones
  290. * available on the system. For PHP5.2, these constants are
  291. * just copied from PHP5.3
  292. *
  293. * @since Symphony 2.3
  294. * @link http://au2.php.net/manual/en/class.datetimezone.php
  295. * @return array
  296. */
  297. public static function getZones() {
  298. if(PHP_VERSION_ID >= 50300) {
  299. $ref = new ReflectionClass('DateTimeZone');
  300. return $ref->getConstants();
  301. }
  302. else {
  303. return array(
  304. 'AFRICA' => 1,
  305. 'AMERICA' => 2,
  306. 'ANTARCTICA' => 4,
  307. 'ARCTIC' => 8,
  308. 'ASIA' => 16,
  309. 'ATLANTIC' => 32,
  310. 'AUSTRALIA' => 64,
  311. 'EUROPE' => 128,
  312. 'INDIAN' => 256,
  313. 'PACIFIC' => 512,
  314. 'UTC' => 1024
  315. );
  316. }
  317. }
  318. /**
  319. * This functions acts as a standard way to get the timezones
  320. * regardless of PHP version. It accepts a single parameter,
  321. * zone, which returns the timezones associated with that 'zone'
  322. *
  323. * @since Symphony 2.3
  324. * @link http://au2.php.net/manual/en/class.datetimezone.php
  325. * @link http://au2.php.net/manual/en/datetimezone.listidentifiers.php
  326. * @param string $zone
  327. * The zone for the timezones the field wants. This maps to the
  328. * DateTimeZone constants
  329. * @return array
  330. */
  331. public static function getTimezones($zone = null) {
  332. // PHP5.3 supports the `$what` parameter of the listIdentifiers function
  333. if(PHP_VERSION_ID >= 50300) {
  334. return DateTimeZone::listIdentifiers(constant('DateTimeZone::' . $zone));
  335. }
  336. else {
  337. $timezones = DateTimeZone::listIdentifiers();
  338. foreach($timezones as $index => $timezone) {
  339. if(stripos($timezone, $zone) === false) unset($timezones[$index]);
  340. }
  341. return $timezones;
  342. }
  343. }
  344. /**
  345. * Loads all available timezones using `getTimezones()` and builds an
  346. * array where timezones are grouped by their region (Europe/America etc.)
  347. * The options array that is returned is designed to be used with
  348. * `Widget::Select`
  349. *
  350. * @since Symphony 2.3
  351. * @see core.DateTimeObj#getTimezones()
  352. * @see core.Widget#Select()
  353. * @param string $selected
  354. * A preselected timezone, defaults to null
  355. * @return array
  356. * An associative array, for use with `Widget::Select`
  357. */
  358. public static function getTimezonesSelectOptions($selected = null){
  359. $zones = self::getZones();
  360. $groups = array();
  361. foreach($zones as $zone => $value) {
  362. if($value >= 1024) break;
  363. $timezones = self::getTimezones($zone);
  364. $options = array();
  365. foreach($timezones as $timezone) {
  366. $tz = new DateTime('now', new DateTimeZone($timezone));
  367. $options[] = array($timezone, ($timezone == $selected), sprintf("%s %s",
  368. str_replace('_', ' ', substr(strrchr($timezone, '/'),1)),
  369. $tz->format('P')
  370. ));
  371. }
  372. $groups[] = array('label' => ucwords(strtolower($zone)), 'options' => $options);
  373. }
  374. return $groups;
  375. }
  376. /**
  377. * Returns an array of the date formats Symphony supports. These
  378. * formats are a combination of valid PHP format tokens.
  379. *
  380. * @link http://au2.php.net/manual/en/function.date.php
  381. * @since Symphony 2.3
  382. * @return array
  383. */
  384. public static function getDateFormats(){
  385. return array(
  386. 'Y/m/d', // e. g. 2011/01/20
  387. 'm/d/Y', // e. g. 01/20/2011
  388. 'm/d/y', // e. g. 10/20/11
  389. 'Y-m-d', // e. g. 2011-01-20
  390. 'm-d-Y', // e. g. 01-20-2011
  391. 'm-d-y', // e. g. 01-20-11
  392. 'd.m.Y', // e. g. 20.01.2011
  393. 'j.n.Y', // e. g. 20.1.2011 - no leading zeros
  394. 'd.m.y', // e. g. 20.01.11
  395. 'j.n.y', // e. g. 20.1.11 - no leading zeros
  396. 'd F Y', // e. g. 20 January 2011
  397. 'd M Y', // e. g. 20 Jan 2011
  398. 'j. F Y', // e. g. 20. January 2011 - no leading zeros
  399. 'j. M. Y', // e. g. 20. Jan. 2011 - no leading zeros
  400. );
  401. }
  402. /**
  403. * Returns an array of the date formats Symphony supports by applying
  404. * the format to the current datetime. The array returned is for use with
  405. * `Widget::Select()`
  406. *
  407. * @since Symphony 2.3
  408. * @see core.Widget#Select()
  409. * @param string $selected
  410. * A preselected date format, defaults to null
  411. * @return array
  412. * An associative array, for use with `Widget::Select`
  413. */
  414. public static function getDateFormatsSelectOptions($selected = null){
  415. $formats = self::getDateFormats();
  416. $options = array();
  417. foreach($formats as $option) {
  418. $leadingZero = '';
  419. if(strpos($option, 'j') !== false || strpos($option, 'n') !== false) {
  420. $leadingZero = ' (' . __('no leading zeros') . ')';
  421. }
  422. $options[] = array($option, $option == $selected, self::format('now', $option) . $leadingZero);
  423. }
  424. return $options;
  425. }
  426. /**
  427. * Returns an array of the time formats Symphony supports. These
  428. * formats are a combination of valid PHP format tokens.
  429. *
  430. * @link http://au2.php.net/manual/en/function.date.php
  431. * @since Symphony 2.3
  432. * @return array
  433. */
  434. public static function getTimeFormats(){
  435. return array(
  436. 'H:i:s', // e. g. 20:45:32
  437. 'H:i', // e. g. 20:45
  438. 'g:i:s a', // e. g. 8:45:32 pm
  439. 'g:i a', // e. g. 8:45 pm
  440. );
  441. }
  442. /**
  443. * Returns an array of the time formats Symphony supports by applying
  444. * the format to the current datetime. The array returned is for use with
  445. * `Widget::Select()`
  446. *
  447. * @since Symphony 2.3
  448. * @see core.Widget#Select()
  449. * @param string $selected
  450. * A preselected time format, defaults to null
  451. * @return array
  452. * An associative array, for use with `Widget::Select`
  453. */
  454. public static function getTimeFormatsSelectOptions($selected = null){
  455. $formats = self::getTimeFormats();
  456. $options = array();
  457. foreach($formats as $option) {
  458. $options[] = array($option, $option == $selected, self::get($option));
  459. }
  460. return $options;
  461. }
  462. }