PageRenderTime 60ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/html/PEAR/Date.php

https://bitbucket.org/kuy/ecom
PHP | 5863 lines | 4655 code | 145 blank | 1063 comment | 132 complexity | abdae536eec33a194346063607246c06 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.1, GPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
  3. // {{{ Header
  4. /**
  5. * Generic date handling class for PEAR
  6. *
  7. * Handles time zones and changes from local standard to local Summer
  8. * time (daylight-saving time) through the Date_TimeZone class.
  9. * Supports several operations from Date_Calc on Date objects.
  10. *
  11. * PHP versions 4 and 5
  12. *
  13. * LICENSE:
  14. *
  15. * Copyright (c) 1997-2007 Baba Buehler, Pierre-Alain Joye, Firman
  16. * Wandayandi, C.A. Woodcock
  17. * All rights reserved.
  18. *
  19. * Redistribution and use in source and binary forms, with or without
  20. * modification, are permitted under the terms of the BSD License.
  21. *
  22. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  23. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  24. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  25. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  26. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  27. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  28. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  29. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  30. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  31. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  32. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  33. * POSSIBILITY OF SUCH DAMAGE.
  34. *
  35. * @category Date and Time
  36. * @package Date
  37. * @author Baba Buehler <baba@babaz.com>
  38. * @author Pierre-Alain Joye <pajoye@php.net>
  39. * @author Firman Wandayandi <firman@php.net>
  40. * @author C.A. Woodcock <c01234@netcomuk.co.uk>
  41. * @copyright 1997-2007 Baba Buehler, Pierre-Alain Joye, Firman Wandayandi, C.A. Woodcock
  42. * @license http://www.opensource.org/licenses/bsd-license.php
  43. * BSD License
  44. * @version CVS: $Id: Date.php,v 1.89 2008/03/23 18:34:16 c01234 Exp $
  45. * @link http://pear.php.net/package/Date
  46. */
  47. // }}}
  48. // {{{ Error constants
  49. define('DATE_ERROR_INVALIDDATE', 1);
  50. define('DATE_ERROR_INVALIDTIME', 2);
  51. define('DATE_ERROR_INVALIDTIMEZONE', 3);
  52. define('DATE_ERROR_INVALIDDATEFORMAT', 4);
  53. define('DATE_ERROR_INVALIDFORMATSTRING', 5);
  54. // }}}
  55. // {{{ Includes
  56. require_once 'PEAR.php';
  57. /**
  58. * Load Date_TimeZone
  59. */
  60. require_once 'Date/TimeZone.php';
  61. /**
  62. * Load Date_Calc
  63. */
  64. require_once 'Date/Calc.php';
  65. /**
  66. * Load Date_Span
  67. */
  68. require_once 'Date/Span.php';
  69. // }}}
  70. // {{{ General constants
  71. /**
  72. * Whether to capture the micro-time (in microseconds) by default
  73. * in calls to 'Date::setNow()'. Note that this makes a call to
  74. * 'gettimeofday()', which may not work on all systems.
  75. *
  76. * @since Constant available since Release 1.5.0
  77. */
  78. define('DATE_CAPTURE_MICROTIME_BY_DEFAULT', false);
  79. /**
  80. * Whether to correct, by adding the local Summer time offset, the
  81. * specified time if it falls in the 'skipped hour' (encountered
  82. * when the clocks go forward).
  83. *
  84. * N.B. if specified as 'false', and if a time zone that adjusts
  85. * for Summer time is specified, then an object of this class will
  86. * be set to a semi-invalid state if an invalid time is set. That
  87. * is, an error will not be returned, unless the user then calls
  88. * a function, directly or indirectly, that accesses the time
  89. * part of the object. So, for example, if the user calls:
  90. *
  91. * <code>$date_object->format2('HH.MI.SS')</code> or:
  92. * <code>$date->object->addSeconds(30)</code>,
  93. *
  94. * an error will be returned if the time is invalid. However,
  95. * if the user calls:
  96. *
  97. * <code>$date->object->addDays(1)</code>,
  98. *
  99. * for example, such that the time is no longer invalid, then the
  100. * object will no longer be in this invalid state. This behaviour
  101. * is intended to minimize unexpected errors when a user uses the
  102. * class to do addition with days only, and does not intend to
  103. * access the time.
  104. *
  105. * Of course, this constant will be unused if the user chooses to
  106. * work in UTC or a time zone without Summer time, in which case
  107. * this situation will never arise.
  108. *
  109. * This constant is set to 'true' by default for backwards-compatibility
  110. * reasons, however, you are recommended to set it to 'false'. Note that the
  111. * behaviour is not intended to match that of previous versions of the class
  112. * in terms of ignoring the Summer time offset when making calculations which
  113. * involve dates in both standard and Summer time - this was recognized as a
  114. * bug - but in terms of returning a PEAR error object when the user sets the
  115. * object to an invalid date (i.e. a time in the hour which is skipped when
  116. * the clocks go forwards, which in Europe would be a time such as 01.30).
  117. * Backwards compatibility here means that the behaviour is the same as it
  118. * used to be, less the bug.
  119. *
  120. * Note that this problem is not an issue for the user if:
  121. *
  122. * (a) the user uses a time zone that does not observe Summer time, e.g. UTC
  123. * (b) the user never accesses the time, that is, he never makes a call to
  124. * Date::getHour() or Date::format("%H"), for example, even if he sets
  125. * the time to something invalid
  126. * (c) the user sets DATE_CORRECTINVALIDTIME_DEFAULT to true
  127. *
  128. * @since Constant available since Release 1.5.0
  129. */
  130. define('DATE_CORRECTINVALIDTIME_DEFAULT', true);
  131. /**
  132. * Whether to validate dates (i.e. day-month-year, ignoring the time) by
  133. * disallowing invalid dates (e.g. 31st February) being set by the following
  134. * functions:
  135. *
  136. * Date::setYear()
  137. * Date::setMonth()
  138. * Date::setDay()
  139. *
  140. * If the constant is set to 'true', then the date will be checked (by
  141. * default), and if invalid, an error will be returned with the Date object
  142. * left unmodified.
  143. *
  144. * This constant is set to 'false' by default for backwards-compatibility
  145. * reasons, however, you are recommended to set it to 'true'.
  146. *
  147. * Note that setHour(), setMinute(), setSecond() and setPartSecond()
  148. * allow an invalid date/time to be set regardless of the value of this
  149. * constant.
  150. *
  151. * @since Constant available since Release 1.5.0
  152. */
  153. define('DATE_VALIDATE_DATE_BY_DEFAULT', false);
  154. /**
  155. * Whether, by default, to accept times including leap seconds (i.e. '23.59.60')
  156. * when setting the date/time, and whether to count leap seconds in the
  157. * following functions:
  158. *
  159. * Date::addSeconds()
  160. * Date::subtractSeconds()
  161. * Date_Calc::addSeconds()
  162. * Date::round()
  163. * Date::roundSeconds()
  164. *
  165. * This constant is set to 'false' by default for backwards-compatibility
  166. * reasons, however, you are recommended to set it to 'true'.
  167. *
  168. * Note that this constant does not affect Date::addSpan() and
  169. * Date::subtractSpan() which will not count leap seconds in any case.
  170. *
  171. * @since Constant available since Release 1.5.0
  172. */
  173. define('DATE_COUNT_LEAP_SECONDS', false);
  174. // }}}
  175. // {{{ Output format constants (used in 'Date::getDate()')
  176. /**
  177. * "YYYY-MM-DD HH:MM:SS"
  178. */
  179. define('DATE_FORMAT_ISO', 1);
  180. /**
  181. * "YYYYMMSSTHHMMSS(Z|(+/-)HHMM)?"
  182. */
  183. define('DATE_FORMAT_ISO_BASIC', 2);
  184. /**
  185. * "YYYY-MM-SSTHH:MM:SS(Z|(+/-)HH:MM)?"
  186. */
  187. define('DATE_FORMAT_ISO_EXTENDED', 3);
  188. /**
  189. * "YYYY-MM-SSTHH:MM:SS(.S*)?(Z|(+/-)HH:MM)?"
  190. */
  191. define('DATE_FORMAT_ISO_EXTENDED_MICROTIME', 6);
  192. /**
  193. * "YYYYMMDDHHMMSS"
  194. */
  195. define('DATE_FORMAT_TIMESTAMP', 4);
  196. /**
  197. * long int, seconds since the unix epoch
  198. */
  199. define('DATE_FORMAT_UNIXTIME', 5);
  200. // }}}
  201. // {{{ Class: Date
  202. /**
  203. * Generic date handling class for PEAR
  204. *
  205. * Supports time zones with the Date_TimeZone class. Supports several
  206. * operations from Date_Calc on Date objects.
  207. *
  208. * Note to developers: the class stores the local time and date in the
  209. * local standard time. That is, it does not store the time as the
  210. * local Summer time when and if the time zone is in Summer time. It
  211. * is much easier to store local standard time and remember to offset
  212. * it when the user requests it.
  213. *
  214. * @category Date and Time
  215. * @package Date
  216. * @author Baba Buehler <baba@babaz.com>
  217. * @author Pierre-Alain Joye <pajoye@php.net>
  218. * @author Firman Wandayandi <firman@php.net>
  219. * @author C.A. Woodcock <c01234@netcomuk.co.uk>
  220. * @copyright 1997-2007 Baba Buehler, Pierre-Alain Joye, Firman Wandayandi, C.A. Woodcock
  221. * @license http://www.opensource.org/licenses/bsd-license.php
  222. * BSD License
  223. * @version Release: 1.5.0a1
  224. * @link http://pear.php.net/package/Date
  225. */
  226. class Date
  227. {
  228. // {{{ Properties
  229. /**
  230. * The year
  231. *
  232. * @var int
  233. * @access private
  234. * @since Property available since Release 1.0
  235. */
  236. var $year;
  237. /**
  238. * The month
  239. *
  240. * @var int
  241. * @access private
  242. * @since Property available since Release 1.0
  243. */
  244. var $month;
  245. /**
  246. * The day
  247. *
  248. * @var int
  249. * @access private
  250. * @since Property available since Release 1.0
  251. */
  252. var $day;
  253. /**
  254. * The hour
  255. *
  256. * @var int
  257. * @access private
  258. * @since Property available since Release 1.0
  259. */
  260. var $hour;
  261. /**
  262. * The minute
  263. *
  264. * @var int
  265. * @access private
  266. * @since Property available since Release 1.0
  267. */
  268. var $minute;
  269. /**
  270. * The second
  271. *
  272. * @var int
  273. * @access private
  274. * @since Property available since Release 1.0
  275. */
  276. var $second;
  277. /**
  278. * The parts of a second
  279. *
  280. * @var float
  281. * @access private
  282. * @since Property available since Release 1.4.3
  283. */
  284. var $partsecond;
  285. /**
  286. * The year in local standard time
  287. *
  288. * @var int
  289. * @access private
  290. * @since Property available since Release 1.5.0
  291. */
  292. var $on_standardyear;
  293. /**
  294. * The month in local standard time
  295. *
  296. * @var int
  297. * @access private
  298. * @since Property available since Release 1.5.0
  299. */
  300. var $on_standardmonth;
  301. /**
  302. * The day in local standard time
  303. *
  304. * @var int
  305. * @access private
  306. * @since Property available since Release 1.5.0
  307. */
  308. var $on_standardday;
  309. /**
  310. * The hour in local standard time
  311. *
  312. * @var int
  313. * @access private
  314. * @since Property available since Release 1.5.0
  315. */
  316. var $on_standardhour;
  317. /**
  318. * The minute in local standard time
  319. *
  320. * @var int
  321. * @access private
  322. * @since Property available since Release 1.5.0
  323. */
  324. var $on_standardminute;
  325. /**
  326. * The second in local standard time
  327. *
  328. * @var int
  329. * @access private
  330. * @since Property available since Release 1.5.0
  331. */
  332. var $on_standardsecond;
  333. /**
  334. * The part-second in local standard time
  335. *
  336. * @var float
  337. * @access private
  338. * @since Property available since Release 1.5.0
  339. */
  340. var $on_standardpartsecond;
  341. /**
  342. * Whether the object should accept and count leap seconds
  343. *
  344. * @var bool
  345. * @access private
  346. * @since Property available since Release 1.5.0
  347. */
  348. var $ob_countleapseconds;
  349. /**
  350. * Whether the time is valid as a local time (an invalid time
  351. * is one that lies in the 'skipped hour' at the point that
  352. * the clocks go forward)
  353. *
  354. * @var bool
  355. * @access private
  356. * @see Date::isTimeValid()
  357. * @since Property available since Release 1.5.0
  358. */
  359. var $ob_invalidtime = null;
  360. /**
  361. * Date_TimeZone object for this date
  362. *
  363. * @var object Date_TimeZone object
  364. * @access private
  365. * @since Property available since Release 1.0
  366. */
  367. var $tz;
  368. /**
  369. * Defines the default weekday abbreviation length
  370. *
  371. * Formerly used by Date::format(), but now redundant - the abbreviation
  372. * for the current locale of the machine is used.
  373. *
  374. * @var int
  375. * @access private
  376. * @since Property available since Release 1.4.4
  377. */
  378. var $getWeekdayAbbrnameLength = 3;
  379. // }}}
  380. // {{{ Constructor
  381. /**
  382. * Constructor
  383. *
  384. * Creates a new Date Object initialized to the current date/time in the
  385. * system-default timezone by default. A date optionally
  386. * passed in may be in the ISO 8601, TIMESTAMP or UNIXTIME format,
  387. * or another Date object. If no date is passed, the current date/time
  388. * is used.
  389. *
  390. * If a date is passed and an exception is returned by 'setDate()'
  391. * there is nothing that this function can do, so for this reason, it
  392. * is advisable to pass no parameter and to make a separate call to
  393. * 'setDate()'. A date/time should only be passed if known to be a
  394. * valid ISO 8601 string or a valid Unix timestamp.
  395. *
  396. * @param mixed $date optional ISO 8601 date/time to initialize;
  397. * or, a Unix time stamp
  398. * @param bool $pb_countleapseconds whether to count leap seconds
  399. * (defaults to DATE_COUNT_LEAP_SECONDS)
  400. *
  401. * @return void
  402. * @access public
  403. * @see Date::setDate()
  404. */
  405. function Date($date = null,
  406. $pb_countleapseconds = DATE_COUNT_LEAP_SECONDS)
  407. {
  408. $this->ob_countleapseconds = $pb_countleapseconds;
  409. if (is_a($date, 'Date')) {
  410. $this->copy($date);
  411. } else {
  412. if (!is_null($date)) {
  413. // 'setDate()' expects a time zone to be already set:
  414. //
  415. $this->_setTZToDefault();
  416. $this->setDate($date);
  417. } else {
  418. $this->setNow();
  419. }
  420. }
  421. }
  422. // }}}
  423. // {{{ copy()
  424. /**
  425. * Copy values from another Date object
  426. *
  427. * Makes this Date a copy of another Date object. This is a
  428. * PHP4-compatible implementation of '__clone()' in PHP5.
  429. *
  430. * @param object $date Date object to copy
  431. *
  432. * @return void
  433. * @access public
  434. */
  435. function copy($date)
  436. {
  437. $this->year = $date->year;
  438. $this->month = $date->month;
  439. $this->day = $date->day;
  440. $this->hour = $date->hour;
  441. $this->minute = $date->minute;
  442. $this->second = $date->second;
  443. $this->partsecond = $date->partsecond;
  444. $this->on_standardyear = $date->on_standardyear;
  445. $this->on_standardmonth = $date->on_standardmonth;
  446. $this->on_standardday = $date->on_standardday;
  447. $this->on_standardhour = $date->on_standardhour;
  448. $this->on_standardminute = $date->on_standardminute;
  449. $this->on_standardsecond = $date->on_standardsecond;
  450. $this->on_standardpartsecond = $date->on_standardpartsecond;
  451. $this->ob_countleapseconds = $date->ob_countleapseconds;
  452. $this->ob_invalidtime = $date->ob_invalidtime;
  453. $this->tz = new Date_TimeZone($date->getTZID());
  454. $this->getWeekdayAbbrnameLength = $date->getWeekdayAbbrnameLength;
  455. }
  456. // }}}
  457. // {{{ __clone()
  458. /**
  459. * Copy values from another Date object
  460. *
  461. * Makes this Date a copy of another Date object. For PHP5
  462. * only.
  463. *
  464. * @return void
  465. * @access public
  466. * @see Date::copy()
  467. */
  468. function __clone()
  469. {
  470. // This line of code would be preferable, but will only
  471. // compile in PHP5:
  472. //
  473. // $this->tz = clone $this->tz;
  474. $this->tz = new Date_TimeZone($this->getTZID());
  475. }
  476. // }}}
  477. // {{{ setDate()
  478. /**
  479. * Sets the fields of a Date object based on the input date and format
  480. *
  481. * Format parameter should be one of the specified DATE_FORMAT_* constants:
  482. *
  483. * <code>DATE_FORMAT_ISO</code>
  484. * - 'YYYY-MM-DD HH:MI:SS'
  485. * <code>DATE_FORMAT_ISO_BASIC</code>
  486. * - 'YYYYMMSSTHHMMSS(Z|(+/-)HHMM)?'
  487. * <code>DATE_FORMAT_ISO_EXTENDED</code>
  488. * - 'YYYY-MM-SSTHH:MM:SS(Z|(+/-)HH:MM)?'
  489. * <code>DATE_FORMAT_ISO_EXTENDED_MICROTIME</code>
  490. * - 'YYYY-MM-SSTHH:MM:SS(.S*)?(Z|(+/-)HH:MM)?'
  491. * <code>DATE_FORMAT_TIMESTAMP</code>
  492. * - 'YYYYMMDDHHMMSS'
  493. * <code>DATE_FORMAT_UNIXTIME'</code>
  494. * - long integer of the no of seconds since
  495. * the Unix Epoch
  496. * (1st January 1970 00.00.00 GMT)
  497. *
  498. * @param string $date input date
  499. * @param int $format optional format constant
  500. * (DATE_FORMAT_*) of the input date.
  501. * This parameter is not needed,
  502. * except to force the setting of the
  503. * date from a Unix time-stamp
  504. * (DATE_FORMAT_UNIXTIME).
  505. * @param bool $pb_repeatedhourdefault value to return if repeated
  506. * hour is specified (defaults
  507. * to false)
  508. *
  509. * @return void
  510. * @access public
  511. */
  512. function setDate($date,
  513. $format = DATE_FORMAT_ISO,
  514. $pb_repeatedhourdefault = false)
  515. {
  516. if (preg_match('/^([0-9]{4,4})-?(0[1-9]|1[0-2])-?(0[1-9]|[12][0-9]|3[01])' .
  517. '([T\s]?([01][0-9]|2[0-3]):?' . // [hh]
  518. '([0-5][0-9]):?([0-5][0-9]|60)(\.\d+)?' . // [mi]:[ss]
  519. '(Z|[+\-][0-9]{2,2}(:?[0-5][0-9])?)?)?$/i', // offset
  520. $date, $regs) &&
  521. $format != DATE_FORMAT_UNIXTIME
  522. ) {
  523. // DATE_FORMAT_ISO, ISO_BASIC, ISO_EXTENDED, and TIMESTAMP
  524. // These formats are extremely close to each other. This regex
  525. // is very loose and accepts almost any butchered format you could
  526. // throw at it. e.g. 2003-10-07 19:45:15 and 2003-10071945:15
  527. // are the same thing in the eyes of this regex, even though the
  528. // latter is not a valid ISO 8601 date.
  529. if (!Date_Calc::isValidDate($regs[3], $regs[2], $regs[1])) {
  530. return PEAR::raiseError("'" .
  531. Date_Calc::dateFormat($regs[1],
  532. $regs[2],
  533. $regs[3],
  534. "%Y-%m-%d") .
  535. "' is invalid calendar date",
  536. DATE_ERROR_INVALIDDATE);
  537. }
  538. if (isset($regs[9])) {
  539. if ($regs[9] == "Z") {
  540. $this->tz = new Date_TimeZone("UTC");
  541. } else {
  542. $this->tz = new Date_TimeZone("UTC" . $regs[9]);
  543. }
  544. }
  545. $this->setLocalTime($regs[3],
  546. $regs[2],
  547. $regs[1],
  548. isset($regs[5]) ? $regs[5] : 0,
  549. isset($regs[6]) ? $regs[6] : 0,
  550. isset($regs[7]) ? $regs[7] : 0,
  551. isset($regs[8]) ? $regs[8] : 0.0,
  552. $pb_repeatedhourdefault);
  553. } else if (is_numeric($date)) {
  554. // Unix Time; N.B. Unix Time is defined relative to GMT,
  555. // so it needs to be adjusted for the current time zone;
  556. // however we do not know if it is in Summer time until
  557. // we have converted it from Unix time:
  558. //
  559. // Get current time zone details:
  560. //
  561. $hs_id = $this->getTZID();
  562. // Input Unix time as UTC:
  563. //
  564. $this->tz = new Date_TimeZone("UTC");
  565. $this->setDate(gmdate("Y-m-d H:i:s", $date));
  566. // Convert back to correct time zone:
  567. //
  568. $this->convertTZByID($hs_id);
  569. } else {
  570. return PEAR::raiseError("Date not in ISO 8601 format",
  571. DATE_ERROR_INVALIDDATEFORMAT);
  572. }
  573. }
  574. // }}}
  575. // {{{ setNow()
  576. /**
  577. * Sets to local current time and time zone
  578. *
  579. * @param bool $pb_setmicrotime whether to set micro-time (defaults to the
  580. * value of the constant
  581. * DATE_CAPTURE_MICROTIME_BY_DEFAULT)
  582. *
  583. * @return void
  584. * @access public
  585. * @since Method available since Release 1.5.0
  586. */
  587. function setNow($pb_setmicrotime = DATE_CAPTURE_MICROTIME_BY_DEFAULT)
  588. {
  589. $this->_setTZToDefault();
  590. if ($pb_setmicrotime) {
  591. $ha_unixtime = gettimeofday();
  592. } else {
  593. $ha_unixtime = array("sec" => time());
  594. }
  595. $this->setDate(date("Y-m-d H:i:s", $ha_unixtime["sec"]) .
  596. (isset($ha_unixtime["usec"]) ?
  597. "." . sprintf("%06d", $ha_unixtime["usec"]) :
  598. ""));
  599. }
  600. // }}}
  601. // {{{ round()
  602. /**
  603. * Rounds the date according to the specified precision (defaults
  604. * to nearest day)
  605. *
  606. * The precision parameter must be one of the following constants:
  607. *
  608. * <code>DATE_PRECISION_YEAR</code>
  609. * <code>DATE_PRECISION_MONTH</code>
  610. * <code>DATE_PRECISION_DAY</code>
  611. * <code>DATE_PRECISION_HOUR</code>
  612. * <code>DATE_PRECISION_10MINUTES</code>
  613. * <code>DATE_PRECISION_MINUTE</code>
  614. * <code>DATE_PRECISION_10SECONDS</code>
  615. * <code>DATE_PRECISION_SECOND</code>
  616. *
  617. * N.B. the default is DATE_PRECISION_DAY
  618. *
  619. * The precision can also be specified as an integral offset from
  620. * one of these constants, where the offset reflects a precision
  621. * of 10 to the power of the offset greater than the constant.
  622. * For example:
  623. *
  624. * <code>DATE_PRECISION_YEAR - 1</code> rounds the date to the nearest 10
  625. * years
  626. * <code>DATE_PRECISION_YEAR - 3</code> rounds the date to the nearest 1000
  627. * years
  628. * <code>DATE_PRECISION_SECOND + 1</code> rounds the date to 1 decimal
  629. * point of a second
  630. * <code>DATE_PRECISION_SECOND + 3</code> rounds the date to 3 decimal
  631. * points of a second
  632. * <code>DATE_PRECISION_SECOND - 1</code> rounds the date to the nearest 10
  633. * seconds (thus it is equivalent to
  634. * DATE_PRECISION_10SECONDS)
  635. *
  636. * @param int $pn_precision a 'DATE_PRECISION_*' constant
  637. * @param bool $pb_correctinvalidtime whether to correct, by adding the
  638. * local Summer time offset, the rounded
  639. * time if it falls in the skipped hour
  640. * (defaults to
  641. * DATE_CORRECTINVALIDTIME_DEFAULT)
  642. *
  643. * @return void
  644. * @access public
  645. * @since Method available since Release 1.5.0
  646. */
  647. function round($pn_precision = DATE_PRECISION_DAY,
  648. $pb_correctinvalidtime = DATE_CORRECTINVALIDTIME_DEFAULT)
  649. {
  650. if ($pn_precision <= DATE_PRECISION_DAY) {
  651. list($hn_year,
  652. $hn_month,
  653. $hn_day,
  654. $hn_hour,
  655. $hn_minute,
  656. $hn_secondraw) =
  657. Date_Calc::round($pn_precision,
  658. $this->day,
  659. $this->month,
  660. $this->year,
  661. $this->hour,
  662. $this->minute,
  663. $this->partsecond == 0.0 ?
  664. $this->second :
  665. $this->second + $this->partsecond,
  666. $this->ob_countleapseconds);
  667. if (is_float($hn_secondraw)) {
  668. $hn_second = intval($hn_secondraw);
  669. $hn_partsecond = $hn_secondraw - $hn_second;
  670. } else {
  671. $hn_second = $hn_secondraw;
  672. $hn_partsecond = 0.0;
  673. }
  674. $this->setLocalTime($hn_day,
  675. $hn_month,
  676. $hn_year,
  677. $hn_hour,
  678. $hn_minute,
  679. $hn_second,
  680. $hn_partsecond,
  681. true, // This is unlikely anyway, but the
  682. // day starts with the repeated hour
  683. // the first time around
  684. $pb_correctinvalidtime);
  685. return;
  686. }
  687. // ($pn_precision >= DATE_PRECISION_HOUR)
  688. //
  689. if ($this->tz->getDSTSavings() % 3600000 == 0 ||
  690. ($this->tz->getDSTSavings() % 60000 == 0 &&
  691. $pn_precision >= DATE_PRECISION_MINUTE)
  692. ) {
  693. list($hn_year,
  694. $hn_month,
  695. $hn_day,
  696. $hn_hour,
  697. $hn_minute,
  698. $hn_secondraw) =
  699. Date_Calc::round($pn_precision,
  700. $this->on_standardday,
  701. $this->on_standardmonth,
  702. $this->on_standardyear,
  703. $this->on_standardhour,
  704. $this->on_standardminute,
  705. $this->on_standardpartsecond == 0.0 ?
  706. $this->on_standardsecond :
  707. $this->on_standardsecond +
  708. $this->on_standardpartsecond,
  709. $this->ob_countleapseconds);
  710. if (is_float($hn_secondraw)) {
  711. $hn_second = intval($hn_secondraw);
  712. $hn_partsecond = $hn_secondraw - $hn_second;
  713. } else {
  714. $hn_second = $hn_secondraw;
  715. $hn_partsecond = 0.0;
  716. }
  717. $this->setStandardTime($hn_day,
  718. $hn_month,
  719. $hn_year,
  720. $hn_hour,
  721. $hn_minute,
  722. $hn_second,
  723. $hn_partsecond);
  724. return;
  725. }
  726. // Very unlikely anyway (as I write, the only time zone like this
  727. // is Lord Howe Island in Australia (offset of half an hour)):
  728. //
  729. // (This algorithm could be better)
  730. //
  731. list($hn_year,
  732. $hn_month,
  733. $hn_day,
  734. $hn_hour,
  735. $hn_minute,
  736. $hn_secondraw) =
  737. Date_Calc::round($pn_precision,
  738. $this->day,
  739. $this->month,
  740. $this->year,
  741. $this->hour,
  742. $this->minute,
  743. $this->partsecond == 0.0 ?
  744. $this->second :
  745. $this->second + $this->partsecond,
  746. $this->ob_countleapseconds);
  747. if (is_float($hn_secondraw)) {
  748. $hn_second = intval($hn_secondraw);
  749. $hn_partsecond = $hn_secondraw - $hn_second;
  750. } else {
  751. $hn_second = $hn_secondraw;
  752. $hn_partsecond = 0.0;
  753. }
  754. $this->setLocalTime($hn_day,
  755. $hn_month,
  756. $hn_year,
  757. $hn_hour,
  758. $hn_minute,
  759. $hn_second,
  760. $hn_partsecond,
  761. false, // This will be right half the time
  762. $pb_correctinvalidtime); // This will be right
  763. // some of the time
  764. // (depends on Summer
  765. // time offset)
  766. }
  767. // }}}
  768. // {{{ roundSeconds()
  769. /**
  770. * Rounds seconds up or down to the nearest specified unit
  771. *
  772. * N.B. this function is equivalent to calling:
  773. * <code>'round(DATE_PRECISION_SECOND + $pn_precision)'</code>
  774. *
  775. * @param int $pn_precision number of digits after the decimal point
  776. * @param bool $pb_correctinvalidtime whether to correct, by adding the
  777. * local Summer time offset, the rounded
  778. * time if it falls in the skipped hour
  779. * (defaults to
  780. * DATE_CORRECTINVALIDTIME_DEFAULT)
  781. *
  782. * @return void
  783. * @access public
  784. * @since Method available since Release 1.5.0
  785. */
  786. function roundSeconds($pn_precision = 0,
  787. $pb_correctinvalidtime = DATE_CORRECTINVALIDTIME_DEFAULT)
  788. {
  789. $this->round(DATE_PRECISION_SECOND + $pn_precision,
  790. $pb_correctinvalidtime);
  791. }
  792. // }}}
  793. // {{{ trunc()
  794. /**
  795. * Truncates the date according to the specified precision (by
  796. * default, it truncates the time part of the date)
  797. *
  798. * The precision parameter must be one of the following constants:
  799. *
  800. * <code>DATE_PRECISION_YEAR</code>
  801. * <code>DATE_PRECISION_MONTH</code>
  802. * <code>DATE_PRECISION_DAY</code>
  803. * <code>DATE_PRECISION_HOUR</code>
  804. * <code>DATE_PRECISION_10MINUTES</code>
  805. * <code>DATE_PRECISION_MINUTE</code>
  806. * <code>DATE_PRECISION_10SECONDS</code>
  807. * <code>DATE_PRECISION_SECOND</code>
  808. *
  809. * N.B. the default is DATE_PRECISION_DAY
  810. *
  811. * The precision can also be specified as an integral offset from
  812. * one of these constants, where the offset reflects a precision
  813. * of 10 to the power of the offset greater than the constant.
  814. * For example:
  815. *
  816. * <code>DATE_PRECISION_YEAR</code> truncates the month, day and time
  817. * part of the year
  818. * <code>DATE_PRECISION_YEAR - 1</code> truncates the unit part of the
  819. * year, e.g. 1987 becomes 1980
  820. * <code>DATE_PRECISION_YEAR - 3</code> truncates the hundreds part of the
  821. * year, e.g. 1987 becomes 1000
  822. * <code>DATE_PRECISION_SECOND + 1</code> truncates the part of the second
  823. * less than 0.1 of a second, e.g.
  824. * 3.26301 becomes 3.2 seconds
  825. * <code>DATE_PRECISION_SECOND + 3</code> truncates the part of the second
  826. * less than 0.001 of a second, e.g.
  827. * 3.26301 becomes 3.263 seconds
  828. * <code>DATE_PRECISION_SECOND - 1</code> truncates the unit part of the
  829. * seconds (thus it is equivalent to
  830. * DATE_PRECISION_10SECONDS)
  831. *
  832. * @param int $pn_precision a 'DATE_PRECISION_*' constant
  833. * @param bool $pb_correctinvalidtime whether to correct, by adding the
  834. * local Summer time offset, the
  835. * truncated time if it falls in the
  836. * skipped hour (defaults to
  837. * DATE_CORRECTINVALIDTIME_DEFAULT)
  838. *
  839. * @return void
  840. * @access public
  841. * @since Method available since Release 1.5.0
  842. */
  843. function trunc($pn_precision = DATE_PRECISION_DAY,
  844. $pb_correctinvalidtime = DATE_CORRECTINVALIDTIME_DEFAULT)
  845. {
  846. if ($pn_precision <= DATE_PRECISION_DAY) {
  847. if ($pn_precision <= DATE_PRECISION_YEAR) {
  848. $hn_month = 0;
  849. $hn_day = 0;
  850. $hn_hour = 0;
  851. $hn_minute = 0;
  852. $hn_second = 0;
  853. $hn_partsecond = 0.0;
  854. $hn_invprecision = DATE_PRECISION_YEAR - $pn_precision;
  855. if ($hn_invprecision > 0) {
  856. $hn_year = intval($this->year / pow(10, $hn_invprecision)) *
  857. pow(10, $hn_invprecision);
  858. //
  859. // (Conversion to int necessary for PHP <= 4.0.6)
  860. } else {
  861. $hn_year = $this->year;
  862. }
  863. } else if ($pn_precision == DATE_PRECISION_MONTH) {
  864. $hn_year = $this->year;
  865. $hn_month = $this->month;
  866. $hn_day = 0;
  867. $hn_hour = 0;
  868. $hn_minute = 0;
  869. $hn_second = 0;
  870. $hn_partsecond = 0.0;
  871. } else if ($pn_precision == DATE_PRECISION_DAY) {
  872. $hn_year = $this->year;
  873. $hn_month = $this->month;
  874. $hn_day = $this->day;
  875. $hn_hour = 0;
  876. $hn_minute = 0;
  877. $hn_second = 0;
  878. $hn_partsecond = 0.0;
  879. }
  880. $this->setLocalTime($hn_day,
  881. $hn_month,
  882. $hn_year,
  883. $hn_hour,
  884. $hn_minute,
  885. $hn_second,
  886. $hn_partsecond,
  887. true, // This is unlikely anyway, but the
  888. // day starts with the repeated
  889. // hour the first time around
  890. $pb_correctinvalidtime);
  891. return;
  892. }
  893. // Precision is at least equal to DATE_PRECISION_HOUR
  894. //
  895. if ($pn_precision == DATE_PRECISION_HOUR) {
  896. $this->addSeconds($this->partsecond == 0.0 ?
  897. -$this->second :
  898. -$this->second - $this->partsecond);
  899. //
  900. // (leap seconds irrelevant)
  901. $this->addMinutes(-$this->minute);
  902. } else if ($pn_precision <= DATE_PRECISION_MINUTE) {
  903. if ($pn_precision == DATE_PRECISION_10MINUTES) {
  904. $this->addMinutes(-$this->minute % 10);
  905. }
  906. $this->addSeconds($this->partsecond == 0.0 ?
  907. -$this->second :
  908. -$this->second - $this->partsecond);
  909. //
  910. // (leap seconds irrelevant)
  911. } else if ($pn_precision == DATE_PRECISION_10SECONDS) {
  912. $this->addSeconds($this->partsecond == 0.0 ?
  913. -$this->second % 10 :
  914. (-$this->second % 10) - $this->partsecond);
  915. //
  916. // (leap seconds irrelevant)
  917. } else {
  918. // Assume Summer time offset cannot be composed of part-seconds:
  919. //
  920. $hn_precision = $pn_precision - DATE_PRECISION_SECOND;
  921. $hn_partsecond = intval($this->on_standardpartsecond *
  922. pow(10, $hn_precision)) /
  923. pow(10, $hn_precision);
  924. $this->setStandardTime($this->on_standardday,
  925. $this->on_standardmonth,
  926. $this->on_standardyear,
  927. $this->on_standardhour,
  928. $this->on_standardminute,
  929. $this->on_standardsecond,
  930. $hn_partsecond);
  931. }
  932. }
  933. // }}}
  934. // {{{ truncSeconds()
  935. /**
  936. * Truncates seconds according to the specified precision
  937. *
  938. * N.B. this function is equivalent to calling:
  939. * <code>'Date::trunc(DATE_PRECISION_SECOND + $pn_precision)'</code>
  940. *
  941. * @param int $pn_precision number of digits after the decimal point
  942. * @param bool $pb_correctinvalidtime whether to correct, by adding the
  943. * local Summer time offset, the
  944. * truncated time if it falls in the
  945. * skipped hour (defaults to
  946. * DATE_CORRECTINVALIDTIME_DEFAULT)
  947. *
  948. * @return void
  949. * @access public
  950. * @since Method available since Release 1.5.0
  951. */
  952. function truncSeconds($pn_precision = 0,
  953. $pb_correctinvalidtime = DATE_CORRECTINVALIDTIME_DEFAULT)
  954. {
  955. $this->trunc(DATE_PRECISION_SECOND + $pn_precision,
  956. $pb_correctinvalidtime);
  957. }
  958. // }}}
  959. // {{{ getDate()
  960. /**
  961. * Gets a string (or other) representation of this date
  962. *
  963. * Returns a date in the format specified by the DATE_FORMAT_* constants.
  964. *
  965. * @param int $format format constant (DATE_FORMAT_*) of the output date
  966. *
  967. * @return string the date in the requested format
  968. * @access public
  969. */
  970. function getDate($format = DATE_FORMAT_ISO)
  971. {
  972. switch ($format) {
  973. case DATE_FORMAT_ISO:
  974. return $this->format("%Y-%m-%d %T");
  975. break;
  976. case DATE_FORMAT_ISO_BASIC:
  977. $format = "%Y%m%dT%H%M%S";
  978. if ($this->getTZID() == 'UTC') {
  979. $format .= "Z";
  980. }
  981. return $this->format($format);
  982. break;
  983. case DATE_FORMAT_ISO_EXTENDED:
  984. $format = "%Y-%m-%dT%H:%M:%S";
  985. if ($this->getTZID() == 'UTC') {
  986. $format .= "Z";
  987. }
  988. return $this->format($format);
  989. break;
  990. case DATE_FORMAT_ISO_EXTENDED_MICROTIME:
  991. $format = "%Y-%m-%dT%H:%M:%s";
  992. if ($this->getTZID() == 'UTC') {
  993. $format .= "Z";
  994. }
  995. return $this->format($format);
  996. break;
  997. case DATE_FORMAT_TIMESTAMP:
  998. return $this->format("%Y%m%d%H%M%S");
  999. break;
  1000. case DATE_FORMAT_UNIXTIME:
  1001. // Enter a time in UTC, so use 'gmmktime()' (the alternative
  1002. // is to offset additionally by the local time, but the object
  1003. // is not necessarily using local time):
  1004. //
  1005. if ($this->ob_invalidtime)
  1006. return $this->_getErrorInvalidTime();
  1007. return gmmktime($this->on_standardhour,
  1008. $this->on_standardminute,
  1009. $this->on_standardsecond,
  1010. $this->on_standardmonth,
  1011. $this->on_standardday,
  1012. $this->on_standardyear) -
  1013. $this->tz->getRawOffset() / 1000; // N.B. Unix-time excludes
  1014. // leap seconds by
  1015. // definition
  1016. break;
  1017. }
  1018. }
  1019. // }}}
  1020. // {{{ format()
  1021. /**
  1022. * Date pretty printing, similar to strftime()
  1023. *
  1024. * Formats the date in the given format, much like
  1025. * strftime(). Most strftime() options are supported.<br><br>
  1026. *
  1027. * Formatting options:<br><br>
  1028. *
  1029. * <code>%a </code> abbreviated weekday name (Sun, Mon, Tue) <br>
  1030. * <code>%A </code> full weekday name (Sunday, Monday, Tuesday) <br>
  1031. * <code>%b </code> abbreviated month name (Jan, Feb, Mar) <br>
  1032. * <code>%B </code> full month name (January, February, March) <br>
  1033. * <code>%C </code> century number (the year divided by 100 and truncated
  1034. * to an integer, range 00 to 99) <br>
  1035. * <code>%d </code> day of month (range 00 to 31) <br>
  1036. * <code>%D </code> equivalent to "%m/%d/%y" <br>
  1037. * <code>%e </code> day of month without leading noughts (range 0 to 31) <br>
  1038. * <code>%E </code> Julian day - no of days since Monday, 24th November,
  1039. * 4714 B.C. (in the proleptic Gregorian calendar) <br>
  1040. * <code>%g </code> like %G, but without the century <br>
  1041. * <code>%G </code> the 4-digit year corresponding to the ISO week
  1042. * number (see %V). This has the same format and value
  1043. * as %Y, except that if the ISO week number belongs
  1044. * to the previous or next year, that year is used
  1045. * instead. <br>
  1046. * <code>%h </code> hour as decimal number without leading noughts (0
  1047. * to 23) <br>
  1048. * <code>%H </code> hour as decimal number (00 to 23) <br>
  1049. * <code>%i </code> hour as decimal number on 12-hour clock without
  1050. * leading noughts (1 to 12) <br>
  1051. * <code>%I </code> hour as decimal number on 12-hour clock (01 to 12) <br>
  1052. * <code>%j </code> day of year (range 001 to 366) <br>
  1053. * <code>%m </code> month as decimal number (range 01 to 12) <br>
  1054. * <code>%M </code> minute as a decimal number (00 to 59) <br>
  1055. * <code>%n </code> newline character ("\n") <br>
  1056. * <code>%o </code> raw timezone offset expressed as '+/-HH:MM' <br>
  1057. * <code>%O </code> dst-corrected timezone offset expressed as '+/-HH:MM' <br>
  1058. * <code>%p </code> either 'am' or 'pm' depending on the time <br>
  1059. * <code>%P </code> either 'AM' or 'PM' depending on the time <br>
  1060. * <code>%r </code> time in am/pm notation; equivalent to "%I:%M:%S %p" <br>
  1061. * <code>%R </code> time in 24-hour notation; equivalent to "%H:%M" <br>
  1062. * <code>%s </code> seconds including the micro-time (the decimal
  1063. * representation less than one second to six decimal
  1064. * places<br>
  1065. * <code>%S </code> seconds as a decimal number (00 to 59) <br>
  1066. * <code>%t </code> tab character ("\t") <br>
  1067. * <code>%T </code> current time; equivalent to "%H:%M:%S" <br>
  1068. * <code>%u </code> day of week as decimal (1 to 7; where 1 = Monday) <br>
  1069. * <code>%U </code> week number of the current year as a decimal
  1070. * number, starting with the first Sunday as the first
  1071. * day of the first week (i.e. the first full week of
  1072. * the year, and the week that contains 7th January)
  1073. * (00 to 53) <br>
  1074. * <code>%V </code> the ISO 8601:1988 week number of the current year
  1075. * as a decimal number, range 01 to 53, where week 1
  1076. * is the first week that has at least 4 days in the
  1077. * current year, and with Monday as the first day of
  1078. * the week. (Use %G or %g for the year component
  1079. * that corresponds to the week number for the
  1080. * specified timestamp.)
  1081. * <code>%w </code> day of week as decimal (0 to 6; where 0 = Sunday) <br>
  1082. * <code>%W </code> week number of the current year as a decimal
  1083. * number, starting with the first Monday as the first
  1084. * day of the first week (i.e. the first full week of
  1085. * the year, and the week that contains 7th January)
  1086. * (00 to 53) <br>
  1087. * <code>%y </code> year as decimal (range 00 to 99) <br>
  1088. * <code>%Y </code> year as decimal including century (range 0000 to
  1089. * 9999) <br>
  1090. * <code>%Z </code> Abbreviated form of time zone name, e.g. 'GMT', or
  1091. * the abbreviation for Summer time if the date falls
  1092. * in Summer time, e.g. 'BST'. <br>
  1093. * <code>%% </code> literal '%' <br>
  1094. * <br>
  1095. *
  1096. * The following codes render a different output to that of 'strftime()':
  1097. *
  1098. * <code>%e</code> in 'strftime()' a single digit is preceded by a space
  1099. * <code>%h</code> in 'strftime()' is equivalent to '%b'
  1100. * <code>%U</code> '%U' and '%W' are different in 'strftime()' in that
  1101. * if week 1 does not start on 1st January, '00' is
  1102. * returned, whereas this function returns '53', that is,
  1103. * the week is counted as the last of the previous year.
  1104. * <code>%W</code>
  1105. *
  1106. * @param string $format the format string for returned date/time
  1107. *
  1108. * @return string date/time in given format
  1109. * @access public
  1110. */
  1111. function format($format)
  1112. {
  1113. $output = "";
  1114. $hn_isoyear = null;
  1115. $hn_isoweek = null;
  1116. $hn_isoday = null;
  1117. for ($strpos = 0; $strpos < strlen($format); $strpos++) {
  1118. $char = substr($format, $strpos, 1);
  1119. if ($char == "%") {
  1120. $nextchar = substr($format, $strpos + 1, 1);
  1121. switch ($nextchar) {
  1122. case "a":
  1123. $output .= Date_Calc::getWeekdayAbbrname($this->day,
  1124. $this->month, $this->year,
  1125. $this->getWeekdayAbbrnameLength);
  1126. break;
  1127. case "A":
  1128. $output .= Date_Calc::getWeekdayFullname($this->day,
  1129. $this->month, $this->year);
  1130. break;
  1131. case "b":
  1132. $output .= Date_Calc::getMonthAbbrname($this->month);
  1133. break;
  1134. case "B":
  1135. $output .= Date_Calc::getMonthFullname($this->month);
  1136. break;
  1137. case "C":
  1138. $output .= sprintf("%02d", intval($this->year / 100));
  1139. break;
  1140. case "d":
  1141. $output .= sprintf("%02d", $this->day);
  1142. break;
  1143. case "D":
  1144. $output .= sprintf("%02d/%02d/%02d", $this->month,
  1145. $this->day, $this->year);
  1146. break;
  1147. case "e":
  1148. $output .= $this->day;
  1149. break;
  1150. case "E":
  1151. $output .= Date_Calc::dateToDays($this->day, $this->month,
  1152. $this->year);
  1153. break;
  1154. case "g":
  1155. if (is_null($hn_isoyear))
  1156. list($hn_isoyear, $hn_isoweek, $hn_isoday) =
  1157. Date_Calc::isoWeekDate($this->day,
  1158. $this->month,
  1159. $this->year);
  1160. $output .= sprintf("%02d", $hn_isoyear % 100);
  1161. break;
  1162. case "G":
  1163. if (is_null($hn_isoyear))
  1164. list($hn_isoyear, $hn_isoweek, $hn_isoday) =
  1165. Date_Calc::isoWeekDate($this->day,
  1166. $this->month,
  1167. $this->year);
  1168. $output .= sprintf("%04d", $hn_isoyear);
  1169. break;
  1170. case 'h':
  1171. if ($this->ob_invalidtime)
  1172. return $this->_getErrorInvalidTime();
  1173. $output .= sprintf("%d", $this->hour);
  1174. break;
  1175. case "H":
  1176. if ($this->ob_invalidtime)
  1177. return $this->_getErrorInvalidTime();
  1178. $output .= sprintf("%02d", $this->hour);
  1179. break;
  1180. case "i":
  1181. case "I":
  1182. if ($this->ob_invalidtime)

Large files files are truncated, but you can click here to view the full file