PageRenderTime 50ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/src/legacy/util/DateUtil.php

https://github.com/antoniom/core
PHP | 951 lines | 507 code | 103 blank | 341 comment | 112 complexity | 7a98aa976c1379d6ec73a4078b909030 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-3.0, MIT
  1. <?php
  2. /**
  3. * Copyright Zikula Foundation 2009 - Zikula Application Framework
  4. *
  5. * This work is contributed to the Zikula Foundation under one or more
  6. * Contributor Agreements and licensed to You under the following license:
  7. *
  8. * @license GNU/LGPLv3 (or at your option, any later version).
  9. * @package Util
  10. *
  11. * Please see the NOTICE file distributed with this source code for further
  12. * information regarding copyright and licensing.
  13. */
  14. /**
  15. * constants for this class
  16. */
  17. define('DATEFORMAT_FIXED', '%Y-%m-%d %H:%M:%S');
  18. define('DATEONLYFORMAT_FIXED', '%Y-%m-%d');
  19. /**
  20. * DateUtil.
  21. */
  22. class DateUtil
  23. {
  24. /**
  25. * Return a formatted datetime for the given timestamp (or for now).
  26. *
  27. * @param string $time The timestamp (string) which we wish to format (default==now).
  28. * @param string $format The format to use when formatting the date (optional).
  29. *
  30. * @return datetime The datetime formatted according to the specified format.
  31. */
  32. public static function getDatetime($time=null, $format=null)
  33. {
  34. if (is_null($format)) {
  35. $format = DATEFORMAT_FIXED;
  36. }
  37. switch (trim(strtolower($format))) {
  38. case 'datelong':
  39. //! datelong
  40. $format = __('%A, %B %d, %Y');
  41. break;
  42. case 'datebrief':
  43. //! datebrief
  44. $format = __('%b %d, %Y');
  45. break;
  46. case 'datestring':
  47. //! datestring
  48. $format = __('%A, %B %d @ %H:%M:%S');
  49. break;
  50. case 'datestring2':
  51. //! datestring2
  52. $format = __('%A, %B %d');
  53. break;
  54. case 'datetimebrief':
  55. //! datetimebrief
  56. $format = __('%b %d, %Y - %I:%M %p');
  57. break;
  58. case 'datetimelong':
  59. //! datetimelong
  60. $format = __('%A, %B %d, %Y - %I:%M %p');
  61. break;
  62. case 'datefeed':
  63. //! RFC 822 date format for RSS feeds
  64. $format = __('%a, %d %b %Y %H:%M:%S %Z');
  65. break;
  66. case 'timebrief':
  67. //! timebrief
  68. $format = __('%I:%M %p');
  69. break;
  70. case 'timelong':
  71. //! timelong
  72. $format = __('%T %p');
  73. break;
  74. default:
  75. $format = __($format);
  76. break;
  77. } // switch
  78. if ($time) {
  79. $dtstr = self::strftime($format, $time);
  80. } else {
  81. $dtstr = self::strftime($format);
  82. }
  83. return $dtstr;
  84. }
  85. /**
  86. * Transform a timestamp to internal datetime format.
  87. *
  88. * @param int $timestamp The timestamp.
  89. *
  90. * @return string The datetime into internal format.
  91. */
  92. public static function transformInternalDateTime($timestamp)
  93. {
  94. return self::strftime(DATEFORMAT_FIXED, $timestamp);
  95. }
  96. /**
  97. * Transform a timestamp to internal date only format.
  98. *
  99. * @param int $timestamp The timestamp.
  100. *
  101. * @return string The date into internal format.
  102. */
  103. public static function transformInternalDate($timestamp)
  104. {
  105. return self::strftime(DATEONLYFORMAT_FIXED, $timestamp);
  106. }
  107. /**
  108. * Reformat a given datetime according to the specified format.
  109. *
  110. * @param string $datetime The (string) datetime to reformat.
  111. * @param string $format The format to use when formatting the date (optional).
  112. * @param boolean $TZadjust Adjust the output according to Timezone, default true.
  113. *
  114. * @return string The datetime formatted according to the specified format.
  115. */
  116. public static function formatDatetime($datetime=null, $format=DATEFORMAT_FIXED, $TZadjust=true)
  117. {
  118. if ($datetime === null) {
  119. return '';
  120. }
  121. if (!empty($datetime)) {
  122. if ($datetime instanceof DateTime) {
  123. $time = $datetime->getTimestamp();
  124. } else {
  125. $time = self::makeTimestamp($datetime);
  126. }
  127. //$time = self::parseUIDate($datetime);
  128. } else {
  129. $time = time();
  130. }
  131. // adjust with the user timezone diff
  132. if ($TZadjust) {
  133. $time -= self::getTimezoneUserDiff();
  134. }
  135. return self::getDatetime($time, $format);
  136. }
  137. /**
  138. * Build a datetime string from the supplied fields.
  139. *
  140. * This method uses the PHP function {@link http://www.php.net/mktime mktime}
  141. * to construct a UNIX timestamp prior to returning the output from
  142. * {@link DateUtil::strftime}. It is, therefore, subject to the same
  143. * limitations as mktime. Specifically, on most systems where time is stored
  144. * as a 32-bit integer the possible timestamps that can be constructed fall
  145. * between 13 Decemnber 1901 at 20:45:52 UTC and 19 January 2038 at
  146. * 03:14:07 UTC.
  147. *
  148. * @param integer $year The year.
  149. * @param integer $month The month.
  150. * @param integer $day The day.
  151. * @param integer $hour The hour (optional) (default==0).
  152. * @param integer $minute The minute (optional) (default==0).
  153. * @param integer $second The second (optional) (default==0).
  154. * @param string $format The format to use when formatting the date (optional) (default==DATEFORMAT_FIXED).
  155. *
  156. * @return string The datetime formatted according to the specified format.
  157. */
  158. public static function buildDatetime($year, $month, $day, $hour=0, $minute=0, $second=0, $format=DATEFORMAT_FIXED)
  159. {
  160. $dTime = mktime($hour, $minute, $second, $month, $day, $year);
  161. return self::strftime($format, $dTime);
  162. }
  163. /**
  164. * Return a formatted datetime at the end of the business day n days from now.
  165. *
  166. * @param integer $num The number of days to advance (optional) (default=1).
  167. * @param string $format The format to use when formatting the date (optional).
  168. * @param integer $year The year of the target date to set (optional) (default=null, means params is taken from now).
  169. * @param integer $month The month of the target date to set (optional) (default=null, means params is taken from now).
  170. * @param integer $day The day of the target date to set (optional) (default=null, means params is taken from now).
  171. * @param integer $hour The hour of the target time to set (optional) (default=null, means params is taken from now).
  172. * @param integer $minute The minute of the target time to set (optional) (default=null, means params is taken from now).
  173. * @param integer $second The second of the target time to set (optional) (default=null, means params is taken from now).
  174. *
  175. * @return string The datetime formatted according to the specified format.
  176. */
  177. public static function getDatetime_NextDay($num=1, $format=DATEFORMAT_FIXED, $year=null, $month=null, $day=null, $hour=null, $minute=null, $second=null)
  178. {
  179. $next = mktime($hour != null ? (int)$hour : date('H'),
  180. $minute != null ? (int)$minute : date('i'),
  181. $second != null ? (int)$second : date('s'),
  182. $month != null ? (int)$month : date('m'),
  183. $day != null ? (int)$day + $num : date('d') + $num,
  184. $year != null ? (int)$year : date('y'));
  185. return self::strftime($format, $next);
  186. }
  187. /**
  188. * Return a formatted datetime at the end of the business day n week from now.
  189. *
  190. * @param integer $num The number of weeks to advance (optional) (default=1).
  191. * @param string $format The format to use when formatting the date (optional).
  192. * @param integer $year The year of the target time to set (optional) (default=null, means param is taken from now).
  193. * @param integer $month The month of the target time to set (optional) (default=null, means param is taken from now).
  194. * @param integer $day The day of the target time to set (optional) (default=null, means param is taken from now).
  195. * @param integer $hour The hour of the target time to set (optional) (default=null, means param is taken from now).
  196. * @param integer $minute The minute of the target time to set (optional) (default=null, means param is taken from now).
  197. * @param integer $second The second of the target time to set (optional) (default=null, means param is taken from now).
  198. *
  199. * @return string The datetime formatted according to the specified format.
  200. */
  201. public static function getDatetime_NextWeek($num=1, $format=DATEFORMAT_FIXED, $year=null, $month=null, $day=null, $hour=null, $minute=null, $second=null)
  202. {
  203. $num *= 7;
  204. $next = mktime($hour != null ? (int)$hour : date('H'),
  205. $minute != null ? (int)$minute : date('i'),
  206. $second != null ? (int)$second : date('s'),
  207. $month != null ? (int)$month : date('m'),
  208. $day != null ? (int)$day + $num : date('d') + $num,
  209. $year != null ? (int)$year : date('y'));
  210. return self::strftime($format, $next);
  211. }
  212. /**
  213. * Return a formatted datetime at the end of the business day n months from now.
  214. *
  215. * @param integer $num The number of months to advance (optional) (default=1).
  216. * @param string $format The format to use when formatting the date (optional).
  217. * @param integer $year The year of the target time to set (optional) (default=null, means param is taken from now).
  218. * @param integer $month The month of the target time to set (optional) (default=null, means param is taken from now).
  219. * @param integer $day The day of the target time to set (optional) (default=null, means param is taken from now).
  220. * @param integer $hour The hour of the target time to set (optional) (default=null, means param is taken from now).
  221. * @param integer $minute The minute of the target time to set (optional) (default=null, means param is taken from now).
  222. * @param integer $second The second of the target time to set (optional) (default=null, means param is taken from now).
  223. *
  224. * @return string The datetime formatted according to the specified format.
  225. */
  226. public static function getDatetime_NextMonth($num=1, $format=DATEFORMAT_FIXED, $year=null, $month=null, $day=null, $hour=null, $minute=null, $second=null)
  227. {
  228. $next = mktime($hour != null ? (int)$hour : date('H'),
  229. $minute != null ? (int)$minute : date('i'),
  230. $second != null ? (int)$second : date('s'),
  231. $month != null ? (int)$month + $num : date('m') + $num,
  232. $day != null ? (int)$day : date('d'),
  233. $year != null ? (int)$year : date('y'));
  234. return self::strftime($format, $next);
  235. }
  236. /**
  237. * Return a formatted datetime at the end of the business day n years from now
  238. *
  239. * @param integer $num The number of years to advance (optional) (default=1).
  240. * @param string $format The format to use when formatting the date (optional).
  241. * @param integer $year The year of the target time to set (optional) (default=null, means param is taken from now).
  242. * @param integer $month The month of the target time to set (optional) (default=null, means param is taken from now).
  243. * @param integer $day The day of the target time to set (optional) (default=null, means param is taken from now).
  244. * @param integer $hour The hour of the target time to set (optional) (default=null, means param is taken from now).
  245. * @param integer $minute The minute of the target time to set (optional) (default=null, means param is taken from now).
  246. * @param integer $second The second of the target time to set (optional) (default=null, means param is taken from now).
  247. *
  248. * @return string The datetime formatted according to the specified format.
  249. */
  250. public static function getDatetime_NextYear($num=1, $format=DATEFORMAT_FIXED, $year=null, $month=null, $day=null, $hour=null, $minute=null, $second=null)
  251. {
  252. $next = mktime($hour != null ? (int)$hour : date('H'),
  253. $minute != null ? (int)$minute : date('i'),
  254. $second != null ? (int)$second : date('s'),
  255. $month != null ? (int)$month : date('m'),
  256. $day != null ? (int)$day : date('d'),
  257. $year != null ? (int)$year + $num : date('y') + $num);
  258. return self::strftime($format, $next);
  259. }
  260. /**
  261. * Return the date portion of a datetime timestamp.
  262. *
  263. * @param string $datetime The date to parse (optional) (default=='', reverts to now).
  264. * @param string $format The format to use when formatting the date (optional).
  265. *
  266. * @return string The Date portion of the specified datetime.
  267. */
  268. public static function getDatetime_Date($datetime='', $format=DATEFORMAT_FIXED)
  269. {
  270. if (!$datetime) {
  271. $datetime = self::getDatetime();
  272. }
  273. $dTime = strtotime($datetime);
  274. $sTime = self::getDatetime($dTime, $format);
  275. if ($format == DATEFORMAT_FIXED) {
  276. return substr($sTime, 0, 10);
  277. }
  278. $spaceOffset = strpos($datetime, ' ');
  279. return substr($sTime, 0, $spaceOffset);
  280. }
  281. /**
  282. * Return the time portion of a datetime timestamp.
  283. *
  284. * @param string $datetime The date to parse (optional) (default=='', reverts to now).
  285. * @param string $format The format to use when formatting the date (optional).
  286. *
  287. * @return string The Time portion of the specified datetime.
  288. */
  289. public static function getDatetime_Time($datetime='', $format=DATEFORMAT_FIXED)
  290. {
  291. if (!$datetime) {
  292. $datetime = self::getDatetime();
  293. }
  294. $dTime = strtotime($datetime);
  295. $sTime = self::getDatetime($dTime, $format);
  296. if ($format == DATEFORMAT_FIXED) {
  297. return substr($sTime, 11);
  298. }
  299. $spaceOffset = strpos($datetime, ' ');
  300. return substr($datetime, $spaceOffset + 1);
  301. }
  302. /**
  303. * Return the requested field from the supplied date.
  304. *
  305. * Since the date fields can change depending on the date format,
  306. * the following convention is used when referring to date fields:<br />
  307. * Field 1 -> Year<br />
  308. * Field 2 -> Month<br />
  309. * Field 3 -> Day<br />
  310. * Field 4 -> Hour<br />
  311. * Field 5 -> Minute<br />
  312. * Field 6 -> Second<br />
  313. *
  314. * @param string $datetime The field number to return.
  315. * @param string $field The date to parse (default=='', reverts to now).
  316. *
  317. * @return string The requested datetime field
  318. */
  319. public static function getDatetime_Field($datetime, $field)
  320. {
  321. if (!$datetime) {
  322. $datetime = self::getDatetime();
  323. }
  324. $dTime = strtotime($datetime);
  325. $sTime = self::getDatetime($dTime);
  326. // adjust for human counting
  327. $field--;
  328. if ($field <= 2) {
  329. // looking for a date part
  330. $date = self::getDatetime_Date($sTime);
  331. $fields = explode('-', $date);
  332. } else {
  333. // looking for a time part
  334. $field -= 3;
  335. $time = self::getDatetime_Time($sTime);
  336. $fields = explode(':', $time);
  337. }
  338. return $fields[$field];
  339. }
  340. /**
  341. * Return an structured array holding the differences between 2 dates.
  342. *
  343. * The returned array will be structured as follows:<br>
  344. * Array (<br />
  345. * [d] => _numeric_day_value_<br />
  346. * [h] => _numeric_hour_value_<br />
  347. * [m] => _numeric_minute_value_<br />
  348. * [s] => _numeric_second_value_ )<br />
  349. *
  350. * @param string $date1 The first date.
  351. * @param string $date2 The second date.
  352. *
  353. * @return array The structured array containing the datetime difference.
  354. */
  355. public static function getDatetimeDiff($date1, $date2)
  356. {
  357. if (!is_numeric($date1)) {
  358. $date1 = strtotime($date1);
  359. }
  360. if (!is_numeric($date2)) {
  361. $date2 = strtotime($date2);
  362. }
  363. $s = $date2 - $date1;
  364. $d = intval($s / 86400);
  365. $s -= $d * 86400;
  366. $h = intval($s / 3600);
  367. $s -= $h * 3600;
  368. $m = intval($s / 60);
  369. $s -= $m * 60;
  370. return array('d' => $d, 'h' => $h, 'm' => $m, 's' => $s);
  371. }
  372. /**
  373. * Return an field holding the differences between 2 dates expressed in units of the field requested.
  374. *
  375. * Since the date fields can change depending on the date format,
  376. * the following convention is used when referring to date fields:<br />
  377. * Field 1 -> Year<br />
  378. * Field 2 -> Month<br />
  379. * Field 3 -> Day<br />
  380. * Field 4 -> Hour<br />
  381. * Field 5 -> Minute<br />
  382. * Field 6 -> Second<br />
  383. *
  384. * @param string $date1 The first date.
  385. * @param string $date2 The second date.
  386. * @param integer $field The field (unit) in which we want the different (optional) (default=5).
  387. *
  388. * @return float The difference in units of the specified field.
  389. */
  390. public static function getDatetimeDiff_AsField($date1, $date2, $field=5)
  391. {
  392. if (!is_numeric($date1)) {
  393. $date1 = strtotime($date1);
  394. }
  395. if (!is_numeric($date2)) {
  396. $date2 = strtotime($date2);
  397. }
  398. $s = $date2 - $date1;
  399. $diff = 0;
  400. if ($field == 1) {
  401. $diff = $s / (60 * 60 * 24 * 31 * 12);
  402. } elseif ($field == 2) {
  403. $diff = $s / (60 * 60 * 24 * 31);
  404. } elseif ($field == 3) {
  405. $diff = $s / (60 * 60 * 24);
  406. } elseif ($field == 4) {
  407. $diff = $s / (60 * 60);
  408. } elseif ($field == 5) {
  409. $diff = $s / (60);
  410. } else {
  411. $diff = $s;
  412. }
  413. return $diff;
  414. }
  415. /**
  416. * Calculate day-x of KW in a YEAR.
  417. *
  418. * @param integer $day Values :0 for monday, 6 for sunday,....
  419. * @param integer $kw Week of the year.
  420. * @param integer $year Year.
  421. * @param string $flag The u or s (unixtimestamp or MySQLDate).
  422. *
  423. * @return unixtimestamp or sqlDate.
  424. */
  425. public static function getDateofKW($day, $kw, $year, $flag='s')
  426. {
  427. $wday = date('w', mktime(0, 0, 0, 1, 1, $year)); // 1=Monday,...,7 = Sunday
  428. if ($wday <= 4) {
  429. $firstday = mktime(0, 0, 0, 1, 1 - ($wday - 1) + $day, $year);
  430. } else {
  431. $firstday = mktime(0, 0, 0, 1, 1 + (7 - $wday + 1) + $day, $year);
  432. }
  433. $month = date('m', $firstday);
  434. $year = date('Y', $firstday);
  435. $day = date('d', $firstday);
  436. $adddays = ($kw - 1) * 7;
  437. if ($flag != 's') {
  438. $return = mktime(0, 0, 0, $month, $day + $adddays, $year);
  439. } else {
  440. $return = self::getDatetime(mktime(0, 0, 0, $month, $day + $adddays, $year));
  441. }
  442. return $return;
  443. }
  444. /**
  445. * Return a the number of days in the given month/year.
  446. *
  447. * @param integer $month The (human) month number to check.
  448. * @param integer $year The year number to check.
  449. *
  450. * @return integer The number of days in the given month/year
  451. */
  452. public static function getDaysInMonth($month, $year)
  453. {
  454. if ($month < 1 || $month > 12) {
  455. return 0;
  456. }
  457. $days = array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
  458. $d = $days[$month - 1];
  459. if ($month == 2) {
  460. // Check for leap year, no 4000 rule
  461. if ($year % 4 == 0) {
  462. if ($year % 100 == 0) {
  463. if ($year % 400 == 0) {
  464. $d = 29;
  465. }
  466. } else {
  467. $d = 29;
  468. }
  469. }
  470. }
  471. return $d;
  472. }
  473. /**
  474. * Return an array of weekdays for the given month.
  475. *
  476. * @param integer $month The (human) month number to check.
  477. * @param integer $year The year number to check.
  478. *
  479. * @return integer The number of days in the given month/year.
  480. */
  481. public static function getWeekdaysInMonth($month, $year)
  482. {
  483. $nDays = self::getDaysInMonth($month, $year);
  484. $weekdays = array();
  485. for ($i = 1; $i <= $nDays; $i++) {
  486. $time = mktime(12, 0, 0, $month, $i, $year);
  487. $tDate = getdate($time);
  488. $weekdays[$i] = $tDate['wday'];
  489. }
  490. return $weekdays;
  491. }
  492. /**
  493. * Return an array of dates for the given month.
  494. *
  495. * @param integer $month The (human) month number to check.
  496. * @param integer $year The year number to check.
  497. *
  498. * @return integer The number of days in the given month/year.
  499. */
  500. public static function getMonthDates($month, $year)
  501. {
  502. $dates = array();
  503. $days = self::getDaysInMonth($month, $year);
  504. for ($i = 1; $i <= $days; $i++) {
  505. $dates[$i] = self::buildDatetime($year, $month, $i);
  506. }
  507. return $dates;
  508. }
  509. /**
  510. * Parses a user interface date string (excluding time) into a timestamp.
  511. *
  512. * @param string $text The UI date string.
  513. * @param string $format The format date string.
  514. *
  515. * @return string The timestamp or null in case of errors.
  516. */
  517. public static function parseUIDate($text, $format=null)
  518. {
  519. return self::parseUIDateTime($text, $format);
  520. }
  521. /**
  522. * Parses a user interface date+time string into a timestamp.
  523. *
  524. * @param string $text The UI date+time string.
  525. * @param string $dateformat The format of the date.
  526. *
  527. * @return string The timestamp or null in case of errors.
  528. */
  529. public static function parseUIDateTime($text, $dateformat=null)
  530. {
  531. $format = self::getDateFormatData($dateformat);
  532. $yearPos = $format['matches']['year'];
  533. $monthPos = $format['matches']['month'];
  534. $dayPos = $format['matches']['day'];
  535. if ($format['type'] == 'datetimeshort') {
  536. $hourPos = $format['matches']['hour'];
  537. $minutePos = $format['matches']['minute'];
  538. } elseif ($format['type'] == 'datetimefull') {
  539. $hourPos = $format['matches']['hour'];
  540. $minutePos = $format['matches']['minute'];
  541. $secondPos = $format['matches']['second'];
  542. }
  543. $regex = $format['regex'];
  544. if (preg_match("/$regex/", $text, $matches)) {
  545. $year = $matches[$yearPos];
  546. $month = $matches[$monthPos];
  547. $day = $matches[$dayPos];
  548. $sec = 0;
  549. $min = 0;
  550. $hour = 0;
  551. if ($format['type'] == 'datetimeshort') {
  552. $hour = $matches[$hourPos];
  553. $min = $matches[$minutePos];
  554. } elseif ($format['type'] == 'datetimefull') {
  555. $hour = $matches[$hourPos];
  556. $min = $matches[$minutePos];
  557. $sec = $matches[$secondPos];
  558. }
  559. if (!checkdate($month, $day, $year) || $hour > 23 || $min > 59 || $sec > 59) {
  560. return null;
  561. }
  562. } else {
  563. return null;
  564. }
  565. return mktime($hour, $min, $sec, $month, $day, $year);
  566. }
  567. /**
  568. * Create a unix timestamp from either a unix timestamp (sic!), a MySQL timestamp or a string.
  569. *
  570. * This code is taken from smarty_make_timestamp.php, credits go to Monte Ohrt <monte at ohrt dot com>.
  571. *
  572. * We use a copy of the code here due to performance reasons.
  573. *
  574. * @param mixed $string A timestamp in one of the formats mentioned.
  575. *
  576. * @return integer A unix timestamp.
  577. */
  578. public static function makeTimestamp($string='')
  579. {
  580. if (empty($string)) {
  581. // use 'now'
  582. $time = time();
  583. } elseif (preg_match('/^\d{14}$/', $string)) {
  584. // it is mysql timestamp format of YYYYMMDDHHMMSS?
  585. $time = mktime(substr($string, 8, 2), substr($string, 10, 2), substr($string, 12, 2),
  586. substr($string, 4, 2), substr($string, 6, 2), substr($string, 0, 4));
  587. } elseif (is_numeric($string)) {
  588. // it is a numeric string, we handle it as timestamp
  589. $time = (int)$string;
  590. } else {
  591. // strtotime should handle it
  592. $time = strtotime($string);
  593. if ($time == -1 || $time === false) {
  594. // strtotime() was not able to parse $string, use 'now'
  595. $time = time();
  596. }
  597. }
  598. return $time;
  599. }
  600. /**
  601. * Identify timezone using the date PHP function.
  602. *
  603. * Does not use the strftime because it varies depending of the operative system.
  604. *
  605. * @return string timezone integer (hour value).
  606. */
  607. public static function getTimezone()
  608. {
  609. $ts = self::makeTimestamp();
  610. $tz = date('O', $ts);
  611. if (!is_numeric($tz)) {
  612. return false;
  613. }
  614. // we probably need some fixes depending on the day light saving here
  615. // fix the value to match the Zikula timezones ones
  616. return (float)sprintf('%2.2f', $tz / 100);
  617. }
  618. /**
  619. * Return the translated name of a specific timezone if exists.
  620. *
  621. * @param integer $tz Timezone identifier.
  622. *
  623. * @return string Timezone translation (hour value).
  624. */
  625. public static function getTimezoneText($tz=null)
  626. {
  627. if (!is_numeric($tz)) {
  628. return false;
  629. }
  630. $timezones = self::getTimezones();
  631. if (isset($timezones[$tz])) {
  632. return $timezones[$tz];
  633. }
  634. // string freeze: can't return 'Unknown timezone'
  635. return __('Unknown timezone');
  636. }
  637. /**
  638. * Return the translated list of timezones.
  639. *
  640. * @return array Timezones values and gettext strings.
  641. */
  642. public static function getTimezones()
  643. {
  644. return array('-12' => __('(GMT -12:00 hours) Baker Island'),
  645. '-11' => __('(GMT -11:00 hours) Midway Island, Samoa'),
  646. '-10' => __('(GMT -10:00 hours) Hawaii'),
  647. '-9.5' => __('(GMT -9:30 hours) French Polynesia'),
  648. '-9' => __('(GMT -9:00 hours) Alaska'),
  649. '-8' => __('(GMT -8:00 hours) Pacific Time (US & Canada)'),
  650. '-7' => __('(GMT -7:00 hours) Mountain Time (US & Canada)'),
  651. '-6' => __('(GMT -6:00 hours) Central Time (US & Canada), Mexico City'),
  652. '-5' => __('(GMT -5:00 hours) Eastern Time (US & Canada), Bogota, Lima, Quito'),
  653. '-4' => __('(GMT -4:00 hours) Atlantic Time (Canada), Caracas, La Paz'),
  654. '-3.5' => __('(GMT -3:30 hours) Newfoundland'),
  655. '-3' => __('(GMT -3:00 hours) Brazil, Buenos Aires, Georgetown'),
  656. '-2' => __('(GMT -2:00 hours) Mid-Atlantic'),
  657. '-1' => __('(GMT -1:00 hours) Azores, Cape Verde Islands'),
  658. '0' => __('(GMT) Western Europe Time, London, Lisbon, Casablanca, Monrovia'),
  659. '1' => __('(GMT +1:00 hours) CET (Central Europe Time), Brussels, Copenhagen, Madrid, Paris'),
  660. '2' => __('(GMT +2:00 hours) EET (Eastern Europe Time), Kaliningrad, South Africa'),
  661. '3' => __('(GMT +3:00 hours) Baghdad, Kuwait, Riyadh, Moscow, St. Petersburg'),
  662. '3.5' => __('(GMT +3:30 hours) Tehran'),
  663. '4' => __('(GMT +4:00 hours) Abu Dhabi, Muscat, Baku, Tbilisi'),
  664. '4.5' => __('(GMT +4:30 hours) Kabul'),
  665. '5' => __('(GMT +5:00 hours) Ekaterinburg, Islamabad, Karachi, Tashkent'),
  666. '5.5' => __('(GMT +5:30 hours) Bombay, Calcutta, Madras, New Delhi'),
  667. '5.75' => __('(GMT +5:45 hours) Kathmandu'),
  668. '6' => __('(GMT +6:00 hours) Almaty, Dhaka, Colombo'),
  669. '6.5' => __('(GMT +6:30 hours) Cocos Islands, Myanmar'),
  670. '7' => __('(GMT +7:00 hours) Bangkok, Hanoi, Jakarta'),
  671. '8' => __('(GMT +8:00 hours) Beijing, Perth, Singapore, Hong Kong, Chongqing, Urumqi, Taipei'),
  672. '9' => __('(GMT +9:00 hours) Tokyo, Seoul, Osaka, Sapporo, Yakutsk'),
  673. '9.5' => __('(GMT +9:30 hours) Adelaide, Darwin'),
  674. '10' => __('(GMT +10:00 hours) EAST (East Australian Standard)'),
  675. '10.5' => __('(GMT +10:30 hours) Lord Howe Island (NSW, Australia)'),
  676. '11' => __('(GMT +11:00 hours) Magadan, Solomon Islands, New Caledonia'),
  677. '11.5' => __('(GMT +11:30 hours) Norfolk Island'),
  678. '12' => __('(GMT +12:00 hours) Auckland, Wellington, Fiji, Kamchatka, Marshall Island'),
  679. '12.75' => __('(GMT +12:45 hours) Chatham Islands'),
  680. '13' => __('(GMT +13:00 hours Tonga, Kiribati (Phoenix Islands)'),
  681. '14' => __('(GMT +14:00 hours) Kiribati (Line Islands)'));
  682. }
  683. /**
  684. * Identify timezone abbreviation using the date PHP function.
  685. *
  686. * Does not use the strftime because it varies depending of the operative system.
  687. *
  688. * @return string Timezone abbreviation.
  689. */
  690. public static function getTimezoneAbbr()
  691. {
  692. $ts = self::makeTimestamp();
  693. return date('T', $ts);
  694. }
  695. /**
  696. * Return the time difference between the server and user timezone in seconds.
  697. *
  698. * @return integer The time difference between the server and user timezone in seconds.
  699. */
  700. public static function getTimezoneUserDiff()
  701. {
  702. $srv_tz = System::getVar('timezone_server');
  703. $usr_tz = UserUtil::getVar('tzoffset') ? UserUtil::getVar('tzoffset') : System::getVar('timezone_offset');
  704. return ($srv_tz - $usr_tz) * 60 * 60;
  705. }
  706. /**
  707. * Multilingual format time method.
  708. *
  709. * @param string $format Format date.
  710. * @param string $timestamp Timestamp.
  711. *
  712. * @return string The formatted time.
  713. */
  714. public static function strftime($format, $timestamp=null)
  715. {
  716. if (empty($format)) {
  717. return null;
  718. }
  719. if (empty($timestamp)) {
  720. $timestamp = time();
  721. }
  722. static $day_of_week_short, $month_short, $day_of_week_long, $month_long, $timezone;
  723. if (!isset($day_of_week_short)) {
  724. $day_of_week_short = explode(' ', __('Sun Mon Tue Wed Thu Fri Sat'));
  725. $month_short = explode(' ', __('Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec'));
  726. $day_of_week_long = explode(' ', __('Sunday Monday Tuesday Wednesday Thursday Friday Saturday'));
  727. $month_long = explode(' ', __('January February March April May June July August September October November December'));
  728. // build the timezone
  729. $timezone_all = explode(' ', __('GMT-12 GMT-11 HST GMT-9:30 AKST PST MST CST EST AST GMT-3:30 GMT-3 GMT-2 GMT-1 GMT CET EET GMT+3 GMT+3:30 GMT+4 GMT+4:30 GMT+5 GMT+5:30 GMT+5:45 GMT+6 GMT+6:30 GMT+7 AWST ACDT JST ACST AEST GMT+11 GMT+11:30 GMT+12 GMT+12:45 GMT+13 GMT+14'));
  730. $offset_all = explode(' ', __('-12 -11 -10 -9.5 -9 -8 -7 -6 -5 -4 -3.5 -3 -2 -1 0 1 2 3 3.5 4 4.5 5 5.5 5.75 6 6.5 7 8 9 9.5 10 10.5 11 11.5 12 12.75 13 14'));
  731. $thezone = null;
  732. if (UserUtil::isLoggedIn()) {
  733. $thezone = UserUtil::getVar('tzoffset');
  734. }
  735. $thezone = $thezone ? $thezone : System::getVar('timezone_offset');
  736. $timezone = 'GMT';
  737. $offset_all = array_flip($offset_all);
  738. if (isset($offset_all[$thezone])) {
  739. $timezone = $timezone_all[$offset_all[$thezone]];
  740. }
  741. }
  742. $trformat = preg_replace('/%a/', $day_of_week_short[(int)strftime('%w', $timestamp)], $format);
  743. $trformat = preg_replace('/%A/', $day_of_week_long[(int)strftime('%w', $timestamp)], $trformat);
  744. $trformat = preg_replace('/%b/', $month_short[(int)strftime('%m', $timestamp) - 1], $trformat);
  745. $trformat = preg_replace('/%B/', $month_long[(int)strftime('%m', $timestamp) - 1], $trformat);
  746. $trformat = preg_replace('/%Z/', $timezone, $trformat);
  747. return strftime($trformat, $timestamp);
  748. }
  749. /**
  750. * Get dateformat data.
  751. *
  752. * Parses strftime formatted __('%Y-%m-%d), __('%Y-%m-%d %H:%M') or __('%Y-%m-%d %H:%M:%S')
  753. * into meaning data that can be used to process a date string.
  754. *
  755. * format strings can contain %d, %e, %y, %Y, %g, %G, %H, %I, %l, %M and %S.
  756. *
  757. * @param string $dateformat Default current language default (strftime formatted).
  758. *
  759. * @return array Array of the meaning of each match.
  760. */
  761. public static function getDateFormatData($dateformat=null)
  762. {
  763. if (is_null($dateformat)) {
  764. $dateformat = __('%Y-%m-%d');
  765. }
  766. // 8 = __('%Y-%m-%d');
  767. // 14 = __('%Y-%m-%d %H:%M');
  768. // 17 = __('%Y-%m-%d %h:%M:%S');
  769. $length = strlen($dateformat);
  770. switch ($length) {
  771. case 8:
  772. $regex = '#%(\w)(.)%(\w)(.)%(\w)#';
  773. $type = 'date';
  774. break;
  775. case 14:
  776. $regex = '#%(\w)(.)%(\w)(.)%(\w)\s%(\w)(.)%(\w)#';
  777. $type = 'datetimeshort';
  778. break;
  779. case 17:
  780. $regex = '#%(\w)(.)%(\w)(.)%(\w)\s%(\w)(.)%(\w)(.)%(\w)#';
  781. $type = 'datetimefull';
  782. break;
  783. default:
  784. z_exit(__f('Dateformat must be with 8, 14 or 17 characters long.', $dateformat));
  785. }
  786. if (preg_match($regex, $dateformat, $matches)) {
  787. $matchCount = count($matches);
  788. // validate separator
  789. if ($matches[2] != $matches[4]) {
  790. // TODO A throw exception here (dateformat separators must match) - drak
  791. z_exit(__f('Dateformat separators must be the same in %s', $dateformat));
  792. }
  793. // construct separator regex
  794. $separator = preg_quote($matches[2]);
  795. $dateMap = array('d' => array('regex' => '(\d{2})', 'type' => 'day'),
  796. 'e' => array('regex' => '(\d{1,2})', 'type' => 'day'),
  797. 'm' => array('regex' => '(\d{2})', 'type' => 'month'),
  798. 'y' => array('regex' => '(\d{2})', 'type' => 'year'),
  799. 'Y' => array('regex' => '(\d{4})', 'type' => 'year'),
  800. 'g' => array('regex' => '(\d{2})', 'type' => 'year'),
  801. 'G' => array('regex' => '(\d{4})', 'type' => 'year'),
  802. 'H' => array('regex' => '(\d{2})', 'type' => 'hour'),
  803. 'I' => array('regex' => '(\d{2})', 'type' => 'hour'),
  804. 'l' => array('regex' => '(\d{1,2})', 'type' => 'hour'),
  805. 'M' => array('regex' => '(\d{2})', 'type' => 'minute'),
  806. 'S' => array('regex' => '(\d{2})', 'type' => 'second'));
  807. // define elements
  808. $format = array();
  809. $format[] = $matches[1]; // position 1
  810. $format[] = $matches[3]; // position 2
  811. $format[] = $matches[5]; // position 3
  812. if ($matchCount > 8) {
  813. if ($matchCount == 11 && $matches[7] != $matches[9]) {
  814. // TODO A throw exception here (dateformat separators must match) - drak
  815. z_exit(__f('Dateformat time separators must be the same in %s', $dateformat));
  816. }
  817. $timeseparator = preg_quote($matches[7]);
  818. $format[] = $matches[6]; // position 3
  819. $format[] = $matches[8]; // position 3
  820. if ($matchCount == 11) {
  821. $format[] = $matches[10]; // position 3
  822. }
  823. }
  824. // map elements
  825. foreach ($format as $key) {
  826. $meaning[] = array('key' => $key, 'type' => $dateMap[$key]['type'], 'regex' => $dateMap[$key]['regex']);
  827. }
  828. // build regex
  829. $regex = $meaning[0]['regex'] . $separator . $meaning[1]['regex'] . $separator . $meaning[2]['regex'];
  830. if ($matchCount > 7) {
  831. $regex .= '\s' . $meaning[3]['regex'] . $timeseparator . $meaning[4]['regex'];
  832. if ($matchCount == 11) {
  833. $regex .= $timeseparator . $meaning[5]['regex'];
  834. }
  835. }
  836. // find month, day, year, hour, minute and second positions in the dateformat
  837. $count = 1;
  838. foreach ($meaning as $m) {
  839. $positionMatch[$m['type']] = $count;
  840. $count++;
  841. }
  842. // build and return array
  843. return array('regex' => $regex, 'matches' => $positionMatch, 'type' => $type);
  844. }
  845. // TODO A throw exception here in 1.3.0 - drak
  846. z_exit(__f('Dateformat did not match known format in %s', $dateformat));
  847. }
  848. }