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