Date
[ class tree: Date ] [ index: Date ] [ all elements ]

Source for file Date.php

Documentation is available at Date.php

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
  3.  
  4. // {{{ Header
  5.  
  6. /**
  7.  * Generic date handling class for PEAR
  8.  *
  9.  * Handles time zones and changes from local standard to local Summer
  10.  * time (daylight-saving time) through the Date_TimeZone class.
  11.  * Supports several operations from Date_Calc on Date objects.
  12.  *
  13.  * PHP versions 4 and 5
  14.  *
  15.  * LICENSE:
  16.  *
  17.  * Copyright (c) 1997-2007 Baba Buehler, Pierre-Alain Joye, Firman
  18.  * Wandayandi, C.A. Woodcock
  19.  * All rights reserved.
  20.  *
  21.  * Redistribution and use in source and binary forms, with or without
  22.  * modification, are permitted under the terms of the BSD License.
  23.  *
  24.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  25.  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  26.  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  27.  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  28.  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  29.  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  30.  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  31.  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  32.  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  33.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  34.  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  35.  * POSSIBILITY OF SUCH DAMAGE.
  36.  *
  37.  * @category   Date and Time
  38.  * @package    Date
  39.  * @author     Baba Buehler <baba@babaz.com>
  40.  * @author     Pierre-Alain Joye <pajoye@php.net>
  41.  * @author     Firman Wandayandi <firman@php.net>
  42.  * @author     C.A. Woodcock <c01234@netcomuk.co.uk>
  43.  * @copyright  1997-2007 Baba Buehler, Pierre-Alain Joye, Firman Wandayandi, C.A. Woodcock
  44.  * @license    http://www.opensource.org/licenses/bsd-license.php
  45.  *              BSD License
  46.  * @version    CVS: $Id: Date.php,v 1.89 2008/03/23 18:34:16 c01234 Exp $
  47.  * @link       http://pear.php.net/package/Date
  48.  */
  49.  
  50.  
  51. // }}}
  52. // {{{ Error constants
  53.  
  54. define('DATE_ERROR_INVALIDDATE'1);
  55. define('DATE_ERROR_INVALIDTIME'2);
  56. define('DATE_ERROR_INVALIDTIMEZONE'3);
  57. define('DATE_ERROR_INVALIDDATEFORMAT'4);
  58. define('DATE_ERROR_INVALIDFORMATSTRING'5);
  59.  
  60.  
  61. // }}}
  62. // {{{ Includes
  63.  
  64. require_once 'PEAR.php';
  65.  
  66. /**
  67.  * Load Date_TimeZone
  68.  */
  69. require_once 'Date/TimeZone.php';
  70.  
  71. /**
  72.  * Load Date_Calc
  73.  */
  74. require_once 'Date/Calc.php';
  75.  
  76. /**
  77.  * Load Date_Span
  78.  */
  79. require_once 'Date/Span.php';
  80.  
  81.  
  82. // }}}
  83. // {{{ General constants
  84.  
  85. /**
  86.  * Whether to capture the micro-time (in microseconds) by default
  87.  * in calls to 'Date::setNow()'.  Note that this makes a call to
  88.  * 'gettimeofday()', which may not work on all systems.
  89.  *
  90.  * @since    Constant available since Release 1.5.0
  91.  */
  92. define('DATE_CAPTURE_MICROTIME_BY_DEFAULT'false);
  93.  
  94. /**
  95.  * Whether to correct, by adding the local Summer time offset, the
  96.  * specified time if it falls in the 'skipped hour' (encountered
  97.  * when the clocks go forward).
  98.  *
  99.  * N.B. if specified as 'false', and if a time zone that adjusts
  100.  * for Summer time is specified, then an object of this class will
  101.  * be set to a semi-invalid state if an invalid time is set.  That
  102.  * is, an error will not be returned, unless the user then calls
  103.  * a function, directly or indirectly, that accesses the time
  104.  * part of the object.  So, for example, if the user calls:
  105.  *
  106.  *  <code>$date_object->format2('HH.MI.SS')</code> or:
  107.  *  <code>$date->object->addSeconds(30)</code>,
  108.  *
  109.  * an error will be returned if the time is invalid.  However,
  110.  * if the user calls:
  111.  *
  112.  *  <code>$date->object->addDays(1)</code>,
  113.  *
  114.  * for example, such that the time is no longer invalid, then the
  115.  * object will no longer be in this invalid state.  This behaviour
  116.  * is intended to minimize unexpected errors when a user uses the
  117.  * class to do addition with days only, and does not intend to
  118.  * access the time.
  119.  *
  120.  * Of course, this constant will be unused if the user chooses to
  121.  * work in UTC or a time zone without Summer time, in which case
  122.  * this situation will never arise.
  123.  *
  124.  * This constant is set to 'true' by default for backwards-compatibility
  125.  * reasons, however, you are recommended to set it to 'false'.  Note that the
  126.  * behaviour is not intended to match that of previous versions of the class
  127.  * in terms of ignoring the Summer time offset when making calculations which
  128.  * involve dates in both standard and Summer time - this was recognized as a
  129.  * bug - but in terms of returning a PEAR error object when the user sets the
  130.  * object to an invalid date (i.e. a time in the hour which is skipped when
  131.  * the clocks go forwards, which in Europe would be a time such as 01.30).
  132.  * Backwards compatibility here means that the behaviour is the same as it
  133.  * used to be, less the bug.
  134.  *
  135.  * Note that this problem is not an issue for the user if:
  136.  *
  137.  *  (a) the user uses a time zone that does not observe Summer time, e.g. UTC
  138.  *  (b) the user never accesses the time, that is, he never makes a call to
  139.  *       Date::getHour() or Date::format("%H"), for example, even if he sets
  140.  *       the time to something invalid
  141.  *  (c) the user sets DATE_CORRECTINVALIDTIME_DEFAULT to true
  142.  *
  143.  * @since    Constant available since Release 1.5.0
  144.  */
  145. define('DATE_CORRECTINVALIDTIME_DEFAULT'true);
  146.  
  147. /**
  148.  * Whether to validate dates (i.e. day-month-year, ignoring the time) by
  149.  * disallowing invalid dates (e.g. 31st February) being set by the following
  150.  * functions:
  151.  *
  152.  *  Date::setYear()
  153.  *  Date::setMonth()
  154.  *  Date::setDay()
  155.  *
  156.  * If the constant is set to 'true', then the date will be checked (by
  157.  * default), and if invalid, an error will be returned with the Date object
  158.  * left unmodified.
  159.  *
  160.  * This constant is set to 'false' by default for backwards-compatibility
  161.  * reasons, however, you are recommended to set it to 'true'.
  162.  *
  163.  * Note that setHour(), setMinute(), setSecond() and setPartSecond()
  164.  * allow an invalid date/time to be set regardless of the value of this
  165.  * constant.
  166.  *
  167.  * @since    Constant available since Release 1.5.0
  168.  */
  169. define('DATE_VALIDATE_DATE_BY_DEFAULT'false);
  170.  
  171. /**
  172.  * Whether, by default, to accept times including leap seconds (i.e. '23.59.60')
  173.  * when setting the date/time, and whether to count leap seconds in the
  174.  * following functions:
  175.  *
  176.  *  Date::addSeconds()
  177.  *  Date::subtractSeconds()
  178.  *  Date_Calc::addSeconds()
  179.  *  Date::round()
  180.  *  Date::roundSeconds()
  181.  *
  182.  * This constant is set to 'false' by default for backwards-compatibility
  183.  * reasons, however, you are recommended to set it to 'true'.
  184.  *
  185.  * Note that this constant does not affect Date::addSpan() and
  186.  * Date::subtractSpan() which will not count leap seconds in any case.
  187.  *
  188.  * @since    Constant available since Release 1.5.0
  189.  */
  190. define('DATE_COUNT_LEAP_SECONDS'false);
  191.  
  192.  
  193. // }}}
  194. // {{{ Output format constants (used in 'Date::getDate()')
  195.  
  196. /**
  197.  * "YYYY-MM-DD HH:MM:SS"
  198.  */
  199. define('DATE_FORMAT_ISO'1);
  200.  
  201. /**
  202.  * "YYYYMMSSTHHMMSS(Z|(+/-)HHMM)?"
  203.  */
  204. define('DATE_FORMAT_ISO_BASIC'2);
  205.  
  206. /**
  207.  * "YYYY-MM-SSTHH:MM:SS(Z|(+/-)HH:MM)?"
  208.  */
  209. define('DATE_FORMAT_ISO_EXTENDED'3);
  210.  
  211. /**
  212.  * "YYYY-MM-SSTHH:MM:SS(.S*)?(Z|(+/-)HH:MM)?"
  213.  */
  214. define('DATE_FORMAT_ISO_EXTENDED_MICROTIME'6);
  215.  
  216. /**
  217.  * "YYYYMMDDHHMMSS"
  218.  */
  219. define('DATE_FORMAT_TIMESTAMP'4);
  220.  
  221. /**
  222.  * long int, seconds since the unix epoch
  223.  */
  224. define('DATE_FORMAT_UNIXTIME'5);
  225.  
  226.  
  227. // }}}
  228. // {{{ Class: Date
  229.  
  230. /**
  231.  * Generic date handling class for PEAR
  232.  *
  233.  * Supports time zones with the Date_TimeZone class.  Supports several
  234.  * operations from Date_Calc on Date objects.
  235.  *
  236.  * Note to developers: the class stores the local time and date in the
  237.  * local standard time.  That is, it does not store the time as the
  238.  * local Summer time when and if the time zone is in Summer time.  It
  239.  * is much easier to store local standard time and remember to offset
  240.  * it when the user requests it.
  241.  *
  242.  * @category  Date and Time
  243.  * @package   Date
  244.  * @author    Baba Buehler <baba@babaz.com>
  245.  * @author    Pierre-Alain Joye <pajoye@php.net>
  246.  * @author    Firman Wandayandi <firman@php.net>
  247.  * @author    C.A. Woodcock <c01234@netcomuk.co.uk>
  248.  * @copyright 1997-2007 Baba Buehler, Pierre-Alain Joye, Firman Wandayandi, C.A. Woodcock
  249.  * @license   http://www.opensource.org/licenses/bsd-license.php
  250.  *             BSD License
  251.  * @version   Release: 1.5.0a1
  252.  * @link      http://pear.php.net/package/Date
  253.  */
  254. class Date
  255. {
  256.  
  257.     // {{{ Properties
  258.  
  259.     /**
  260.      * The year
  261.      *
  262.      * @var      int 
  263.      * @access   private
  264.      * @since    Property available since Release 1.0
  265.      */
  266.     var $year;
  267.  
  268.     /**
  269.      * The month
  270.      *
  271.      * @var      int 
  272.      * @access   private
  273.      * @since    Property available since Release 1.0
  274.      */
  275.     var $month;
  276.  
  277.     /**
  278.      * The day
  279.      *
  280.      * @var      int 
  281.      * @access   private
  282.      * @since    Property available since Release 1.0
  283.      */
  284.     var $day;
  285.  
  286.     /**
  287.      * The hour
  288.      *
  289.      * @var      int 
  290.      * @access   private
  291.      * @since    Property available since Release 1.0
  292.      */
  293.     var $hour;
  294.  
  295.     /**
  296.      * The minute
  297.      *
  298.      * @var      int 
  299.      * @access   private
  300.      * @since    Property available since Release 1.0
  301.      */
  302.     var $minute;
  303.  
  304.     /**
  305.      * The second
  306.      *
  307.      * @var      int 
  308.      * @access   private
  309.      * @since    Property available since Release 1.0
  310.      */
  311.     var $second;
  312.  
  313.     /**
  314.      * The parts of a second
  315.      *
  316.      * @var      float 
  317.      * @access   private
  318.      * @since    Property available since Release 1.4.3
  319.      */
  320.     var $partsecond;
  321.  
  322.     /**
  323.      * The year in local standard time
  324.      *
  325.      * @var      int 
  326.      * @access   private
  327.      * @since    Property available since Release 1.5.0
  328.      */
  329.     var $on_standardyear;
  330.  
  331.     /**
  332.      * The month in local standard time
  333.      *
  334.      * @var      int 
  335.      * @access   private
  336.      * @since    Property available since Release 1.5.0
  337.      */
  338.     var $on_standardmonth;
  339.  
  340.     /**
  341.      * The day in local standard time
  342.      *
  343.      * @var      int 
  344.      * @access   private
  345.      * @since    Property available since Release 1.5.0
  346.      */
  347.     var $on_standardday;
  348.  
  349.     /**
  350.      * The hour in local standard time
  351.      *
  352.      * @var      int 
  353.      * @access   private
  354.      * @since    Property available since Release 1.5.0
  355.      */
  356.     var $on_standardhour;
  357.  
  358.     /**
  359.      * The minute in local standard time
  360.      *
  361.      * @var      int 
  362.      * @access   private
  363.      * @since    Property available since Release 1.5.0
  364.      */
  365.     var $on_standardminute;
  366.  
  367.     /**
  368.      * The second in local standard time
  369.      *
  370.      * @var      int 
  371.      * @access   private
  372.      * @since    Property available since Release 1.5.0
  373.      */
  374.     var $on_standardsecond;
  375.  
  376.     /**
  377.      * The part-second in local standard time
  378.      *
  379.      * @var      float 
  380.      * @access   private
  381.      * @since    Property available since Release 1.5.0
  382.      */
  383.     var $on_standardpartsecond;
  384.  
  385.     /**
  386.      * Whether the object should accept and count leap seconds
  387.      *
  388.      * @var      bool 
  389.      * @access   private
  390.      * @since    Property available since Release 1.5.0
  391.      */
  392.     var $ob_countleapseconds;
  393.  
  394.     /**
  395.      * Whether the time is valid as a local time (an invalid time
  396.      * is one that lies in the 'skipped hour' at the point that
  397.      * the clocks go forward)
  398.      *
  399.      * @var      bool 
  400.      * @access   private
  401.      * @see      Date::isTimeValid()
  402.      * @since    Property available since Release 1.5.0
  403.      */
  404.     var $ob_invalidtime = null;
  405.  
  406.     /**
  407.      * Date_TimeZone object for this date
  408.      *
  409.      * @var      object     Date_TimeZone object
  410.      * @access   private
  411.      * @since    Property available since Release 1.0
  412.      */
  413.     var $tz;
  414.  
  415.     /**
  416.      * Defines the default weekday abbreviation length
  417.      *
  418.      * Formerly used by Date::format(), but now redundant - the abbreviation
  419.      * for the current locale of the machine is used.
  420.      *
  421.      * @var      int 
  422.      * @access   private
  423.      * @since    Property available since Release 1.4.4
  424.      */
  425.     var $getWeekdayAbbrnameLength = 3;
  426.  
  427.  
  428.     // }}}
  429.     // {{{ Constructor
  430.  
  431.     /**
  432.      * Constructor
  433.      *
  434.      * Creates a new Date Object initialized to the current date/time in the
  435.      * system-default timezone by default.  A date optionally
  436.      * passed in may be in the ISO 8601, TIMESTAMP or UNIXTIME format,
  437.      * or another Date object.  If no date is passed, the current date/time
  438.      * is used.
  439.      *
  440.      * If a date is passed and an exception is returned by 'setDate()'
  441.      * there is nothing that this function can do, so for this reason, it
  442.      * is advisable to pass no parameter and to make a separate call to
  443.      * 'setDate()'.  A date/time should only be passed if known to be a
  444.      * valid ISO 8601 string or a valid Unix timestamp.
  445.      *
  446.      * @param mixed $date                optional ISO 8601 date/time to initialize;
  447.      *                                     or, a Unix time stamp
  448.      * @param bool  $pb_countleapseconds whether to count leap seconds
  449.      *                                     (defaults to DATE_COUNT_LEAP_SECONDS)
  450.      *
  451.      * @return   void 
  452.      * @access   public
  453.      * @see      Date::setDate()
  454.      */
  455.     function Date($date = null,
  456.                   $pb_countleapseconds = DATE_COUNT_LEAP_SECONDS)
  457.     {
  458.         $this->ob_countleapseconds $pb_countleapseconds;
  459.  
  460.         if (is_a($date'Date')) {
  461.             $this->copy($date);
  462.         else {
  463.             if (!is_null($date)) {
  464.                 // 'setDate()' expects a time zone to be already set:
  465.                 //
  466.                 $this->_setTZToDefault();
  467.                 $this->setDate($date);
  468.             else {
  469.                 $this->setNow();
  470.             }
  471.         }
  472.     }
  473.  
  474.  
  475.     // }}}
  476.     // {{{ copy()
  477.  
  478.     /**
  479.      * Copy values from another Date object
  480.      *
  481.      * Makes this Date a copy of another Date object.  This is a
  482.      * PHP4-compatible implementation of '__clone()' in PHP5.
  483.      *
  484.      * @param object $date Date object to copy
  485.      *
  486.      * @return   void 
  487.      * @access   public
  488.      */
  489.     function copy($date)
  490.     {
  491.         $this->year       $date->year;
  492.         $this->month      $date->month;
  493.         $this->day        $date->day;
  494.         $this->hour       $date->hour;
  495.         $this->minute     $date->minute;
  496.         $this->second     $date->second;
  497.         $this->partsecond $date->partsecond;
  498.  
  499.         $this->on_standardyear       $date->on_standardyear;
  500.         $this->on_standardmonth      $date->on_standardmonth;
  501.         $this->on_standardday        $date->on_standardday;
  502.         $this->on_standardhour       $date->on_standardhour;
  503.         $this->on_standardminute     $date->on_standardminute;
  504.         $this->on_standardsecond     $date->on_standardsecond;
  505.         $this->on_standardpartsecond $date->on_standardpartsecond;
  506.  
  507.         $this->ob_countleapseconds $date->ob_countleapseconds;
  508.         $this->ob_invalidtime      $date->ob_invalidtime;
  509.  
  510.         $this->tz = new Date_TimeZone($date->getTZID());
  511.  
  512.         $this->getWeekdayAbbrnameLength $date->getWeekdayAbbrnameLength;
  513.     }
  514.  
  515.  
  516.     // }}}
  517.     // {{{ __clone()
  518.  
  519.     /**
  520.      * Copy values from another Date object
  521.      *
  522.      * Makes this Date a copy of another Date object.  For PHP5
  523.      * only.
  524.      *
  525.      * @return   void 
  526.      * @access   public
  527.      * @see      Date::copy()
  528.      */
  529.     function __clone()
  530.     {
  531.         // This line of code would be preferable, but will only
  532.         // compile in PHP5:
  533.         //
  534.         // $this->tz = clone $this->tz;
  535.  
  536.         $this->tz = new Date_TimeZone($this->getTZID());
  537.     }
  538.  
  539.  
  540.     // }}}
  541.     // {{{ setDate()
  542.  
  543.     /**
  544.      * Sets the fields of a Date object based on the input date and format
  545.      *
  546.      * Format parameter should be one of the specified DATE_FORMAT_* constants:
  547.      *
  548.      *  <code>DATE_FORMAT_ISO</code>
  549.      *                              - 'YYYY-MM-DD HH:MI:SS'
  550.      *  <code>DATE_FORMAT_ISO_BASIC</code>
  551.      *                              - 'YYYYMMSSTHHMMSS(Z|(+/-)HHMM)?'
  552.      *  <code>DATE_FORMAT_ISO_EXTENDED</code>
  553.      *                              - 'YYYY-MM-SSTHH:MM:SS(Z|(+/-)HH:MM)?'
  554.      *  <code>DATE_FORMAT_ISO_EXTENDED_MICROTIME</code>
  555.      *                              - 'YYYY-MM-SSTHH:MM:SS(.S*)?(Z|(+/-)HH:MM)?'
  556.      *  <code>DATE_FORMAT_TIMESTAMP</code>
  557.      *                              - 'YYYYMMDDHHMMSS'
  558.      *  <code>DATE_FORMAT_UNIXTIME'</code>
  559.      *                              - long integer of the no of seconds since
  560.      *                                 the Unix Epoch
  561.      *                                 (1st January 1970 00.00.00 GMT)
  562.      *
  563.      * @param string $date                   input date
  564.      * @param int    $format                 optional format constant
  565.      *                                         (DATE_FORMAT_*) of the input date.
  566.      *                                         This parameter is not needed,
  567.      *                                         except to force the setting of the
  568.      *                                         date from a Unix time-stamp
  569.      *                                         (DATE_FORMAT_UNIXTIME).
  570.      * @param bool   $pb_repeatedhourdefault value to return if repeated
  571.      *                                         hour is specified (defaults
  572.      *                                         to false)
  573.      *
  574.      * @return   void 
  575.      * @access   public
  576.      */
  577.     function setDate($date,
  578.                      $format = DATE_FORMAT_ISO,
  579.                      $pb_repeatedhourdefault = false)
  580.     {
  581.  
  582.         if (preg_match('/^([0-9]{4,4})-?(0[1-9]|1[0-2])-?(0[1-9]|[12][0-9]|3[01])' .
  583.                          '([T\s]?([01][0-9]|2[0-3]):?' .             // [hh]
  584.                          '([0-5][0-9]):?([0-5][0-9]|60)(\.\d+)?' .   // [mi]:[ss]
  585.                          '(Z|[+\-][0-9]{2,2}(:?[0-5][0-9])?)?)?$/i'// offset
  586.                          $date$regs&&
  587.             $format != DATE_FORMAT_UNIXTIME
  588.             {
  589.             // DATE_FORMAT_ISO, ISO_BASIC, ISO_EXTENDED, and TIMESTAMP
  590.             // These formats are extremely close to each other.  This regex
  591.             // is very loose and accepts almost any butchered format you could
  592.             // throw at it.  e.g. 2003-10-07 19:45:15 and 2003-10071945:15
  593.             // are the same thing in the eyes of this regex, even though the
  594.             // latter is not a valid ISO 8601 date.
  595.  
  596.             if (!Date_Calc::isValidDate($regs[3]$regs[2]$regs[1])) {
  597.                 return PEAR::raiseError("'" .
  598.                                         Date_Calc::dateFormat($regs[1],
  599.                                                               $regs[2],
  600.                                                               $regs[3],
  601.                                                               "%Y-%m-%d".
  602.                                         "' is invalid calendar date",
  603.                                         DATE_ERROR_INVALIDDATE);
  604.             }
  605.  
  606.             if (isset($regs[9])) {
  607.                 if ($regs[9== "Z"{
  608.                     $this->tz = new Date_TimeZone("UTC");
  609.                 else {
  610.                     $this->tz = new Date_TimeZone("UTC" $regs[9]);
  611.                 }
  612.             }
  613.  
  614.             $this->setLocalTime($regs[3],
  615.                                 $regs[2],
  616.                                 $regs[1],
  617.                                 isset($regs[5]$regs[5: 0,
  618.                                 isset($regs[6]$regs[6: 0,
  619.                                 isset($regs[7]$regs[7: 0,
  620.                                 isset($regs[8]$regs[8: 0.0,
  621.                                 $pb_repeatedhourdefault);
  622.  
  623.         else if (is_numeric($date)) {
  624.             // Unix Time; N.B. Unix Time is defined relative to GMT,
  625.             // so it needs to be adjusted for the current time zone;
  626.             // however we do not know if it is in Summer time until
  627.             // we have converted it from Unix time:
  628.             //
  629.  
  630.             // Get current time zone details:
  631.             //
  632.             $hs_id $this->getTZID();
  633.  
  634.             // Input Unix time as UTC:
  635.             //
  636.             $this->tz = new Date_TimeZone("UTC");
  637.             $this->setDate(gmdate("Y-m-d H:i:s"$date));
  638.  
  639.             // Convert back to correct time zone:
  640.             //
  641.             $this->convertTZByID($hs_id);
  642.         else {
  643.             return PEAR::raiseError("Date not in ISO 8601 format",
  644.                                     DATE_ERROR_INVALIDDATEFORMAT);
  645.         }
  646.     }
  647.  
  648.  
  649.     // }}}
  650.     // {{{ setNow()
  651.  
  652.     /**
  653.      * Sets to local current time and time zone
  654.      *
  655.      * @param bool $pb_setmicrotime whether to set micro-time (defaults to the
  656.      *                                value of the constant
  657.      *                                DATE_CAPTURE_MICROTIME_BY_DEFAULT)
  658.      *
  659.      * @return   void 
  660.      * @access   public
  661.      * @since    Method available since Release 1.5.0
  662.      */
  663.     function setNow($pb_setmicrotime = DATE_CAPTURE_MICROTIME_BY_DEFAULT)
  664.     {
  665.         $this->_setTZToDefault();
  666.  
  667.         if ($pb_setmicrotime{
  668.             $ha_unixtime gettimeofday();
  669.         else {
  670.             $ha_unixtime = array("sec" => time());
  671.         }
  672.  
  673.         $this->setDate(date("Y-m-d H:i:s"$ha_unixtime["sec"].
  674.                        (isset($ha_unixtime["usec"]?
  675.                         "." sprintf("%06d"$ha_unixtime["usec"]:
  676.                         ""));
  677.     }
  678.  
  679.  
  680.     // }}}
  681.     // {{{ round()
  682.  
  683.     /**
  684.      * Rounds the date according to the specified precision (defaults
  685.      * to nearest day)
  686.      *
  687.      * The precision parameter must be one of the following constants:
  688.      *
  689.      *  <code>DATE_PRECISION_YEAR</code>
  690.      *  <code>DATE_PRECISION_MONTH</code>
  691.      *  <code>DATE_PRECISION_DAY</code>
  692.      *  <code>DATE_PRECISION_HOUR</code>
  693.      *  <code>DATE_PRECISION_10MINUTES</code>
  694.      *  <code>DATE_PRECISION_MINUTE</code>
  695.      *  <code>DATE_PRECISION_10SECONDS</code>
  696.      *  <code>DATE_PRECISION_SECOND</code>
  697.      *
  698.      * N.B. the default is DATE_PRECISION_DAY
  699.      *
  700.      * The precision can also be specified as an integral offset from
  701.      * one of these constants, where the offset reflects a precision
  702.      * of 10 to the power of the offset greater than the constant.
  703.      * For example:
  704.      *
  705.      *  <code>DATE_PRECISION_YEAR - 1</code> rounds the date to the nearest 10
  706.      *                                      years
  707.      *  <code>DATE_PRECISION_YEAR - 3</code> rounds the date to the nearest 1000
  708.      *                                      years
  709.      *  <code>DATE_PRECISION_SECOND + 1</code> rounds the date to 1 decimal
  710.      *                                        point of a second
  711.      *  <code>DATE_PRECISION_SECOND + 3</code> rounds the date to 3 decimal
  712.      *                                        points of a second
  713.      *  <code>DATE_PRECISION_SECOND - 1</code> rounds the date to the nearest 10
  714.      *                                        seconds (thus it is equivalent to
  715.      *                                        DATE_PRECISION_10SECONDS)
  716.      *
  717.      * @param int  $pn_precision          a 'DATE_PRECISION_*' constant
  718.      * @param bool $pb_correctinvalidtime whether to correct, by adding the
  719.      *                                      local Summer time offset, the rounded
  720.      *                                      time if it falls in the skipped hour
  721.      *                                      (defaults to
  722.      *                                      DATE_CORRECTINVALIDTIME_DEFAULT)
  723.      *
  724.      * @return   void 
  725.      * @access   public
  726.      * @since    Method available since Release 1.5.0
  727.      */
  728.     function round($pn_precision = DATE_PRECISION_DAY,
  729.                    $pb_correctinvalidtime = DATE_CORRECTINVALIDTIME_DEFAULT)
  730.     {
  731.         if ($pn_precision <= DATE_PRECISION_DAY{
  732.             list($hn_year,
  733.                  $hn_month,
  734.                  $hn_day,
  735.                  $hn_hour,
  736.                  $hn_minute,
  737.                  $hn_secondraw=
  738.                  Date_Calc::round($pn_precision,
  739.                                   $this->day,
  740.                                   $this->month,
  741.                                   $this->year,
  742.                                   $this->hour,
  743.                                   $this->minute,
  744.                                   $this->partsecond == 0.0 ?
  745.                                       $this->second :
  746.                                       $this->second $this->partsecond,
  747.                                   $this->ob_countleapseconds);
  748.             if (is_float($hn_secondraw)) {
  749.                 $hn_second     intval($hn_secondraw);
  750.                 $hn_partsecond $hn_secondraw $hn_second;
  751.             else {
  752.                 $hn_second     $hn_secondraw;
  753.                 $hn_partsecond = 0.0;
  754.             }
  755.  
  756.             $this->setLocalTime($hn_day,
  757.                                 $hn_month,
  758.                                 $hn_year,
  759.                                 $hn_hour,
  760.                                 $hn_minute,
  761.                                 $hn_second,
  762.                                 $hn_partsecond,
  763.                                 true// This is unlikely anyway, but the
  764.                                       // day starts with the repeated hour
  765.                                       // the first time around
  766.                                 $pb_correctinvalidtime);
  767.             return;
  768.         }
  769.  
  770.         // ($pn_precision >= DATE_PRECISION_HOUR)
  771.         //
  772.         if ($this->tz->getDSTSavings(% 3600000 == 0 ||
  773.             ($this->tz->getDSTSavings(% 60000 == 0 &&
  774.              $pn_precision >= DATE_PRECISION_MINUTE)
  775.             {
  776.             list($hn_year,
  777.                  $hn_month,
  778.                  $hn_day,
  779.                  $hn_hour,
  780.                  $hn_minute,
  781.                  $hn_secondraw=
  782.                  Date_Calc::round($pn_precision,
  783.                                   $this->on_standardday,
  784.                                   $this->on_standardmonth,
  785.                                   $this->on_standardyear,
  786.                                   $this->on_standardhour,
  787.                                   $this->on_standardminute,
  788.                                   $this->on_standardpartsecond == 0.0 ?
  789.                                       $this->on_standardsecond :
  790.                                       $this->on_standardsecond +
  791.                                           $this->on_standardpartsecond,
  792.                                   $this->ob_countleapseconds);
  793.             if (is_float($hn_secondraw)) {
  794.                 $hn_second     intval($hn_secondraw);
  795.                 $hn_partsecond $hn_secondraw $hn_second;
  796.             else {
  797.                 $hn_second     $hn_secondraw;
  798.                 $hn_partsecond = 0.0;
  799.             }
  800.  
  801.             $this->setStandardTime($hn_day,
  802.                                    $hn_month,
  803.                                    $hn_year,
  804.                                    $hn_hour,
  805.                                    $hn_minute,
  806.                                    $hn_second,
  807.                                    $hn_partsecond);
  808.             return;
  809.         }
  810.  
  811.         // Very unlikely anyway (as I write, the only time zone like this
  812.         // is Lord Howe Island in Australia (offset of half an hour)):
  813.         //
  814.         // (This algorithm could be better)
  815.         //
  816.         list($hn_year,
  817.              $hn_month,
  818.              $hn_day,
  819.              $hn_hour,
  820.              $hn_minute,
  821.              $hn_secondraw=
  822.              Date_Calc::round($pn_precision,
  823.                               $this->day,
  824.                               $this->month,
  825.                               $this->year,
  826.                               $this->hour,
  827.                               $this->minute,
  828.                               $this->partsecond == 0.0 ?
  829.                                   $this->second :
  830.                                   $this->second $this->partsecond,
  831.                               $this->ob_countleapseconds);
  832.         if (is_float($hn_secondraw)) {
  833.             $hn_second     intval($hn_secondraw);
  834.             $hn_partsecond $hn_secondraw $hn_second;
  835.         else {
  836.             $hn_second     $hn_secondraw;
  837.             $hn_partsecond = 0.0;
  838.         }
  839.  
  840.         $this->setLocalTime($hn_day,
  841.                             $hn_month,
  842.                             $hn_year,
  843.                             $hn_hour,
  844.                             $hn_minute,
  845.                             $hn_second,
  846.                             $hn_partsecond,
  847.                             false// This will be right half the time
  848.                             $pb_correctinvalidtime);   // This will be right
  849.                                                        // some of the time
  850.                                                        // (depends on Summer
  851.                                                        // time offset)
  852.     }
  853.  
  854.  
  855.     // }}}
  856.     // {{{ roundSeconds()
  857.  
  858.     /**
  859.      * Rounds seconds up or down to the nearest specified unit
  860.      *
  861.      * N.B. this function is equivalent to calling:
  862.      *  <code>'round(DATE_PRECISION_SECOND + $pn_precision)'</code>
  863.      *
  864.      * @param int  $pn_precision          number of digits after the decimal point
  865.      * @param bool $pb_correctinvalidtime whether to correct, by adding the
  866.      *                                      local Summer time offset, the rounded
  867.      *                                      time if it falls in the skipped hour
  868.      *                                      (defaults to
  869.      *                                      DATE_CORRECTINVALIDTIME_DEFAULT)
  870.      *
  871.      * @return   void 
  872.      * @access   public
  873.      * @since    Method available since Release 1.5.0
  874.      */
  875.     function roundSeconds($pn_precision = 0,
  876.                           $pb_correctinvalidtime = DATE_CORRECTINVALIDTIME_DEFAULT)
  877.     {
  878.         $this->round(DATE_PRECISION_SECOND + $pn_precision,
  879.                      $pb_correctinvalidtime);
  880.     }
  881.  
  882.  
  883.     // }}}
  884.     // {{{ trunc()
  885.  
  886.     /**
  887.      * Truncates the date according to the specified precision (by
  888.      * default, it truncates the time part of the date)
  889.      *
  890.      * The precision parameter must be one of the following constants:
  891.      *
  892.      *  <code>DATE_PRECISION_YEAR</code>
  893.      *  <code>DATE_PRECISION_MONTH</code>
  894.      *  <code>DATE_PRECISION_DAY</code>
  895.      *  <code>DATE_PRECISION_HOUR</code>
  896.      *  <code>DATE_PRECISION_10MINUTES</code>
  897.      *  <code>DATE_PRECISION_MINUTE</code>
  898.      *  <code>DATE_PRECISION_10SECONDS</code>
  899.      *  <code>DATE_PRECISION_SECOND</code>
  900.      *
  901.      * N.B. the default is DATE_PRECISION_DAY
  902.      *
  903.      * The precision can also be specified as an integral offset from
  904.      * one of these constants, where the offset reflects a precision
  905.      * of 10 to the power of the offset greater than the constant.
  906.      * For example:
  907.      *
  908.      *  <code>DATE_PRECISION_YEAR</code> truncates the month, day and time
  909.      *                                  part of the year
  910.      *  <code>DATE_PRECISION_YEAR - 1</code> truncates the unit part of the
  911.      *                                      year, e.g. 1987 becomes 1980
  912.      *  <code>DATE_PRECISION_YEAR - 3</code> truncates the hundreds part of the
  913.      *                                      year, e.g. 1987 becomes 1000
  914.      *  <code>DATE_PRECISION_SECOND + 1</code> truncates the part of the second
  915.      *                                        less than 0.1 of a second, e.g.
  916.      *                                        3.26301 becomes 3.2 seconds
  917.      *  <code>DATE_PRECISION_SECOND + 3</code> truncates the part of the second
  918.      *                                        less than 0.001 of a second, e.g.
  919.      *                                        3.26301 becomes 3.263 seconds
  920.      *  <code>DATE_PRECISION_SECOND - 1</code> truncates the unit part of the
  921.      *                                        seconds (thus it is equivalent to
  922.      *                                        DATE_PRECISION_10SECONDS)
  923.      *
  924.      * @param int  $pn_precision          a 'DATE_PRECISION_*' constant
  925.      * @param bool $pb_correctinvalidtime whether to correct, by adding the
  926.      *                                      local Summer time offset, the
  927.      *                                      truncated time if it falls in the
  928.      *                                      skipped hour (defaults to
  929.      *                                      DATE_CORRECTINVALIDTIME_DEFAULT)
  930.      *
  931.      * @return   void 
  932.      * @access   public
  933.      * @since    Method available since Release 1.5.0
  934.      */
  935.     function trunc($pn_precision = DATE_PRECISION_DAY,
  936.                    $pb_correctinvalidtime = DATE_CORRECTINVALIDTIME_DEFAULT)
  937.     {
  938.         if ($pn_precision <= DATE_PRECISION_DAY{
  939.             if ($pn_precision <= DATE_PRECISION_YEAR{
  940.                 $hn_month      = 0;
  941.                 $hn_day        = 0;
  942.                 $hn_hour       = 0;
  943.                 $hn_minute     = 0;
  944.                 $hn_second     = 0;
  945.                 $hn_partsecond = 0.0;
  946.  
  947.                 $hn_invprecision DATE_PRECISION_YEAR - $pn_precision;
  948.                 if ($hn_invprecision > 0{
  949.                     $hn_year intval($this->year pow(10$hn_invprecision)) *
  950.                                pow(10$hn_invprecision);
  951.                     //
  952.                     // (Conversion to int necessary for PHP <= 4.0.6)
  953.                 else {
  954.                     $hn_year $this->year;
  955.                 }
  956.             else if ($pn_precision == DATE_PRECISION_MONTH{
  957.                 $hn_year       $this->year;
  958.                 $hn_month      $this->month;
  959.                 $hn_day        = 0;
  960.                 $hn_hour       = 0;
  961.                 $hn_minute     = 0;
  962.                 $hn_second     = 0;
  963.                 $hn_partsecond = 0.0;
  964.             else if ($pn_precision == DATE_PRECISION_DAY{
  965.                 $hn_year       $this->year;
  966.                 $hn_month      $this->month;
  967.                 $hn_day        $this->day;
  968.                 $hn_hour       = 0;
  969.                 $hn_minute     = 0;
  970.                 $hn_second     = 0;
  971.                 $hn_partsecond = 0.0;
  972.             }
  973.  
  974.             $this->setLocalTime($hn_day,
  975.                                 $hn_month,
  976.                                 $hn_year,
  977.                                 $hn_hour,
  978.                                 $hn_minute,
  979.                                 $hn_second,
  980.                                 $hn_partsecond,
  981.                                 true// This is unlikely anyway, but the
  982.                                       // day starts with the repeated
  983.                                       // hour the first time around
  984.                                 $pb_correctinvalidtime);
  985.             return;
  986.         }
  987.  
  988.         // Precision is at least equal to DATE_PRECISION_HOUR
  989.         //
  990.         if ($pn_precision == DATE_PRECISION_HOUR{
  991.             $this->addSeconds($this->partsecond == 0.0 ?
  992.                               -$this->second :
  993.                               -$this->second $this->partsecond);
  994.             //
  995.             // (leap seconds irrelevant)
  996.  
  997.             $this->addMinutes(-$this->minute);
  998.         else if ($pn_precision <= DATE_PRECISION_MINUTE{
  999.             if ($pn_precision == DATE_PRECISION_10MINUTES{
  1000.                 $this->addMinutes(-$this->minute % 10);
  1001.             }
  1002.  
  1003.             $this->addSeconds($this->partsecond == 0.0 ?
  1004.                               -$this->second :
  1005.                               -$this->second $this->partsecond);
  1006.             //
  1007.             // (leap seconds irrelevant)
  1008.  
  1009.         else if ($pn_precision == DATE_PRECISION_10SECONDS{
  1010.             $this->addSeconds($this->partsecond == 0.0 ?
  1011.                               -$this->second % 10 :
  1012.                               (-$this->second % 10$this->partsecond);
  1013.             //
  1014.             // (leap seconds irrelevant)
  1015.  
  1016.         else {
  1017.             // Assume Summer time offset cannot be composed of part-seconds:
  1018.             //
  1019.             $hn_precision  $pn_precision DATE_PRECISION_SECOND;
  1020.             $hn_partsecond intval($this->on_standardpartsecond *
  1021.                                     pow(10$hn_precision)) /
  1022.                                     pow(10$hn_precision);
  1023.             $this->setStandardTime($this->on_standardday,
  1024.                                    $this->on_standardmonth,
  1025.                                    $this->on_standardyear,
  1026.                                    $this->on_standardhour,
  1027.                                    $this->on_standardminute,
  1028.                                    $this->on_standardsecond,
  1029.                                    $hn_partsecond);
  1030.         }
  1031.     }
  1032.  
  1033.  
  1034.     // }}}
  1035.     // {{{ truncSeconds()
  1036.  
  1037.     /**
  1038.      * Truncates seconds according to the specified precision
  1039.      *
  1040.      * N.B. this function is equivalent to calling:
  1041.      *  <code>'Date::trunc(DATE_PRECISION_SECOND + $pn_precision)'</code>
  1042.      *
  1043.      * @param int  $pn_precision          number of digits after the decimal point
  1044.      * @param bool $pb_correctinvalidtime whether to correct, by adding the
  1045.      *                                      local Summer time offset, the
  1046.      *                                      truncated time if it falls in the
  1047.      *                                      skipped hour (defaults to
  1048.      *                                      DATE_CORRECTINVALIDTIME_DEFAULT)
  1049.      *
  1050.      * @return   void 
  1051.      * @access   public
  1052.      * @since    Method available since Release 1.5.0
  1053.      */
  1054.     function truncSeconds($pn_precision = 0,
  1055.                           $pb_correctinvalidtime = DATE_CORRECTINVALIDTIME_DEFAULT)
  1056.     {
  1057.         $this->trunc(DATE_PRECISION_SECOND + $pn_precision,
  1058.                      $pb_correctinvalidtime);
  1059.     }
  1060.  
  1061.  
  1062.     // }}}
  1063.     // {{{ getDate()
  1064.  
  1065.     /**
  1066.      * Gets a string (or other) representation of this date
  1067.      *
  1068.      * Returns a date in the format specified by the DATE_FORMAT_* constants.
  1069.      *
  1070.      * @param int $format format constant (DATE_FORMAT_*) of the output date
  1071.      *
  1072.      * @return   string     the date in the requested format
  1073.      * @access   public
  1074.      */
  1075.     function getDate($format = DATE_FORMAT_ISO)
  1076.     {
  1077.         switch ($format{
  1078.         case DATE_FORMAT_ISO:
  1079.             return $this->format("%Y-%m-%d %T");
  1080.             break;
  1081.         case DATE_FORMAT_ISO_BASIC:
  1082.             $format "%Y%m%dT%H%M%S";
  1083.             if ($this->getTZID(== 'UTC'{
  1084.                 $format .= "Z";
  1085.             }
  1086.             return $this->format($format);
  1087.             break;
  1088.         case DATE_FORMAT_ISO_EXTENDED:
  1089.             $format "%Y-%m-%dT%H:%M:%S";
  1090.             if ($this->getTZID(== 'UTC'{
  1091.                 $format .= "Z";
  1092.             }
  1093.             return $this->format($format);
  1094.             break;
  1095.         case DATE_FORMAT_ISO_EXTENDED_MICROTIME:
  1096.             $format "%Y-%m-%dT%H:%M:%s";
  1097.             if ($this->getTZID(== 'UTC'{
  1098.                 $format .= "Z";
  1099.             }
  1100.             return $this->format($format);
  1101.             break;
  1102.         case DATE_FORMAT_TIMESTAMP:
  1103.             return $this->format("%Y%m%d%H%M%S");
  1104.             break;
  1105.         case DATE_FORMAT_UNIXTIME:
  1106.             // Enter a time in UTC, so use 'gmmktime()' (the alternative
  1107.             // is to offset additionally by the local time, but the object
  1108.             // is not necessarily using local time):
  1109.             //
  1110.             if ($this->ob_invalidtime)
  1111.                 return $this->_getErrorInvalidTime();
  1112.  
  1113.             return gmmktime($this->on_standardhour,
  1114.                             $this->on_standardminute,
  1115.                             $this->on_standardsecond,
  1116.                             $this->on_standardmonth,
  1117.                             $this->on_standardday,
  1118.                             $this->on_standardyear-
  1119.                    $this->tz->getRawOffset(/ 1000; // N.B. Unix-time excludes
  1120.                                                      // leap seconds by
  1121.                                                      // definition
  1122.             break;
  1123.         }
  1124.     }
  1125.  
  1126.  
  1127.     // }}}
  1128.     // {{{ format()
  1129.  
  1130.     /**
  1131.      *  Date pretty printing, similar to strftime()
  1132.      *
  1133.      *  Formats the date in the given format, much like
  1134.      *  strftime().  Most strftime() options are supported.<br><br>
  1135.      *
  1136.      *  Formatting options:<br><br>
  1137.      *
  1138.      *  <code>%a  </code>  abbreviated weekday name (Sun, Mon, Tue) <br>
  1139.      *  <code>%A  </code>  full weekday name (Sunday, Monday, Tuesday) <br>
  1140.      *  <code>%b  </code>  abbreviated month name (Jan, Feb, Mar) <br>
  1141.      *  <code>%B  </code>  full month name (January, February, March) <br>
  1142.      *  <code>%C  </code>  century number (the year divided by 100 and truncated
  1143.      *                     to an integer, range 00 to 99) <br>
  1144.      *  <code>%d  </code>  day of month (range 00 to 31) <br>
  1145.      *  <code>%D  </code>  equivalent to "%m/%d/%y" <br>
  1146.      *  <code>%e  </code>  day of month without leading noughts (range 0 to 31) <br>
  1147.      *  <code>%E  </code>  Julian day - no of days since Monday, 24th November,
  1148.      *                     4714 B.C. (in the proleptic Gregorian calendar) <br>
  1149.      *  <code>%g  </code>  like %G, but without the century <br>
  1150.      *  <code>%G  </code>  the 4-digit year corresponding to the ISO week
  1151.      *                     number (see %V). This has the same format and value
  1152.      *                     as %Y, except that if the ISO week number belongs
  1153.      *                     to the previous or next year, that year is used
  1154.      *                     instead. <br>
  1155.      *  <code>%h  </code>  hour as decimal number without leading noughts (0
  1156.      *                     to 23) <br>
  1157.      *  <code>%H  </code>  hour as decimal number (00 to 23) <br>
  1158.      *  <code>%i  </code>  hour as decimal number on 12-hour clock without
  1159.      *                     leading noughts (1 to 12) <br>
  1160.      *  <code>%I  </code>  hour as decimal number on 12-hour clock (01 to 12) <br>
  1161.      *  <code>%j  </code>  day of year (range 001 to 366) <br>
  1162.      *  <code>%m  </code>  month as decimal number (range 01 to 12) <br>
  1163.      *  <code>%M  </code>  minute as a decimal number (00 to 59) <br>
  1164.      *  <code>%n  </code>  newline character ("\n") <br>
  1165.      *  <code>%o  </code>  raw timezone offset expressed as '+/-HH:MM' <br>
  1166.      *  <code>%O  </code>  dst-corrected timezone offset expressed as '+/-HH:MM' <br>
  1167.      *  <code>%p  </code>  either 'am' or 'pm' depending on the time <br>
  1168.      *  <code>%P  </code>  either 'AM' or 'PM' depending on the time <br>
  1169.      *  <code>%r  </code>  time in am/pm notation; equivalent to "%I:%M:%S %p" <br>
  1170.      *  <code>%R  </code>  time in 24-hour notation; equivalent to "%H:%M" <br>
  1171.      *  <code>%s  </code>  seconds including the micro-time (the decimal
  1172.      *                     representation less than one second to six decimal
  1173.      *                     places<br>
  1174.      *  <code>%S  </code>  seconds as a decimal number (00 to 59) <br>
  1175.      *  <code>%t  </code>  tab character ("\t") <br>
  1176.      *  <code>%T  </code>  current time; equivalent to "%H:%M:%S" <br>
  1177.      *  <code>%u  </code>  day of week as decimal (1 to 7; where 1 = Monday) <br>
  1178.      *  <code>%U  </code>  week number of the current year as a decimal
  1179.      *                     number, starting with the first Sunday as the first
  1180.      *                     day of the first week (i.e. the first full week of
  1181.      *                     the year, and the week that contains 7th January)
  1182.      *                     (00 to 53) <br>
  1183.      *  <code>%V  </code>  the ISO 8601:1988 week number of the current year
  1184.      *                     as a decimal number, range 01 to 53, where week 1
  1185.      *                     is the first week that has at least 4 days in the
  1186.      *                     current year, and with Monday as the first day of
  1187.      *                     the week.  (Use %G or %g for the year component
  1188.      *                     that corresponds to the week number for the
  1189.      *                     specified timestamp.)
  1190.      *  <code>%w  </code>  day of week as decimal (0 to 6; where 0 = Sunday) <br>
  1191.      *  <code>%W  </code>  week number of the current year as a decimal
  1192.      *                     number, starting with the first Monday as the first
  1193.      *                     day of the first week (i.e. the first full week of
  1194.      *                     the year, and the week that contains 7th January)
  1195.      *                     (00 to 53) <br>
  1196.      *  <code>%y  </code>  year as decimal (range 00 to 99) <br>
  1197.      *  <code>%Y  </code>  year as decimal including century (range 0000 to
  1198.      *                     9999) <br>
  1199.      *  <code>%Z  </code>  Abbreviated form of time zone name, e.g. 'GMT', or
  1200.      *                     the abbreviation for Summer time if the date falls
  1201.      *                     in Summer time, e.g. 'BST'. <br>
  1202.      *  <code>%%  </code>  literal '%' <br>
  1203.      * <br>
  1204.      *
  1205.      * The following codes render a different output to that of 'strftime()':
  1206.      *
  1207.      *  <code>%e</code> in 'strftime()' a single digit is preceded by a space
  1208.      *  <code>%h</code> in 'strftime()' is equivalent to '%b'
  1209.      *  <code>%U</code> '%U' and '%W' are different in 'strftime()' in that
  1210.      *                  if week 1 does not start on 1st January, '00' is
  1211.      *                  returned, whereas this function returns '53', that is,
  1212.      *                  the week is counted as the last of the previous year.
  1213.      *  <code>%W</code>
  1214.      *
  1215.      * @param string $format the format string for returned date/time
  1216.      *
  1217.      * @return   string     date/time in given format
  1218.      * @access   public
  1219.      */
  1220.     function format($format)
  1221.     {
  1222.         $output "";
  1223.  
  1224.         $hn_isoyear = null;
  1225.         $hn_isoweek = null;
  1226.         $hn_isoday  = null;
  1227.  
  1228.         for ($strpos = 0; $strpos strlen($format)$strpos++{
  1229.             $char substr($format$strpos1);
  1230.             if ($char == "%"{
  1231.                 $nextchar substr($format$strpos + 11);
  1232.                 switch ($nextchar{
  1233.                 case "a":
  1234.                     $output .= Date_Calc::getWeekdayAbbrname($this->day,
  1235.                                    $this->month$this->year,
  1236.                                    $this->getWeekdayAbbrnameLength);
  1237.                     break;
  1238.                 case "A":
  1239.                     $output .= Date_Calc::getWeekdayFullname($this->day,
  1240.                                    $this->month$this->year);
  1241.                     break;
  1242.                 case "b":
  1243.                     $output .= Date_Calc::getMonthAbbrname($this->month);
  1244.                     break;
  1245.                 case "B":
  1246.                     $output .= Date_Calc::getMonthFullname($this->month);
  1247.                     break;
  1248.                 case "C":
  1249.                     $output .= sprintf("%02d"intval($this->year / 100));
  1250.                     break;
  1251.                 case "d":
  1252.                     $output .= sprintf("%02d"$this->day);
  1253.                     break;
  1254.                 case "D":
  1255.                     $output .= sprintf("%02d/%02d/%02d"$this->month,
  1256.                                    $this->day$this->year);
  1257.                     break;
  1258.                 case "e":
  1259.                     $output .= $this->day;
  1260.                     break;
  1261.                 case "E":
  1262.                     $output .= Date_Calc::dateToDays($this->day$this->month,
  1263.                                    $this->year);
  1264.                     break;
  1265.                 case "g":
  1266.                     if (is_null($hn_isoyear))
  1267.                         list($hn_isoyear$hn_isoweek$hn_isoday=
  1268.                             Date_Calc::isoWeekDate($this->day,
  1269.                                                    $this->month,
  1270.                                                    $this->year);
  1271.  
  1272.                     $output .= sprintf("%02d"$hn_isoyear % 100);
  1273.                     break;
  1274.                 case "G":
  1275.                     if (is_null($hn_isoyear))
  1276.                         list($hn_isoyear$hn_isoweek$hn_isoday=
  1277.                             Date_Calc::isoWeekDate($this->day,
  1278.                                                    $this->month,
  1279.                                                    $this->year);
  1280.  
  1281.                     $output .= sprintf("%04d"$hn_isoyear);
  1282.                     break;
  1283.                 case 'h':
  1284.                     if ($this->ob_invalidtime)
  1285.                         return $this->_getErrorInvalidTime();
  1286.                     $output .= sprintf("%d"$this->hour);
  1287.                     break;
  1288.                 case "H":
  1289.                     if ($this->ob_invalidtime)
  1290.                         return $this->_getErrorInvalidTime();
  1291.                     $output .= sprintf("%02d"$this->hour);
  1292.                     break;
  1293.                 case "i":
  1294.                 case "I":
  1295.                     if ($this->ob_invalidtime)
  1296.                         return $this->_getErrorInvalidTime();
  1297.                     $hour    $this->hour + 1 > 12 ?
  1298.                                $this->hour - 12 :
  1299.                                $this->hour;
  1300.                     $output .= $hour == 0 ?
  1301.                                12 :
  1302.                                ($nextchar == "i" ?
  1303.                                 $hour :
  1304.                                 sprintf('%02d'$hour));
  1305.                     break;
  1306.                 case "j":
  1307.                     $output .= sprintf("%03d",
  1308.                                        Date_Calc::dayOfYear($this->day,
  1309.                                                             $this->month,
  1310.                                                             $this->year));
  1311.                     break;
  1312.                 case "m":
  1313.                     $output .= sprintf("%02d"$this->month);
  1314.                     break;
  1315.                 case "M":
  1316.                     $output .= sprintf("%02d"$this->minute);
  1317.                     break;
  1318.                 case "n":
  1319.                     $output .= "\n";
  1320.                     break;
  1321.                 case "O":
  1322.                     if ($this->ob_invalidtime)
  1323.                         return $this->_getErrorInvalidTime();
  1324.                     $offms     $this->getTZOffset();
  1325.                     $direction $offms >= 0 ? "+" "-";
  1326.                     $offmins   abs($offms/ 1000 / 60;
  1327.                     $hours     $offmins / 60;
  1328.                     $minutes   $offmins % 60;
  1329.  
  1330.                     $output .= sprintf("%s%02d:%02d"$direction$hours$minutes);
  1331.                     break;
  1332.                 case "o":
  1333.                     $offms     $this->tz->getRawOffset($this);
  1334.                     $direction $offms >= 0 ? "+" "-";
  1335.                     $offmins   abs($offms/ 1000 / 60;
  1336.                     $hours     $offmins / 60;
  1337.                     $minutes   $offmins % 60;
  1338.  
  1339.                     $output .= sprintf("%s%02d:%02d"$direction$hours$minutes);
  1340.                     break;
  1341.                 case "p":
  1342.                     if ($this->ob_invalidtime)
  1343.                         return $this->_getErrorInvalidTime();
  1344.                     $output .= $this->hour >= 12 ? "pm" "am";
  1345.                     break;
  1346.                 case "P":
  1347.                     if ($this->ob_invalidtime)
  1348.                         return $this->_getErrorInvalidTime();
  1349.                     $output .= $this->hour >= 12 ? "PM" "AM";
  1350.                     break;
  1351.                 case "r":
  1352.                     if ($this->ob_invalidtime)
  1353.                         return $this->_getErrorInvalidTime();
  1354.                     $hour    $this->hour + 1 > 12 ?
  1355.                                $this->hour - 12 :
  1356.                                $this->hour;
  1357.                     $output .= sprintf("%02d:%02d:%02d %s",
  1358.                                        $hour == 0 ?  12 : $hour,
  1359.                                        $this->minute,
  1360.                                        $this->second,
  1361.                                        $this->hour >= 12 ? "PM" "AM");
  1362.                     break;
  1363.                 case "R":
  1364.                     if ($this->ob_invalidtime)
  1365.                         return $this->_getErrorInvalidTime();
  1366.                     $output .= sprintf("%02d:%02d"$this->hour$this->minute);
  1367.                     break;
  1368.                 case "s":
  1369.                     $output .= str_replace(',',
  1370.                                            '.',
  1371.                                            sprintf("%09f",
  1372.                                                    (float)((float) $this->second +
  1373.                                                            $this->partsecond)));
  1374.                     break;
  1375.                 case "S":
  1376.                     $output .= sprintf("%02d"$this->second);
  1377.                     break;
  1378.                 case "t":
  1379.                     $output .= "\t";
  1380.                     break;
  1381.                 case "T":
  1382.                     if ($this->ob_invalidtime)
  1383.                         return $this->_getErrorInvalidTime();
  1384.                     $output .= sprintf("%02d:%02d:%02d",
  1385.                                        $this->hour,
  1386.                                        $this->minute,
  1387.                                        $this->second);
  1388.                     break;
  1389.                 case "u":
  1390.                     $hn_dayofweek $this->getDayOfWeek();
  1391.                     $output      .= $hn_dayofweek == 0 ? 7 : $hn_dayofweek;
  1392.                     break;
  1393.                 case "U":
  1394.                     $ha_week Date_Calc::weekOfYear7th($this->day,
  1395.                                                         $this->month,
  1396.                                                         $this->year,
  1397.                                                         0);
  1398.                     $output .= sprintf("%02d"$ha_week[1]);
  1399.                     break;
  1400.                 case "V":
  1401.                     if (is_null($hn_isoyear))
  1402.                         list($hn_isoyear$hn_isoweek$hn_isoday=
  1403.                             Date_Calc::isoWeekDate($this->day,
  1404.                                                    $this->month,
  1405.                                                    $this->year);
  1406.  
  1407.                     $output .= $hn_isoweek;
  1408.                     break;
  1409.                 case "w":
  1410.                     $output .= $this->getDayOfWeek();
  1411.                     break;
  1412.                 case "W":
  1413.                     $ha_week Date_Calc::weekOfYear7th($this->day,
  1414.                                                         $this->month,
  1415.                                                         $this->year,
  1416.                                                         1);
  1417.                     $output .= sprintf("%02d"$ha_week[1]);
  1418.                     break;
  1419.                 case 'y':
  1420.                     $output .= sprintf('%0' .
  1421.                                        ($this->year < 0 ? '3' '2'.
  1422.                                        'd',
  1423.                                        $this->year % 100);
  1424.                     break;
  1425.                 case "Y":
  1426.                     $output .= sprintf('%0' .
  1427.                                        ($this->year < 0 ? '5' '4'.
  1428.                                        'd',
  1429.                                        $this->year);
  1430.                     break;
  1431.                 case "Z":
  1432.                     if ($this->ob_invalidtime)
  1433.                         return $this->_getErrorInvalidTime();
  1434.                     $output .= $this->getTZShortName();
  1435.                     break;
  1436.                 case "%":
  1437.                     $output .= "%";
  1438.                     break;
  1439.                 default:
  1440.                     $output .= $char.$nextchar;
  1441.                 }
  1442.                 $strpos++;
  1443.             else {
  1444.                 $output .= $char;
  1445.             }
  1446.         }
  1447.         return $output;
  1448.  
  1449.     }
  1450.  
  1451.  
  1452.     // }}}
  1453.     // {{{ _getOrdinalSuffix()
  1454.  
  1455.     /**
  1456.      * Returns appropriate ordinal suffix (i.e. 'th', 'st', 'nd' or 'rd')
  1457.      *
  1458.      * @param int  $pn_num       number with which to determine suffix
  1459.      * @param bool $pb_uppercase boolean specifying if the suffix should be
  1460.      *                             capitalized
  1461.      *
  1462.      * @return   string 
  1463.      * @access   private
  1464.      * @since    Method available since Release 1.5.0
  1465.      */
  1466.     function _getOrdinalSuffix($pn_num$pb_uppercase = true)
  1467.     {
  1468.         switch (($pn_numabs abs($pn_num)) % 100{
  1469.         case 11:
  1470.         case 12:
  1471.         case 13:
  1472.             $hs_suffix "th";
  1473.             break;
  1474.         default:
  1475.             switch ($pn_numabs % 10{
  1476.             case 1:
  1477.                 $hs_suffix "st";
  1478.                 break;
  1479.             case 2:
  1480.                 $hs_suffix "nd";
  1481.                 break;
  1482.             case 3:
  1483.                 $hs_suffix "rd";
  1484.                 break;
  1485.             default:
  1486.                 $hs_suffix "th";
  1487.             }
  1488.         }
  1489.  
  1490.         return $pb_uppercase strtoupper($hs_suffix$hs_suffix;
  1491.     }
  1492.  
  1493.  
  1494.     // }}}
  1495.     // {{{ _spellNumber()
  1496.  
  1497.     /**
  1498.      * Converts a number to its word representation
  1499.      *
  1500.      * Private helper function, particularly for 'format2()'.  N.B. The
  1501.      * second argument is the 'SP' code which can be specified in the
  1502.      * format string for 'format2()' and is interpreted as follows:
  1503.      *  'SP' - returns upper-case spelling, e.g. 'FOUR HUNDRED'
  1504.      *  'Sp' - returns spelling with first character of each word
  1505.      *         capitalized, e.g. 'Four Hundred'
  1506.      *  'sp' - returns lower-case spelling, e.g. 'four hundred'
  1507.      *
  1508.      * @param int    $pn_num            number to be converted to words
  1509.      * @param bool   $pb_ordinal        boolean specifying if the number should
  1510.      *                                    be ordinal
  1511.      * @param string $ps_capitalization string for specifying capitalization
  1512.      *                                    options
  1513.      * @param string $ps_locale         language name abbreviation used for
  1514.      *                                    formatting numbers as spelled-out words
  1515.      *
  1516.      * @return   string 
  1517.      * @access   private
  1518.      * @since    Method available since Release 1.5.0
  1519.      */
  1520.     function _spellNumber($pn_num,
  1521.                           $pb_ordinal = false,
  1522.                           $ps_capitalization "SP",
  1523.                           $ps_locale "en_GB")
  1524.     {
  1525.         include_once "Numbers/Words.php";
  1526.         $hs_words = Numbers_Words::toWords($pn_num$ps_locale);
  1527.         if (Pear::isError($hs_words)) {
  1528.             return $hs_words;
  1529.         }
  1530.  
  1531.         if ($pb_ordinal && substr($ps_locale02== "en"{
  1532.             if (($pn_rem ($pn_numabs abs($pn_num)) % 100== 12{
  1533.                 $hs_words substr($hs_words0-2"fth";
  1534.             else if ($pn_rem >= 11 && $pn_rem <= 15{
  1535.                 $hs_words .= "th";
  1536.             else {
  1537.                 switch ($pn_numabs % 10{
  1538.                 case 1:
  1539.                     $hs_words substr($hs_words0-3"first";
  1540.                     break;
  1541.                 case 2:
  1542.                     $hs_words substr($hs_words0-3"second";
  1543.                     break;
  1544.                 case 3:
  1545.                     $hs_words substr($hs_words0-3"ird";
  1546.                     break;
  1547.                 case 5:
  1548.                     $hs_words substr($hs_words0-2"fth";
  1549.                     break;
  1550.                 default:
  1551.                     switch (substr($hs_words-1)) {
  1552.                     case "e":
  1553.                         $hs_words substr($hs_words0-1"th";
  1554.                         break;
  1555.                     case "t":
  1556.                         $hs_words .= "h";
  1557.                         break;
  1558.                     case "y":
  1559.                         $hs_words substr($hs_words0-1"ieth";
  1560.                         break;
  1561.                     default:
  1562.                         $hs_words .= "th";
  1563.                     }
  1564.                 }
  1565.             }
  1566.         }
  1567.  
  1568.         if (($hs_char substr($ps_capitalization01)) ==
  1569.             strtolower($hs_char)) {
  1570.             $hb_upper = false;
  1571.             $hs_words strtolower($hs_words);
  1572.         else if (($hs_char substr($ps_capitalization11)) ==
  1573.                    strtolower($hs_char)) {
  1574.             $hb_upper = false;
  1575.             $hs_words ucwords($hs_words);
  1576.         else {
  1577.             $hb_upper = true;
  1578.             $hs_words strtoupper($hs_words);
  1579.         }
  1580.  
  1581.         return $hs_words;
  1582.     }
  1583.  
  1584.  
  1585.     // }}}
  1586.     // {{{ _formatNumber()
  1587.  
  1588.     /**
  1589.      * Formats a number according to the specified format string
  1590.      *
  1591.      * Private helper function, for 'format2()', which interprets the
  1592.      * codes 'SP' and 'TH' and the combination of the two as follows:
  1593.      *
  1594.      *  <code>TH</code> Ordinal number
  1595.      *  <code>SP</code> Spelled cardinal number
  1596.      *  <code>SPTH</code> Spelled ordinal number (combination of 'SP' and 'TH'
  1597.      *                   in any order)
  1598.      *  <code>THSP</code>
  1599.      *
  1600.      * Code 'SP' can have the following three variations (which can also be used
  1601.      * in combination with 'TH'):
  1602.      *
  1603.      *  <code>SP</code> returns upper-case spelling, e.g. 'FOUR HUNDRED'
  1604.      *  <code>Sp</code> returns spelling with first character of each word
  1605.      *                 capitalized, e.g. 'Four Hundred'
  1606.      *  <code>sp</code> returns lower-case spelling, e.g. 'four hundred'
  1607.      *
  1608.      * Code 'TH' can have the following two variations (although in combination
  1609.      * with code 'SP', the case specification of 'SP' takes precedence):
  1610.      *
  1611.      *  <code>TH</code> returns upper-case ordinal suffix, e.g. 400TH
  1612.      *  <code>th</code> returns lower-case ordinal suffix, e.g. 400th
  1613.      *
  1614.      * N.B. The format string is passed by reference, in order to pass back
  1615.      * the part of the format string that matches the valid codes 'SP' and
  1616.      * 'TH'.  If none of these are found, then it is set to an empty string;
  1617.      * If both codes are found then a string is returned with code 'SP'
  1618.      * preceding code 'TH' (i.e. 'SPTH', 'Spth' or 'spth').
  1619.      *
  1620.      * @param int    $pn_num         integer to be converted to words
  1621.      * @param string &$ps_format     string of formatting codes (max. length 4)
  1622.      * @param int    $pn_numofdigits no of digits to display if displayed as
  1623.      *                                 numeral (i.e. not spelled out), not
  1624.      *                                 including the sign (if negative); to
  1625.      *                                 allow all digits specify 0
  1626.      * @param bool   $pb_nopad       boolean specifying whether to suppress
  1627.      *                                 padding with leading noughts (if displayed
  1628.      *                                 as numeral)
  1629.      * @param bool   $pb_nosign      boolean specifying whether to suppress the
  1630.      *                                 display of the sign (if negative)
  1631.      * @param string $ps_locale      language name abbreviation used for
  1632.      *                                 formatting
  1633.      * @param string $ps_thousandsep optional thousand-separator (e.g. a comma)
  1634.      *                                 numbers as spelled-out words
  1635.      * @param int    $pn_padtype     optional integer to specify padding (if
  1636.      *                                 displayed as numeral) - can be
  1637.      *                                 STR_PAD_LEFT or STR_PAD_RIGHT
  1638.      *
  1639.      * @return   string 
  1640.      * @access   private
  1641.      * @since    Method available since Release 1.5.0
  1642.      */
  1643.     function _formatNumber($pn_num,
  1644.                            &$ps_format,
  1645.                            $pn_numofdigits,
  1646.                            $pb_nopad = false,
  1647.                            $pb_nosign = false,
  1648.                            $ps_locale "en_GB",
  1649.                            $ps_thousandsep = null,
  1650.                            $pn_padtype = STR_PAD_LEFT)
  1651.     {
  1652.         $hs_code1 substr($ps_format02);
  1653.         $hs_code2 substr($ps_format22);
  1654.  
  1655.         $hs_sp = null;
  1656.         $hs_th = null;
  1657.         if (strtoupper($hs_code1== "SP"{
  1658.             $hs_sp $hs_code1;
  1659.             if (strtoupper($hs_code2== "TH"{
  1660.                 $hs_th $hs_code2;
  1661.             }
  1662.         else if (strtoupper($hs_code1== "TH"{
  1663.             $hs_th $hs_code1;
  1664.             if (strtoupper($hs_code2== "SP"{
  1665.                 $hs_sp $hs_code2;
  1666.             }
  1667.         }
  1668.  
  1669.         $hn_absnum abs($pn_num);
  1670.         if ($pn_numofdigits > 0 && strlen($hn_absnum$pn_numofdigits{
  1671.             $hn_absnum intval(substr($hn_absnum-$pn_numofdigits));
  1672.         }
  1673.         $hs_num $hn_absnum;
  1674.  
  1675.         if (!is_null($hs_sp)) {
  1676.             // Spell out number:
  1677.             //
  1678.             $ps_format $hs_sp .
  1679.                          (is_null($hs_th"" ($hs_sp == "SP" "TH" "th"));
  1680.             return $this->_spellNumber(!$pb_nosign && $pn_num < 0 ?
  1681.                                            $hn_absnum * -1 :
  1682.                                            $hn_absnum,
  1683.                                        !is_null($hs_th),
  1684.                                        $hs_sp,
  1685.                                        $ps_locale);
  1686.         else {
  1687.             // Display number as Arabic numeral:
  1688.             //
  1689.             if (!$pb_nopad{
  1690.                 $hs_num str_pad($hs_num$pn_numofdigits"0"$pn_padtype);
  1691.             }
  1692.  
  1693.             if (!is_null($ps_thousandsep)) {
  1694.                 for ($i strlen($hs_num- 3; $i > 0; $i -= 3{
  1695.                     $hs_num substr($hs_num0$i.
  1696.                               $ps_thousandsep .
  1697.                               substr($hs_num$i);
  1698.                 }
  1699.             }
  1700.  
  1701.             if (!$pb_nosign{
  1702.                 if ($pn_num < 0)
  1703.                     $hs_num "-" $hs_num;
  1704.                 else if (!$pb_nopad)
  1705.                     $hs_num " " $hs_num;
  1706.             }
  1707.  
  1708.             if (!is_null($hs_th)) {
  1709.                 $ps_format $hs_th;
  1710.                 return $hs_num .
  1711.                        $this->_getOrdinalSuffix($pn_num,
  1712.                                                 substr($hs_th01== "T");
  1713.             else {
  1714.                 $ps_format "";
  1715.                 return $hs_num;
  1716.             }
  1717.         }
  1718.     }
  1719.  
  1720.  
  1721.     // }}}
  1722.     // {{{ format2()
  1723.  
  1724.     /**
  1725.      * Extended version of 'format()' with variable-length formatting codes
  1726.      *
  1727.      * Most codes reproduce the no of digits equal to the length of the code,
  1728.      * for example, 'YYY' will return the last 3 digits of the year, and so
  1729.      * the year 2007 will produce '007', and the year 89 will produce '089',
  1730.      * unless the no-padding code is used as in 'NPYYY', which will return
  1731.      * '89'.
  1732.      *
  1733.      * For negative values, the sign will be discarded, unless the 'S' code
  1734.      * is used in combination, but note that for positive values the value
  1735.      * will be padded with a leading space unless it is suppressed with
  1736.      * the no-padding modifier, for example for 2007:
  1737.      *
  1738.      *  <code>YYYY</code> returns '2007'
  1739.      *  <code>SYYYY</code> returns ' 2007'
  1740.      *  <code>NPSYYYY</code> returns '2007'
  1741.      *
  1742.      * The no-padding modifier 'NP' can be used with numeric codes to
  1743.      * suppress leading (or trailing in the case of code 'F') noughts, and
  1744.      * with character-returning codes such as 'DAY' to suppress trailing
  1745.      * spaces, which will otherwise be padded to the maximum possible length
  1746.      * of the return-value of the code; for example, for Monday:
  1747.      *
  1748.      *  <code>Day</code> returns 'Monday   ' because the maximum length of
  1749.      *                  this code is 'Wednesday';
  1750.      *  <code>NPDay</code> returns 'Monday'
  1751.      *
  1752.      * N.B. this code affects the code immediately following only, and
  1753.      * without this code the default is always to apply padding.
  1754.      *
  1755.      * Most character-returning codes, such as 'MONTH', will
  1756.      * set the capitalization according to the code, so for example:
  1757.      *
  1758.      *  <code>MONTH</code> returns upper-case spelling, e.g. 'JANUARY'
  1759.      *  <code>Month</code> returns spelling with first character of each word
  1760.      *                    capitalized, e.g. 'January'
  1761.      *  <code>month</code> returns lower-case spelling, e.g. 'january'
  1762.      *
  1763.      * Where it makes sense, numeric codes can be combined with a following
  1764.      * 'SP' code which spells out the number, or with a 'TH' code, which
  1765.      * renders the code as an ordinal ('TH' only works in English), for
  1766.      * example, for 31st December:
  1767.      *
  1768.      *  <code>DD</code> returns '31'
  1769.      *  <code>DDTH</code> returns '31ST'
  1770.      *  <code>DDth</code> returns '31st'
  1771.      *  <code>DDSP</code> returns 'THIRTY-ONE'
  1772.      *  <code>DDSp</code> returns 'Thirty-one'
  1773.      *  <code>DDsp</code> returns 'thirty-one'
  1774.      *  <code>DDSPTH</code> returns 'THIRTY-FIRST'
  1775.      *  <code>DDSpth</code> returns 'Thirty-first'
  1776.      *  <code>DDspth</code> returns 'thirty-first'
  1777.      *
  1778.      *
  1779.      * All formatting options:
  1780.      *
  1781.      *  <code>-</code> All punctuation and white-space is reproduced unchanged
  1782.      *  <code>/</code>
  1783.      *  <code>,</code>
  1784.      *  <code>.</code>
  1785.      *  <code>;</code>
  1786.      *  <code>:</code>
  1787.      *  <code> </code>
  1788.      *  <code>"text"</code> Quoted text is reproduced unchanged (escape using
  1789.      *                     '\')
  1790.      *  <code>AD</code> AD indicator with or without full stops; N.B. if you
  1791.      *                 are using 'Astronomical' year numbering then 'A.D./B.C.'
  1792.      *                 indicators will be out for negative years
  1793.      *  <code>A.D.</code>
  1794.      *  <code>AM</code> Meridian indicator with or without full stops
  1795.      *  <code>A.M.</code>
  1796.      *  <code>BC</code> BC indicator with or without full stops
  1797.      *  <code>B.C.</code>
  1798.      *  <code>BCE</code> BCE indicator with or without full stops
  1799.      *  <code>B.C.E.</code>
  1800.      *  <code>CC</code> Century, i.e. the year divided by 100, discarding the
  1801.      *                 remainder; 'S' prefixes negative years with a minus sign
  1802.      *  <code>SCC</code>
  1803.      *  <code>CE</code> CE indicator with or without full stops
  1804.      *  <code>C.E.</code>
  1805.      *  <code>D</code> Day of week (0-6), where 0 represents Sunday
  1806.      *  <code>DAY</code> Name of day, padded with blanks to display width of the
  1807.      *                  widest name of day in the locale of the machine
  1808.      *  <code>DD</code> Day of month (1-31)
  1809.      *  <code>DDD</code> Day of year (1-366)
  1810.      *  <code>DY</code> Abbreviated name of day
  1811.      *  <code>FFF</code> Fractional seconds; no radix character is printed.  The
  1812.      *                  no of 'F's determines the no of digits of the
  1813.      *                  part-second to return; e.g. 'HH:MI:SS.FF'
  1814.      *  <code>F[integer]</code> The integer after 'F' specifies the number of
  1815.      *                         digits of the part-second to return.  This is an
  1816.      *                         alternative to using F[integer], and 'F3' is thus
  1817.      *                         equivalent to using 'FFF'.
  1818.      *  <code>HH</code> Hour of day (0-23)
  1819.      *  <code>HH12</code> Hour of day (1-12)
  1820.      *  <code>HH24</code> Hour of day (0-23)
  1821.      *  <code>ID</code> Day of week (1-7) based on the ISO standard
  1822.      *  <code>IW</code> Week of year (1-52 or 1-53) based on the ISO standard
  1823.      *  <code>IYYY</code> 4-digit year based on the ISO 8601 standard; 'S'
  1824.      *                   prefixes negative years with a minus sign
  1825.      *  <code>SIYYY</code>
  1826.      *  <code>IYY</code> Last 3, 2, or 1 digit(s) of ISO year
  1827.      *  <code>IY</code>
  1828.      *  <code>I</code>
  1829.      *  <code>J</code> Julian day - the number of days since Monday, 24th
  1830.      *                November, 4714 B.C. (proleptic Gregorian calendar)
  1831.      *  <code>MI</code> Minute (0-59)
  1832.      *  <code>MM</code> Month (01-12; January = 01)
  1833.      *  <code>MON</code> Abbreviated name of month
  1834.      *  <code>MONTH</code> Name of month, padded with blanks to display width of
  1835.      *                    the widest name of month in the date language used for
  1836.      *  <code>PM</code> Meridian indicator with or without full stops
  1837.      *  <code>P.M.</code>
  1838.      *  <code>Q</code> Quarter of year (1, 2, 3, 4; January - March = 1)
  1839.      *  <code>RM</code> Roman numeral month (I-XII; January = I); N.B. padded
  1840.      *                 with leading spaces.
  1841.      *  <code>SS</code> Second (0-59)
  1842.      *  <code>SSSSS</code> Seconds past midnight (0-86399)
  1843.      *  <code>TZC</code> Abbreviated form of time zone name, e.g. 'GMT', or the
  1844.      *                  abbreviation for Summer time if the date falls in Summer
  1845.      *                  time, e.g. 'BST'.
  1846.      *                  N.B. this is not a unique identifier - for this purpose
  1847.      *                  use the time zone region (code 'TZR').
  1848.      *  <code>TZH</code> Time zone hour; 'S' prefixes the hour with the correct
  1849.      *                  sign, (+/-), which otherwise is not displayed.  Note
  1850.      *                  that the leading nought can be suppressed with the
  1851.      *                  no-padding code 'NP').  Also note that if you combine
  1852.      *                  with the 'SP' code, the sign will not be spelled out.
  1853.      *                  (I.e. 'STZHSp' will produce '+One', for example, and
  1854.      *                  not 'Plus One'.
  1855.      *                  'TZH:TZM' will produce, for example, '+05:30'.  (Also
  1856.      *                  see 'TZM' format code)
  1857.      *  <code>STZH</code>
  1858.      *  <code>TZI</code> Whether or not the date is in Summer time (daylight
  1859.      *                  saving time).  Returns '1' if Summer time, else '0'.
  1860.      *  <code>TZM</code> Time zone minute, without any +/- sign.  (Also see
  1861.      *                  'TZH' format element)
  1862.      *  <code>TZN</code> Long form of time zone name, e.g.
  1863.      *                  'Greenwich Mean Time', or the name of the Summer time if
  1864.      *                  the date falls in Summer time, e.g.
  1865.      *                  'British Summer Time'.  N.B. this is not a unique
  1866.      *                  identifier - for this purpose use the time zone region
  1867.      *                  (code 'TZR').
  1868.      *  <code>TZO</code> Time zone offset in ISO 8601 form - that is, 'Z' if
  1869.      *                  UTC, else [+/-][hh]:[mm] (which would be equivalent
  1870.      *                  to 'STZH:TZM').  Note that this result is right padded
  1871.      *                  with spaces by default, (i.e. if 'Z').
  1872.      *  <code>TZS</code> Time zone offset in seconds; 'S' prefixes negative
  1873.      *                  sign with minus sign '-' if negative, and no sign if
  1874.      *                  positive (i.e. -43200 to 50400).
  1875.      *  <code>STZS</code>
  1876.      *  <code>TZR</code> Time zone region, that is, the name or ID of the time
  1877.      *                  zone e.g. 'Europe/London'.  This value is unique for
  1878.      *                  each time zone.
  1879.      *  <code>U</code> Seconds since the Unix Epoch -
  1880.      *                January 1 1970 00:00:00 GMT
  1881.      *  <code>W</code> 'Absolute' week of month (1-5), counting week 1 as
  1882.      *                1st-7th of the year, regardless of the day
  1883.      *  <code>W1</code> Week of year (1-54), counting week 1 as the week that
  1884.      *                 contains 1st January
  1885.      *  <code>W4</code> Week of year (1-53), counting week 1 as the week that
  1886.      *                 contains 4th January (i.e. first week with at least 4
  1887.      *                 days)
  1888.      *  <code>W7</code> Week of year (1-53), counting week 1 as the week that
  1889.      *                 contains 7th January (i.e. first full week)
  1890.      *  <code>WW</code> 'Absolute' week of year (1-53), counting week 1 as
  1891.      *                 1st-7th of the year, regardless of the day
  1892.      *  <code>YEAR</code> Year, spelled out; 'S' prefixes negative years with
  1893.      *                  'MINUS'; N.B. 'YEAR' differs from 'YYYYSP' in that the
  1894.      *                   first will render 1923, for example, as 'NINETEEN
  1895.      *                   TWENTY-THREE, and the second as 'ONE THOUSAND NINE
  1896.      *                   HUNDRED TWENTY-THREE'
  1897.      *  <code>SYEAR</code>
  1898.      *  <code>YYYY</code> 4-digit year; 'S' prefixes negative years with a minus
  1899.      *                   sign
  1900.      *  <code>SYYYY</code>
  1901.      *  <code>YYY</code> Last 3, 2, or 1 digit(s) of year
  1902.      *  <code>YY</code>
  1903.      *  <code>Y</code>
  1904.      *  <code>Y,YYY</code> Year with thousands-separator in this position; five
  1905.      *                    possible separators
  1906.      *  <code>Y.YYY</code>
  1907.      *  <code>Y·YYY</code> N.B. space-dot (mid-dot, interpunct) is valid only in
  1908.      *                    ISO 8859-1 (so take care when using UTF-8 in
  1909.      *                    particular)
  1910.      *  <code>Y'YYY</code>
  1911.      *  <code>Y YYY</code>
  1912.      *
  1913.      * In addition the following codes can be used in combination with other
  1914.      * codes;
  1915.      *  Codes that modify the next code in the format string:
  1916.      *
  1917.      *  <code>NP</code> 'No Padding' - Returns a value with no trailing blanks
  1918.      *                 and no leading or trailing noughts; N.B. that the
  1919.      *                 default is to include this padding in the return string.
  1920.      *                 N.B. affects the code immediately following only.
  1921.      *
  1922.      *  Codes that modify the previous code in the format string (can only
  1923.      *  be used with integral codes such as 'MM'):
  1924.      *
  1925.      *  <code>TH</code> Ordinal number
  1926.      *  <code>SP</code> Spelled cardinal number
  1927.      *  <code>SPTH</code> Spelled ordinal number (combination of 'SP' and 'TH'
  1928.      *                   in any order)
  1929.      *  <code>THSP</code>
  1930.      *
  1931.      * Code 'SP' can have the following three variations (which can also be used
  1932.      * in combination with 'TH'):
  1933.      *
  1934.      *  <code>SP</code> returns upper-case spelling, e.g. 'FOUR HUNDRED'
  1935.      *  <code>Sp</code> returns spelling with first character of each word
  1936.      *                 capitalized, e.g. 'Four Hundred'
  1937.      *  <code>sp</code> returns lower-case spelling, e.g. 'four hundred'
  1938.      *
  1939.      * Code 'TH' can have the following two variations (although in combination
  1940.      * with code 'SP', the case specification of 'SP' takes precedence):
  1941.      *
  1942.      *  <code>TH</code> returns upper-case ordinal suffix, e.g. 400TH
  1943.      *  <code>th</code> returns lower-case ordinal suffix, e.g. 400th
  1944.      *
  1945.      * @param string $ps_format format string for returned date/time
  1946.      * @param string $ps_locale language name abbreviation used for formatting
  1947.      *                            numbers as spelled-out words
  1948.      *
  1949.      * @return   string     date/time in given format
  1950.      * @access   public
  1951.      * @since    Method available since Release 1.5.0
  1952.      */
  1953.     function format2($ps_format$ps_locale "en_GB")
  1954.     {
  1955.         if (!preg_match('/^("([^"\\\\]|\\\\\\\\|\\\\")*"|(D{1,3}|S?C+|' .
  1956.                         'HH(12|24)?|I[DW]|S?IY*|J|M[IM]|Q|SS(SSS)?|S?TZ[HS]|' .
  1957.                         'TZM|U|W[W147]?|S?Y{1,3}([,.·\' ]?YYY)*)(SP(TH)?|' .
  1958.                         'TH(SP)?)?|AD|A\.D\.|AM|A\.M\.|BCE?|B\.C\.(E\.)?|CE|' .
  1959.                         'C\.E\.|DAY|DY|F(F*|[1-9][0-9]*)|MON(TH)?|NP|PM|' .
  1960.                         'P\.M\.|RM|TZ[CINOR]|S?YEAR|[^A-Z0-9"])*$/i',
  1961.                         $ps_format)) {
  1962.             return PEAR::raiseError("Invalid date format '$ps_format'",
  1963.                                     DATE_ERROR_INVALIDFORMATSTRING);
  1964.         }
  1965.  
  1966.         $ret "";
  1967.         $i   = 0;
  1968.  
  1969.         $hb_nopadflag    = false;
  1970.         $hb_showsignflag = false;
  1971.  
  1972.         $hn_weekdaypad = null;
  1973.         $hn_monthpad   = null;
  1974.         $hn_isoyear    = null;
  1975.         $hn_isoweek    = null;
  1976.         $hn_isoday     = null;
  1977.         $hn_tzoffset   = null;
  1978.  
  1979.         while ($i strlen($ps_format)) {
  1980.             $hb_lower = false;
  1981.  
  1982.             if ($hb_nopadflag{
  1983.                 $hb_nopad = true;
  1984.             else {
  1985.                 $hb_nopad = false;
  1986.             }
  1987.             if ($hb_showsignflag{
  1988.                 $hb_nosign = false;
  1989.             else {
  1990.                 $hb_nosign = true;
  1991.             }
  1992.             $hb_nopadflag    = false;
  1993.             $hb_showsignflag = false;
  1994.  
  1995.             switch ($hs_char substr($ps_format$i1)) {
  1996.             case "-":
  1997.             case "/":
  1998.             case ",":
  1999.             case ".":
  2000.             case ";":
  2001.             case ":":
  2002.             case " ":
  2003.                 $ret .= $hs_char;
  2004.                 $i   += 1;
  2005.                 break;
  2006.             case "\"":
  2007.                 preg_match('/(([^"\\\\]|\\\\\\\\|\\\\")*)"/',
  2008.                            $ps_format,
  2009.                            $ha_matches,
  2010.                            PREG_OFFSET_CAPTURE,
  2011.                            $i + 1);
  2012.                 $ret .= str_replace(array('\\\\''\\"'),
  2013.                                     array('\\''"'),
  2014.                                     $ha_matches[1][0]);
  2015.                 $i   += strlen($ha_matches[0][0]+ 1;
  2016.                 break;
  2017.             case "a":
  2018.                 $hb_lower = true;
  2019.             case "A":
  2020.                 if (strtoupper(substr($ps_format$i4)) == "A.D."{
  2021.                     $ret .= $this->year >= 0 ?
  2022.                             ($hb_lower "a.d." "A.D.":
  2023.                             ($hb_lower "b.c." "B.C.");
  2024.                     $i   += 4;
  2025.                 else if (strtoupper(substr($ps_format$i2)) == "AD"{
  2026.                     $ret .= $this->year >= 0 ?
  2027.                             ($hb_lower "ad" "AD":
  2028.                             ($hb_lower "bc" "BC");
  2029.                     $i   += 2;
  2030.                 else {
  2031.                     if ($this->ob_invalidtime)
  2032.                         return $this->_getErrorInvalidTime();
  2033.                     if (strtoupper(substr($ps_format$i4)) == "A.M."{
  2034.                         $ret .= $this->hour < 12 ?
  2035.                                 ($hb_lower "a.m." "A.M.":
  2036.                                 ($hb_lower "p.m." "P.M.");
  2037.                         $i   += 4;
  2038.                     else if (strtoupper(substr($ps_format$i2)) == "AM"{
  2039.                         $ret .= $this->hour < 12 ?
  2040.                                 ($hb_lower "am" "AM":
  2041.                                 ($hb_lower "pm" "PM");
  2042.                         $i   += 2;
  2043.                     }
  2044.                 }
  2045.  
  2046.                 break;
  2047.             case "b":
  2048.                 $hb_lower = true;
  2049.             case "B":
  2050.                 // Check for 'B.C.E.' first:
  2051.                 //
  2052.                 if (strtoupper(substr($ps_format$i6)) == "B.C.E."{
  2053.                     if ($this->year >= 0{
  2054.                         $hs_era $hb_lower "c.e." "C.E.";
  2055.                         $ret   .= $hb_nopad ?
  2056.                                   $hs_era :
  2057.                                   str_pad($hs_era6" "STR_PAD_RIGHT);
  2058.                     else {
  2059.                         $ret .= $hb_lower "b.c.e." "B.C.E.";
  2060.                     }
  2061.                     $i += 6;
  2062.                 else if (strtoupper(substr($ps_format$i3)) == "BCE"{
  2063.                     if ($this->year >= 0{
  2064.                         $hs_era $hb_lower "ce" "CE";
  2065.                         $ret   .= $hb_nopad ?
  2066.                                   $hs_era :
  2067.                                   str_pad($hs_era3" "STR_PAD_RIGHT);
  2068.                     else {
  2069.                         $ret .= $hb_lower "bce" "BCE";
  2070.                     }
  2071.                     $i += 3;
  2072.                 else if (strtoupper(substr($ps_format$i4)) == "B.C."{
  2073.                     $ret .= $this->year >= 0 ?
  2074.                             ($hb_lower "a.d." "A.D.":
  2075.                             ($hb_lower "b.c." "B.C.");
  2076.                     $i   += 4;
  2077.                 else if (strtoupper(substr($ps_format$i2)) == "BC"{
  2078.                     $ret .= $this->year >= 0 ?
  2079.                             ($hb_lower "ad" "AD":
  2080.                             ($hb_lower "bc" "BC");
  2081.                     $i   += 2;
  2082.                 }
  2083.  
  2084.                 break;
  2085.             case "c":
  2086.                 $hb_lower = true;
  2087.             case "C":
  2088.                 if (strtoupper(substr($ps_format$i4)) == "C.E."{
  2089.                     if ($this->year >= 0{
  2090.                         $hs_era $hb_lower "c.e." "C.E.";
  2091.                         $ret   .= $hb_nopad ?
  2092.                                   $hs_era :
  2093.                                   str_pad($hs_era6" "STR_PAD_RIGHT);
  2094.                     else {
  2095.                         $ret .= $hb_lower "b.c.e." "B.C.E.";
  2096.                     }
  2097.                     $i += 4;
  2098.                 else if (strtoupper(substr($ps_format$i2)) == "CE"{
  2099.                     if ($this->year >= 0{
  2100.                         $hs_era $hb_lower "ce" "CE";
  2101.                         $ret   .= $hb_nopad ?
  2102.                                   $hs_era :
  2103.                                   str_pad($hs_era3" "STR_PAD_RIGHT);
  2104.                     else {
  2105.                         $ret .= $hb_lower "bce" "BCE";
  2106.                     }
  2107.                     $i += 2;
  2108.                 else {
  2109.                     // Code C(CCC...):
  2110.                     //
  2111.                     $hn_codelen = 1;
  2112.                     while (strtoupper(substr($ps_format,
  2113.                                              $i $hn_codelen,
  2114.                                              1)) == "C")
  2115.                         ++$hn_codelen;
  2116.  
  2117.                     // Check next code is not 'CE' or 'C.E.'
  2118.                     //
  2119.                     if ($hn_codelen > 1 &&
  2120.                         (strtoupper(substr($ps_format,
  2121.                                            $i $hn_codelen - 1,
  2122.                                            4)) == "C.E." ||
  2123.                          strtoupper(substr($ps_format,
  2124.                                            $i $hn_codelen - 1,
  2125.                                            2)) == "CE"
  2126.                          ))
  2127.                         --$hn_codelen;
  2128.  
  2129.                     $hn_century      intval($this->year / 100);
  2130.                     $hs_numberformat substr($ps_format$i $hn_codelen4);
  2131.                     $hs_century      $this->_formatNumber($hn_century,
  2132.                                                             $hs_numberformat,
  2133.                                                             $hn_codelen,
  2134.                                                             $hb_nopad,
  2135.                                                             $hb_nosign,
  2136.                                                             $ps_locale);
  2137.                     if (Pear::isError($hs_century))
  2138.                         return $hs_century;
  2139.  
  2140.                     $ret .= $hs_century;
  2141.                     $i   += $hn_codelen strlen($hs_numberformat);
  2142.                 }
  2143.  
  2144.                 break;
  2145.             case "d":
  2146.                 $hb_lower = true;
  2147.             case "D":
  2148.                 if (strtoupper(substr($ps_format$i3)) == "DAY"{
  2149.                     $hs_day Date_Calc::getWeekdayFullname($this->day,
  2150.                                                             $this->month,
  2151.                                                             $this->year);
  2152.  
  2153.                     if (!$hb_nopad{
  2154.                         if (is_null($hn_weekdaypad)) {
  2155.                             // Set week-day padding variable:
  2156.                             //
  2157.                             $hn_weekdaypad = 0;
  2158.                             foreach (Date_Calc::getWeekDays(as $hs_weekday)
  2159.                                 $hn_weekdaypad max($hn_weekdaypad,
  2160.                                                      strlen($hs_weekday));
  2161.                         }
  2162.                         $hs_day str_pad($hs_day,
  2163.                                           $hn_weekdaypad,
  2164.                                           " ",
  2165.                                           STR_PAD_RIGHT);
  2166.                     }
  2167.  
  2168.                     $ret .= $hb_lower ?
  2169.                             strtolower($hs_day:
  2170.                             (substr($ps_format$i + 11== "A" ?
  2171.                              strtoupper($hs_day:
  2172.                              $hs_day);
  2173.                     $i   += 3;
  2174.                 else if (strtoupper(substr($ps_format$i2)) == "DY"{
  2175.                     $hs_day Date_Calc::getWeekdayAbbrname($this->day,
  2176.                                                             $this->month,
  2177.                                                             $this->year);
  2178.                     $ret   .= $hb_lower ?
  2179.                               strtolower($hs_day:
  2180.                               (substr($ps_format$i + 11== "Y" ?
  2181.                                strtoupper($hs_day:
  2182.                                $hs_day);
  2183.                     $i     += 2;
  2184.                 else if (strtoupper(substr($ps_format$i3)) == "DDD" &&
  2185.                            strtoupper(substr($ps_format$i + 23)) != "DAY" &&
  2186.                            strtoupper(substr($ps_format$i + 22)) != "DY"
  2187.                            {
  2188.                     $hn_day Date_Calc::dayOfYear($this->day,
  2189.                                                    $this->month,
  2190.                                                    $this->year);
  2191.                     $hs_numberformat substr($ps_format$i + 34);
  2192.                     $hs_day $this->_formatNumber($hn_day,
  2193.                                                    $hs_numberformat,
  2194.                                                    3,
  2195.                                                    $hb_nopad,
  2196.                                                    true,
  2197.                                                    $ps_locale);
  2198.                     if (Pear::isError($hs_day))
  2199.                         return $hs_day;
  2200.  
  2201.                     $ret .= $hs_day;
  2202.                     $i   += 3 + strlen($hs_numberformat);
  2203.                 else if (strtoupper(substr($ps_format$i2)) == "DD" &&
  2204.                            strtoupper(substr($ps_format$i + 13)) != "DAY" &&
  2205.                            strtoupper(substr($ps_format$i + 12)) != "DY"
  2206.                            {
  2207.                     $hs_numberformat substr($ps_format$i + 24);
  2208.                     $hs_day $this->_formatNumber($this->day,
  2209.                                                    $hs_numberformat,
  2210.                                                    2,
  2211.                                                    $hb_nopad,
  2212.                                                    true,
  2213.                                                    $ps_locale);
  2214.                     if (Pear::isError($hs_day))
  2215.                         return $hs_day;
  2216.  
  2217.                     $ret .= $hs_day;
  2218.                     $i   += 2 + strlen($hs_numberformat);
  2219.                 else {
  2220.                     // Code 'D':
  2221.                     //
  2222.                     $hn_day Date_Calc::dayOfWeek($this->day,
  2223.                                                    $this->month,
  2224.                                                    $this->year);
  2225.                     $hs_numberformat substr($ps_format$i + 14);
  2226.                     $hs_day $this->_formatNumber($hn_day,
  2227.                                                    $hs_numberformat,
  2228.                                                    1,
  2229.                                                    $hb_nopad,
  2230.                                                    true,
  2231.                                                    $ps_locale);
  2232.                     if (Pear::isError($hs_day))
  2233.                         return $hs_day;
  2234.  
  2235.                     $ret .= $hs_day;
  2236.                     $i   += 1 + strlen($hs_numberformat);
  2237.                 }
  2238.  
  2239.                 break;
  2240.             case "f":
  2241.             case "F":
  2242.                 if ($this->ob_invalidtime)
  2243.                     return $this->_getErrorInvalidTime();
  2244.                 $hn_codelen = 1;
  2245.                 if (is_numeric(substr($ps_format$i $hn_codelen1))) {
  2246.                     ++$hn_codelen;
  2247.                     while (is_numeric(substr($ps_format$i $hn_codelen1)))
  2248.                         ++$hn_codelen;
  2249.  
  2250.                     $hn_partsecdigits substr($ps_format$i + 1$hn_codelen - 1);
  2251.                 else {
  2252.                     while (strtoupper(substr($ps_format,
  2253.                                              $i $hn_codelen,
  2254.                                              1)) == "F")
  2255.                         ++$hn_codelen;
  2256.  
  2257.                     // Check next code is not F[numeric]:
  2258.                     //
  2259.                     if ($hn_codelen > 1 &&
  2260.                         is_numeric(substr($ps_format$i $hn_codelen1)))
  2261.                         --$hn_codelen;
  2262.  
  2263.                     $hn_partsecdigits $hn_codelen;
  2264.                 }
  2265.  
  2266.                 $hs_partsec = (string) $this->partsecond;
  2267.                 if (preg_match('/^([0-9]+)(\.([0-9]+))?E-([0-9]+)$/i',
  2268.                                $hs_partsec,
  2269.                                $ha_matches)) {
  2270.                     $hs_partsec =
  2271.                         str_repeat("0"$ha_matches[4strlen($ha_matches[1])) .
  2272.                         $ha_matches[1.
  2273.                         $ha_matches[3];
  2274.                 else {
  2275.                     $hs_partsec substr($hs_partsec2);
  2276.                 }
  2277.                 $hs_partsec substr($hs_partsec0$hn_partsecdigits);
  2278.  
  2279.                 // '_formatNumber() will not work for this because the
  2280.                 // part-second is an int, and we want it to behave like a float:
  2281.                 //
  2282.                 if ($hb_nopad{
  2283.                     $hs_partsec rtrim($hs_partsec"0");
  2284.                     if ($hs_partsec == "")
  2285.                         $hs_partsec "0";
  2286.                 else {
  2287.                     $hs_partsec str_pad($hs_partsec,
  2288.                                           $hn_partsecdigits,
  2289.                                           "0",
  2290.                                           STR_PAD_RIGHT);
  2291.                 }
  2292.  
  2293.                 $ret .= $hs_partsec;
  2294.                 $i   += $hn_codelen;
  2295.                 break;
  2296.             case "h":
  2297.             case "H":
  2298.                 if ($this->ob_invalidtime)
  2299.                     return $this->_getErrorInvalidTime();
  2300.                 if (strtoupper(substr($ps_format$i4)) == "HH12"{
  2301.                     $hn_hour $this->hour % 12;
  2302.                     if ($hn_hour == 0)
  2303.                         $hn_hour = 12;
  2304.  
  2305.                     $hn_codelen = 4;
  2306.                 else {
  2307.                     // Code 'HH' or 'HH24':
  2308.                     //
  2309.                     $hn_hour    $this->hour;
  2310.                     $hn_codelen strtoupper(substr($ps_format,
  2311.                                                     $i,
  2312.                                                     4)) == "HH24" ? 4 : 2;
  2313.                 }
  2314.  
  2315.                 $hs_numberformat substr($ps_format$i $hn_codelen4);
  2316.                 $hs_hour $this->_formatNumber($hn_hour,
  2317.                                                 $hs_numberformat,
  2318.                                                 2,
  2319.                                                 $hb_nopad,
  2320.                                                 true,
  2321.                                                 $ps_locale);
  2322.                 if (Pear::isError($hs_hour))
  2323.                     return $hs_hour;
  2324.  
  2325.                 $ret .= $hs_hour;
  2326.                 $i   += $hn_codelen strlen($hs_numberformat);
  2327.                 break;
  2328.             case "i":
  2329.             case "I":
  2330.                 if (is_null($hn_isoyear))
  2331.                     list($hn_isoyear$hn_isoweek$hn_isoday=
  2332.                         Date_Calc::isoWeekDate($this->day,
  2333.                                                $this->month,
  2334.                                                $this->year);
  2335.  
  2336.                 if (strtoupper(substr($ps_format$i2)) == "ID" &&
  2337.                     strtoupper(substr($ps_format$i + 13)) != "DAY"
  2338.                     {
  2339.                     $hs_numberformat substr($ps_format$i + 24);
  2340.                     $hs_isoday $this->_formatNumber($hn_isoday,
  2341.                                                       $hs_numberformat,
  2342.                                                       1,
  2343.                                                       $hb_nopad,
  2344.                                                       true,
  2345.                                                       $ps_locale);
  2346.                     if (Pear::isError($hs_isoday))
  2347.                         return $hs_isoday;
  2348.  
  2349.                     $ret .= $hs_isoday;
  2350.                     $i   += 2 + strlen($hs_numberformat);
  2351.                 else if (strtoupper(substr($ps_format$i2)) == "IW"{
  2352.                     $hs_numberformat substr($ps_format$i + 24);
  2353.                     $hs_isoweek $this->_formatNumber($hn_isoweek,
  2354.                                                        $hs_numberformat,
  2355.                                                        2,
  2356.                                                        $hb_nopad,
  2357.                                                        true,
  2358.                                                        $ps_locale);
  2359.                     if (Pear::isError($hs_isoweek))
  2360.                         return $hs_isoweek;
  2361.  
  2362.                     $ret .= $hs_isoweek;
  2363.                     $i   += 2 + strlen($hs_numberformat);
  2364.                 else {
  2365.                     // Code I(YYY...):
  2366.                     //
  2367.                     $hn_codelen = 1;
  2368.                     while (strtoupper(substr($ps_format,
  2369.                                              $i $hn_codelen,
  2370.                                              1)) == "Y")
  2371.                         ++$hn_codelen;
  2372.  
  2373.                     $hs_numberformat substr($ps_format$i $hn_codelen4);
  2374.                     $hs_isoyear $this->_formatNumber($hn_isoyear,
  2375.                                                        $hs_numberformat,
  2376.                                                        $hn_codelen,
  2377.                                                        $hb_nopad,
  2378.                                                        $hb_nosign,
  2379.                                                        $ps_locale);
  2380.                     if (Pear::isError($hs_isoyear))
  2381.                         return $hs_isoyear;
  2382.  
  2383.                     $ret .= $hs_isoyear;
  2384.                     $i   += $hn_codelen strlen($hs_numberformat);
  2385.                 }
  2386.  
  2387.                 break;
  2388.             case "j":
  2389.             case "J":
  2390.                 $hn_jd Date_Calc::dateToDays($this->day,
  2391.                                                $this->month,
  2392.                                                $this->year);
  2393.                 $hs_numberformat substr($ps_format$i + 14);
  2394.  
  2395.                 // Allow sign if negative; allow all digits (specify nought);
  2396.                 // suppress padding:
  2397.                 //
  2398.                 $hs_jd $this->_formatNumber($hn_jd,
  2399.                                               $hs_numberformat,
  2400.                                               0,
  2401.                                               true,
  2402.                                               false,
  2403.                                               $ps_locale);
  2404.                 if (Pear::isError($hs_jd))
  2405.                     return $hs_jd;
  2406.  
  2407.                 $ret .= $hs_jd;
  2408.                 $i   += 1 + strlen($hs_numberformat);
  2409.                 break;
  2410.             case "m":
  2411.                 $hb_lower = true;
  2412.             case "M":
  2413.                 if (strtoupper(substr($ps_format$i2)) == "MI"{
  2414.                     if ($this->ob_invalidtime)
  2415.                         return $this->_getErrorInvalidTime();
  2416.                     $hs_numberformat substr($ps_format$i + 24);
  2417.                     $hs_minute $this->_formatNumber($this->minute,
  2418.                                                       $hs_numberformat,
  2419.                                                       2,
  2420.                                                       $hb_nopad,
  2421.                                                       true,
  2422.                                                       $ps_locale);
  2423.                     if (Pear::isError($hs_minute))
  2424.                         return $hs_minute;
  2425.  
  2426.                     $ret .= $hs_minute;
  2427.                     $i   += 2 + strlen($hs_numberformat);
  2428.                 else if (strtoupper(substr($ps_format$i2)) == "MM"{
  2429.                     $hs_numberformat substr($ps_format$i + 24);
  2430.                     $hs_month $this->_formatNumber($this->month,
  2431.                                                      $hs_numberformat,
  2432.                                                      2,
  2433.                                                      $hb_nopad,
  2434.                                                      true,
  2435.                                                      $ps_locale);
  2436.                     if (Pear::isError($hs_month))
  2437.                         return $hs_month;
  2438.  
  2439.                     $ret .= $hs_month;
  2440.                     $i   += 2 + strlen($hs_numberformat);
  2441.                 else if (strtoupper(substr($ps_format$i5)) == "MONTH"{
  2442.                     $hs_month Date_Calc::getMonthFullname($this->month);
  2443.  
  2444.                     if (!$hb_nopad{
  2445.                         if (is_null($hn_monthpad)) {
  2446.                             // Set month padding variable:
  2447.                             //
  2448.                             $hn_monthpad = 0;
  2449.                             foreach (Date_Calc::getMonthNames(as $hs_monthofyear)
  2450.                                 $hn_monthpad max($hn_monthpad,
  2451.                                                    strlen($hs_monthofyear));
  2452.                         }
  2453.                         $hs_month str_pad($hs_month,
  2454.                                             $hn_monthpad,
  2455.                                             " ",
  2456.                                             STR_PAD_RIGHT);
  2457.                     }
  2458.  
  2459.                     $ret .= $hb_lower ?
  2460.                             strtolower($hs_month:
  2461.                             (substr($ps_format$i + 11== "O" ?
  2462.                              strtoupper($hs_month:
  2463.                              $hs_month);
  2464.                     $i   += 5;
  2465.                 else if (strtoupper(substr($ps_format$i3)) == "MON"{
  2466.                     $hs_month Date_Calc::getMonthAbbrname($this->month);
  2467.                     $ret     .= $hb_lower ?
  2468.                                 strtolower($hs_month:
  2469.                                 (substr($ps_format$i + 11== "O" ?
  2470.                                  strtoupper($hs_month:
  2471.                                  $hs_month);
  2472.                     $i       += 3;
  2473.                 }
  2474.  
  2475.                 break;
  2476.             case "n":
  2477.             case "N":
  2478.                 // No-Padding rule 'NP' applies to the next code (either trailing
  2479.                 // spaces or leading/trailing noughts):
  2480.                 //
  2481.                 $hb_nopadflag = true;
  2482.                 $i           += 2;
  2483.                 break;
  2484.             case "p":
  2485.                 $hb_lower = true;
  2486.             case "P":
  2487.                 if ($this->ob_invalidtime)
  2488.                     return $this->_getErrorInvalidTime();
  2489.                 if (strtoupper(substr($ps_format$i4)) == "P.M."{
  2490.                     $ret .= $this->hour < 12 ?
  2491.                             ($hb_lower "a.m." "A.M.":
  2492.                             ($hb_lower "p.m." "P.M.");
  2493.                     $i   += 4;
  2494.                 else if (strtoupper(substr($ps_format$i2)) == "PM"{
  2495.                     $ret .= $this->hour < 12 ?
  2496.                             ($hb_lower "am" "AM":
  2497.                             ($hb_lower "pm" "PM");
  2498.                     $i   += 2;
  2499.                 }
  2500.  
  2501.                 break;
  2502.             case "q":
  2503.             case "Q":
  2504.                 // N.B. Current implementation ignores the day and year, but
  2505.                 // it is possible that a different implementation might be
  2506.                 // desired, so pass these parameters anyway:
  2507.                 //
  2508.                 $hn_quarter Date_Calc::quarterOfYear($this->day,
  2509.                                                        $this->month,
  2510.                                                        $this->year);
  2511.                 $hs_numberformat substr($ps_format$i + 14);
  2512.                 $hs_quarter $this->_formatNumber($hn_quarter,
  2513.                                                    $hs_numberformat,
  2514.                                                    1,
  2515.                                                    $hb_nopad,
  2516.                                                    true,
  2517.                                                    $ps_locale);
  2518.                 if (Pear::isError($hs_quarter))
  2519.                     return $hs_quarter;
  2520.  
  2521.                 $ret .= $hs_quarter;
  2522.                 $i   += 1 + strlen($hs_numberformat);
  2523.                 break;
  2524.             case "r":
  2525.                 $hb_lower = true;
  2526.             case "R":
  2527.                 // Code 'RM':
  2528.                 //
  2529.                 switch ($this->month{
  2530.                 case 1:
  2531.                     $hs_monthroman "i";
  2532.                     break;
  2533.                 case 2:
  2534.                     $hs_monthroman "ii";
  2535.                     break;
  2536.                 case 3:
  2537.                     $hs_monthroman "iii";
  2538.                     break;
  2539.                 case 4:
  2540.                     $hs_monthroman "iv";
  2541.                     break;
  2542.                 case 5:
  2543.                     $hs_monthroman "v";
  2544.                     break;
  2545.                 case 6:
  2546.                     $hs_monthroman "vi";
  2547.                     break;
  2548.                 case 7:
  2549.                     $hs_monthroman "vii";
  2550.                     break;
  2551.                 case 8:
  2552.                     $hs_monthroman "viii";
  2553.                     break;
  2554.                 case 9:
  2555.                     $hs_monthroman "ix";
  2556.                     break;
  2557.                 case 10:
  2558.                     $hs_monthroman "x";
  2559.                     break;
  2560.                 case 11:
  2561.                     $hs_monthroman "xi";
  2562.                     break;
  2563.                 case 12:
  2564.                     $hs_monthroman "xii";
  2565.                     break;
  2566.                 }
  2567.  
  2568.                 $hs_monthroman $hb_lower ?
  2569.                                  $hs_monthroman :
  2570.                                  strtoupper($hs_monthroman);
  2571.                 $ret .= $hb_nopad ?
  2572.                         $hs_monthroman :
  2573.                         str_pad($hs_monthroman4" "STR_PAD_LEFT);
  2574.                 $i   += 2;
  2575.                 break;
  2576.             case "s":
  2577.             case "S":
  2578.                 // Check for 'SSSSS' before 'SS':
  2579.                 //
  2580.                 if (strtoupper(substr($ps_format$i5)) == "SSSSS"{
  2581.                     if ($this->ob_invalidtime)
  2582.                         return $this->_getErrorInvalidTime();
  2583.                     $hs_numberformat substr($ps_format$i + 54);
  2584.                     $hn_second Date_Calc::secondsPastMidnight($this->hour,
  2585.                                                                 $this->minute,
  2586.                                                                 $this->second);
  2587.                     $hs_second $this->_formatNumber($hn_second,
  2588.                                                       $hs_numberformat,
  2589.                                                       5,
  2590.                                                       $hb_nopad,
  2591.                                                       true,
  2592.                                                       $ps_locale);
  2593.                     if (Pear::isError($hs_second))
  2594.                         return $hs_second;
  2595.  
  2596.                     $ret .= $hs_second;
  2597.                     $i   += 5 + strlen($hs_numberformat);
  2598.                 else if (strtoupper(substr($ps_format$i2)) == "SS"{
  2599.                     if ($this->ob_invalidtime)
  2600.                         return $this->_getErrorInvalidTime();
  2601.                     $hs_numberformat substr($ps_format$i + 24);
  2602.                     $hs_second $this->_formatNumber($this->second,
  2603.                                                       $hs_numberformat,
  2604.                                                       2,
  2605.                                                       $hb_nopad,
  2606.                                                       true,
  2607.                                                       $ps_locale);
  2608.                     if (Pear::isError($hs_second))
  2609.                         return $hs_second;
  2610.  
  2611.                     $ret .= $hs_second;
  2612.                     $i   += 2 + strlen($hs_numberformat);
  2613.                 else {
  2614.                     // One of the following codes:
  2615.                     //  'SC(CCC...)'
  2616.                     //  'SY(YYY...)'
  2617.                     //  'SIY(YYY...)'
  2618.                     //  'STZH'
  2619.                     //  'STZS'
  2620.                     //  'SYEAR'
  2621.                     //
  2622.                     $hb_showsignflag = true;
  2623.                     if ($hb_nopad)
  2624.                         $hb_nopadflag = true;
  2625.                     ++$i;
  2626.                 }
  2627.  
  2628.                 break;
  2629.             case "t":
  2630.             case "T":
  2631.                 // Code TZ[...]:
  2632.                 //
  2633.  
  2634.                 if (strtoupper(substr($ps_format$i3)) == "TZR"{
  2635.                     // This time-zone-related code can be called when the time is
  2636.                     // invalid, but the others should return an error:
  2637.                     //
  2638.                     $ret .= $this->getTZID();
  2639.                     $i   += 3;
  2640.                 else {
  2641.                     if ($this->ob_invalidtime)
  2642.                         return $this->_getErrorInvalidTime();
  2643.  
  2644.                     if (strtoupper(substr($ps_format$i3)) == "TZC"{
  2645.                         $ret .= $this->getTZShortName();
  2646.                         $i   += 3;
  2647.                     else if (strtoupper(substr($ps_format$i3)) == "TZH"{
  2648.                         if (is_null($hn_tzoffset))
  2649.                             $hn_tzoffset $this->getTZOffset();
  2650.  
  2651.                         $hs_numberformat substr($ps_format$i + 34);
  2652.                         $hn_tzh intval($hn_tzoffset / 3600000);
  2653.  
  2654.                         // Suppress sign here (it is added later):
  2655.                         //
  2656.                         $hs_tzh $this->_formatNumber($hn_tzh,
  2657.                                                        $hs_numberformat,
  2658.                                                        2,
  2659.                                                        $hb_nopad,
  2660.                                                        true,
  2661.                                                        $ps_locale);
  2662.                         if (Pear::isError($hs_tzh))
  2663.                             return $hs_tzh;
  2664.  
  2665.                         // Display sign, even if positive:
  2666.                         //
  2667.                         $ret .= ($hb_nosign "" ($hn_tzh >= 0 ? '+' '-')) .
  2668.                                 $hs_tzh;
  2669.                         $i   += 3 + strlen($hs_numberformat);
  2670.                     else if (strtoupper(substr($ps_format$i3)) == "TZI"{
  2671.                         $ret .= ($this->inDaylightTime('1' '0');
  2672.                         $i   += 3;
  2673.                     else if (strtoupper(substr($ps_format$i3)) == "TZM"{
  2674.                         if (is_null($hn_tzoffset))
  2675.                             $hn_tzoffset $this->getTZOffset();
  2676.  
  2677.                         $hs_numberformat substr($ps_format$i + 34);
  2678.                         $hn_tzm intval(($hn_tzoffset % 3600000/ 60000);
  2679.  
  2680.                         // Suppress sign:
  2681.                         //
  2682.                         $hs_tzm $this->_formatNumber($hn_tzm,
  2683.                                                        $hs_numberformat,
  2684.                                                        2,
  2685.                                                        $hb_nopad,
  2686.                                                        true,
  2687.                                                        $ps_locale);
  2688.                         if (Pear::isError($hs_tzm))
  2689.                             return $hs_tzm;
  2690.  
  2691.                         $ret .= $hs_tzm;
  2692.                         $i   += 3 + strlen($hs_numberformat);
  2693.                     else if (strtoupper(substr($ps_format$i3)) == "TZN"{
  2694.                         $ret .= $this->getTZLongName();
  2695.                         $i   += 3;
  2696.                     else if (strtoupper(substr($ps_format$i3)) == "TZO"{
  2697.                         if (is_null($hn_tzoffset))
  2698.                             $hn_tzoffset $this->getTZOffset();
  2699.  
  2700.                         $hn_tzh intval(abs($hn_tzoffset/ 3600000);
  2701.                         $hn_tzm intval((abs($hn_tzoffset% 3600000/ 60000);
  2702.  
  2703.                         if ($hn_tzoffset == 0{
  2704.                             $ret .= $hb_nopad "Z" "Z     ";
  2705.                         else {
  2706.                             // Display sign, even if positive:
  2707.                             //
  2708.                             $ret .= ($hn_tzoffset >= 0 ? '+' '-'.
  2709.                                     sprintf("%02d"$hn_tzh.
  2710.                                     ":" .
  2711.                                     sprintf("%02d"$hn_tzm);
  2712.                         }
  2713.                         $i += 3;
  2714.                     else if (strtoupper(substr($ps_format$i3)) == "TZS"{
  2715.                         if (is_null($hn_tzoffset))
  2716.                             $hn_tzoffset $this->getTZOffset();
  2717.  
  2718.                         $hs_numberformat substr($ps_format$i + 34);
  2719.                         $hn_tzs intval($hn_tzoffset / 1000);
  2720.                         $hs_tzs $this->_formatNumber($hn_tzs,
  2721.                                                        $hs_numberformat,
  2722.                                                        5,
  2723.                                                        $hb_nopad,
  2724.                                                        $hb_nosign,
  2725.                                                        $ps_locale);
  2726.                         if (Pear::isError($hs_tzs))
  2727.                             return $hs_tzs;
  2728.  
  2729.                         $ret .= $hs_tzs;
  2730.                         $i   += 3 + strlen($hs_numberformat);
  2731.                     }
  2732.                 }
  2733.  
  2734.                 break;
  2735.             case "u":
  2736.             case "U":
  2737.                 if ($this->ob_invalidtime)
  2738.                     return $this->_getErrorInvalidTime();
  2739.                 $hn_unixtime     $this->getTime();
  2740.                 $hs_numberformat substr($ps_format$i + 14);
  2741.  
  2742.                 // Allow sign if negative; allow all digits (specify nought);
  2743.                 // suppress padding:
  2744.                 //
  2745.                 $hs_unixtime $this->_formatNumber($hn_unixtime,
  2746.                                                     $hs_numberformat,
  2747.                                                     0,
  2748.                                                     true,
  2749.                                                     false,
  2750.                                                     $ps_locale);
  2751.                 if (Pear::isError($hs_unixtime))
  2752.                     return $hs_unixtime;
  2753.  
  2754.                 $ret .= $hs_unixtime;
  2755.                 $i   += 1 + strlen($hs_numberformat);
  2756.                 break;
  2757.             case "w":
  2758.             case "W":
  2759.                 // Check for 'WW' before 'W':
  2760.                 //
  2761.                 if (strtoupper(substr($ps_format$i2)) == "WW"{
  2762.                     $hn_week Date_Calc::weekOfYearAbsolute($this->day,
  2763.                                                              $this->month,
  2764.                                                              $this->year);
  2765.                     $hs_numberformat substr($ps_format$i + 24);
  2766.                     $hs_week $this->_formatNumber($hn_week,
  2767.                                                     $hs_numberformat,
  2768.                                                     2,
  2769.                                                     $hb_nopad,
  2770.                                                     true,
  2771.                                                     $ps_locale);
  2772.                     if (Pear::isError($hs_week))
  2773.                         return $hs_week;
  2774.  
  2775.                     $ret .= $hs_week;
  2776.                     $i   += 2 + strlen($hs_numberformat);
  2777.                 else if (strtoupper(substr($ps_format$i2)) == "W1"{
  2778.                     $hn_week Date_Calc::weekOfYear1st($this->day,
  2779.                                                         $this->month,
  2780.                                                         $this->year);
  2781.                     $hs_numberformat substr($ps_format$i + 24);
  2782.                     $hs_week $this->_formatNumber($hn_week,
  2783.                                                     $hs_numberformat,
  2784.                                                     2,
  2785.                                                     $hb_nopad,
  2786.                                                     true,
  2787.                                                     $ps_locale);
  2788.                     if (Pear::isError($hs_week))
  2789.                         return $hs_week;
  2790.  
  2791.                     $ret .= $hs_week;
  2792.                     $i   += 2 + strlen($hs_numberformat);
  2793.                 else if (strtoupper(substr($ps_format$i2)) == "W4"{
  2794.                     $ha_week Date_Calc::weekOfYear4th($this->day,
  2795.                                                         $this->month,
  2796.                                                         $this->year);
  2797.                     $hn_week $ha_week[1];
  2798.                     $hs_numberformat substr($ps_format$i + 24);
  2799.                     $hs_week $this->_formatNumber($hn_week,
  2800.                                                     $hs_numberformat,
  2801.                                                     2,
  2802.                                                     $hb_nopad,
  2803.                                                     true,
  2804.                                                     $ps_locale);
  2805.                     if (Pear::isError($hs_week))
  2806.                         return $hs_week;
  2807.  
  2808.                     $ret .= $hs_week;
  2809.                     $i   += 2 + strlen($hs_numberformat);
  2810.                 else if (strtoupper(substr($ps_format$i2)) == "W7"{
  2811.                     $ha_week Date_Calc::weekOfYear7th($this->day,
  2812.                                                         $this->month,
  2813.                                                         $this->year);
  2814.                     $hn_week $ha_week[1];
  2815.                     $hs_numberformat substr($ps_format$i + 24);
  2816.                     $hs_week $this->_formatNumber($hn_week,
  2817.                                                     $hs_numberformat,
  2818.                                                     2,
  2819.                                                     $hb_nopad,
  2820.                                                     true,
  2821.                                                     $ps_locale);
  2822.                     if (Pear::isError($hs_week))
  2823.                         return $hs_week;
  2824.  
  2825.                     $ret .= $hs_week;
  2826.                     $i   += 2 + strlen($hs_numberformat);
  2827.                 else {
  2828.                     // Code 'W':
  2829.                     //
  2830.                     $hn_week Date_Calc::weekOfMonthAbsolute($this->day,
  2831.                                                               $this->month,
  2832.                                                               $this->year);
  2833.                     $hs_numberformat substr($ps_format$i + 14);
  2834.                     $hs_week $this->_formatNumber($hn_week,
  2835.                                                     $hs_numberformat,
  2836.                                                     1,
  2837.                                                     $hb_nopad,
  2838.                                                     true,
  2839.                                                     $ps_locale);
  2840.                     if (Pear::isError($hs_week))
  2841.                         return $hs_week;
  2842.  
  2843.                     $ret .= $hs_week;
  2844.                     $i   += 1 + strlen($hs_numberformat);
  2845.                 }
  2846.  
  2847.                 break;
  2848.             case "y":
  2849.             case "Y":
  2850.                 // Check for 'YEAR' first:
  2851.                 //
  2852.                 if (strtoupper(substr($ps_format$i4)) == "YEAR"{
  2853.                     switch (substr($ps_format$i2)) {
  2854.                     case "YE":
  2855.                         $hs_spformat "SP";
  2856.                         break;
  2857.                     case "Ye":
  2858.                         $hs_spformat "Sp";
  2859.                         break;
  2860.                     default:
  2861.                         $hs_spformat "sp";
  2862.                     }
  2863.  
  2864.                     if (($hn_yearabs abs($this->year)) < 100 ||
  2865.                         $hn_yearabs % 100 < 10{
  2866.  
  2867.                         $hs_numberformat $hs_spformat;
  2868.  
  2869.                         // Allow all digits (specify nought); padding irrelevant:
  2870.                         //
  2871.                         $hs_year $this->_formatNumber($this->year,
  2872.                                                         $hs_numberformat,
  2873.                                                         0,
  2874.                                                         true,
  2875.                                                         $hb_nosign,
  2876.                                                         $ps_locale);
  2877.                         if (Pear::isError($hs_year))
  2878.                             return $hs_year;
  2879.  
  2880.                         $ret .= $hs_year;
  2881.                     else {
  2882.                         // Year is spelled 'Nineteen Twelve' rather than
  2883.                         // 'One thousand Nine Hundred Twelve':
  2884.                         //
  2885.                         $hn_century intval($this->year / 100);
  2886.                         $hs_numberformat $hs_spformat;
  2887.  
  2888.                         // Allow all digits (specify nought); padding irrelevant:
  2889.                         //
  2890.                         $hs_century $this->_formatNumber($hn_century,
  2891.                                                            $hs_numberformat,
  2892.                                                            0,
  2893.                                                            true,
  2894.                                                            $hb_nosign,
  2895.                                                            $ps_locale);
  2896.                         if (Pear::isError($hs_century))
  2897.                             return $hs_century;
  2898.  
  2899.                         $ret .= $hs_century " ";
  2900.  
  2901.                         $hs_numberformat $hs_spformat;
  2902.  
  2903.                         // Discard sign; padding irrelevant:
  2904.                         //
  2905.                         $hs_year $this->_formatNumber($this->year,
  2906.                                                         $hs_numberformat,
  2907.                                                         2,
  2908.                                                         false,
  2909.                                                         true,
  2910.                                                         $ps_locale);
  2911.                         if (Pear::isError($hs_year))
  2912.                             return $hs_year;
  2913.  
  2914.                         $ret .= $hs_year;
  2915.                     }
  2916.  
  2917.                     $i += 4;
  2918.                 else {
  2919.                     // Code Y(YYY...):
  2920.                     //
  2921.                     $hn_codelen = 1;
  2922.                     while (strtoupper(substr($ps_format,
  2923.                                              $i $hn_codelen,
  2924.                                              1)) == "Y")
  2925.                         ++$hn_codelen;
  2926.  
  2927.                     $hs_thousandsep  = null;
  2928.                     $hn_thousandseps = 0;
  2929.                     if ($hn_codelen <= 3{
  2930.                         while (preg_match('/([,.·\' ])YYY/i',
  2931.                                           substr($ps_format,
  2932.                                                  $i $hn_codelen,
  2933.                                                  4),
  2934.                                           $ha_matches)) {
  2935.                             $hn_codelen    += 4;
  2936.                             $hs_thousandsep $ha_matches[1];
  2937.                             ++$hn_thousandseps;
  2938.                         }
  2939.                     }
  2940.  
  2941.                     // Check next code is not 'YEAR'
  2942.                     //
  2943.                     if ($hn_codelen > 1 &&
  2944.                         strtoupper(substr($ps_format,
  2945.                                           $i $hn_codelen - 1,
  2946.                                           4)) == "YEAR")
  2947.                         --$hn_codelen;
  2948.  
  2949.                     $hs_numberformat substr($ps_format$i $hn_codelen4);
  2950.                     $hs_year $this->_formatNumber($this->year,
  2951.                                                     $hs_numberformat,
  2952.                                                     $hn_codelen -
  2953.                                                         $hn_thousandseps,
  2954.                                                     $hb_nopad,
  2955.                                                     $hb_nosign,
  2956.                                                     $ps_locale,
  2957.                                                    $hs_thousandsep);
  2958.                     if (Pear::isError($hs_year))
  2959.                         return $hs_year;
  2960.  
  2961.                     $ret .= $hs_year;
  2962.                     $i   += $hn_codelen strlen($hs_numberformat);
  2963.                 }
  2964.  
  2965.                 break;
  2966.             default:
  2967.                 $ret .= $hs_char;
  2968.                 ++$i;
  2969.                 break;
  2970.             }
  2971.         }
  2972.         return $ret;
  2973.     }
  2974.  
  2975.  
  2976.     // }}}
  2977.     // {{{ format3()
  2978.  
  2979.     /**
  2980.      * Formats the date in the same way as 'format()', but using the
  2981.      * formatting codes used by the PHP function 'date()'
  2982.      *
  2983.      * All 'date()' formatting options are supported except 'B'.  This
  2984.      * function also responds to the DATE_* constants, such as DATE_COOKIE,
  2985.      * which are specified at:
  2986.      *
  2987.      *  http://www.php.net/manual/en/ref.datetime.php#datetime.constants
  2988.      *
  2989.      *
  2990.      * Formatting options:
  2991.      *
  2992.      * (Day)
  2993.      *
  2994.      *  <code>d</code> Day of the month, 2 digits with leading zeros (01 to 31)
  2995.      *  <code>D</code> A textual representation of a day, three letters ('Mon'
  2996.      *                to 'Sun')
  2997.      *  <code>j</code> Day of the month without leading zeros (1 to 31)
  2998.      *  <code>l</code> [lowercase 'L'] A full textual representation of the day
  2999.      *                of the week ('Sunday' to 'Saturday')
  3000.      *  <code>N</code> ISO-8601 numeric representation of the day of the week
  3001.      *                (1 (for Monday) to 7 (for Sunday))
  3002.      *  <code>S</code> English ordinal suffix for the day of the month, 2
  3003.      *                characters ('st', 'nd', 'rd' or 'th')
  3004.      *  <code>w</code> Numeric representation of the day of the week (0 (for
  3005.      *                Sunday) to 6 (for Saturday))
  3006.      *  <code>z</code> The day of the year, starting from 0 (0 to 365)
  3007.      *
  3008.      * (Week)
  3009.      *
  3010.      *  <code>W</code> ISO-8601 week number of year, weeks starting on Monday
  3011.      *                (00 to 53)
  3012.      *
  3013.      * (Month)
  3014.      *
  3015.      *  <code>F</code> A full textual representation of a month ('January' to
  3016.      *                'December')
  3017.      *  <code>m</code> Numeric representation of a month, with leading zeros
  3018.      *                (01 to 12)
  3019.      *  <code>M</code> A short textual representation of a month, three letters
  3020.      *                ('Jan' to 'Dec')
  3021.      *  <code>n</code> Numeric representation of a month, without leading zeros
  3022.      *                (1 to 12)
  3023.      *  <code>t</code> Number of days in the given month (28 to 31)
  3024.      *
  3025.      * (Year)
  3026.      *
  3027.      *  <code>L</code> Whether it is a leap year (1 if it is a leap year, 0
  3028.      *                otherwise)
  3029.      *  <code>o</code> ISO-8601 year number. This has the same value as Y,
  3030.      *                except that if the ISO week number (W) belongs to the
  3031.      *                previous or next year, that year is used instead.
  3032.      *  <code>Y</code> A full numeric representation of a year, 4 digits (0000
  3033.      *                to 9999)
  3034.      *  <code>y</code> A two digit representation of a year (00 to 99)
  3035.      *
  3036.      * (Time)
  3037.      *
  3038.      *  <code>a</code> Lowercase Ante meridiem and Post meridiem ('am' or
  3039.      *                'pm')
  3040.      *  <code>A</code> Uppercase Ante meridiem and Post meridiem ('AM' or
  3041.      *                'PM')
  3042.      *  <code>g</code> 12-hour format of an hour without leading zeros (1 to 12)
  3043.      *  <code>G</code> 24-hour format of an hour without leading zeros (0 to 23)
  3044.      *  <code>h</code> 12-hour format of an hour with leading zeros (01 to 12)
  3045.      *  <code>H</code> 24-hour format of an hour with leading zeros (00 to 23)
  3046.      *  <code>i</code> Minutes with leading zeros (00 to 59)
  3047.      *  <code>s</code> Seconds, with leading zeros (00 to 59)
  3048.      *  <code>u</code> Milliseconds, e.g. '54321'
  3049.      *
  3050.      * (Time Zone)
  3051.      *
  3052.      *  <code>e</code> Timezone identifier, e.g. Europe/London
  3053.      *  <code>I</code> Whether or not the date is in Summer time (1 if Summer
  3054.      *                time, 0 otherwise)
  3055.      *  <code>O</code> Difference to Greenwich time (GMT) in hours, e.g. '+0200'
  3056.      *  <code>P</code> Difference to Greenwich time (GMT) with colon between
  3057.      *                hours and minutes, e.g. '+02:00'
  3058.      *  <code>T</code> Timezone abbreviation, e.g. 'GMT', 'EST'
  3059.      *  <code>Z</code> Timezone offset in seconds. The offset for timezones west
  3060.      *                of UTC is always negative, and for those east of UTC is
  3061.      *                always positive. (-43200 to 50400)
  3062.      *
  3063.      * (Full Date/Time)
  3064.      *
  3065.      *  <code>c</code> ISO 8601 date, e.g. '2004-02-12T15:19:21+00:00'
  3066.      *  <code>r</code> RFC 2822 formatted date, e.g.
  3067.      *                'Thu, 21 Dec 2000 16:01:07 +0200'
  3068.      *  <code>U</code> Seconds since the Unix Epoch
  3069.      *                (January 1 1970 00:00:00 GMT)
  3070.      *
  3071.      * @param string $ps_format the format string for returned date/time
  3072.      *
  3073.      * @return   string     date/time in given format
  3074.      * @access   public
  3075.      * @since    Method available since Release 1.5.0
  3076.      */
  3077.     function format3($ps_format)
  3078.     {
  3079.         $hs_format2str "";
  3080.  
  3081.         for ($i = 0; $i strlen($ps_format); ++$i{
  3082.             switch ($hs_char substr($ps_format$i1)) {
  3083.             case 'd':
  3084.                 $hs_format2str .= 'DD';
  3085.                 break;
  3086.             case 'D':
  3087.                 $hs_format2str .= 'NPDy';
  3088.                 break;
  3089.             case 'j':
  3090.                 $hs_format2str .= 'NPDD';
  3091.                 break;
  3092.             case 'l':
  3093.                 $hs_format2str .= 'NPDay';
  3094.                 break;
  3095.             case 'N':
  3096.                 $hs_format2str .= 'ID';
  3097.                 break;
  3098.             case 'S':
  3099.                 $hs_format2str .= 'th';
  3100.                 break;
  3101.             case 'w':
  3102.                 $hs_format2str .= 'D';
  3103.                 break;
  3104.             case 'z':
  3105.                 $hs_format2str .= '"' ($this->getDayOfYear(- 1'"';
  3106.                 break;
  3107.             case 'W':
  3108.                 $hs_format2str .= 'IW';
  3109.                 break;
  3110.             case 'F':
  3111.                 $hs_format2str .= 'NPMonth';
  3112.                 break;
  3113.             case 'm':
  3114.                 $hs_format2str .= 'MM';
  3115.                 break;
  3116.             case 'M':
  3117.                 $hs_format2str .= 'NPMon';
  3118.                 break;
  3119.             case 'n':
  3120.                 $hs_format2str .= 'NPMM';
  3121.                 break;
  3122.             case 't':
  3123.                 $hs_format2str .= '"' $this->getDaysInMonth('"';
  3124.                 break;
  3125.             case 'L':
  3126.                 $hs_format2str .= '"' ($this->isLeapYear(? 1 : 0'"';
  3127.                 break;
  3128.             case 'o':
  3129.                 $hs_format2str .= 'IYYY';
  3130.                 break;
  3131.             case 'Y':
  3132.                 $hs_format2str .= 'YYYY';
  3133.                 break;
  3134.             case 'y':
  3135.                 $hs_format2str .= 'YY';
  3136.                 break;
  3137.             case 'a':
  3138.                 $hs_format2str .= 'am';
  3139.                 break;
  3140.             case 'A':
  3141.                 $hs_format2str .= 'AM';
  3142.                 break;
  3143.             case 'g':
  3144.                 $hs_format2str .= 'NPHH12';
  3145.                 break;
  3146.             case 'G':
  3147.                 $hs_format2str .= 'NPHH24';
  3148.                 break;
  3149.             case 'h':
  3150.                 $hs_format2str .= 'HH12';
  3151.                 break;
  3152.             case 'H':
  3153.                 $hs_format2str .= 'HH24';
  3154.                 break;
  3155.             case 'i':
  3156.                 $hs_format2str .= 'MI';
  3157.                 break;
  3158.             case 's':
  3159.                 $hs_format2str .= 'SS';
  3160.                 break;
  3161.             case 'u':
  3162.                 $hs_format2str .= 'SSFFF';
  3163.                 break;
  3164.             case 'e':
  3165.                 $hs_format2str .= 'TZR';
  3166.                 break;
  3167.             case 'I':
  3168.                 $hs_format2str .= 'TZI';
  3169.                 break;
  3170.             case 'O':
  3171.                 $hs_format2str .= 'STZHTZM';
  3172.                 break;
  3173.             case 'P':
  3174.                 $hs_format2str .= 'STZH:TZM';
  3175.                 break;
  3176.             case 'T':
  3177.                 $hs_format2str .= 'TZC';
  3178.                 break;
  3179.             case 'Z':
  3180.                 $hs_format2str .= 'TZS';
  3181.                 break;
  3182.             case 'c':
  3183.                 $hs_format2str .= 'YYYY-MM-DD"T"HH24:MI:SSSTZH:TZM';
  3184.                 break;
  3185.             case 'r':
  3186.                 $hs_format2str .= 'Dy, DD Mon YYYY HH24:MI:SS STZHTZM';
  3187.                 break;
  3188.             case 'U':
  3189.                 $hs_format2str .= 'U';
  3190.                 break;
  3191.             case '\\':
  3192.                 $hs_char substr($ps_format++$i1);
  3193.                 $hs_format2str .= '"' ($hs_char == '\\' '\\\\' $hs_char'"';
  3194.                 break;
  3195.             case '"':
  3196.                 $hs_format2str .= '"\\""';
  3197.                 break;
  3198.             default:
  3199.                 $hs_format2str .= '"' $hs_char '"';
  3200.             }
  3201.         }
  3202.  
  3203.         $ret $this->format2($hs_format2str);
  3204.         if (PEAR::isError($ret&&
  3205.             $ret->getCode(== DATE_ERROR_INVALIDFORMATSTRING{
  3206.             return PEAR::raiseError("Invalid date format '$ps_format'",
  3207.                                     DATE_ERROR_INVALIDFORMATSTRING);
  3208.         }
  3209.  
  3210.         return $ret;
  3211.     }
  3212.  
  3213.  
  3214.     // }}}
  3215.     // {{{ getTime()
  3216.  
  3217.     /**
  3218.      * Returns the date/time in Unix time() format
  3219.      *
  3220.      * Returns a representation of this date in Unix time() format.  This may
  3221.      * only be valid for dates from 1970 to ~2038.
  3222.      *
  3223.      * @return   int        number of seconds since the unix epoch
  3224.      * @access   public
  3225.      */
  3226.     function getTime()
  3227.     {
  3228.         return $this->getDate(DATE_FORMAT_UNIXTIME);
  3229.     }
  3230.  
  3231.  
  3232.     // }}}
  3233.     // {{{ getTZID()
  3234.  
  3235.     /**
  3236.      * Returns the unique ID of the time zone, e.g. 'America/Chicago'
  3237.      *
  3238.      * @return   string     the time zone ID
  3239.      * @access   public
  3240.      * @since    Method available since Release 1.5.0
  3241.      */
  3242.     function getTZID()
  3243.     {
  3244.         return $this->tz->getID();
  3245.     }
  3246.  
  3247.  
  3248.     // }}}
  3249.     // {{{ _setTZToDefault()
  3250.  
  3251.     /**
  3252.      * sets time zone to the default time zone
  3253.      *
  3254.      * If PHP version >= 5.1.0, uses the php.ini configuration directive
  3255.      * 'date.timezone' if set and valid, else the value returned by
  3256.      * 'date("e")' if valid, else the default specified if the global
  3257.      * constant '$GLOBALS["_DATE_TIMEZONE_DEFAULT"]', which if itself
  3258.      * left unset, defaults to "UTC".
  3259.      *
  3260.      * N.B. this is a private method; to set the time zone to the
  3261.      * default publicly you should call 'setTZByID()', that is, with no
  3262.      * parameter (or a parameter of null).
  3263.      *
  3264.      * @return   void 
  3265.      * @access   private
  3266.      * @since    Method available since Release 1.5.0
  3267.      */
  3268.     function _setTZToDefault()
  3269.     {
  3270.         if (function_exists('version_compare'&&
  3271.             version_compare(phpversion()"5.1.0"">="&&
  3272.             (Date_TimeZone::isValidID($hs_id ini_get("date.timezone")) ||
  3273.              Date_TimeZone::isValidID($hs_id date("e"))
  3274.              )
  3275.             {
  3276.             $this->tz = new Date_TimeZone($hs_id);
  3277.         else {
  3278.             $this->tz Date_TimeZone::getDefault();
  3279.         }
  3280.     }
  3281.  
  3282.  
  3283.     // }}}
  3284.     // {{{ setTZ()
  3285.  
  3286.     /**
  3287.      * Sets the time zone of this Date
  3288.      *
  3289.      * Sets the time zone of this date with the given
  3290.      * Date_TimeZone object.  Does not alter the date/time,
  3291.      * only assigns a new time zone.  For conversion, use
  3292.      * convertTZ().
  3293.      *
  3294.      * @param object $tz the Date_TimeZone object to use.  If called with a
  3295.      *                     parameter that is not a Date_TimeZone object, will
  3296.      *                     fall through to setTZByID().
  3297.      *
  3298.      * @return   void 
  3299.      * @access   public
  3300.      * @see      Date::setTZByID()
  3301.      */
  3302.     function setTZ($tz)
  3303.     {
  3304.         if (is_a($tz'Date_Timezone')) {
  3305.             $this->setTZByID($tz->getID());
  3306.         else {
  3307.             $res $this->setTZByID($tz);
  3308.             if (PEAR::isError($res))
  3309.                 return $res;
  3310.         }
  3311.     }
  3312.  
  3313.  
  3314.     // }}}
  3315.     // {{{ setTZByID()
  3316.  
  3317.     /**
  3318.      * Sets the time zone of this date with the given time zone ID
  3319.      *
  3320.      * The time zone IDs are drawn from the 'tz data-base' (see
  3321.      * http://en.wikipedia.org/wiki/Zoneinfo), which is the de facto
  3322.      * internet and IT standard.  (There is no official standard, and
  3323.      * the tz data-base is not intended to be a regulating body
  3324.      * anyway.)  Lists of valid IDs are maintained at:
  3325.      *
  3326.      *  http://en.wikipedia.org/wiki/List_of_zoneinfo_timezones
  3327.      *  http://www.php.net/manual/en/timezones.php
  3328.      *
  3329.      * If no time-zone is specified and PHP version >= 5.1.0, the time
  3330.      * zone is set automatically to the php.ini configuration directive
  3331.      * 'date.timezone' if set and valid, else the value returned by
  3332.      * 'date("e")' if valid, else the default specified if the global
  3333.      * constant '$GLOBALS["_DATE_TIMEZONE_DEFAULT"]', which if itself
  3334.      * left unset, defaults to "UTC".
  3335.      *
  3336.      * N.B. this function preserves the local date and time, that is,
  3337.      * whether in local Summer time or local standard time.  For example,
  3338.      * if the time is set to 11.00 Summer time, and the time zone is then
  3339.      * set to another time zone, using this function, in which the date
  3340.      * falls in standard time, then the time will remain set to 11.00 UTC,
  3341.      * and not 10.00.  You can convert a date to another time zone by
  3342.      * calling 'convertTZ()'.
  3343.      *
  3344.      * The ID can also be specified as a UTC offset in one of the following
  3345.      * forms, i.e. an offset with no geographical or political base:
  3346.      *
  3347.      *  UTC[+/-][h]       - e.g. UTC-1     (the preferred form)
  3348.      *  UTC[+/-][hh]      - e.g. UTC+03
  3349.      *  UTC[+/-][hh][mm]  - e.g. UTC-0530
  3350.      *  UTC[+/-][hh]:[mm] - e.g. UTC+03:00
  3351.      *
  3352.      * N.B. 'UTC' seems to be technically preferred over 'GMT'.  GMT-based
  3353.      * IDs still exist in the tz data-base, but beware of POSIX-style
  3354.      * offsets which are the opposite way round to what people normally
  3355.      * expect.
  3356.      *
  3357.      * @param string $ps_id a valid time zone id, e.g. 'Europe/London'
  3358.      *
  3359.      * @return   void 
  3360.      * @access   public
  3361.      * @see      Date::convertTZByID(), Date_TimeZone::isValidID(),
  3362.      *             Date_TimeZone::Date_TimeZone()
  3363.      */
  3364.     function setTZByID($ps_id = null)
  3365.     {
  3366.         // Whether the date is in Summer time forms the default for
  3367.         // the new time zone (if needed, which is very unlikely anyway).
  3368.         // This is mainly to prevent unexpected (defaulting) behaviour
  3369.         // if the user is in the repeated hour, and switches to a time
  3370.         // zone that is also in the repeated hour (e.g. 'Europe/London'
  3371.         // and 'Europe/Lisbon').
  3372.         //
  3373.         $hb_insummertime $this->inDaylightTime();
  3374.         if (PEAR::isError($hb_insummertime)) {
  3375.             if ($hb_insummertime->getCode(== DATE_ERROR_INVALIDTIME{
  3376.                 $hb_insummertime = false;
  3377.             else {
  3378.                 return $hb_insummertime;
  3379.             }
  3380.         }
  3381.  
  3382.         if (is_null($ps_id)) {
  3383.             $this->_setTZToDefault();
  3384.         else if (Date_TimeZone::isValidID($ps_id)) {
  3385.             $this->tz = new Date_TimeZone($ps_id);
  3386.         else {
  3387.             return PEAR::raiseError("Invalid time zone ID '$ps_id'",
  3388.                                     DATE_ERROR_INVALIDTIMEZONE);
  3389.         }
  3390.  
  3391.         $this->setLocalTime($this->day,
  3392.                             $this->month,
  3393.                             $this->year,
  3394.                             $this->hour,
  3395.                             $this->minute,
  3396.                             $this->second,
  3397.                             $this->partsecond,
  3398.                             $hb_insummertime);
  3399.     }
  3400.  
  3401.  
  3402.     // }}}
  3403.     // {{{ getTZLongName()
  3404.  
  3405.     /**
  3406.      * Returns the long name of the time zone
  3407.      *
  3408.      * Returns long form of time zone name, e.g. 'Greenwich Mean Time'.
  3409.      * N.B. if the date falls in Summer time, the Summer time name will be
  3410.      * returned instead, e.g. 'British Summer Time'.
  3411.      *
  3412.      * N.B. this is not a unique identifier for the time zone - for this
  3413.      * purpose use the time zone ID.
  3414.      *
  3415.      * @return   string     the long name of the time zone
  3416.      * @access   public
  3417.      * @since    Method available since Release 1.5.0
  3418.      */
  3419.     function getTZLongName()
  3420.     {
  3421.         if ($this->ob_invalidtime)
  3422.             return $this->_getErrorInvalidTime();
  3423.  
  3424.         return $this->tz->getLongName($this->inDaylightTime());
  3425.     }
  3426.  
  3427.  
  3428.     // }}}
  3429.     // {{{ getTZShortName()
  3430.  
  3431.     /**
  3432.      * Returns the short name of the time zone
  3433.      *
  3434.      * Returns abbreviated form of time zone name, e.g. 'GMT'.  N.B. if the
  3435.      * date falls in Summer time, the Summer time name will be returned
  3436.      * instead, e.g. 'BST'.
  3437.      *
  3438.      * N.B. this is not a unique identifier - for this purpose use the
  3439.      * time zone ID.
  3440.      *
  3441.      * @return   string     the short name of the time zone
  3442.      * @access   public
  3443.      * @since    Method available since Release 1.5.0
  3444.      */
  3445.     function getTZShortName()
  3446.     {
  3447.         if ($this->ob_invalidtime)
  3448.             return $this->_getErrorInvalidTime();
  3449.  
  3450.         return $this->tz->getShortName($this->inDaylightTime());
  3451.     }
  3452.  
  3453.  
  3454.     // }}}
  3455.     // {{{ getTZOffset()
  3456.  
  3457.     /**
  3458.      * Returns the DST-corrected offset from UTC for the given date
  3459.      *
  3460.      * Gets the offset to UTC for a given date/time, taking into
  3461.      * account daylight savings time, if the time zone observes it and if
  3462.      * it is in effect.
  3463.      *
  3464.      * N.B. that the offset is calculated historically
  3465.      * and in the future according to the current Summer time rules,
  3466.      * and so this function is proleptically correct, but not necessarily
  3467.      * historically correct.  (Although if you want to be correct about
  3468.      * times in the distant past, this class is probably not for you
  3469.      * because the whole notion of time zones does not apply, and
  3470.      * historically there are so many time zone changes, Summer time
  3471.      * rule changes, name changes, calendar changes, that calculating
  3472.      * this sort of information is beyond the scope of this package
  3473.      * altogether.)
  3474.      *
  3475.      * @return   int        the corrected offset to UTC in milliseconds
  3476.      * @access   public
  3477.      * @since    Method available since Release 1.5.0
  3478.      */
  3479.     function getTZOffset()
  3480.     {
  3481.         if ($this->ob_invalidtime)
  3482.             return $this->_getErrorInvalidTime();
  3483.  
  3484.         return $this->tz->getOffset($this->inDaylightTime());
  3485.     }
  3486.  
  3487.  
  3488.     // }}}
  3489.     // {{{ inDaylightTime()
  3490.  
  3491.     /**
  3492.      * Tests if this date/time is in DST
  3493.      *
  3494.      * Returns true if daylight savings time is in effect for
  3495.      * this date in this date's time zone.
  3496.      *
  3497.      * @param bool $pb_repeatedhourdefault value to return if repeated hour is
  3498.      *                                       specified (defaults to false)
  3499.      *
  3500.      * @return   boolean    true if DST is in effect for this date
  3501.      * @access   public
  3502.      */
  3503.     function inDaylightTime($pb_repeatedhourdefault = false)
  3504.     {
  3505.         if (!$this->tz->hasDaylightTime())
  3506.             return false;
  3507.         if ($this->ob_invalidtime)
  3508.             return $this->_getErrorInvalidTime();
  3509.  
  3510.         // The return value is 'cached' whenever the date/time is set:
  3511.         //
  3512.         return $this->hour != $this->on_standardhour ||
  3513.                $this->minute != $this->on_standardminute ||
  3514.                $this->second != $this->on_standardsecond ||
  3515.                $this->partsecond != $this->on_standardpartsecond ||
  3516.                $this->day != $this->on_standardday ||
  3517.                $this->month != $this->on_standardmonth ||
  3518.                $this->year != $this->on_standardyear;
  3519.         //
  3520.         // (these last 3 conditions are theoretical
  3521.         // possibilities but normally will never occur)
  3522.     }
  3523.  
  3524.  
  3525.     // }}}
  3526.     // {{{ convertTZ()
  3527.  
  3528.     /**
  3529.      * Converts this date to a new time zone
  3530.      *
  3531.      * Previously this might not have worked correctly if your system did
  3532.      * not allow putenv() or if localtime() did not work in your
  3533.      * environment, but this implementation is no longer used.
  3534.      *
  3535.      * @param object $tz Date_TimeZone object to convert to
  3536.      *
  3537.      * @return   void 
  3538.      * @access   public
  3539.      * @see      Date::convertTZByID()
  3540.      */
  3541.     function convertTZ($tz)
  3542.     {
  3543.         if ($this->getTZID(== $tz->getID())
  3544.             return;
  3545.         if ($this->ob_invalidtime)
  3546.             return $this->_getErrorInvalidTime();
  3547.  
  3548.         $hn_rawoffset $tz->getRawOffset($this->tz->getRawOffset();
  3549.         $this->tz     = new Date_TimeZone($tz->getID());
  3550.  
  3551.         list($hn_standardyear,
  3552.              $hn_standardmonth,
  3553.              $hn_standardday,
  3554.              $hn_standardhour,
  3555.              $hn_standardminute,
  3556.              $hn_standardsecond,
  3557.              $hn_standardpartsecond=
  3558.             $this->_addOffset($hn_rawoffset,
  3559.                               $this->on_standardday,
  3560.                               $this->on_standardmonth,
  3561.                               $this->on_standardyear,
  3562.                               $this->on_standardhour,
  3563.                               $this->on_standardminute,
  3564.                               $this->on_standardsecond,
  3565.                               $this->on_standardpartsecond);
  3566.  
  3567.         $this->setStandardTime($hn_standardday,
  3568.                                $hn_standardmonth,
  3569.                                $hn_standardyear,
  3570.                                $hn_standardhour,
  3571.                                $hn_standardminute,
  3572.                                $hn_standardsecond,
  3573.                                $hn_standardpartsecond);
  3574.     }
  3575.  
  3576.  
  3577.     // }}}
  3578.     // {{{ toUTC()
  3579.  
  3580.     /**
  3581.      * Converts this date to UTC and sets this date's timezone to UTC
  3582.      *
  3583.      * @return   void 
  3584.      * @access   public
  3585.      */
  3586.     function toUTC()
  3587.     {
  3588.         if ($this->getTZID(== "UTC")
  3589.             return;
  3590.         if ($this->ob_invalidtime)
  3591.             return $this->_getErrorInvalidTime();
  3592.  
  3593.         $res $this->convertTZ(new Date_TimeZone("UTC"));
  3594.         if (PEAR::isError($res))
  3595.             return $res;
  3596.     }
  3597.  
  3598.  
  3599.     // }}}
  3600.     // {{{ convertTZByID()
  3601.  
  3602.     /**
  3603.      * Converts this date to a new time zone, given a valid time zone ID
  3604.      *
  3605.      * Previously this might not have worked correctly if your system did
  3606.      * not allow putenv() or if localtime() does not work in your
  3607.      * environment, but this implementation is no longer used.
  3608.      *
  3609.      * @param string $ps_id a valid time zone id, e.g. 'Europe/London'
  3610.      *
  3611.      * @return   void 
  3612.      * @access   public
  3613.      * @see      Date::setTZByID(), Date_TimeZone::isValidID(),
  3614.      *             Date_TimeZone::Date_TimeZone()
  3615.      */
  3616.     function convertTZByID($ps_id)
  3617.     {
  3618.         if (!Date_TimeZone::isValidID($ps_id)) {
  3619.             return PEAR::raiseError("Invalid time zone ID '$ps_id'",
  3620.                                     DATE_ERROR_INVALIDTIMEZONE);
  3621.         }
  3622.  
  3623.         $res $this->convertTZ(new Date_TimeZone($ps_id));
  3624.  
  3625.         if (PEAR::isError($res))
  3626.             return $res;
  3627.     }
  3628.  
  3629.  
  3630.     // }}}
  3631.     // {{{ toUTCbyOffset()
  3632.  
  3633.     /**
  3634.      * Converts the date/time to UTC by the offset specified
  3635.      *
  3636.      * This function is no longer called from within the Date class
  3637.      * itself because a time zone can be set using a pure offset
  3638.      * (e.g. UTC+1), i.e. not a geographical time zone.  However
  3639.      * it is retained for backwards compaibility.
  3640.      *
  3641.      * @param string $ps_offset offset of the form '[+/-][hh]:[mm]',
  3642.      *                            '[+/-][hh][mm]', or 'Z'
  3643.      *
  3644.      * @return   bool 
  3645.      * @access   private
  3646.      */
  3647.     function toUTCbyOffset($ps_offset)
  3648.     {
  3649.         if ($ps_offset == "Z" ||
  3650.             preg_match('/^[+\-](00:?00|0{1,2})$/'$ps_offset)) {
  3651.             $hs_tzid "UTC";
  3652.         else if (preg_match('/^[+\-]([0-9]{2,2}:?[0-5][0-9]|[0-9]{1,2})$/',
  3653.                    $ps_offset)) {
  3654.             $hs_tzid "UTC" $ps_offset;
  3655.         else {
  3656.             return PEAR::raiseError("Invalid offset '$ps_offset'");
  3657.         }
  3658.  
  3659.         // If the time is invalid, it does not matter here:
  3660.         //
  3661.         $this->setTZByID($hs_tzid);
  3662.  
  3663.         // Now the time will be valid because it is a time zone that
  3664.         // does not observe Summer time:
  3665.         //
  3666.         $this->toUTC();
  3667.     }
  3668.  
  3669.  
  3670.     // }}}
  3671.     // {{{ addYears()
  3672.  
  3673.     /**
  3674.      * Converts the date to the specified no of years from the given date
  3675.      *
  3676.      * To subtract years use a negative value for the '$pn_years'
  3677.      * parameter
  3678.      *
  3679.      * @param int $pn_years years to add
  3680.      *
  3681.      * @return   void 
  3682.      * @access   public
  3683.      * @since    Method available since Release 1.5.0
  3684.      */
  3685.     function addYears($pn_years)
  3686.     {
  3687.         list($hs_year$hs_month$hs_day=
  3688.             explode(" "Date_Calc::addYears($pn_years,
  3689.                                              $this->day,
  3690.                                              $this->month,
  3691.                                              $this->year,
  3692.                                              "%Y %m %d"));
  3693.         $this->setLocalTime($hs_day,
  3694.                             $hs_month,
  3695.                             $hs_year,
  3696.                             $this->hour,
  3697.                             $this->minute,
  3698.                             $this->second,
  3699.                             $this->partsecond);
  3700.     }
  3701.  
  3702.  
  3703.     // }}}
  3704.     // {{{ addMonths()
  3705.  
  3706.     /**
  3707.      * Converts the date to the specified no of months from the given date
  3708.      *
  3709.      * To subtract months use a negative value for the '$pn_months'
  3710.      * parameter
  3711.      *
  3712.      * @param int $pn_months months to add
  3713.      *
  3714.      * @return   void 
  3715.      * @access   public
  3716.      * @since    Method available since Release 1.5.0
  3717.      */
  3718.     function addMonths($pn_months)
  3719.     {
  3720.         list($hs_year$hs_month$hs_day=
  3721.             explode(" "Date_Calc::addMonths($pn_months,
  3722.                                               $this->day,
  3723.                                               $this->month,
  3724.                                               $this->year,
  3725.                                               "%Y %m %d"));
  3726.         $this->setLocalTime($hs_day,
  3727.                             $hs_month,
  3728.                             $hs_year,
  3729.                             $this->hour,
  3730.                             $this->minute,
  3731.                             $this->second,
  3732.                             $this->partsecond);
  3733.     }
  3734.  
  3735.  
  3736.     // }}}
  3737.     // {{{ addDays()
  3738.  
  3739.     /**
  3740.      * Converts the date to the specified no of days from the given date
  3741.      *
  3742.      * To subtract days use a negative value for the '$pn_days' parameter
  3743.      *
  3744.      * @param int $pn_days days to add
  3745.      *
  3746.      * @return   void 
  3747.      * @access   public
  3748.      * @since    Method available since Release 1.5.0
  3749.      */
  3750.     function addDays($pn_days)
  3751.     {
  3752.         list($hs_year$hs_month$hs_day=
  3753.             explode(" "Date_Calc::addDays($pn_days,
  3754.                                             $this->day,
  3755.                                             $this->month,
  3756.                                             $this->year,
  3757.                                             "%Y %m %d"));
  3758.         $this->setLocalTime($hs_day,
  3759.                             $hs_month,
  3760.                             $hs_year,
  3761.                             $this->hour,
  3762.                             $this->minute,
  3763.                             $this->second,
  3764.                             $this->partsecond);
  3765.     }
  3766.  
  3767.  
  3768.     // }}}
  3769.     // {{{ addHours()
  3770.  
  3771.     /**
  3772.      * Converts the date to the specified no of hours from the given date
  3773.      *
  3774.      * To subtract hours use a negative value for the '$pn_hours' parameter
  3775.      *
  3776.      * @param int $pn_hours hours to add
  3777.      *
  3778.      * @return   void 
  3779.      * @access   public
  3780.      * @since    Method available since Release 1.5.0
  3781.      */
  3782.     function addHours($pn_hours)
  3783.     {
  3784.         if ($this->ob_invalidtime)
  3785.             return $this->_getErrorInvalidTime();
  3786.  
  3787.         list($hn_standardyear,
  3788.              $hn_standardmonth,
  3789.              $hn_standardday,
  3790.              $hn_standardhour=
  3791.              Date_Calc::addHours($pn_hours,
  3792.                                  $this->on_standardday,
  3793.                                  $this->on_standardmonth,
  3794.                                  $this->on_standardyear,
  3795.                                  $this->on_standardhour);
  3796.  
  3797.         $this->setStandardTime($hn_standardday,
  3798.                                $hn_standardmonth,
  3799.                                $hn_standardyear,
  3800.                                $hn_standardhour,
  3801.                                $this->on_standardminute,
  3802.                                $this->on_standardsecond,
  3803.                                $this->on_standardpartsecond);
  3804.     }
  3805.  
  3806.  
  3807.     // }}}
  3808.     // {{{ addMinutes()
  3809.  
  3810.     /**
  3811.      * Converts the date to the specified no of minutes from the given date
  3812.      *
  3813.      * To subtract minutes use a negative value for the '$pn_minutes' parameter
  3814.      *
  3815.      * @param int $pn_minutes minutes to add
  3816.      *
  3817.      * @return   void 
  3818.      * @access   public
  3819.      * @since    Method available since Release 1.5.0
  3820.      */
  3821.     function addMinutes($pn_minutes)
  3822.     {
  3823.         if ($this->ob_invalidtime)
  3824.             return $this->_getErrorInvalidTime();
  3825.  
  3826.         list($hn_standardyear,
  3827.              $hn_standardmonth,
  3828.              $hn_standardday,
  3829.              $hn_standardhour,
  3830.              $hn_standardminute=
  3831.              Date_Calc::addMinutes($pn_minutes,
  3832.                                    $this->on_standardday,
  3833.                                    $this->on_standardmonth,
  3834.                                    $this->on_standardyear,
  3835.                                    $this->on_standardhour,
  3836.                                    $this->on_standardminute);
  3837.  
  3838.         $this->setStandardTime($hn_standardday,
  3839.                                $hn_standardmonth,
  3840.                                $hn_standardyear,
  3841.                                $hn_standardhour,
  3842.                                $hn_standardminute,
  3843.                                $this->on_standardsecond,
  3844.                                $this->on_standardpartsecond);
  3845.     }
  3846.  
  3847.  
  3848.     // }}}
  3849.     // {{{ addSeconds()
  3850.  
  3851.     /**
  3852.      * Adds a given number of seconds to the date
  3853.      *
  3854.      * @param mixed $sec          the no of seconds to add as integer or float
  3855.      * @param bool  $pb_countleap whether to count leap seconds (defaults to
  3856.      *                              value of count-leap-second object property)
  3857.      *
  3858.      * @return   void 
  3859.      * @access   public
  3860.      */
  3861.     function addSeconds($sec$pb_countleap = null)
  3862.     {
  3863.         if ($this->ob_invalidtime)
  3864.             return $this->_getErrorInvalidTime();
  3865.         if (!is_int($sec&& !is_float($sec))
  3866.             settype($sec'int');
  3867.         if (!is_null($pb_countleap))
  3868.             $pb_countleap $this->ob_countleapseconds;
  3869.  
  3870.         if ($pb_countleap{
  3871.             // Convert to UTC:
  3872.             //
  3873.             list($hn_standardyear,
  3874.                  $hn_standardmonth,
  3875.                  $hn_standardday,
  3876.                  $hn_standardhour,
  3877.                  $hn_standardminute,
  3878.                  $hn_standardsecond,
  3879.                  $hn_standardpartsecond=
  3880.                 $this->_addOffset($this->tz->getRawOffset(* -1,
  3881.                                   $this->on_standardday,
  3882.                                   $this->on_standardmonth,
  3883.                                   $this->on_standardyear,
  3884.                                   $this->on_standardhour,
  3885.                                   $this->on_standardminute,
  3886.                                   $this->on_standardsecond,
  3887.                                   $this->on_standardpartsecond);
  3888.             list($hn_standardyear,
  3889.                  $hn_standardmonth,
  3890.                  $hn_standardday,
  3891.                  $hn_standardhour,
  3892.                  $hn_standardminute,
  3893.                  $hn_secondraw=
  3894.                 Date_Calc::addSeconds($sec,
  3895.                                       $hn_standardday,
  3896.                                       $hn_standardmonth,
  3897.                                       $hn_standardyear,
  3898.                                       $hn_standardhour,
  3899.                                       $hn_standardminute,
  3900.                                       $hn_standardpartsecond == 0.0 ?
  3901.                                           $hn_standardsecond :
  3902.                                           $hn_standardsecond +
  3903.                                           $hn_standardpartsecond,
  3904.                                       $pb_countleap);
  3905.  
  3906.             if (is_float($hn_secondraw)) {
  3907.                 $hn_standardsecond     intval($hn_secondraw);
  3908.                 $hn_standardpartsecond $hn_secondraw $hn_standardsecond;
  3909.             else {
  3910.                 $hn_standardsecond     $hn_secondraw;
  3911.                 $hn_standardpartsecond = 0.0;
  3912.             }
  3913.  
  3914.             list($hn_standardyear,
  3915.                  $hn_standardmonth,
  3916.                  $hn_standardday,
  3917.                  $hn_standardhour,
  3918.                  $hn_standardminute,
  3919.                  $hn_standardsecond,
  3920.                  $hn_standardpartsecond=
  3921.                 $this->_addOffset($this->tz->getRawOffset(),
  3922.                                   $hn_standardday,
  3923.                                   $hn_standardmonth,
  3924.                                   $hn_standardyear,
  3925.                                   $hn_standardhour,
  3926.                                   $hn_standardminute,
  3927.                                   $hn_standardsecond,
  3928.                                   $hn_standardpartsecond);
  3929.         else {
  3930.             // Use local standard time:
  3931.             //
  3932.             list($hn_standardyear,
  3933.                  $hn_standardmonth,
  3934.                  $hn_standardday,
  3935.                  $hn_standardhour,
  3936.                  $hn_standardminute,
  3937.                  $hn_secondraw=
  3938.                 Date_Calc::addSeconds($sec,
  3939.                                       $this->on_standardday,
  3940.                                       $this->on_standardmonth,
  3941.                                       $this->on_standardyear,
  3942.                                       $this->on_standardhour,
  3943.                                       $this->on_standardminute,
  3944.                                       $this->on_standardpartsecond == 0.0 ?
  3945.                                           $this->on_standardsecond :
  3946.                                           $this->on_standardsecond +
  3947.                                           $this->on_standardpartsecond,
  3948.                                       false);
  3949.  
  3950.             if (is_float($hn_secondraw)) {
  3951.                 $hn_standardsecond     intval($hn_secondraw);
  3952.                 $hn_standardpartsecond $hn_secondraw $hn_standardsecond;
  3953.             else {
  3954.                 $hn_standardsecond     $hn_secondraw;
  3955.                 $hn_standardpartsecond = 0.0;
  3956.             }
  3957.         }
  3958.  
  3959.         $this->setStandardTime($hn_standardday,
  3960.                                $hn_standardmonth,
  3961.                                $hn_standardyear,
  3962.                                $hn_standardhour,
  3963.                                $hn_standardminute,
  3964.                                $hn_standardsecond,
  3965.                                $hn_standardpartsecond);
  3966.     }
  3967.  
  3968.  
  3969.     // }}}
  3970.     // {{{ subtractSeconds()
  3971.  
  3972.     /**
  3973.      * Subtracts a given number of seconds from the date
  3974.      *
  3975.      * @param mixed $sec          the no of seconds to subtract as integer or
  3976.      *                              float
  3977.      * @param bool  $pb_countleap whether to count leap seconds (defaults to
  3978.      *                              value of count-leap-second object property)
  3979.      *
  3980.      * @return   void 
  3981.      * @access   public
  3982.      */
  3983.     function subtractSeconds($sec$pb_countleap = null)
  3984.     {
  3985.         if (is_null($pb_countleap))
  3986.             $pb_countleap $this->ob_countleapseconds;
  3987.  
  3988.         $res $this->addSeconds(-$sec$pb_countleap);
  3989.  
  3990.         if (PEAR::isError($res))
  3991.             return $res;
  3992.     }
  3993.  
  3994.  
  3995.     // }}}
  3996.     // {{{ addSpan()
  3997.  
  3998.     /**
  3999.      * Adds a time span to the date
  4000.      *
  4001.      * A time span is defined as a unsigned no of days, hours, minutes
  4002.      * and seconds, where the no of minutes and seconds must be less than
  4003.      * 60, and the no of hours must be less than 24.
  4004.      *
  4005.      * A span is added (and subtracted) according to the following logic:
  4006.      *  
  4007.      *  Hours, minutes and seconds are added such that if they fall over
  4008.      *   a leap second, the leap second is ignored, and not counted.
  4009.      *   For example, if a leap second occurred at 23.59.60, the
  4010.      *   following calculations:
  4011.      *
  4012.      *    23.59.59 + one second
  4013.      *    23.59.00 + one minute
  4014.      *    23.00.00 + one hour
  4015.      *
  4016.      *   would all produce 00.00.00 the next day.
  4017.      *
  4018.      *  A day is treated as equivalent to 24 hours, so if the clocks
  4019.      *   went backwards at 01.00, and one day was added to the time
  4020.      *   00.30, the result would be 23.30 the same day.
  4021.      *
  4022.      * This is the implementation which is thought to yield the behaviour
  4023.      * that the user is most likely to expect, or in another way of
  4024.      * looking at it, it is the implementation that produces the least
  4025.      * unexpected behaviour.  It basically works in hours, that is, a day
  4026.      * is treated as exactly equivalent to 24 hours, and minutes and
  4027.      * seconds are treated as equivalent to 1/60th and 1/3600th of an
  4028.      * hour.  It should be obvious that working in days is impractical;
  4029.      * working in seconds is problematic when it comes to adding days
  4030.      * that fall over leap seconds, where it would appear to most users
  4031.      * that the function adds only 23 hours, 59 minutes and 59 seconds.
  4032.      * It is also problematic to work in any kind of mixture of days,
  4033.      * hours, minutes, and seconds, because then the addition of a span
  4034.      * would sometimes depend on which order you add the constituent
  4035.      * parts, which undermines the concept of a span altogether.
  4036.      *
  4037.      * If you want alternative functionality, you must use a mixture of
  4038.      * the following functions instead:
  4039.      *
  4040.      *  addYears()
  4041.      *  addMonths()
  4042.      *  addDays()
  4043.      *  addHours()
  4044.      *  addMinutes()
  4045.      *  addSeconds()
  4046.      *
  4047.      * @param object $span the time span to add
  4048.      *
  4049.      * @return   void 
  4050.      * @access   public
  4051.      */
  4052.     function addSpan($span)
  4053.     {
  4054.         if (!is_a($span'Date_Span')) {
  4055.             return PEAR::raiseError("Invalid argument - not 'Date_Span' object");
  4056.         else if ($this->ob_invalidtime{
  4057.             return $this->_getErrorInvalidTime();
  4058.         }
  4059.  
  4060.         $hn_days           $span->day;
  4061.         $hn_standardhour   $this->on_standardhour $span->hour;
  4062.         $hn_standardminute $this->on_standardminute $span->minute;
  4063.         $hn_standardsecond $this->on_standardsecond $span->second;
  4064.  
  4065.         if ($hn_standardsecond >= 60{
  4066.             ++$hn_standardminute;
  4067.             $hn_standardsecond -= 60;
  4068.         }
  4069.  
  4070.         if ($hn_standardminute >= 60{
  4071.             ++$hn_standardhour;
  4072.             $hn_standardminute -= 60;
  4073.         }
  4074.  
  4075.         if ($hn_standardhour >= 24{
  4076.             ++$hn_days;
  4077.             $hn_standardhour -= 24;
  4078.         }
  4079.  
  4080.         list($hn_standardyear$hn_standardmonth$hn_standardday=
  4081.             explode(" ",
  4082.                     Date_Calc::addDays($hn_days,
  4083.                                        $this->on_standardday,
  4084.                                        $this->on_standardmonth,
  4085.                                        $this->on_standardyear,
  4086.                                        "%Y %m %d"));
  4087.  
  4088.         $this->setStandardTime($hn_standardday,
  4089.                                $hn_standardmonth,
  4090.                                $hn_standardyear,
  4091.                                $hn_standardhour,
  4092.                                $hn_standardminute,
  4093.                                $hn_standardsecond,
  4094.                                $this->on_standardpartsecond);
  4095.     }
  4096.  
  4097.  
  4098.     // }}}
  4099.     // {{{ subtractSpan()
  4100.  
  4101.     /**
  4102.      * Subtracts a time span from the date
  4103.      *
  4104.      * N.B. it is impossible for this function to count leap seconds,
  4105.      * because the result would be dependent on which order the consituent
  4106.      * parts of the span are subtracted from the date.  Therefore, leap
  4107.      * seconds are ignored by this function.  If you want to count leap
  4108.      * seconds, use 'subtractSeconds()'.
  4109.      *
  4110.      * @param object $span the time span to subtract
  4111.      *
  4112.      * @return   void 
  4113.      * @access   public
  4114.      */
  4115.     function subtractSpan($span)
  4116.     {
  4117.         if (!is_a($span'Date_Span')) {
  4118.             return PEAR::raiseError("Invalid argument - not 'Date_Span' object");
  4119.         else if ($this->ob_invalidtime{
  4120.             return $this->_getErrorInvalidTime();
  4121.         }
  4122.  
  4123.         $hn_days           = -$span->day;
  4124.         $hn_standardhour   $this->on_standardhour $span->hour;
  4125.         $hn_standardminute $this->on_standardminute $span->minute;
  4126.         $hn_standardsecond $this->on_standardsecond $span->second;
  4127.  
  4128.         if ($hn_standardsecond < 0{
  4129.             --$hn_standardminute;
  4130.             $hn_standardsecond += 60;
  4131.         }
  4132.  
  4133.         if ($hn_standardminute < 0{
  4134.             --$hn_standardhour;
  4135.             $hn_standardminute += 60;
  4136.         }
  4137.  
  4138.         if ($hn_standardhour < 0{
  4139.             --$hn_days;
  4140.             $hn_standardhour += 24;
  4141.         }
  4142.  
  4143.         list($hn_standardyear$hn_standardmonth$hn_standardday=
  4144.             explode(" ",
  4145.                     Date_Calc::addDays($hn_days,
  4146.                                        $this->on_standardday,
  4147.                                        $this->on_standardmonth,
  4148.                                        $this->on_standardyear,
  4149.                                        "%Y %m %d"));
  4150.  
  4151.         $this->setStandardTime($hn_standardday,
  4152.                                $hn_standardmonth,
  4153.                                $hn_standardyear,
  4154.                                $hn_standardhour,
  4155.                                $hn_standardminute,
  4156.                                $hn_standardsecond,
  4157.                                $this->on_standardpartsecond);
  4158.     }
  4159.  
  4160.  
  4161.     // }}}
  4162.     // {{{ dateDiff()
  4163.  
  4164.     /**
  4165.      * Subtract supplied date and return answer in days
  4166.      *
  4167.      * If the second parameter '$pb_ignoretime' is specified as false, the time
  4168.      * parts of the two dates will be ignored, and the integral no of days
  4169.      * between the day-month-year parts of the two dates will be returned.  If
  4170.      * either of the two dates have an invalid time, the integral no of days
  4171.      * will also be returned, else the returned value will be the no of days as
  4172.      * a float, with each hour being treated as 1/24th of a day and so on.
  4173.      *
  4174.      * For example,
  4175.      *  21/11/2007 13.00 minus 21/11/2007 01.00
  4176.      * returns 0.5
  4177.      *
  4178.      * Note that if the passed date is in the past, a positive value will be
  4179.      * returned, and if it is in the future, a negative value will be returned.
  4180.      *
  4181.      * @param object $po_date       date to subtract
  4182.      * @param bool   $pb_ignoretime whether to ignore the time values of the two
  4183.      *                                dates in subtraction (defaults to false)
  4184.      *
  4185.      * @return   mixed      days between two dates as int or float
  4186.      * @access   public
  4187.      * @since    Method available since Release 1.5.0
  4188.      */
  4189.     function dateDiff($po_date$pb_ignoretime = false)
  4190.     {
  4191.         if ($pb_ignoretime || $this->ob_invalidtime{
  4192.             return Date_Calc::dateToDays($this->day,
  4193.                                          $this->month,
  4194.                                          $this->year-
  4195.                    Date_Calc::dateToDays($po_date->getDay(),
  4196.                                          $po_date->getMonth(),
  4197.                                          $po_date->getYear());
  4198.         }
  4199.  
  4200.         $hn_secondscompare $po_date->getStandardSecondsPastMidnight();
  4201.         if (PEAR::isError($hn_secondscompare)) {
  4202.             if ($hn_secondscompare->getCode(!= DATE_ERROR_INVALIDTIME{
  4203.                 return $hn_secondscompare;
  4204.             }
  4205.  
  4206.             return Date_Calc::dateToDays($this->day,
  4207.                                          $this->month,
  4208.                                          $this->year-
  4209.                    Date_Calc::dateToDays($po_date->getDay(),
  4210.                                          $po_date->getMonth(),
  4211.                                          $po_date->getYear());
  4212.         }
  4213.  
  4214.         $hn_seconds $this->getStandardSecondsPastMidnight();
  4215.  
  4216.         // If time parts are equal, return int, else return float:
  4217.         //
  4218.         return Date_Calc::dateToDays($this->on_standardday,
  4219.                                      $this->on_standardmonth,
  4220.                                      $this->on_standardyear-
  4221.                Date_Calc::dateToDays($po_date->getStandardDay(),
  4222.                                      $po_date->getStandardMonth(),
  4223.                                      $po_date->getStandardYear()) +
  4224.                ($hn_seconds == $hn_secondscompare ? 0 :
  4225.                 ($hn_seconds $hn_secondscompare/ 86400);
  4226.     }
  4227.  
  4228.  
  4229.     // }}}
  4230.     // {{{ inEquivalentTimeZones()
  4231.  
  4232.     /**
  4233.      * Tests whether two dates are in equivalent time zones
  4234.      *
  4235.      * Equivalence in this context consists in the time zones of the two dates
  4236.      * having:
  4237.      *
  4238.      *  an equal offset from UTC in both standard and Summer time (if
  4239.      *   the time zones observe Summer time)
  4240.      *  the same Summer time start and end rules, that is, the two time zones
  4241.      *   must switch from standard time to Summer time, and vice versa, on the
  4242.      *   same day and at the same time
  4243.      *
  4244.      * An example of two equivalent time zones is 'Europe/London' and
  4245.      * 'Europe/Lisbon', which in London is known as GMT/BST, and in Lisbon as
  4246.      * WET/WEST.
  4247.      *
  4248.      * @param object $po_date1 the first Date object to compare
  4249.      * @param object $po_date2 the second Date object to compare
  4250.      *
  4251.      * @return   bool       true if the time zones are equivalent
  4252.      * @access   public
  4253.      * @static
  4254.      * @since    Method available since Release 1.5.0
  4255.      */
  4256.     function inEquivalentTimeZones($po_date1$po_date2)
  4257.     {
  4258.         return $po_date1->tz->isEquivalent($po_date2->getTZID());
  4259.     }
  4260.  
  4261.  
  4262.     // }}}
  4263.     // {{{ compare()
  4264.  
  4265.     /**
  4266.      * Compares two dates
  4267.      *
  4268.      * Suitable for use in sorting functions.
  4269.      *
  4270.      * @param object $od1 the first Date object to compare
  4271.      * @param object $od2 the second Date object to compare
  4272.      *
  4273.      * @return   int        0 if the dates are equal, -1 if '$od1' is
  4274.      *                        before '$od2', 1 if '$od1' is after '$od2'
  4275.      * @access   public
  4276.      * @static
  4277.      */
  4278.     function compare($od1$od2)
  4279.     {
  4280.         $d1 = new Date($od1);
  4281.         $d2 = new Date($od2);
  4282.  
  4283.         // If the time zones are equivalent, do nothing:
  4284.         //
  4285.         if (!Date::inEquivalentTimeZones($d1$d2)) {
  4286.             // Only a time zone with a valid time can be converted:
  4287.             //
  4288.             if ($d2->isTimeValid()) {
  4289.                 $d2->convertTZByID($d1->getTZID());
  4290.             else if ($d1->isTimeValid()) {
  4291.                 $d1->convertTZByID($d2->getTZID());
  4292.             else {
  4293.                 // No comparison can be made without guessing the time:
  4294.                 //
  4295.                 return PEAR::raiseError("Both dates have invalid time",
  4296.                                         DATE_ERROR_INVALIDTIME);
  4297.             }
  4298.         }
  4299.  
  4300.         $days1 Date_Calc::dateToDays($d1->getDay(),
  4301.                                        $d1->getMonth(),
  4302.                                        $d1->getYear());
  4303.         $days2 Date_Calc::dateToDays($d2->getDay(),
  4304.                                        $d2->getMonth(),
  4305.                                        $d2->getYear());
  4306.         if ($days1 $days2)
  4307.             return -1;
  4308.         if ($days1 $days2)
  4309.             return 1;
  4310.  
  4311.         $hn_hour1 $d1->getStandardHour();
  4312.         if (PEAR::isError($hn_hour1))
  4313.             return $hn_hour1;
  4314.         $hn_hour2 $d2->getStandardHour();
  4315.         if (PEAR::isError($hn_hour2))
  4316.             return $hn_hour2;
  4317.  
  4318.         if ($hn_hour1 $hn_hour2return -1;
  4319.         if ($hn_hour1 $hn_hour2return 1;
  4320.         if ($d1->getStandardMinute($d2->getStandardMinute()) return -1;
  4321.         if ($d1->getStandardMinute($d2->getStandardMinute()) return 1;
  4322.         if ($d1->getStandardSecond($d2->getStandardSecond()) return -1;
  4323.         if ($d1->getStandardSecond($d2->getStandardSecond()) return 1;
  4324.         if ($d1->getStandardPartSecond($d2->getStandardPartSecond()) return -1;
  4325.         if ($d1->getStandardPartSecond($d2->getStandardPartSecond()) return 1;
  4326.         return 0;
  4327.     }
  4328.  
  4329.  
  4330.     // }}}
  4331.     // {{{ before()
  4332.  
  4333.     /**
  4334.      * Test if this date/time is before a certain date/time
  4335.      *
  4336.      * @param object $when the Date object to test against
  4337.      *
  4338.      * @return   boolean    true if this date is before $when
  4339.      * @access   public
  4340.      */
  4341.     function before($when)
  4342.     {
  4343.         $hn_compare Date::compare($this$when);
  4344.         if (PEAR::isError($hn_compare))
  4345.             return $hn_compare;
  4346.  
  4347.         if ($hn_compare == -1{
  4348.             return true;
  4349.         else {
  4350.             return false;
  4351.         }
  4352.     }
  4353.  
  4354.  
  4355.     // }}}
  4356.     // {{{ after()
  4357.  
  4358.     /**
  4359.      * Test if this date/time is after a certain date/time
  4360.      *
  4361.      * @param object $when the Date object to test against
  4362.      *
  4363.      * @return   boolean    true if this date is after $when
  4364.      * @access   public
  4365.      */
  4366.     function after($when)
  4367.     {
  4368.         $hn_compare Date::compare($this$when);
  4369.         if (PEAR::isError($hn_compare))
  4370.             return $hn_compare;
  4371.  
  4372.         if ($hn_compare == 1{
  4373.             return true;
  4374.         else {
  4375.             return false;
  4376.         }
  4377.     }
  4378.  
  4379.  
  4380.     // }}}
  4381.     // {{{ equals()
  4382.  
  4383.     /**
  4384.      * Test if this date/time is exactly equal to a certain date/time
  4385.      *
  4386.      * @param object $when the Date object to test against
  4387.      *
  4388.      * @return   boolean    true if this date is exactly equal to $when
  4389.      * @access   public
  4390.      */
  4391.     function equals($when)
  4392.     {
  4393.         $hn_compare Date::compare($this$when);
  4394.         if (PEAR::isError($hn_compare))
  4395.             return $hn_compare;
  4396.  
  4397.         if ($hn_compare == 0{
  4398.             return true;
  4399.         else {
  4400.             return false;
  4401.         }
  4402.     }
  4403.  
  4404.  
  4405.     // }}}
  4406.     // {{{ isFuture()
  4407.  
  4408.     /**
  4409.      * Determine if this date is in the future
  4410.      *
  4411.      * @return   boolean    true if this date is in the future
  4412.      * @access   public
  4413.      */
  4414.     function isFuture()
  4415.     {
  4416.         $now = new Date();
  4417.         return $this->after($now);
  4418.     }
  4419.  
  4420.  
  4421.     // }}}
  4422.     // {{{ isPast()
  4423.  
  4424.     /**
  4425.      * Determine if this date is in the past
  4426.      *
  4427.      * @return   boolean    true if this date is in the past
  4428.      * @access   public
  4429.      */
  4430.     function isPast()
  4431.     {
  4432.         $now = new Date();
  4433.         return $this->before($now);
  4434.     }
  4435.  
  4436.  
  4437.     // }}}
  4438.     // {{{ isLeapYear()
  4439.  
  4440.     /**
  4441.      * Determine if the year in this date is a leap year
  4442.      *
  4443.      * @return   boolean    true if this year is a leap year
  4444.      * @access   public
  4445.      */
  4446.     function isLeapYear()
  4447.     {
  4448.         return Date_Calc::isLeapYear($this->year);
  4449.     }
  4450.  
  4451.  
  4452.     // }}}
  4453.     // {{{ getJulianDate()
  4454.  
  4455.     /**
  4456.      * Returns the no of days (1-366) since 31st December of the previous year
  4457.      *
  4458.      * N.B. this function does not return (and never has returned) the 'Julian
  4459.      * Date', as described, for example, at:
  4460.      *
  4461.      *  http://en.wikipedia.org/wiki/Julian_day
  4462.      *
  4463.      * If you want the day of the year (0-366), use 'getDayOfYear()' instead.
  4464.      * If you want the true Julian Day, call one of the following:
  4465.      *
  4466.      *  <code>format("%E")</code>
  4467.      *  <code>format2("J")</code>
  4468.      *
  4469.      * There currently is no function that calls the Julian Date (as opposed
  4470.      * to the 'Julian Day'), although the Julian Day is an approximation.
  4471.      *
  4472.      * @return     int        the Julian date
  4473.      * @access     public
  4474.      * @see        Date::getDayOfYear()
  4475.      * @deprecated Method deprecated in Release 1.5.0
  4476.      */
  4477.     function getJulianDate()
  4478.     {
  4479.         return Date_Calc::julianDate($this->day$this->month$this->year);
  4480.     }
  4481.  
  4482.  
  4483.     // }}}
  4484.     // {{{ getDayOfYear()
  4485.  
  4486.     /**
  4487.      * Returns the no of days (1-366) since 31st December of the previous year
  4488.      *
  4489.      * @return   int        an integer between 1 and 366
  4490.      * @access   public
  4491.      * @since    Method available since Release 1.5.0
  4492.      */
  4493.     function getDayOfYear()
  4494.     {
  4495.         return Date_Calc::dayOfYear($this->day$this->month$this->year);
  4496.     }
  4497.  
  4498.  
  4499.     // }}}
  4500.     // {{{ getDayOfWeek()
  4501.  
  4502.     /**
  4503.      * Gets the day of the week for this date (0 = Sunday)
  4504.      *
  4505.      * @return   int        the day of the week (0 = Sunday)
  4506.      * @access   public
  4507.      */
  4508.     function getDayOfWeek()
  4509.     {
  4510.         return Date_Calc::dayOfWeek($this->day$this->month$this->year);
  4511.     }
  4512.  
  4513.  
  4514.     // }}}
  4515.     // {{{ getWeekOfYear()
  4516.  
  4517.     /**
  4518.      * Gets the week of the year for this date
  4519.      *
  4520.      * @return   int        the week of the year
  4521.      * @access   public
  4522.      */
  4523.     function getWeekOfYear()
  4524.     {
  4525.         return Date_Calc::weekOfYear($this->day$this->month$this->year);
  4526.     }
  4527.  
  4528.  
  4529.     // }}}
  4530.     // {{{ getQuarterOfYear()
  4531.  
  4532.     /**
  4533.      * Gets the quarter of the year for this date
  4534.      *
  4535.      * @return   int        the quarter of the year (1-4)
  4536.      * @access   public
  4537.      */
  4538.     function getQuarterOfYear()
  4539.     {
  4540.         return Date_Calc::quarterOfYear($this->day$this->month$this->year);
  4541.     }
  4542.  
  4543.  
  4544.     // }}}
  4545.     // {{{ getDaysInMonth()
  4546.  
  4547.     /**
  4548.      * Gets number of days in the month for this date
  4549.      *
  4550.      * @return   int        number of days in this month
  4551.      * @access   public
  4552.      */
  4553.     function getDaysInMonth()
  4554.     {
  4555.         return Date_Calc::daysInMonth($this->month$this->year);
  4556.     }
  4557.  
  4558.  
  4559.     // }}}
  4560.     // {{{ getWeeksInMonth()
  4561.  
  4562.     /**
  4563.      * Gets the number of weeks in the month for this date
  4564.      *
  4565.      * @return   int        number of weeks in this month
  4566.      * @access   public
  4567.      */
  4568.     function getWeeksInMonth()
  4569.     {
  4570.         return Date_Calc::weeksInMonth($this->month$this->year);
  4571.     }
  4572.  
  4573.  
  4574.     // }}}
  4575.     // {{{ getDayName()
  4576.  
  4577.     /**
  4578.      * Gets the full name or abbreviated name of this weekday
  4579.      *
  4580.      * @param bool $abbr   abbreviate the name
  4581.      * @param int  $length length of abbreviation
  4582.      *
  4583.      * @return   string     name of this day
  4584.      * @access   public
  4585.      */
  4586.     function getDayName($abbr = false$length = 3)
  4587.     {
  4588.         if ($abbr{
  4589.             return Date_Calc::getWeekdayAbbrname($this->day,
  4590.                                                  $this->month,
  4591.                                                  $this->year,
  4592.                                                  $length);
  4593.         else {
  4594.             return Date_Calc::getWeekdayFullname($this->day,
  4595.                                                  $this->month,
  4596.                                                  $this->year);
  4597.         }
  4598.     }
  4599.  
  4600.  
  4601.     // }}}
  4602.     // {{{ getMonthName()
  4603.  
  4604.     /**
  4605.      * Gets the full name or abbreviated name of this month
  4606.      *
  4607.      * @param boolean $abbr abbreviate the name
  4608.      *
  4609.      * @return   string     name of this month
  4610.      * @access   public
  4611.      */
  4612.     function getMonthName($abbr = false)
  4613.     {
  4614.         if ($abbr{
  4615.             return Date_Calc::getMonthAbbrname($this->month);
  4616.         else {
  4617.             return Date_Calc::getMonthFullname($this->month);
  4618.         }
  4619.     }
  4620.  
  4621.  
  4622.     // }}}
  4623.     // {{{ getNextDay()
  4624.  
  4625.     /**
  4626.      * Get a Date object for the day after this one
  4627.      *
  4628.      * The time of the returned Date object is the same as this time.
  4629.      *
  4630.      * @return   object     Date object representing the next day
  4631.      * @access   public
  4632.      */
  4633.     function getNextDay()
  4634.     {
  4635.         $ret = new Date($this);
  4636.         $ret->addDays(1);
  4637.         return $ret;
  4638.     }
  4639.  
  4640.  
  4641.     // }}}
  4642.     // {{{ getPrevDay()
  4643.  
  4644.     /**
  4645.      * Get a Date object for the day before this one
  4646.      *
  4647.      * The time of the returned Date object is the same as this time.
  4648.      *
  4649.      * @return   object     Date object representing the previous day
  4650.      * @access   public
  4651.      */
  4652.     function getPrevDay()
  4653.     {
  4654.         $ret = new Date($this);
  4655.         $ret->addDays(-1);
  4656.         return $ret;
  4657.     }
  4658.  
  4659.  
  4660.     // }}}
  4661.     // {{{ getNextWeekday()
  4662.  
  4663.     /**
  4664.      * Get a Date object for the weekday after this one
  4665.      *
  4666.      * The time of the returned Date object is the same as this time.
  4667.      *
  4668.      * @return   object     Date object representing the next week-day
  4669.      * @access   public
  4670.      */
  4671.     function getNextWeekday()
  4672.     {
  4673.         $ret = new Date($this);
  4674.         list($hs_year$hs_month$hs_day=
  4675.             explode(" "Date_Calc::nextWeekday($this->day,
  4676.                                                 $this->month,
  4677.                                                 $this->year,
  4678.                                                 "%Y %m %d"));
  4679.         $ret->setDayMonthYear($hs_day$hs_month$hs_year);
  4680.         return $ret;
  4681.     }
  4682.  
  4683.  
  4684.     // }}}
  4685.     // {{{ getPrevWeekday()
  4686.  
  4687.     /**
  4688.      * Get a Date object for the weekday before this one
  4689.      *
  4690.      * The time of the returned Date object is the same as this time.
  4691.      *
  4692.      * @return   object     Date object representing the previous week-day
  4693.      * @access   public
  4694.      */
  4695.     function getPrevWeekday()
  4696.     {
  4697.         $ret = new Date($this);
  4698.         list($hs_year$hs_month$hs_day=
  4699.             explode(" "Date_Calc::prevWeekday($this->day,
  4700.                                                 $this->month,
  4701.                                                 $this->year,
  4702.                                                 "%Y %m %d"));
  4703.         $ret->setDayMonthYear($hs_day$hs_month$hs_year);
  4704.         return $ret;
  4705.     }
  4706.  
  4707.  
  4708.     // }}}
  4709.     // {{{ getYear()
  4710.  
  4711.     /**
  4712.      * Returns the year field of the date object
  4713.      *
  4714.      * @return   int        the year
  4715.      * @access   public
  4716.      */
  4717.     function getYear()
  4718.     {
  4719.         return $this->year;
  4720.     }
  4721.  
  4722.  
  4723.     // }}}
  4724.     // {{{ getMonth()
  4725.  
  4726.     /**
  4727.      * Returns the month field of the date object
  4728.      *
  4729.      * @return   int        the minute
  4730.      * @access   public
  4731.      */
  4732.     function getMonth()
  4733.     {
  4734.         return $this->month;
  4735.     }
  4736.  
  4737.  
  4738.     // }}}
  4739.     // {{{ getDay()
  4740.  
  4741.     /**
  4742.      * Returns the day field of the date object
  4743.      *
  4744.      * @return   int        the day
  4745.      * @access   public
  4746.      */
  4747.     function getDay()
  4748.     {
  4749.         return $this->day;
  4750.     }
  4751.  
  4752.  
  4753.     // }}}
  4754.     // {{{ _getErrorInvalidTime()
  4755.  
  4756.     /**
  4757.      * Returns invalid time PEAR Error
  4758.      *
  4759.      * @return   object 
  4760.      * @access   private
  4761.      * @since    Method available since Release 1.5.0
  4762.      */
  4763.     function _getErrorInvalidTime()
  4764.     {
  4765.         return PEAR::raiseError("Invalid time '" .
  4766.                                 sprintf("%02d.%02d.%02d",
  4767.                                         $this->hour,
  4768.                                         $this->minute,
  4769.                                         $this->second.
  4770.                                 "' specified for date '" .
  4771.                                 Date_Calc::dateFormat($this->day,
  4772.                                                       $this->month,
  4773.                                                       $this->year,
  4774.                                                       "%Y-%m-%d".
  4775.                                 "' and in this timezone",
  4776.                                 DATE_ERROR_INVALIDTIME);
  4777.     }
  4778.  
  4779.  
  4780.     // }}}
  4781.     // {{{ _secondsInDayIsValid()
  4782.  
  4783.     /**
  4784.      * If leap seconds are observed, checks if the seconds in the day is valid
  4785.      *
  4786.      * Note that only the local standard time is accessed.
  4787.      *
  4788.      * @return   bool 
  4789.      * @access   private
  4790.      * @since    Method available since Release 1.5.0
  4791.      */
  4792.     function _secondsInDayIsValid()
  4793.     {
  4794.         if ($this->ob_countleapseconds{
  4795.             // Convert to UTC:
  4796.             //
  4797.             list($hn_year,
  4798.                  $hn_month,
  4799.                  $hn_day,
  4800.                  $hn_hour,
  4801.                  $hn_minute,
  4802.                  $hn_second,
  4803.                  $hn_partsecond=
  4804.                 $this->_addOffset($this->tz->getRawOffset(* -1,
  4805.                                   $this->on_standardday,
  4806.                                   $this->on_standardmonth,
  4807.                                   $this->on_standardyear,
  4808.                                   $this->on_standardhour,
  4809.                                   $this->on_standardminute,
  4810.                                   $this->on_standardsecond,
  4811.                                   $this->on_standardpartsecond);
  4812.             return Date_Calc::secondsPastMidnight($hn_hour,
  4813.                                                   $hn_minute,
  4814.                                                   $hn_second +
  4815.                                                       $hn_partsecond<
  4816.                    Date_Calc::getSecondsInDay($hn_day$hn_month$hn_year);
  4817.         else {
  4818.             return $this->getStandardSecondsPastMidnight(< 86400;
  4819.         }
  4820.     }
  4821.  
  4822.  
  4823.     // }}}
  4824.     // {{{ isTimeValid()
  4825.  
  4826.     /**
  4827.      * Whether the stored time is valid as a local time
  4828.      *
  4829.      * An invalid time is one that lies in the 'skipped hour' at the point
  4830.      * that the clocks go forward.  Note that the stored date (i.e.
  4831.      * the day/month/year, is always valid).
  4832.      *
  4833.      * The object is able to store an invalid time because a user might
  4834.      * unwittingly and correctly store a valid time, and then add one day so
  4835.      * as to put the object in the 'skipped' hour (when the clocks go forward).
  4836.      * This could be corrected by a conversion to Summer time (by adding one
  4837.      * hour); however, if the user then added another day, and had no need for
  4838.      * or interest in the time anyway, the behaviour may be rather unexpected.
  4839.      * And anyway in this situation, the time originally specified would now,
  4840.      * two days on, be valid again.
  4841.      *
  4842.      * So this class allows an invalid time like this so long as the user does
  4843.      * not in any way make use of or request the time while it is in this
  4844.      * semi-invalid state, in order to allow for for the fact that he might be
  4845.      * only interested in the date, and not the time, and in order not to behave
  4846.      * in an unexpected way, especially without throwing an exception to tell
  4847.      * the user about it.
  4848.      *
  4849.      * @return   bool 
  4850.      * @access   public
  4851.      * @since    Method available since Release 1.5.0
  4852.      */
  4853.     function isTimeValid()
  4854.     {
  4855.         return !$this->ob_invalidtime;
  4856.     }
  4857.  
  4858.  
  4859.     // }}}
  4860.     // {{{ getHour()
  4861.  
  4862.     /**
  4863.      * Returns the hour field of the date object
  4864.      *
  4865.      * @return   int        the hour
  4866.      * @access   public
  4867.      */
  4868.     function getHour()
  4869.     {
  4870.         if ($this->ob_invalidtime)
  4871.             return $this->_getErrorInvalidTime();
  4872.  
  4873.         return $this->hour;
  4874.     }
  4875.  
  4876.  
  4877.     // }}}
  4878.     // {{{ getMinute()
  4879.  
  4880.     /**
  4881.      * Returns the minute field of the date object
  4882.      *
  4883.      * @return   int        the minute
  4884.      * @access   public
  4885.      */
  4886.     function getMinute()
  4887.     {
  4888.         if ($this->ob_invalidtime)
  4889.             return $this->_getErrorInvalidTime();
  4890.  
  4891.         return $this->minute;
  4892.     }
  4893.  
  4894.  
  4895.     // }}}
  4896.     // {{{ getSecond()
  4897.  
  4898.     /**
  4899.      * Returns the second field of the date object
  4900.      *
  4901.      * @return   int        the second
  4902.      * @access   public
  4903.      */
  4904.     function getSecond()
  4905.     {
  4906.         if ($this->ob_invalidtime)
  4907.             return $this->_getErrorInvalidTime();
  4908.  
  4909.         return $this->second;
  4910.     }
  4911.  
  4912.  
  4913.     // }}}
  4914.     // {{{ getSecondsPastMidnight()
  4915.  
  4916.     /**
  4917.      * Returns the no of seconds since midnight (0-86400) as float
  4918.      *
  4919.      * @return   float      float which is at least 0 and less than 86400
  4920.      * @access   public
  4921.      * @since    Method available since Release 1.5.0
  4922.      */
  4923.     function getSecondsPastMidnight()
  4924.     {
  4925.         if ($this->ob_invalidtime)
  4926.             return $this->_getErrorInvalidTime();
  4927.  
  4928.         return Date_Calc::secondsPastMidnight($this->hour,
  4929.                                               $this->minute,
  4930.                                               $this->second+
  4931.                $this->partsecond;
  4932.     }
  4933.  
  4934.  
  4935.     // }}}
  4936.     // {{{ getPartSecond()
  4937.  
  4938.     /**
  4939.      * Returns the part-second field of the date object
  4940.      *
  4941.      * @return   float      the part-second
  4942.      * @access   protected
  4943.      * @since    Method available since Release 1.5.0
  4944.      */
  4945.     function getPartSecond()
  4946.     {
  4947.         if ($this->ob_invalidtime)
  4948.             return $this->_getErrorInvalidTime();
  4949.  
  4950.         return $this->partsecond;
  4951.     }
  4952.  
  4953.  
  4954.     // }}}
  4955.     // {{{ getStandardYear()
  4956.  
  4957.     /**
  4958.      * Returns the year field of the local standard time
  4959.      *
  4960.      * @return   int        the year
  4961.      * @access   public
  4962.      * @since    Method available since Release 1.5.0
  4963.      */
  4964.     function getStandardYear()
  4965.     {
  4966.         if ($this->ob_invalidtime)
  4967.             return $this->_getErrorInvalidTime();
  4968.  
  4969.         return $this->on_standardyear;
  4970.     }
  4971.  
  4972.  
  4973.     // }}}
  4974.     // {{{ getStandardMonth()
  4975.  
  4976.     /**
  4977.      * Returns the month field of the local standard time
  4978.      *
  4979.      * @return   int        the minute
  4980.      * @access   public
  4981.      * @since    Method available since Release 1.5.0
  4982.      */
  4983.     function getStandardMonth()
  4984.     {
  4985.         if ($this->ob_invalidtime)
  4986.             return $this->_getErrorInvalidTime();
  4987.  
  4988.         return $this->on_standardmonth;
  4989.     }
  4990.  
  4991.  
  4992.     // }}}
  4993.     // {{{ getStandardDay()
  4994.  
  4995.     /**
  4996.      * Returns the day field of the local standard time
  4997.      *
  4998.      * @return   int        the day
  4999.      * @access   public
  5000.      * @since    Method available since Release 1.5.0
  5001.      */
  5002.     function getStandardDay()
  5003.     {
  5004.         if ($this->ob_invalidtime)
  5005.             return $this->_getErrorInvalidTime();
  5006.  
  5007.         return $this->on_standardday;
  5008.     }
  5009.  
  5010.  
  5011.     // }}}
  5012.     // {{{ getStandardHour()
  5013.  
  5014.     /**
  5015.      * Returns the hour field of the local standard time
  5016.      *
  5017.      * @return   int        the hour
  5018.      * @access   public
  5019.      * @since    Method available since Release 1.5.0
  5020.      */
  5021.     function getStandardHour()
  5022.     {
  5023.         if ($this->ob_invalidtime)
  5024.             return $this->_getErrorInvalidTime();
  5025.  
  5026.         return $this->on_standardhour;
  5027.     }
  5028.  
  5029.  
  5030.     // }}}
  5031.     // {{{ getStandardMinute()
  5032.  
  5033.     /**
  5034.      * Returns the minute field of the local standard time
  5035.      *
  5036.      * @return   int        the minute
  5037.      * @access   public
  5038.      * @since    Method available since Release 1.5.0
  5039.      */
  5040.     function getStandardMinute()
  5041.     {
  5042.         if ($this->ob_invalidtime)
  5043.             return $this->_getErrorInvalidTime();
  5044.  
  5045.         return $this->on_standardminute;
  5046.     }
  5047.  
  5048.  
  5049.     // }}}
  5050.     // {{{ getStandardSecond()
  5051.  
  5052.     /**
  5053.      * Returns the second field of the local standard time
  5054.      *
  5055.      * @return   int        the second
  5056.      * @access   public
  5057.      * @since    Method available since Release 1.5.0
  5058.      */
  5059.     function getStandardSecond()
  5060.     {
  5061.         if ($this->ob_invalidtime)
  5062.             return $this->_getErrorInvalidTime();
  5063.  
  5064.         return $this->on_standardsecond;
  5065.     }
  5066.  
  5067.  
  5068.     // }}}
  5069.     // {{{ getStandardSecondsPastMidnight()
  5070.  
  5071.     /**
  5072.      * Returns the no of seconds since midnight (0-86400) of the
  5073.      * local standard time as float
  5074.      *
  5075.      * @return   float      float which is at least 0 and less than 86400
  5076.      * @access   public
  5077.      * @since    Method available since Release 1.5.0
  5078.      */
  5079.     function getStandardSecondsPastMidnight()
  5080.     {
  5081.         if ($this->ob_invalidtime)
  5082.             return $this->_getErrorInvalidTime();
  5083.  
  5084.         return Date_Calc::secondsPastMidnight($this->on_standardhour,
  5085.                                               $this->on_standardminute,
  5086.                                               $this->on_standardsecond+
  5087.                $this->on_standardpartsecond;
  5088.     }
  5089.  
  5090.  
  5091.     // }}}
  5092.     // {{{ getStandardPartSecond()
  5093.  
  5094.     /**
  5095.      * Returns the part-second field of the local standard time
  5096.      *
  5097.      * @return   float      the part-second
  5098.      * @access   protected
  5099.      * @since    Method available since Release 1.5.0
  5100.      */
  5101.     function getStandardPartSecond()
  5102.     {
  5103.         if ($this->ob_invalidtime)
  5104.             return $this->_getErrorInvalidTime();
  5105.  
  5106.         return $this->on_standardpartsecond;
  5107.     }
  5108.  
  5109.  
  5110.     // }}}
  5111.     // {{{ _addOffset()
  5112.  
  5113.     /**
  5114.      * Add a time zone offset to the passed date/time
  5115.      *
  5116.      * @param int   $pn_offset     the offset to add in milliseconds
  5117.      * @param int   $pn_day        the day
  5118.      * @param int   $pn_month      the month
  5119.      * @param int   $pn_year       the year
  5120.      * @param int   $pn_hour       the hour
  5121.      * @param int   $pn_minute     the minute
  5122.      * @param int   $pn_second     the second
  5123.      * @param float $pn_partsecond the part-second
  5124.      *
  5125.      * @return   array      array of year, month, day, hour, minute, second,
  5126.      *                        and part-second
  5127.      * @access   private
  5128.      * @static
  5129.      * @since    Method available since Release 1.5.0
  5130.      */
  5131.     function _addOffset($pn_offset,
  5132.                         $pn_day,
  5133.                         $pn_month,
  5134.                         $pn_year,
  5135.                         $pn_hour,
  5136.                         $pn_minute,
  5137.                         $pn_second,
  5138.                         $pn_partsecond)
  5139.     {
  5140.         if ($pn_offset == 0{
  5141.             return array((int) $pn_year,
  5142.                          (int) $pn_month,
  5143.                          (int) $pn_day,
  5144.                          (int) $pn_hour,
  5145.                          (int) $pn_minute,
  5146.                          (int) $pn_second,
  5147.                          (float) $pn_partsecond);
  5148.         }
  5149.                          
  5150.         if ($pn_offset % 3600000 == 0{
  5151.             list($hn_year,
  5152.                  $hn_month,
  5153.                  $hn_day,
  5154.                  $hn_hour=
  5155.                  Date_Calc::addHours($pn_offset / 3600000,
  5156.                                      $pn_day,
  5157.                                      $pn_month,
  5158.                                      $pn_year,
  5159.                                      $pn_hour);
  5160.  
  5161.             $hn_minute     = (int) $pn_minute;
  5162.             $hn_second     = (int) $pn_second;
  5163.             $hn_partsecond = (float) $pn_partsecond;
  5164.         else if ($pn_offset % 60000 == 0{
  5165.             list($hn_year,
  5166.                  $hn_month,
  5167.                  $hn_day,
  5168.                  $hn_hour,
  5169.                  $hn_minute=
  5170.                  Date_Calc::addMinutes($pn_offset / 60000,
  5171.                                        $pn_day,
  5172.                                        $pn_month,
  5173.                                        $pn_year,
  5174.                                        $pn_hour,
  5175.                                        $pn_minute);
  5176.  
  5177.             $hn_second     = (int) $pn_second;
  5178.             $hn_partsecond = (float) $pn_partsecond;
  5179.         else {
  5180.             list($hn_year,
  5181.                  $hn_month,
  5182.                  $hn_day,
  5183.                  $hn_hour,
  5184.                  $hn_minute,
  5185.                  $hn_secondraw=
  5186.                  Date_Calc::addSeconds($pn_offset / 1000,
  5187.                                        $pn_day,
  5188.                                        $pn_month,
  5189.                                        $pn_year,
  5190.                                        $pn_hour,
  5191.                                        $pn_partsecond == 0.0 ?
  5192.                                            $pn_second :
  5193.                                            $pn_second $pn_partsecond,
  5194.                                        false);  // N.B. do not count
  5195.                                                 // leap seconds
  5196.  
  5197.             if (is_float($hn_secondraw)) {
  5198.                 $hn_second     intval($hn_secondraw);
  5199.                 $hn_partsecond $hn_secondraw $hn_second;
  5200.             else {
  5201.                 $hn_second     $hn_secondraw;
  5202.                 $hn_partsecond = 0.0;
  5203.             }
  5204.         }
  5205.  
  5206.         return array($hn_year,
  5207.                      $hn_month,
  5208.                      $hn_day,
  5209.                      $hn_hour,
  5210.                      $hn_minute,
  5211.                      $hn_second,
  5212.                      $hn_partsecond);
  5213.     }
  5214.  
  5215.  
  5216.     // }}}
  5217.     // {{{ setLocalTime()
  5218.  
  5219.     /**
  5220.      * Sets local time (Summer-time-adjusted) and then calculates local
  5221.      * standard time
  5222.      *
  5223.      * @param int   $pn_day                 the day
  5224.      * @param int   $pn_month               the month
  5225.      * @param int   $pn_year                the year
  5226.      * @param int   $pn_hour                the hour
  5227.      * @param int   $pn_minute              the minute
  5228.      * @param int   $pn_second              the second
  5229.      * @param float $pn_partsecond          the part-second
  5230.      * @param bool  $pb_repeatedhourdefault whether to assume Summer time if a
  5231.      *                                        repeated hour is specified (defaults
  5232.      *                                        to false)
  5233.      * @param bool  $pb_correctinvalidtime  whether to correct, by adding the
  5234.      *                                        local Summer time offset, the
  5235.      *                                        specified time if it falls in the
  5236.      *                                        skipped hour (defaults to
  5237.      *                                        DATE_CORRECTINVALIDTIME_DEFAULT)
  5238.      *
  5239.      * @return   void 
  5240.      * @access   protected
  5241.      * @see      Date::setStandardTime()
  5242.      * @since    Method available since Release 1.5.0
  5243.      */
  5244.     function setLocalTime($pn_day,
  5245.                           $pn_month,
  5246.                           $pn_year,
  5247.                           $pn_hour,
  5248.                           $pn_minute,
  5249.                           $pn_second,
  5250.                           $pn_partsecond,
  5251.                           $pb_repeatedhourdefault = false,
  5252.                           $pb_correctinvalidtime = DATE_CORRECTINVALIDTIME_DEFAULT)
  5253.     {
  5254.         settype($pn_day"int");
  5255.         settype($pn_month"int");
  5256.         settype($pn_year"int");
  5257.         settype($pn_hour"int");
  5258.         settype($pn_minute"int");
  5259.         settype($pn_second"int");
  5260.         settype($pn_partsecond"float");
  5261.  
  5262.         $hb_insummertime =
  5263.             $this->tz->inDaylightTime(array($pn_day,
  5264.                 $pn_month$pn_yearDate_Calc::secondsPastMidnight($pn_hour,
  5265.                 $pn_minute$pn_second$pn_partsecond),
  5266.                 $pb_repeatedhourdefault);
  5267.         if (PEAR::isError($hb_insummertime)) {
  5268.             if ($hb_insummertime->getCode(!= DATE_ERROR_INVALIDTIME{
  5269.                 return $hb_insummertime;
  5270.             else if ($pb_correctinvalidtime{
  5271.                 // Store passed time as local standard time:
  5272.                 //
  5273.                 $this->on_standardday        $pn_day;
  5274.                 $this->on_standardmonth      $pn_month;
  5275.                 $this->on_standardyear       $pn_year;
  5276.                 $this->on_standardhour       $pn_hour;
  5277.                 $this->on_standardminute     $pn_minute;
  5278.                 $this->on_standardsecond     $pn_second;
  5279.                 $this->on_standardpartsecond $pn_partsecond;
  5280.  
  5281.                 // Add Summer time offset to passed time:
  5282.                 //
  5283.                 list($this->year,
  5284.                      $this->month,
  5285.                      $this->day,
  5286.                      $this->hour,
  5287.                      $this->minute,
  5288.                      $this->second,
  5289.                      $this->partsecond=
  5290.                      $this->_addOffset($this->tz->getDSTSavings(),
  5291.                                        $pn_day,
  5292.                                        $pn_month,
  5293.                                        $pn_year,
  5294.                                        $pn_hour,
  5295.                                        $pn_minute,
  5296.                                        $pn_second,
  5297.                                        $pn_partsecond);
  5298.  
  5299.                 $this->ob_invalidtime !$this->_secondsInDayIsValid();
  5300.             else {
  5301.                 // Hedge bets - if the user adds/subtracts a day, then the time
  5302.                 // will be uncorrupted, and if the user does
  5303.                 // addition/subtraction with the time, or requests the time,
  5304.                 // then return an error at that point:
  5305.                 //
  5306.                 $this->day        $pn_day;
  5307.                 $this->month      $pn_month;
  5308.                 $this->year       $pn_year;
  5309.                 $this->hour       $pn_hour;
  5310.                 $this->minute     $pn_minute;
  5311.                 $this->second     $pn_second;
  5312.                 $this->partsecond $pn_partsecond;
  5313.  
  5314.                 $this->ob_invalidtime = true;
  5315.             }
  5316.  
  5317.             return;
  5318.         else {
  5319.             // Passed time is valid as local time:
  5320.             //
  5321.             $this->day        $pn_day;
  5322.             $this->month      $pn_month;
  5323.             $this->year       $pn_year;
  5324.             $this->hour       $pn_hour;
  5325.             $this->minute     $pn_minute;
  5326.             $this->second     $pn_second;
  5327.             $this->partsecond $pn_partsecond;
  5328.         }
  5329.  
  5330.         $this->ob_invalidtime !$this->_secondsInDayIsValid();
  5331.  
  5332.         if ($hb_insummertime{
  5333.             // Calculate local standard time:
  5334.             //
  5335.             list($this->on_standardyear,
  5336.                  $this->on_standardmonth,
  5337.                  $this->on_standardday,
  5338.                  $this->on_standardhour,
  5339.                  $this->on_standardminute,
  5340.                  $this->on_standardsecond,
  5341.                  $this->on_standardpartsecond=
  5342.                  $this->_addOffset($this->tz->getDSTSavings(* -1,
  5343.                                    $pn_day,
  5344.                                    $pn_month,
  5345.                                    $pn_year,
  5346.                                    $pn_hour,
  5347.                                    $pn_minute,
  5348.                                    $pn_second,
  5349.                                    $pn_partsecond);
  5350.         else {
  5351.             // Time is already local standard time:
  5352.             //
  5353.             $this->on_standardday        $pn_day;
  5354.             $this->on_standardmonth      $pn_month;
  5355.             $this->on_standardyear       $pn_year;
  5356.             $this->on_standardhour       $pn_hour;
  5357.             $this->on_standardminute     $pn_minute;
  5358.             $this->on_standardsecond     $pn_second;
  5359.             $this->on_standardpartsecond $pn_partsecond;
  5360.         }
  5361.     }
  5362.  
  5363.  
  5364.     // }}}
  5365.     // {{{ setStandardTime()
  5366.  
  5367.     /**
  5368.      * Sets local standard time and then calculates local time (i.e.
  5369.      * Summer-time-adjusted)
  5370.      *
  5371.      * @param int   $pn_day        the day
  5372.      * @param int   $pn_month      the month
  5373.      * @param int   $pn_year       the year
  5374.      * @param int   $pn_hour       the hour
  5375.      * @param int   $pn_minute     the minute
  5376.      * @param int   $pn_second     the second
  5377.      * @param float $pn_partsecond the part-second
  5378.      *
  5379.      * @return   void 
  5380.      * @access   protected
  5381.      * @see      Date::setLocalTime()
  5382.      * @since    Method available since Release 1.5.0
  5383.      */
  5384.     function setStandardTime($pn_day,
  5385.                              $pn_month,
  5386.                              $pn_year,
  5387.                              $pn_hour,
  5388.                              $pn_minute,
  5389.                              $pn_second,
  5390.                              $pn_partsecond)
  5391.     {
  5392.         settype($pn_day"int");
  5393.         settype($pn_month"int");
  5394.         settype($pn_year"int");
  5395.         settype($pn_hour"int");
  5396.         settype($pn_minute"int");
  5397.         settype($pn_second"int");
  5398.         settype($pn_partsecond"float");
  5399.  
  5400.         $this->on_standardday        $pn_day;
  5401.         $this->on_standardmonth      $pn_month;
  5402.         $this->on_standardyear       $pn_year;
  5403.         $this->on_standardhour       $pn_hour;
  5404.         $this->on_standardminute     $pn_minute;
  5405.         $this->on_standardsecond     $pn_second;
  5406.         $this->on_standardpartsecond $pn_partsecond;
  5407.  
  5408.         $this->ob_invalidtime !$this->_secondsInDayIsValid();
  5409.  
  5410.         if ($this->tz->inDaylightTimeStandard(array($pn_day$pn_month,
  5411.             $pn_yearDate_Calc::secondsPastMidnight($pn_hour$pn_minute,
  5412.             $pn_second$pn_partsecond))) {
  5413.  
  5414.             // Calculate local time:
  5415.             //
  5416.             list($this->year,
  5417.                  $this->month,
  5418.                  $this->day,
  5419.                  $this->hour,
  5420.                  $this->minute,
  5421.                  $this->second,
  5422.                  $this->partsecond=
  5423.                  $this->_addOffset($this->tz->getDSTSavings(),
  5424.                                    $pn_day,
  5425.                                    $pn_month,
  5426.                                    $pn_year,
  5427.                                    $pn_hour,
  5428.                                    $pn_minute,
  5429.                                    $pn_second,
  5430.                                    $pn_partsecond);
  5431.         else {
  5432.             // Time is already local time:
  5433.             //
  5434.             $this->day        $pn_day;
  5435.             $this->month      $pn_month;
  5436.             $this->year       $pn_year;
  5437.             $this->hour       $pn_hour;
  5438.             $this->minute     $pn_minute;
  5439.             $this->second     $pn_second;
  5440.             $this->partsecond $pn_partsecond;
  5441.         }
  5442.     }
  5443.  
  5444.  
  5445.     // }}}
  5446.     // {{{ setYear()
  5447.  
  5448.     /**
  5449.      * Sets the year field of the date object
  5450.      *
  5451.      * If specified year forms an invalid date, then PEAR error will be
  5452.      * returned, unless the validation is over-ridden using the second
  5453.      * parameter.
  5454.      *
  5455.      * @param int  $y           the year
  5456.      * @param bool $pb_validate whether to check that the new date is valid
  5457.      *
  5458.      * @return   void 
  5459.      * @access   public
  5460.      * @see      Date::setDayMonthYear(), Date::setDateTime()
  5461.      */
  5462.     function setYear($y$pb_validate = DATE_VALIDATE_DATE_BY_DEFAULT)
  5463.     {
  5464.         if ($pb_validate && !Date_Calc::isValidDate($this->day$this->month$y)) {
  5465.             return PEAR::raiseError("'" .
  5466.                                     Date_Calc::dateFormat($this->day,
  5467.                                                           $this->month,
  5468.                                                           $y,
  5469.                                                           "%Y-%m-%d".
  5470.                                     "' is invalid calendar date",
  5471.                                     DATE_ERROR_INVALIDDATE);
  5472.         else {
  5473.             $this->setLocalTime($this->day,
  5474.                                 $this->month,
  5475.                                 $y,
  5476.                                 $this->hour,
  5477.                                 $this->minute,
  5478.                                 $this->second,
  5479.                                 $this->partsecond);
  5480.         }
  5481.     }
  5482.  
  5483.  
  5484.     // }}}
  5485.     // {{{ setMonth()
  5486.  
  5487.     /**
  5488.      * Sets the month field of the date object
  5489.      *
  5490.      * If specified year forms an invalid date, then PEAR error will be
  5491.      * returned, unless the validation is over-ridden using the second
  5492.      * parameter.
  5493.      *
  5494.      * @param int  $m           the month
  5495.      * @param bool $pb_validate whether to check that the new date is valid
  5496.      *
  5497.      * @return   void 
  5498.      * @access   public
  5499.      * @see      Date::setDayMonthYear(), Date::setDateTime()
  5500.      */
  5501.     function setMonth($m$pb_validate = DATE_VALIDATE_DATE_BY_DEFAULT)
  5502.     {
  5503.         if ($pb_validate && !Date_Calc::isValidDate($this->day$m$this->year)) {
  5504.             return PEAR::raiseError("'" .
  5505.                                     Date_Calc::dateFormat($this->day,
  5506.                                                           $m,
  5507.                                                           $this->year,
  5508.                                                           "%Y-%m-%d".
  5509.                                     "' is invalid calendar date",
  5510.                                     DATE_ERROR_INVALIDDATE);
  5511.         else {
  5512.             $this->setLocalTime($this->day,
  5513.                                 $m,
  5514.                                 $this->year,
  5515.                                 $this->hour,
  5516.                                 $this->minute,
  5517.                                 $this->second,
  5518.                                 $this->partsecond);
  5519.         }
  5520.     }
  5521.  
  5522.  
  5523.     // }}}
  5524.     // {{{ setDay()
  5525.  
  5526.     /**
  5527.      * Sets the day field of the date object
  5528.      *
  5529.      * If specified year forms an invalid date, then PEAR error will be
  5530.      * returned, unless the validation is over-ridden using the second
  5531.      * parameter.
  5532.      *
  5533.      * @param int  $d           the day
  5534.      * @param bool $pb_validate whether to check that the new date is valid
  5535.      *
  5536.      * @return   void 
  5537.      * @access   public
  5538.      * @see      Date::setDayMonthYear(), Date::setDateTime()
  5539.      */
  5540.     function setDay($d$pb_validate = DATE_VALIDATE_DATE_BY_DEFAULT)
  5541.     {
  5542.         if ($pb_validate && !Date_Calc::isValidDate($d$this->month$this->year)) {
  5543.             return PEAR::raiseError("'" .
  5544.                                     Date_Calc::dateFormat($d,
  5545.                                                           $this->month,
  5546.                                                           $this->year,
  5547.                                                           "%Y-%m-%d".
  5548.                                     "' is invalid calendar date",
  5549.                                     DATE_ERROR_INVALIDDATE);
  5550.         else {
  5551.             $this->setLocalTime($d,
  5552.                                 $this->month,
  5553.                                 $this->year,
  5554.                                 $this->hour,
  5555.                                 $this->minute,
  5556.                                 $this->second,
  5557.                                 $this->partsecond);
  5558.         }
  5559.     }
  5560.  
  5561.  
  5562.     // }}}
  5563.     // {{{ setDayMonthYear()
  5564.  
  5565.     /**
  5566.      * Sets the day, month and year fields of the date object
  5567.      *
  5568.      * If specified year forms an invalid date, then PEAR error will be
  5569.      * returned.  Note that setting each of these fields separately
  5570.      * may unintentionally return a PEAR error if a transitory date is
  5571.      * invalid between setting these fields.
  5572.      *
  5573.      * @param int $d the day
  5574.      * @param int $m the month
  5575.      * @param int $y the year
  5576.      *
  5577.      * @return   void 
  5578.      * @access   public
  5579.      * @see      Date::setDateTime()
  5580.      * @since    Method available since Release 1.5.0
  5581.      */
  5582.     function setDayMonthYear($d$m$y)
  5583.     {
  5584.         if (!Date_Calc::isValidDate($d$m$y)) {
  5585.             return PEAR::raiseError("'" .
  5586.                                     Date_Calc::dateFormat($d,
  5587.                                                           $m,
  5588.                                                           $y,
  5589.                                                           "%Y-%m-%d".
  5590.                                     "' is invalid calendar date",
  5591.                                     DATE_ERROR_INVALIDDATE);
  5592.         else {
  5593.             $this->setLocalTime($d,
  5594.                                 $m,
  5595.                                 $y,
  5596.                                 $this->hour,
  5597.                                 $this->minute,
  5598.                                 $this->second,
  5599.                                 $this->partsecond);
  5600.         }
  5601.     }
  5602.  
  5603.  
  5604.     // }}}
  5605.     // {{{ setHour()
  5606.  
  5607.     /**
  5608.      * Sets the hour field of the date object
  5609.      *
  5610.      * Expects an hour in 24-hour format.
  5611.      *
  5612.      * @param int  $h                      the hour
  5613.      * @param bool $pb_repeatedhourdefault whether to assume Summer time if a
  5614.      *                                       repeated hour is specified (defaults
  5615.      *                                       to false)
  5616.      *
  5617.      * @return   void 
  5618.      * @access   public
  5619.      * @see      Date::setHourMinuteSecond(), Date::setDateTime()
  5620.      */
  5621.     function setHour($h$pb_repeatedhourdefault = false)
  5622.     {
  5623.         if ($h > 23 || $h < 0{
  5624.             return PEAR::raiseError("Invalid hour value '$h'");
  5625.         else {
  5626.             $ret $this->setHourMinuteSecond($h,
  5627.                                               $this->minute,
  5628.                                               $this->partsecond == 0.0 ?
  5629.                                                   $this->second :
  5630.                                                   $this->second $this->partsecond,
  5631.                                               $pb_repeatedhourdefault);
  5632.  
  5633.             if (PEAR::isError($ret))
  5634.                 return $ret;
  5635.         }
  5636.     }
  5637.  
  5638.  
  5639.     // }}}
  5640.     // {{{ setMinute()
  5641.  
  5642.     /**
  5643.      * Sets the minute field of the date object
  5644.      *
  5645.      * @param int  $m                      the minute
  5646.      * @param bool $pb_repeatedhourdefault whether to assume Summer time if a
  5647.      *                                       repeated hour is specified (defaults
  5648.      *                                       to false)
  5649.      *
  5650.      * @return   void 
  5651.      * @access   public
  5652.      * @see      Date::setHourMinuteSecond(), Date::setDateTime()
  5653.      */
  5654.     function setMinute($m$pb_repeatedhourdefault = false)
  5655.     {
  5656.         if ($m > 59 || $m < 0{
  5657.             return PEAR::raiseError("Invalid minute value '$m'");
  5658.         else {
  5659.             $ret $this->setHourMinuteSecond($this->hour,
  5660.                                               $m,
  5661.                                               $this->partsecond == 0.0 ?
  5662.                                                   $this->second :
  5663.                                                   $this->second $this->partsecond,
  5664.                                               $pb_repeatedhourdefault);
  5665.  
  5666.             if (PEAR::isError($ret))
  5667.                 return $ret;
  5668.         }
  5669.     }
  5670.  
  5671.  
  5672.     // }}}
  5673.     // {{{ setSecond()
  5674.  
  5675.     /**
  5676.      * Sets the second field of the date object
  5677.      *
  5678.      * @param mixed $s                      the second as integer or float
  5679.      * @param bool  $pb_repeatedhourdefault whether to assume Summer time if a
  5680.      *                                        repeated hour is specified
  5681.      *                                        (defaults to false)
  5682.      *
  5683.      * @return   void 
  5684.      * @access   public
  5685.      * @see      Date::setHourMinuteSecond(), Date::setDateTime()
  5686.      */
  5687.     function setSecond($s$pb_repeatedhourdefault = false)
  5688.     {
  5689.         if ($s > 60 || // Leap seconds possible
  5690.             $s < 0{
  5691.             return PEAR::raiseError("Invalid second value '$s'");
  5692.         else {
  5693.             $ret $this->setHourMinuteSecond($this->hour,
  5694.                                               $this->minute,
  5695.                                               $s,
  5696.                                               $pb_repeatedhourdefault);
  5697.  
  5698.             if (PEAR::isError($ret))
  5699.                 return $ret;
  5700.         }
  5701.     }
  5702.  
  5703.  
  5704.     // }}}
  5705.     // {{{ setPartSecond()
  5706.  
  5707.     /**
  5708.      * Sets the part-second field of the date object
  5709.      *
  5710.      * @param float $pn_ps                  the part-second
  5711.      * @param bool  $pb_repeatedhourdefault whether to assume Summer time if a
  5712.      *                                       repeated hour is specified (defaults
  5713.      *                                       to false)
  5714.      *
  5715.      * @return   void 
  5716.      * @access   protected
  5717.      * @see      Date::setHourMinuteSecond(), Date::setDateTime()
  5718.      * @since    Method available since Release 1.5.0
  5719.      */
  5720.     function setPartSecond($pn_ps$pb_repeatedhourdefault = false)
  5721.     {
  5722.         if ($pn_ps >= 1 || $pn_ps < 0{
  5723.             return PEAR::raiseError("Invalid part-second value '$pn_ps'");
  5724.         else {
  5725.             $ret $this->setHourMinuteSecond($this->hour,
  5726.                                               $this->minute,
  5727.                                               $this->second $pn_ps,
  5728.                                               $pb_repeatedhourdefault);
  5729.  
  5730.             if (PEAR::isError($ret))
  5731.                 return $ret;
  5732.         }
  5733.     }
  5734.  
  5735.  
  5736.     // }}}
  5737.     // {{{ setHourMinuteSecond()
  5738.  
  5739.     /**
  5740.      * Sets the hour, minute, second and part-second fields of the date object
  5741.      *
  5742.      * N.B. if the repeated hour, due to the clocks going back, is specified,
  5743.      * the default is to assume local standard time.
  5744.      *
  5745.      * @param int   $h                      the hour
  5746.      * @param int   $m                      the minute
  5747.      * @param mixed $s                      the second as integer or float
  5748.      * @param bool  $pb_repeatedhourdefault whether to assume Summer time if a
  5749.      *                                        repeated hour is specified
  5750.      *                                        (defaults to false)
  5751.      *
  5752.      * @return   void 
  5753.      * @access   public
  5754.      * @see      Date::setDateTime()
  5755.      * @since    Method available since Release 1.5.0
  5756.      */
  5757.     function setHourMinuteSecond($h$m$s$pb_repeatedhourdefault = false)
  5758.     {
  5759.         // Split second into integer and part-second:
  5760.         //
  5761.         if (is_float($s)) {
  5762.             $hn_second     intval($s);
  5763.             $hn_partsecond $s $hn_second;
  5764.         else {
  5765.             $hn_second     = (int) $s;
  5766.             $hn_partsecond = 0.0;
  5767.         }
  5768.  
  5769.         $this->setLocalTime($this->day,
  5770.                             $this->month,
  5771.                             $this->year,
  5772.                             $h,
  5773.                             $m,
  5774.                             $hn_second,
  5775.                             $hn_partsecond,
  5776.                             $pb_repeatedhourdefault);
  5777.     }
  5778.  
  5779.  
  5780.     // }}}
  5781.     // {{{ setDateTime()
  5782.  
  5783.     /**
  5784.      * Sets all the fields of the date object (day, month, year, hour, minute
  5785.      * and second)
  5786.      *
  5787.      * If specified year forms an invalid date, then PEAR error will be
  5788.      * returned.  Note that setting each of these fields separately
  5789.      * may unintentionally return a PEAR error if a transitory date is
  5790.      * invalid between setting these fields.
  5791.      *
  5792.      * N.B. if the repeated hour, due to the clocks going back, is specified,
  5793.      * the default is to assume local standard time.
  5794.      *
  5795.      * @param int   $pn_day                 the day
  5796.      * @param int   $pn_month               the month
  5797.      * @param int   $pn_year                the year
  5798.      * @param int   $pn_hour                the hour
  5799.      * @param int   $pn_minute              the minute
  5800.      * @param mixed $pm_second              the second as integer or float
  5801.      * @param bool  $pb_repeatedhourdefault whether to assume Summer time if a
  5802.      *                                        repeated hour is specified
  5803.      *                                        (defaults to false)
  5804.      *
  5805.      * @return   void 
  5806.      * @access   public
  5807.      * @see      Date::setDayMonthYear(), Date::setHourMinuteSecond()
  5808.      * @since    Method available since Release 1.5.0
  5809.      */
  5810.     function setDateTime($pn_day,
  5811.                          $pn_month,
  5812.                          $pn_year,
  5813.                          $pn_hour,
  5814.                          $pn_minute,
  5815.                          $pm_second,
  5816.                          $pb_repeatedhourdefault = false)
  5817.     {
  5818.         if (!Date_Calc::isValidDate($d$m$y)) {
  5819.             return PEAR::raiseError("'" .
  5820.                                     Date_Calc::dateFormat($d,
  5821.                                                           $m,
  5822.                                                           $y,
  5823.                                                           "%Y-%m-%d".
  5824.                                     "' is invalid calendar date",
  5825.                                     DATE_ERROR_INVALIDDATE);
  5826.         else {
  5827.             // Split second into integer and part-second:
  5828.             //
  5829.             if (is_float($pm_second)) {
  5830.                 $hn_second     intval($pm_second);
  5831.                 $hn_partsecond $pm_second $hn_second;
  5832.             else {
  5833.                 $hn_second     = (int) $pm_second;
  5834.                 $hn_partsecond = 0.0;
  5835.             }
  5836.  
  5837.             $this->setLocalTime($d,
  5838.                                 $m,
  5839.                                 $y,
  5840.                                 $h,
  5841.                                 $m,
  5842.                                 $hn_second,
  5843.                                 $hn_partsecond,
  5844.                                 $pb_repeatedhourdefault);
  5845.         }
  5846.     }
  5847.  
  5848.  
  5849.     // }}}
  5850.  
  5851. }
  5852.  
  5853. // }}}
  5854.  
  5855. /*
  5856.  * Local variables:
  5857.  * mode: php
  5858.  * tab-width: 4
  5859.  * c-basic-offset: 4
  5860.  * c-hanging-comment-ender-p: nil
  5861.  * End:
  5862.  */
  5863. ?>

Documentation generated on Sun, 23 Mar 2008 20:00:29 -0400 by phpDocumentor 1.4.0. PEAR Logo Copyright © PHP Group 2004.