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

Source for file Calc.php

Documentation is available at Calc.php

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
  3.  
  4. // {{{ Header
  5.  
  6. /**
  7.  * Calculates, manipulates and retrieves dates
  8.  *
  9.  * It does not rely on 32-bit system time stamps, so it works dates
  10.  * before 1970 and after 2038.
  11.  *
  12.  * PHP versions 4 and 5
  13.  *
  14.  * LICENSE:
  15.  *
  16.  * Copyright (c) 1999-2007 Monte Ohrt, Pierre-Alain Joye, Daniel Convissor,
  17.  * C.A. Woodcock
  18.  * All rights reserved.
  19.  *
  20.  * Redistribution and use in source and binary forms, with or without
  21.  * modification, are permitted under the terms of the BSD License.
  22.  *
  23.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  24.  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  25.  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  26.  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  27.  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  28.  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  29.  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  30.  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  31.  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  33.  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  34.  * POSSIBILITY OF SUCH DAMAGE.
  35.  *
  36.  * @category   Date and Time
  37.  * @package    Date
  38.  * @author     Monte Ohrt <monte@ispi.net>
  39.  * @author     Pierre-Alain Joye <pajoye@php.net>
  40.  * @author     Daniel Convissor <danielc@php.net>
  41.  * @author     C.A. Woodcock <c01234@netcomuk.co.uk>
  42.  * @copyright  1999-2007 Monte Ohrt, Pierre-Alain Joye, Daniel Convissor, C.A. Woodcock
  43.  * @license    http://www.opensource.org/licenses/bsd-license.php
  44.  *              BSD License
  45.  * @version    CVS: $Id: Calc.php,v 1.57 2008/03/23 18:34:16 c01234 Exp $
  46.  * @link       http://pear.php.net/package/Date
  47.  * @since      File available since Release 1.2
  48.  */
  49.  
  50.  
  51. // }}}
  52. // {{{ General constants:
  53.  
  54. if (!defined('DATE_CALC_BEGIN_WEEKDAY')) {
  55.     /**
  56.      * Defines what day starts the week
  57.      *
  58.      * Monday (1) is the international standard.
  59.      * Redefine this to 0 if you want weeks to begin on Sunday.
  60.      */
  61.     define('DATE_CALC_BEGIN_WEEKDAY'1);
  62. }
  63.  
  64. if (!defined('DATE_CALC_FORMAT')) {
  65.     /**
  66.      * The default value for each method's $format parameter
  67.      *
  68.      * The default is '%Y%m%d'.  To override this default, define
  69.      * this constant before including Calc.php.
  70.      *
  71.      * @since Constant available since Release 1.4.4
  72.      */
  73.     define('DATE_CALC_FORMAT''%Y%m%d');
  74. }
  75.  
  76.  
  77. // {{{ Date precision constants (used in 'round()' and 'trunc()'):
  78.  
  79. define('DATE_PRECISION_YEAR'-2);
  80. define('DATE_PRECISION_MONTH'-1);
  81. define('DATE_PRECISION_DAY'0);
  82. define('DATE_PRECISION_HOUR'1);
  83. define('DATE_PRECISION_10MINUTES'2);
  84. define('DATE_PRECISION_MINUTE'3);
  85. define('DATE_PRECISION_10SECONDS'4);
  86. define('DATE_PRECISION_SECOND'5);
  87.  
  88.  
  89. // }}}
  90. // {{{ Class: Date_Calc
  91.  
  92. /**
  93.  * Calculates, manipulates and retrieves dates
  94.  *
  95.  * It does not rely on 32-bit system time stamps, so it works dates
  96.  * before 1970 and after 2038.
  97.  *
  98.  * @category  Date and Time
  99.  * @package   Date
  100.  * @author    Monte Ohrt <monte@ispi.net>
  101.  * @author    Daniel Convissor <danielc@php.net>
  102.  * @author    C.A. Woodcock <c01234@netcomuk.co.uk>
  103.  * @copyright 1999-2007 Monte Ohrt, Pierre-Alain Joye, Daniel Convissor, C.A. Woodcock
  104.  * @license   http://www.opensource.org/licenses/bsd-license.php
  105.  *             BSD License
  106.  * @version   Release: 1.5.0a1
  107.  * @link      http://pear.php.net/package/Date
  108.  * @since     Class available since Release 1.2
  109.  */
  110. class Date_Calc
  111. {
  112.  
  113.     // {{{ dateFormat()
  114.  
  115.     /**
  116.      * Formats the date in the given format, much like strfmt()
  117.      *
  118.      * This function is used to alleviate the problem with 32-bit numbers for
  119.      * dates pre 1970 or post 2038, as strfmt() has on most systems.
  120.      * Most of the formatting options are compatible.
  121.      *
  122.      * Formatting options:
  123.      * <pre>
  124.      * %a   abbreviated weekday name (Sun, Mon, Tue)
  125.      * %A   full weekday name (Sunday, Monday, Tuesday)
  126.      * %b   abbreviated month name (Jan, Feb, Mar)
  127.      * %B   full month name (January, February, March)
  128.      * %d   day of month (range 00 to 31)
  129.      * %e   day of month, single digit (range 0 to 31)
  130.      * %E   number of days since unspecified epoch (integer)
  131.      *        (%E is useful for passing a date in a URL as
  132.      *        an integer value. Then simply use
  133.      *        daysToDate() to convert back to a date.)
  134.      * %j   day of year (range 001 to 366)
  135.      * %m   month as decimal number (range 1 to 12)
  136.      * %n   newline character (\n)
  137.      * %t   tab character (\t)
  138.      * %w   weekday as decimal (0 = Sunday)
  139.      * %U   week number of current year, first sunday as first week
  140.      * %y   year as decimal (range 00 to 99)
  141.      * %Y   year as decimal including century (range 0000 to 9999)
  142.      * %%   literal '%'
  143.      * </pre>
  144.      *
  145.      * @param int    $day    the day of the month
  146.      * @param int    $month  the month
  147.      * @param int    $year   the year.  Use the complete year instead of the
  148.      *                         abbreviated version.  E.g. use 2005, not 05.
  149.      * @param string $format the format string
  150.      *
  151.      * @return   string     the date in the desired format
  152.      * @access   public
  153.      * @static
  154.      */
  155.     function dateFormat($day$month$year$format)
  156.     {
  157.         if (!Date_Calc::isValidDate($day$month$year)) {
  158.             $year  Date_Calc::dateNow('%Y');
  159.             $month Date_Calc::dateNow('%m');
  160.             $day   Date_Calc::dateNow('%d');
  161.         }
  162.  
  163.         $output '';
  164.  
  165.         for ($strpos = 0; $strpos strlen($format)$strpos++{
  166.             $char substr($format$strpos1);
  167.             if ($char == '%'{
  168.                 $nextchar substr($format$strpos + 11);
  169.                 switch($nextchar{
  170.                 case 'a':
  171.                     $output .= Date_Calc::getWeekdayAbbrname($day$month$year);
  172.                     break;
  173.                 case 'A':
  174.                     $output .= Date_Calc::getWeekdayFullname($day$month$year);
  175.                     break;
  176.                 case 'b':
  177.                     $output .= Date_Calc::getMonthAbbrname($month);
  178.                     break;
  179.                 case 'B':
  180.                     $output .= Date_Calc::getMonthFullname($month);
  181.                     break;
  182.                 case 'd':
  183.                     $output .= sprintf('%02d'$day);
  184.                     break;
  185.                 case 'e':
  186.                     $output .= $day;
  187.                     break;
  188.                 case 'E':
  189.                     $output .= Date_Calc::dateToDays($day$month$year);
  190.                     break;
  191.                 case 'j':
  192.                     $output .= Date_Calc::dayOfYear($day$month$year);
  193.                     break;
  194.                 case 'm':
  195.                     $output .= sprintf('%02d'$month);
  196.                     break;
  197.                 case 'n':
  198.                     $output .= "\n";
  199.                     break;
  200.                 case 't':
  201.                     $output .= "\t";
  202.                     break;
  203.                 case 'w':
  204.                     $output .= Date_Calc::dayOfWeek($day$month$year);
  205.                     break;
  206.                 case 'U':
  207.                     $output .= Date_Calc::weekOfYear($day$month$year);
  208.                     break;
  209.                 case 'y':
  210.                     $output .= sprintf('%0' .
  211.                                        ($year < 0 ? '3' '2'.
  212.                                        'd',
  213.                                        $year % 100);
  214.                     break;
  215.                 case "Y":
  216.                     $output .= sprintf('%0' .
  217.                                        ($year < 0 ? '5' '4'.
  218.                                        'd',
  219.                                        $year);
  220.                     break;
  221.                 case '%':
  222.                     $output .= '%';
  223.                     break;
  224.                 default:
  225.                     $output .= $char.$nextchar;
  226.                 }
  227.                 $strpos++;
  228.             else {
  229.                 $output .= $char;
  230.             }
  231.         }
  232.         return $output;
  233.     }
  234.  
  235.  
  236.     // }}}
  237.     // {{{ dateNow()
  238.  
  239.     /**
  240.      * Returns the current local date
  241.      *
  242.      * NOTE: This function retrieves the local date using strftime(),
  243.      * which may or may not be 32-bit safe on your system.
  244.      *
  245.      * @param string $format the string indicating how to format the output
  246.      *
  247.      * @return   string     the current date in the specified format
  248.      * @access   public
  249.      * @static
  250.      */
  251.     function dateNow($format = DATE_CALC_FORMAT)
  252.     {
  253.         return strftime($formattime());
  254.     }
  255.  
  256.  
  257.     // }}}
  258.     // {{{ getYear()
  259.  
  260.     /**
  261.      * Returns the current local year in format CCYY
  262.      *
  263.      * @return   string     the current year in four digit format
  264.      * @access   public
  265.      * @static
  266.      */
  267.     function getYear()
  268.     {
  269.         return Date_Calc::dateNow('%Y');
  270.     }
  271.  
  272.  
  273.     // }}}
  274.     // {{{ getMonth()
  275.  
  276.     /**
  277.      * Returns the current local month in format MM
  278.      *
  279.      * @return   string     the current month in two digit format
  280.      * @access   public
  281.      * @static
  282.      */
  283.     function getMonth()
  284.     {
  285.         return Date_Calc::dateNow('%m');
  286.     }
  287.  
  288.  
  289.     // }}}
  290.     // {{{ getDay()
  291.  
  292.     /**
  293.      * Returns the current local day in format DD
  294.      *
  295.      * @return   string     the current day of the month in two digit format
  296.      * @access   public
  297.      * @static
  298.      */
  299.     function getDay()
  300.     {
  301.         return Date_Calc::dateNow('%d');
  302.     }
  303.  
  304.  
  305.     // }}}
  306.     // {{{ defaultCentury()
  307.  
  308.     /**
  309.      * Turns a two digit year into a four digit year
  310.      *
  311.      * Return value depends on current year; the century chosen
  312.      * will be the one which forms the year that is closest
  313.      * to the current year.  If the two possibilities are
  314.      * equidistant to the current year (i.e. 50 years in the past
  315.      * and 50 years in the future), then the past year is chosen.
  316.      *
  317.      * For example, if the current year is 2007:
  318.      *  03 - returns 2003
  319.      *  09 - returns 2009
  320.      *  56 - returns 2056 (closer to 2007 than 1956)
  321.      *  57 - returns 1957 (1957 and 2007 are equidistant, so previous century
  322.      *        chosen)
  323.      *  58 - returns 1958
  324.      *
  325.      * @param int $year the 2 digit year
  326.      *
  327.      * @return   int        the 4 digit year
  328.      * @access   public
  329.      * @static
  330.      */
  331.     function defaultCentury($year)
  332.     {
  333.         $hn_century intval(($hn_currentyear date("Y")) / 100);
  334.         $hn_currentyear $hn_currentyear % 100;
  335.  
  336.         if ($year < 0 || $year >= 100
  337.             $year $year % 100;
  338.  
  339.         if ($year $hn_currentyear < -50)
  340.             return ($hn_century + 1* 100 + $year;
  341.         else if ($year $hn_currentyear < 50)
  342.             return $hn_century * 100 + $year;
  343.         else
  344.             return ($hn_century - 1* 100 + $year;
  345.     }
  346.  
  347.  
  348.     // }}}
  349.     // {{{ getSecondsInYear()
  350.  
  351.     /**
  352.      * Returns the total number of seconds in the given year
  353.      *
  354.      * This takes into account leap seconds.
  355.      *
  356.      * @param int $pn_year the year in four digit format
  357.      *
  358.      * @return   int 
  359.      * @access   public
  360.      * @static
  361.      * @since    Method available since Release 1.5.0
  362.      */
  363.     function getSecondsInYear($pn_year)
  364.     {
  365.         $pn_year intval($pn_year);
  366.  
  367.         static $ha_leapseconds;
  368.         if (!isset($ha_leapseconds)) {
  369.             $ha_leapseconds = array(1972 => 2,
  370.                                     1973 => 1,
  371.                                     1974 => 1,
  372.                                     1975 => 1,
  373.                                     1976 => 1,
  374.                                     1977 => 1,
  375.                                     1978 => 1,
  376.                                     1979 => 1,
  377.                                     1981 => 1,
  378.                                     1982 => 1,
  379.                                     1983 => 1,
  380.                                     1985 => 1,
  381.                                     1987 => 1,
  382.                                     1989 => 1,
  383.                                     1990 => 1,
  384.                                     1992 => 1,
  385.                                     1993 => 1,
  386.                                     1994 => 1,
  387.                                     1995 => 1,
  388.                                     1997 => 1,
  389.                                     1998 => 1,
  390.                                     2005 => 1);
  391.         }
  392.  
  393.         $ret Date_Calc::daysInYear($pn_year* 86400;
  394.  
  395.         if (isset($ha_leapseconds[$pn_year])) {
  396.             return $ret $ha_leapseconds[$pn_year];
  397.         else {
  398.             return $ret;
  399.         }
  400.     }
  401.  
  402.  
  403.     // }}}
  404.     // {{{ getSecondsInMonth()
  405.  
  406.     /**
  407.      * Returns the total number of seconds in the given month
  408.      *
  409.      * This takes into account leap seconds.
  410.      *
  411.      * @param int $pn_month the month
  412.      * @param int $pn_year  the year in four digit format
  413.      *
  414.      * @return   int 
  415.      * @access   public
  416.      * @static
  417.      * @since    Method available since Release 1.5.0
  418.      */
  419.     function getSecondsInMonth($pn_month$pn_year)
  420.     {
  421.         $pn_month intval($pn_month);
  422.         $pn_year  intval($pn_year);
  423.  
  424.         static $ha_leapseconds;
  425.         if (!isset($ha_leapseconds)) {
  426.             $ha_leapseconds = array(1972 => array(6  => 1,
  427.                                                   12 => 1),
  428.                                     1973 => array(12 => 1),
  429.                                     1974 => array(12 => 1),
  430.                                     1975 => array(12 => 1),
  431.                                     1976 => array(12 => 1),
  432.                                     1977 => array(12 => 1),
  433.                                     1978 => array(12 => 1),
  434.                                     1979 => array(12 => 1),
  435.                                     1981 => array(6  => 1),
  436.                                     1982 => array(6  => 1),
  437.                                     1983 => array(6  => 1),
  438.                                     1985 => array(6  => 1),
  439.                                     1987 => array(12 => 1),
  440.                                     1989 => array(12 => 1),
  441.                                     1990 => array(12 => 1),
  442.                                     1992 => array(6  => 1),
  443.                                     1993 => array(6  => 1),
  444.                                     1994 => array(6  => 1),
  445.                                     1995 => array(12 => 1),
  446.                                     1997 => array(6  => 1),
  447.                                     1998 => array(12 => 1),
  448.                                     2005 => array(12 => 1));
  449.         }
  450.  
  451.         $ret Date_Calc::daysInMonth($pn_month$pn_year* 86400;
  452.  
  453.         if (isset($ha_leapseconds[$pn_year][$pn_month])) {
  454.             return $ret $ha_leapseconds[$pn_year][$pn_month];
  455.         else {
  456.             return $ret;
  457.         }
  458.     }
  459.  
  460.  
  461.     // }}}
  462.     // {{{ getSecondsInDay()
  463.  
  464.     /**
  465.      * Returns the total number of seconds in the day of the given date
  466.      *
  467.      * This takes into account leap seconds.
  468.      *
  469.      * @param int $pn_day   the day of the month
  470.      * @param int $pn_month the month
  471.      * @param int $pn_year  the year in four digit format
  472.      *
  473.      * @return   int 
  474.      * @access   public
  475.      * @static
  476.      * @since    Method available since Release 1.5.0
  477.      */
  478.     function getSecondsInDay($pn_day$pn_month$pn_year)
  479.     {
  480.         // Note to developers:
  481.         //
  482.         // The leap seconds listed here are a matter of historical fact,
  483.         // that is, it is known on which exact day they occurred.
  484.         // However, the implementation of the class as a whole depends
  485.         // on the fact that they always occur at the end of the month
  486.         // (although it is assumed that they could occur in any month,
  487.         // even though practically they only occur in June or December).
  488.         //
  489.         // Do not define a leap second on a day of the month other than
  490.         // the last day without altering the implementation of the 
  491.         // functions that depend on this one.
  492.         //
  493.         // It is possible, though, to define an un-leap second (i.e. a skipped
  494.         // second (I do not know what they are called), or a number of
  495.         // consecutive leap seconds).
  496.  
  497.         $pn_day   intval($pn_day);
  498.         $pn_month intval($pn_month);
  499.         $pn_year  intval($pn_year);
  500.  
  501.         static $ha_leapseconds;
  502.         if (!isset($ha_leapseconds)) {
  503.             $ha_leapseconds = array(1972 => array(6  => array(30 => 1),
  504.                                                   12 => array(31 => 1)),
  505.                                     1973 => array(12 => array(31 => 1)),
  506.                                     1974 => array(12 => array(31 => 1)),
  507.                                     1975 => array(12 => array(31 => 1)),
  508.                                     1976 => array(12 => array(31 => 1)),
  509.                                     1977 => array(12 => array(31 => 1)),
  510.                                     1978 => array(12 => array(31 => 1)),
  511.                                     1979 => array(12 => array(31 => 1)),
  512.                                     1981 => array(6  => array(30 => 1)),
  513.                                     1982 => array(6  => array(30 => 1)),
  514.                                     1983 => array(6  => array(30 => 1)),
  515.                                     1985 => array(6  => array(30 => 1)),
  516.                                     1987 => array(12 => array(31 => 1)),
  517.                                     1989 => array(12 => array(31 => 1)),
  518.                                     1990 => array(12 => array(31 => 1)),
  519.                                     1992 => array(6  => array(30 => 1)),
  520.                                     1993 => array(6  => array(30 => 1)),
  521.                                     1994 => array(6  => array(30 => 1)),
  522.                                     1995 => array(12 => array(31 => 1)),
  523.                                     1997 => array(6  => array(30 => 1)),
  524.                                     1998 => array(12 => array(31 => 1)),
  525.                                     2005 => array(12 => array(31 => 1)));
  526.         }
  527.  
  528.         if (isset($ha_leapseconds[$pn_year][$pn_month][$pn_day])) {
  529.             return 86400 + $ha_leapseconds[$pn_year][$pn_month][$pn_day];
  530.         else {
  531.             return 86400;
  532.         }
  533.     }
  534.  
  535.  
  536.     // }}}
  537.     // {{{ getSecondsInHour()
  538.  
  539.     /**
  540.      * Returns the total number of seconds in the hour of the given date
  541.      *
  542.      * This takes into account leap seconds.
  543.      *
  544.      * @param int $pn_day   the day of the month
  545.      * @param int $pn_month the month
  546.      * @param int $pn_year  the year in four digit format
  547.      * @param int $pn_hour  the hour
  548.      *
  549.      * @return   int 
  550.      * @access   public
  551.      * @static
  552.      */
  553.     function getSecondsInHour($pn_day$pn_month$pn_year$pn_hour)
  554.     {
  555.         if ($pn_hour < 23)
  556.             return 3600;
  557.         else
  558.             return Date_Calc::getSecondsInDay($pn_day$pn_month$pn_year-
  559.                    82800;
  560.     }
  561.  
  562.  
  563.     // }}}
  564.     // {{{ getSecondsInMinute()
  565.  
  566.     /**
  567.      * Returns the total number of seconds in the minute of the given hour
  568.      *
  569.      * This takes into account leap seconds.
  570.      *
  571.      * @param int $pn_day    the day of the month
  572.      * @param int $pn_month  the month
  573.      * @param int $pn_year   the year in four digit format
  574.      * @param int $pn_hour   the hour
  575.      * @param int $pn_minute the minute
  576.      *
  577.      * @return   int 
  578.      * @access   public
  579.      * @static
  580.      * @since    Method available since Release 1.5.0
  581.      */
  582.     function getSecondsInMinute($pn_day,
  583.                                 $pn_month,
  584.                                 $pn_year,
  585.                                 $pn_hour,
  586.                                 $pn_minute)
  587.     {
  588.         if ($pn_hour < 23 || $pn_minute < 59)
  589.             return 60;
  590.         else
  591.             return Date_Calc::getSecondsInDay($pn_day$pn_month$pn_year-
  592.                    86340;
  593.     }
  594.  
  595.  
  596.     // }}}
  597.     // {{{ secondsPastMidnight()
  598.  
  599.     /**
  600.      * Returns the no of seconds since midnight (0-86399)
  601.      *
  602.      * @param int   $pn_hour   the hour of the day
  603.      * @param int   $pn_minute the minute
  604.      * @param mixed $pn_second the second as integer or float
  605.      *
  606.      * @return   mixed      integer or float from 0-86399
  607.      * @access   public
  608.      * @static
  609.      * @since    Method available since Release 1.5.0
  610.      */
  611.     function secondsPastMidnight($pn_hour$pn_minute$pn_second)
  612.     {
  613.         return 3600 * $pn_hour + 60 * $pn_minute $pn_second;
  614.     }
  615.  
  616.  
  617.     // }}}
  618.     // {{{ secondsPastMidnightToTime()
  619.  
  620.     /**
  621.      * Returns the time as an array (i.e. hour, minute, second)
  622.      *
  623.      * @param mixed $pn_seconds the no of seconds since midnight (0-86399)
  624.      *
  625.      * @return   mixed      array of hour, minute (both as integers), second (as
  626.      *                        integer or float, depending on parameter)
  627.      * @access   public
  628.      * @static
  629.      * @since    Method available since Release 1.5.0
  630.      */
  631.     function secondsPastMidnightToTime($pn_seconds)
  632.     {
  633.         if ($pn_seconds >= 86400{
  634.             return array(2359$pn_seconds - 86340);
  635.         }
  636.  
  637.         $hn_hour   intval($pn_seconds / 3600);
  638.         $hn_minute intval(($pn_seconds $hn_hour * 3600/ 60);
  639.         $hn_second is_float($pn_seconds?
  640.                      fmod($pn_seconds60:
  641.                      $pn_seconds % 60;
  642.  
  643.         return array($hn_hour$hn_minute$hn_second);
  644.     }
  645.  
  646.  
  647.     // }}}
  648.     // {{{ secondsPastTheHour()
  649.  
  650.     /**
  651.      * Returns the no of seconds since the last hour o'clock (0-3599)
  652.      *
  653.      * @param int   $pn_minute the minute
  654.      * @param mixed $pn_second the second as integer or float
  655.      *
  656.      * @return   mixed      integer or float from 0-3599
  657.      * @access   public
  658.      * @static
  659.      * @since    Method available since Release 1.5.0
  660.      */
  661.     function secondsPastTheHour($pn_minute$pn_second)
  662.     {
  663.         return 60 * $pn_minute $pn_second;
  664.     }
  665.  
  666.  
  667.     // }}}
  668.     // {{{ addHours()
  669.  
  670.     /**
  671.      * Returns the date the specified no of hours from the given date
  672.      *
  673.      * To subtract hours use a negative value for the '$pn_hours' parameter
  674.      *
  675.      * @param int $pn_hours hours to add
  676.      * @param int $pn_day   the day of the month
  677.      * @param int $pn_month the month
  678.      * @param int $pn_year  the year
  679.      * @param int $pn_hour  the hour
  680.      *
  681.      * @return   array      array of year, month, day, hour
  682.      * @access   public
  683.      * @static
  684.      * @since    Method available since Release 1.5.0
  685.      */
  686.     function addHours($pn_hours$pn_day$pn_month$pn_year$pn_hour)
  687.     {
  688.         if ($pn_hours == 0)
  689.             return array((int) $pn_year,
  690.                          (int) $pn_month,
  691.                          (int) $pn_day,
  692.                          (int) $pn_hour);
  693.  
  694.         $hn_days intval($pn_hours / 24);
  695.         $hn_hour $pn_hour $pn_hours % 24;
  696.  
  697.         if ($hn_hour >= 24{
  698.             ++$hn_days;
  699.             $hn_hour -= 24;
  700.         else if ($hn_hour < 0{
  701.             --$hn_days;
  702.             $hn_hour += 24;
  703.         }
  704.  
  705.         if ($hn_days == 0{
  706.             $hn_year  $pn_year;
  707.             $hn_month $pn_month;
  708.             $hn_day   $pn_day;
  709.         else {
  710.             list($hn_year$hn_month$hn_day=
  711.                 explode(" ",
  712.                         Date_Calc::addDays($hn_days,
  713.                                            $pn_day,
  714.                                            $pn_month,
  715.                                            $pn_year,
  716.                                            "%Y %m %d"));
  717.         }
  718.  
  719.         return array((int) $hn_year(int) $hn_month(int) $hn_day$hn_hour);
  720.     }
  721.  
  722.  
  723.     // }}}
  724.     // {{{ addMinutes()
  725.  
  726.     /**
  727.      * Returns the date the specified no of minutes from the given date
  728.      *
  729.      * To subtract minutes use a negative value for the '$pn_minutes' parameter
  730.      *
  731.      * @param int $pn_minutes minutes to add
  732.      * @param int $pn_day     the day of the month
  733.      * @param int $pn_month   the month
  734.      * @param int $pn_year    the year
  735.      * @param int $pn_hour    the hour
  736.      * @param int $pn_minute  the minute
  737.      *
  738.      * @return   array      array of year, month, day, hour, minute
  739.      * @access   public
  740.      * @static
  741.      * @since    Method available since Release 1.5.0
  742.      */
  743.     function addMinutes($pn_minutes,
  744.                         $pn_day,
  745.                         $pn_month,
  746.                         $pn_year,
  747.                         $pn_hour,
  748.                         $pn_minute)
  749.     {
  750.         if ($pn_minutes == 0)
  751.             return array((int) $pn_year,
  752.                          (int) $pn_month,
  753.                          (int) $pn_day,
  754.                          (int) $pn_hour,
  755.                          (int) $pn_minute);
  756.  
  757.         $hn_hours  intval($pn_minutes / 60);
  758.         $hn_minute $pn_minute $pn_minutes % 60;
  759.  
  760.         if ($hn_minute >= 60{
  761.             ++$hn_hours;
  762.             $hn_minute -= 60;
  763.         else if ($hn_minute < 0{
  764.             --$hn_hours;
  765.             $hn_minute += 60;
  766.         }
  767.  
  768.         if ($hn_hours == 0{
  769.             $hn_year  $pn_year;
  770.             $hn_month $pn_month;
  771.             $hn_day   $pn_day;
  772.             $hn_hour  $pn_hour;
  773.         else {
  774.             list($hn_year$hn_month$hn_day$hn_hour=
  775.                 Date_Calc::addHours($hn_hours,
  776.                                     $pn_day,
  777.                                     $pn_month,
  778.                                     $pn_year,
  779.                                     $pn_hour);
  780.         }
  781.  
  782.         return array($hn_year$hn_month$hn_day$hn_hour$hn_minute);
  783.     }
  784.  
  785.  
  786.     // }}}
  787.     // {{{ addSeconds()
  788.  
  789.     /**
  790.      * Returns the date the specified no of seconds from the given date
  791.      *
  792.      * If leap seconds are specified to be counted, the passed time must be UTC.
  793.      * To subtract seconds use a negative value for the '$pn_seconds' parameter.
  794.      *
  795.      * N.B. the return type of the second part of the date is float if
  796.      * either '$pn_seconds' or '$pn_second' is a float; otherwise, it
  797.      * is integer.
  798.      *
  799.      * @param mixed $pn_seconds   seconds to add as integer or float
  800.      * @param int   $pn_day       the day of the month
  801.      * @param int   $pn_month     the month
  802.      * @param int   $pn_year      the year
  803.      * @param int   $pn_hour      the hour
  804.      * @param int   $pn_minute    the minute
  805.      * @param mixed $pn_second    the second as integer or float
  806.      * @param bool  $pb_countleap whether to count leap seconds (defaults to
  807.      *                              DATE_COUNT_LEAP_SECONDS)
  808.      *
  809.      * @return   array      array of year, month, day, hour, minute, second
  810.      * @access   public
  811.      * @static
  812.      * @since    Method available since Release 1.5.0
  813.      */
  814.     function addSeconds($pn_seconds,
  815.                         $pn_day,
  816.                         $pn_month,
  817.                         $pn_year,
  818.                         $pn_hour,
  819.                         $pn_minute,
  820.                         $pn_second,
  821.                         $pb_countleap = DATE_COUNT_LEAP_SECONDS)
  822.     {
  823.         if ($pn_seconds == 0)
  824.             return array((int) $pn_year,
  825.                          (int) $pn_month,
  826.                          (int) $pn_day,
  827.                          (int) $pn_hour,
  828.                          (int) $pn_minute,
  829.                          $pn_second);
  830.  
  831.         if ($pb_countleap{
  832.             $hn_seconds $pn_seconds;
  833.  
  834.             $hn_day    = (int) $pn_day;
  835.             $hn_month  = (int) $pn_month;
  836.             $hn_year   = (int) $pn_year;
  837.             $hn_hour   = (int) $pn_hour;
  838.             $hn_minute = (int) $pn_minute;
  839.             $hn_second $pn_second;
  840.  
  841.             $hn_days Date_Calc::dateToDays($pn_day,
  842.                                              $pn_month,
  843.                                              $pn_year);
  844.             $hn_secondsofmonth = 86400 * ($hn_days -
  845.                                           Date_Calc::firstDayOfMonth($pn_month,
  846.                                                                      $pn_year)) +
  847.                                  Date_Calc::secondsPastMidnight($pn_hour,
  848.                                                                 $pn_minute,
  849.                                                                 $pn_second);
  850.  
  851.             if ($hn_seconds > 0{
  852.                 // Advance to end of month:
  853.                 //
  854.                 if ($hn_secondsofmonth != 0 &&
  855.                     $hn_secondsofmonth $hn_seconds >=
  856.                     ($hn_secondsinmonth =
  857.                          Date_Calc::getSecondsInMonth($hn_month$hn_year))) {
  858.  
  859.                     $hn_seconds       -= $hn_secondsinmonth $hn_secondsofmonth;
  860.                     $hn_secondsofmonth = 0;
  861.                     list($hn_year$hn_month=
  862.                         Date_Calc::nextMonth($hn_month$hn_year);
  863.                     $hn_day  Date_Calc::getFirstDayOfMonth($hn_month,
  864.                                                              $hn_year);
  865.                     $hn_hour $hn_minute $hn_second = 0;
  866.                 }
  867.  
  868.                 // Advance to end of year:
  869.                 //
  870.                 if ($hn_secondsofmonth == 0 &&
  871.                     $hn_month != Date_Calc::getFirstMonthOfYear($hn_year)) {
  872.  
  873.                     while ($hn_year == $pn_year &&
  874.                            $hn_seconds >= ($hn_secondsinmonth =
  875.                                Date_Calc::getSecondsInMonth($hn_month,
  876.                                                             $hn_year))) {
  877.                         $hn_seconds -= $hn_secondsinmonth;
  878.                         list($hn_year$hn_month=
  879.                             Date_Calc::nextMonth($hn_month$hn_year);
  880.                         $hn_day Date_Calc::getFirstDayOfMonth($hn_month,
  881.                                                                 $hn_year);
  882.                     }
  883.                 }
  884.  
  885.                 if ($hn_secondsofmonth == 0{
  886.                     // Add years:
  887.                     //
  888.                     if ($hn_month == Date_Calc::getFirstMonthOfYear($hn_year)) {
  889.                         while ($hn_seconds >= ($hn_secondsinyear =
  890.                                    Date_Calc::getSecondsInYear($hn_year))) {
  891.                             $hn_seconds -= $hn_secondsinyear;
  892.                             $hn_month    Date_Calc::getFirstMonthOfYear(++$hn_year);
  893.                             $hn_day      Date_Calc::getFirstDayOfMonth($hn_month,
  894.                                                                          $hn_year);
  895.                         }
  896.                     }
  897.  
  898.                     // Add months:
  899.                     //
  900.                     while ($hn_seconds >= ($hn_secondsinmonth =
  901.                                Date_Calc::getSecondsInMonth($hn_month$hn_year))) {
  902.                         $hn_seconds -= $hn_secondsinmonth;
  903.                         list($hn_year$hn_month=
  904.                             Date_Calc::nextMonth($hn_month$hn_year);
  905.                         $hn_day Date_Calc::getFirstDayOfMonth($hn_month$hn_year);
  906.                     }
  907.                 }
  908.             else {
  909.                 //
  910.                 // (if $hn_seconds < 0)
  911.  
  912.                 // Go back to start of month:
  913.                 //
  914.                 if ($hn_secondsofmonth != 0 &&
  915.                     -$hn_seconds >= $hn_secondsofmonth{
  916.  
  917.                     $hn_seconds       += $hn_secondsofmonth;
  918.                     $hn_secondsofmonth = 0;
  919.                     $hn_day            Date_Calc::getFirstDayOfMonth($hn_month,
  920.                                                                        $hn_year);
  921.                     $hn_hour           $hn_minute $hn_second = 0;
  922.                 }
  923.  
  924.                 // Go back to start of year:
  925.                 //
  926.                 if ($hn_secondsofmonth == 0{
  927.                     while ($hn_month !=
  928.                                Date_Calc::getFirstMonthOfYear($hn_year)) {
  929.  
  930.                         list($hn_year$hn_prevmonth=
  931.                             Date_Calc::prevMonth($hn_month$hn_year);
  932.  
  933.                         if (-$hn_seconds >= ($hn_secondsinmonth =
  934.                                 Date_Calc::getSecondsInMonth($hn_prevmonth,
  935.                                                              $hn_year))) {
  936.                             $hn_seconds += $hn_secondsinmonth;
  937.                             $hn_month    $hn_prevmonth;
  938.                             $hn_day      Date_Calc::getFirstDayOfMonth($hn_month,
  939.                                                                          $hn_year);
  940.                         else {
  941.                             break;
  942.                         }
  943.                     }
  944.                 }
  945.  
  946.                 if ($hn_secondsofmonth == 0{
  947.                     // Subtract years:
  948.                     //
  949.                     if ($hn_month == Date_Calc::getFirstMonthOfYear($hn_year)) {
  950.                         while (-$hn_seconds >= ($hn_secondsinyear =
  951.                                    Date_Calc::getSecondsInYear($hn_year - 1))) {
  952.                             $hn_seconds += $hn_secondsinyear;
  953.                             $hn_month    Date_Calc::getFirstMonthOfYear(--$hn_year);
  954.                             $hn_day      Date_Calc::getFirstDayOfMonth($hn_month,
  955.                                                                          $hn_year);
  956.                         }
  957.                     }
  958.  
  959.                     // Subtract months:
  960.                     //
  961.                     list($hn_pmyear$hn_prevmonth=
  962.                         Date_Calc::prevMonth($hn_month$hn_year);
  963.                     while (-$hn_seconds >= ($hn_secondsinmonth =
  964.                                Date_Calc::getSecondsInMonth($hn_prevmonth,
  965.                                                             $hn_pmyear))) {
  966.                         $hn_seconds += $hn_secondsinmonth;
  967.                         $hn_year     $hn_pmyear;
  968.                         $hn_month    $hn_prevmonth;
  969.                         $hn_day      Date_Calc::getFirstDayOfMonth($hn_month,
  970.                                                                      $hn_year);
  971.                         list($hn_pmyear$hn_prevmonth=
  972.                             Date_Calc::prevMonth($hn_month$hn_year);
  973.                     }
  974.                 }
  975.             }
  976.  
  977.             if ($hn_seconds < 0 && $hn_secondsofmonth == 0{
  978.                 list($hn_year$hn_month=
  979.                     Date_Calc::prevMonth($hn_month$hn_year);
  980.                 $hn_day Date_Calc::getFirstDayOfMonth($hn_month$hn_year);
  981.                 $hn_seconds += Date_Calc::getSecondsInMonth($hn_month$hn_year);
  982.             }
  983.  
  984.             $hn_seconds += Date_Calc::secondsPastMidnight($hn_hour,
  985.                                                           $hn_minute,
  986.                                                           $hn_second);
  987.             if ($hn_seconds < 0{
  988.                 $hn_daysadd intval($hn_seconds / 86400- 1;
  989.             else if ($hn_seconds < 86400{
  990.                 $hn_daysadd = 0;
  991.             else {
  992.                 $hn_daysadd intval($hn_seconds / 86400- 1;
  993.             }
  994.  
  995.             if ($hn_daysadd != 0{
  996.                 list($hn_year$hn_month$hn_day=
  997.                     explode(" ",
  998.                             Date_Calc::addDays($hn_daysadd,
  999.                                                $hn_day,
  1000.                                                $hn_month,
  1001.                                                $hn_year,
  1002.                                                "%Y %m %d"));
  1003.                 $hn_seconds -= $hn_daysadd * 86400;
  1004.             }
  1005.  
  1006.             $hn_secondsinday Date_Calc::getSecondsInDay($hn_day,
  1007.                                                           $hn_month,
  1008.                                                           $hn_year);
  1009.             if ($hn_seconds >= $hn_secondsinday{
  1010.                 list($hn_year$hn_month$hn_day=
  1011.                     explode(" ",
  1012.                             Date_Calc::addDays(1,
  1013.                                                $hn_day,
  1014.                                                $hn_month,
  1015.                                                $hn_year,
  1016.                                                "%Y %m %d"));
  1017.                 $hn_seconds -= $hn_secondsinday;
  1018.             }
  1019.  
  1020.             list($hn_hour$hn_minute$hn_second=
  1021.                 Date_Calc::secondsPastMidnightToTime($hn_seconds);
  1022.  
  1023.             return array((int) $hn_year,
  1024.                          (int) $hn_month,
  1025.                          (int) $hn_day,
  1026.                          $hn_hour,
  1027.                          $hn_minute,
  1028.                          $hn_second);
  1029.         else {
  1030.             // Assume every day has 86400 seconds exactly (ignore leap seconds):
  1031.             //
  1032.             $hn_minutes intval($pn_seconds / 60);
  1033.  
  1034.             if (is_float($pn_seconds)) {
  1035.                 $hn_second $pn_second fmod($pn_seconds60);
  1036.             else {
  1037.                 $hn_second $pn_second $pn_seconds % 60;
  1038.             }
  1039.  
  1040.             if ($hn_second >= 60{
  1041.                 ++$hn_minutes;
  1042.                 $hn_second -= 60;
  1043.             else if ($hn_second < 0{
  1044.                 --$hn_minutes;
  1045.                 $hn_second += 60;
  1046.             }
  1047.  
  1048.             if ($hn_minutes == 0{
  1049.                 $hn_year   $pn_year;
  1050.                 $hn_month  $pn_month;
  1051.                 $hn_day    $pn_day;
  1052.                 $hn_hour   $pn_hour;
  1053.                 $hn_minute $pn_minute;
  1054.             else {
  1055.                 list($hn_year$hn_month$hn_day$hn_hour$hn_minute=
  1056.                     Date_Calc::addMinutes($hn_minutes,
  1057.                                           $pn_day,
  1058.                                           $pn_month,
  1059.                                           $pn_year,
  1060.                                           $pn_hour,
  1061.                                           $pn_minute);
  1062.             }
  1063.  
  1064.             return array($hn_year,
  1065.                          $hn_month,
  1066.                          $hn_day,
  1067.                          $hn_hour,
  1068.                          $hn_minute,
  1069.                          $hn_second);
  1070.         }
  1071.     }
  1072.  
  1073.  
  1074.     // }}}
  1075.     // {{{ dateToDays()
  1076.  
  1077.     /**
  1078.      * Converts a date in the proleptic Gregorian calendar to the no of days
  1079.      * since 24th November, 4714 B.C.
  1080.      *
  1081.      * Returns the no of days since Monday, 24th November, 4714 B.C. in the
  1082.      * proleptic Gregorian calendar (which is 24th November, -4713 using
  1083.      * 'Astronomical' year numbering, and 1st January, 4713 B.C. in the
  1084.      * proleptic Julian calendar).  This is also the first day of the 'Julian
  1085.      * Period' proposed by Joseph Scaliger in 1583, and the number of days
  1086.      * since this date is known as the 'Julian Day'.  (It is not directly
  1087.      * to do with the Julian calendar, although this is where the name
  1088.      * is derived from.)
  1089.      *
  1090.      * The algorithm is valid for all years (positive and negative), and
  1091.      * also for years preceding 4714 B.C.
  1092.      *
  1093.      * @param int $day   the day of the month
  1094.      * @param int $month the month
  1095.      * @param int $year  the year (using 'Astronomical' year numbering)
  1096.      *
  1097.      * @return   int        the number of days since 24th November, 4714 B.C.
  1098.      * @access   public
  1099.      * @static
  1100.      */
  1101.     function dateToDays($day$month$year)
  1102.     {
  1103.         if ($month > 2{
  1104.             // March = 0, April = 1, ..., December = 9,
  1105.             // January = 10, February = 11
  1106.             $month -= 3;
  1107.         else {
  1108.             $month += 9;
  1109.             --$year;
  1110.         }
  1111.  
  1112.         $hb_negativeyear $year < 0;
  1113.         $century         intval($year / 100);
  1114.         $year            $year % 100;
  1115.  
  1116.         if ($hb_negativeyear{
  1117.             // Subtract 1 because year 0 is a leap year;
  1118.             // And N.B. that we must treat the leap years as occurring
  1119.             // one year earlier than they do, because for the purposes
  1120.             // of calculation, the year starts on 1st March:
  1121.             //
  1122.             return intval((14609700 * $century ($year == 0 ? 1 : 0)) / 400+
  1123.                    intval((1461 * $year + 1/ 4+
  1124.                    intval((153 * $month + 2/ 5+
  1125.                    $day + 1721118;
  1126.         else {
  1127.             return intval(146097 * $century / 4+
  1128.                    intval(1461 * $year / 4+
  1129.                    intval((153 * $month + 2/ 5+
  1130.                    $day + 1721119;
  1131.         }
  1132.     }
  1133.  
  1134.  
  1135.     // }}}
  1136.     // {{{ daysToDate()
  1137.  
  1138.     /**
  1139.      * Converts no of days since 24th November, 4714 B.C. (in the proleptic
  1140.      * Gregorian calendar, which is year -4713 using 'Astronomical' year
  1141.      * numbering) to Gregorian calendar date
  1142.      *
  1143.      * Returned date belongs to the proleptic Gregorian calendar, using
  1144.      * 'Astronomical' year numbering.
  1145.      *
  1146.      * The algorithm is valid for all years (positive and negative), and
  1147.      * also for years preceding 4714 B.C. (i.e. for negative 'Julian Days'),
  1148.      * and so the only limitation is platform-dependent (for 32-bit systems
  1149.      * the maximum year would be something like about 1,465,190 A.D.).
  1150.      *
  1151.      * N.B. Monday, 24th November, 4714 B.C. is Julian Day '0'.
  1152.      *
  1153.      * @param int    $days   the number of days since 24th November, 4714 B.C.
  1154.      * @param string $format the string indicating how to format the output
  1155.      *
  1156.      * @return   string     the date in the desired format
  1157.      * @access   public
  1158.      * @static
  1159.      */
  1160.     function daysToDate($days$format = DATE_CALC_FORMAT)
  1161.     {
  1162.         $days intval($days);
  1163.  
  1164.         $days   -= 1721119;
  1165.         $century floor((4 * $days - 1/ 146097);
  1166.         $days    floor(4 * $days - 1 - 146097 * $century);
  1167.         $day     floor($days / 4);
  1168.  
  1169.         $year floor((4 * $day +  3/ 1461);
  1170.         $day  floor(4 * $day +  3 - 1461 * $year);
  1171.         $day  floor(($day +  4/ 4);
  1172.  
  1173.         $month floor((5 * $day - 3/ 153);
  1174.         $day   floor(5 * $day - 3 - 153 * $month);
  1175.         $day   floor(($day +  5/  5);
  1176.  
  1177.         $year $century * 100 + $year;
  1178.         if ($month < 10{
  1179.             $month +=3;
  1180.         else {
  1181.             $month -=9;
  1182.             ++$year;
  1183.         }
  1184.  
  1185.         return Date_Calc::dateFormat($day$month$year$format);
  1186.     }
  1187.  
  1188.  
  1189.     // }}}
  1190.     // {{{ getMonths()
  1191.  
  1192.     /**
  1193.      * Returns array of the month numbers, in order, for the given year
  1194.      *
  1195.      * @param int $pn_year the year (using 'Astronomical' year numbering)
  1196.      *
  1197.      * @return   array      array of integer month numbers, in order
  1198.      * @access   public
  1199.      * @static
  1200.      * @since    Method available since Release 1.5.0
  1201.      */
  1202.     function getMonths($pn_year)
  1203.     {
  1204.         // N.B. Month numbers can be skipped but not duplicated:
  1205.         //
  1206.         return array(123456789101112);
  1207.     }
  1208.  
  1209.  
  1210.     // }}}
  1211.     // {{{ getMonthNames()
  1212.  
  1213.     /**
  1214.      * Returns an array of month names
  1215.      *
  1216.      * Used to take advantage of the setlocale function to return
  1217.      * language specific month names.
  1218.      *
  1219.      * TODO: cache values to some global array to avoid performance
  1220.      * hits when called more than once.
  1221.      *
  1222.      * @param int $pb_abbreviated whether to return the abbreviated form of the
  1223.      *                              months
  1224.      *
  1225.      * @return  array       associative array of integer month numbers, in
  1226.      *                        order, to month names
  1227.      * @access  public
  1228.      * @static
  1229.      */
  1230.     function getMonthNames($pb_abbreviated = false)
  1231.     {
  1232.         $ret = array();
  1233.         foreach (Date_Calc::getMonths(2001as $i{
  1234.             $ret[$istrftime($pb_abbreviated '%b' '%B',
  1235.                                 mktime(000$i12001));
  1236.         }
  1237.         return $ret;
  1238.     }
  1239.  
  1240.  
  1241.     // }}}
  1242.     // {{{ prevMonth()
  1243.  
  1244.     /**
  1245.      * Returns month and year of previous month
  1246.      *
  1247.      * @param int $pn_month the month
  1248.      * @param int $pn_year  the year (using 'Astronomical' year numbering)
  1249.      *
  1250.      * @return   array      array of year, month as integers
  1251.      * @access   public
  1252.      * @static
  1253.      * @since    Method available since Release 1.5.0
  1254.      */
  1255.     function prevMonth($pn_month$pn_year)
  1256.     {
  1257.         $ha_months   Date_Calc::getMonths($pn_year);
  1258.         $hn_monthkey array_search($pn_month$ha_months);
  1259.         if (array_key_exists($hn_monthkey - 1$ha_months)) {
  1260.             return array((int) $pn_year$ha_months[$hn_monthkey - 1]);
  1261.         else {
  1262.             $ha_months Date_Calc::getMonths($pn_year - 1);
  1263.             return array($pn_year - 1end($ha_months));
  1264.         }
  1265.     }
  1266.  
  1267.  
  1268.     // }}}
  1269.     // {{{ nextMonth()
  1270.  
  1271.     /**
  1272.      * Returns month and year of next month
  1273.      *
  1274.      * @param int $pn_month the month
  1275.      * @param int $pn_year  the year (using 'Astronomical' year numbering)
  1276.      *
  1277.      * @return   array      array of year, month as integers
  1278.      * @access   public
  1279.      * @static
  1280.      * @since    Method available since Release 1.5.0
  1281.      */
  1282.     function nextMonth($pn_month$pn_year)
  1283.     {
  1284.         $ha_months   Date_Calc::getMonths($pn_year);
  1285.         $hn_monthkey array_search($pn_month$ha_months);
  1286.         if (array_key_exists($hn_monthkey + 1$ha_months)) {
  1287.             return array((int) $pn_year$ha_months[$hn_monthkey + 1]);
  1288.         else {
  1289.             $ha_months Date_Calc::getMonths($pn_year + 1);
  1290.             return array($pn_year + 1$ha_months[0]);
  1291.         }
  1292.     }
  1293.  
  1294.  
  1295.     // }}}
  1296.     // {{{ addMonthsToDays()
  1297.  
  1298.     /**
  1299.      * Returns 'Julian Day' of the date the specified no of months
  1300.      * from the given date
  1301.      *
  1302.      * To subtract months use a negative value for the '$pn_months'
  1303.      * parameter
  1304.      *
  1305.      * @param int $pn_months months to add
  1306.      * @param int $pn_days   'Julian Day', i.e. the no of days since 1st
  1307.      *                         January, 4713 B.C.
  1308.      *
  1309.      * @return   int        'Julian Day', i.e. the no of days since 1st January,
  1310.      *                        4713 B.C.
  1311.      * @access   public
  1312.      * @static
  1313.      * @since    Method available since Release 1.5.0
  1314.      */
  1315.     function addMonthsToDays($pn_months$pn_days)
  1316.     {
  1317.         if ($pn_months == 0)
  1318.             return (int) $pn_days;
  1319.  
  1320.         list($hn_year$hn_month$hn_day=
  1321.             explode(" "Date_Calc::daysToDate($pn_days"%Y %m %d"));
  1322.  
  1323.         $hn_retmonth $hn_month $pn_months % 12;
  1324.         $hn_retyear  $hn_year intval($pn_months / 12);
  1325.         if ($hn_retmonth < 1{
  1326.             $hn_retmonth += 12;
  1327.             --$hn_retyear;
  1328.         else if ($hn_retmonth > 12{
  1329.             $hn_retmonth -= 12;
  1330.             ++$hn_retyear;
  1331.         }
  1332.  
  1333.         if (Date_Calc::isValidDate($hn_day$hn_retmonth$hn_retyear))
  1334.             return Date_Calc::dateToDays($hn_day$hn_retmonth$hn_retyear);
  1335.  
  1336.         // Calculate days since first of month:
  1337.         //
  1338.         $hn_dayoffset $pn_days -
  1339.                         Date_Calc::firstDayOfMonth($hn_month$hn_year);
  1340.  
  1341.         $hn_retmonthfirstday Date_Calc::firstDayOfMonth($hn_retmonth,
  1342.                                                           $hn_retyear);
  1343.         $hn_retmonthlastday  Date_Calc::lastDayOfMonth($hn_retmonth,
  1344.                                                          $hn_retyear);
  1345.  
  1346.         if ($hn_dayoffset $hn_retmonthlastday $hn_retmonthfirstday{
  1347.             return $hn_retmonthlastday;
  1348.         else {
  1349.             return $hn_retmonthfirstday $hn_dayoffset;
  1350.         }
  1351.     }
  1352.  
  1353.  
  1354.     // }}}
  1355.     // {{{ addMonths()
  1356.  
  1357.     /**
  1358.      * Returns the date the specified no of months from the given date
  1359.      *
  1360.      * To subtract months use a negative value for the '$pn_months'
  1361.      * parameter
  1362.      *
  1363.      * @param int    $pn_months months to add
  1364.      * @param int    $pn_day    the day of the month, default is current local
  1365.      *                            day
  1366.      * @param int    $pn_month  the month, default is current local month
  1367.      * @param int    $pn_year   the year in four digit format, default is
  1368.      *                            current local year
  1369.      * @param string $ps_format string specifying how to format the output
  1370.      *
  1371.      * @return   string     the date in the desired format
  1372.      * @access   public
  1373.      * @static
  1374.      * @since    Method available since Release 1.5.0
  1375.      */
  1376.     function addMonths($pn_months,
  1377.                        $pn_day,
  1378.                        $pn_month,
  1379.                        $pn_year,
  1380.                        $ps_format = DATE_CALC_FORMAT)
  1381.     {
  1382.         if (is_null($pn_year)) {
  1383.             $pn_year Date_Calc::dateNow('%Y');
  1384.         }
  1385.         if (empty($pn_month)) {
  1386.             $pn_month Date_Calc::dateNow('%m');
  1387.         }
  1388.         if (empty($pn_day)) {
  1389.             $pn_day Date_Calc::dateNow('%d');
  1390.         }
  1391.  
  1392.         if ($pn_months == 0)
  1393.             return Date_Calc::dateFormat($pn_day,
  1394.                                          $pn_month,
  1395.                                          $pn_year,
  1396.                                          $ps_format);
  1397.  
  1398.         $hn_days Date_Calc::dateToDays($pn_day$pn_month$pn_year);
  1399.         return Date_Calc::daysToDate(Date_Calc::addMonthsToDays($pn_months,
  1400.                                                                 $hn_days),
  1401.                                      $ps_format);
  1402.     }
  1403.  
  1404.  
  1405.     // }}}
  1406.     // {{{ addYearsToDays()
  1407.  
  1408.     /**
  1409.      * Returns 'Julian Day' of the date the specified no of years
  1410.      * from the given date
  1411.      *
  1412.      * To subtract years use a negative value for the '$pn_years'
  1413.      * parameter
  1414.      *
  1415.      * @param int $pn_years years to add
  1416.      * @param int $pn_days  'Julian Day', i.e. the no of days since 1st January,
  1417.      *                        4713 B.C.
  1418.      *
  1419.      * @return   int        'Julian Day', i.e. the no of days since 1st January,
  1420.      *                        4713 B.C.
  1421.      * @access   public
  1422.      * @static
  1423.      * @since    Method available since Release 1.5.0
  1424.      */
  1425.     function addYearsToDays($pn_years$pn_days)
  1426.     {
  1427.         if ($pn_years == 0)
  1428.             return (int) $pn_days;
  1429.  
  1430.         list($hn_year$hn_month$hn_day=
  1431.             explode(" "Date_Calc::daysToDate($pn_days"%Y %m %d"));
  1432.  
  1433.         $hn_retyear $hn_year $pn_years;
  1434.         if (Date_Calc::isValidDate($hn_day$hn_month$hn_retyear))
  1435.             return Date_Calc::dateToDays($hn_day$hn_month$hn_retyear);
  1436.  
  1437.         $ha_months Date_Calc::getMonths($hn_retyear);
  1438.         if (in_array($hn_month$ha_months)) {
  1439.             $hn_retmonth $hn_month;
  1440.  
  1441.             // Calculate days since first of month:
  1442.             //
  1443.             $hn_dayoffset $pn_days Date_Calc::firstDayOfMonth($hn_month,
  1444.                                                                   $hn_year);
  1445.  
  1446.             $hn_retmonthfirstday Date_Calc::firstDayOfMonth($hn_retmonth,
  1447.                                                               $hn_retyear);
  1448.             $hn_retmonthlastday  Date_Calc::lastDayOfMonth($hn_retmonth,
  1449.                                                              $hn_retyear);
  1450.  
  1451.             if ($hn_dayoffset $hn_retmonthlastday $hn_retmonthfirstday{
  1452.                 return $hn_retmonthlastday;
  1453.             else {
  1454.                 return $hn_retmonthfirstday $hn_dayoffset;
  1455.             }
  1456.         else {
  1457.             // Calculate days since first of year:
  1458.             //
  1459.             $hn_dayoffset $pn_days Date_Calc::firstDayOfYear($hn_year);
  1460.  
  1461.             $hn_retyearfirstday Date_Calc::firstDayOfYear($hn_retyear);
  1462.             $hn_retyearlastday  Date_Calc::lastDayOfYear($hn_retyear);
  1463.  
  1464.             if ($hn_dayoffset $hn_retyearlastday $hn_retyearfirstday{
  1465.                 return $hn_retyearlastday;
  1466.             else {
  1467.                 return $hn_retyearfirstday $hn_dayoffset;
  1468.             }
  1469.         }
  1470.     }
  1471.  
  1472.  
  1473.     // }}}
  1474.     // {{{ addYears()
  1475.  
  1476.     /**
  1477.      * Returns the date the specified no of years from the given date
  1478.      *
  1479.      * To subtract years use a negative value for the '$pn_years'
  1480.      * parameter
  1481.      *
  1482.      * @param int    $pn_years  years to add
  1483.      * @param int    $pn_day    the day of the month, default is current local
  1484.      *                            day
  1485.      * @param int    $pn_month  the month, default is current local month
  1486.      * @param int    $pn_year   the year in four digit format, default is
  1487.      *                            current local year
  1488.      * @param string $ps_format string specifying how to format the output
  1489.      *
  1490.      * @return   string     the date in the desired format
  1491.      * @access   public
  1492.      * @static
  1493.      * @since    Method available since Release 1.5.0
  1494.      */
  1495.     function addYears($pn_years,
  1496.                       $pn_day,
  1497.                       $pn_month,
  1498.                       $pn_year,
  1499.                       $ps_format = DATE_CALC_FORMAT)
  1500.     {
  1501.         if (is_null($pn_year)) {
  1502.             $pn_year Date_Calc::dateNow('%Y');
  1503.         }
  1504.         if (empty($pn_month)) {
  1505.             $pn_month Date_Calc::dateNow('%m');
  1506.         }
  1507.         if (empty($pn_day)) {
  1508.             $pn_day Date_Calc::dateNow('%d');
  1509.         }
  1510.  
  1511.         if ($pn_years == 0)
  1512.             return Date_Calc::dateFormat($pn_day,
  1513.                                          $pn_month,
  1514.                                          $pn_year,
  1515.                                          $ps_format);
  1516.  
  1517.         $hn_days Date_Calc::dateToDays($pn_day$pn_month$pn_year);
  1518.         return Date_Calc::daysToDate(Date_Calc::addYearsToDays($pn_years,
  1519.                                                                $hn_days),
  1520.                                      $ps_format);
  1521.     }
  1522.  
  1523.  
  1524.     // }}}
  1525.     // {{{ addDays()
  1526.  
  1527.     /**
  1528.      * Returns the date the specified no of days from the given date
  1529.      *
  1530.      * To subtract days use a negative value for the '$pn_days' parameter
  1531.      *
  1532.      * @param int    $pn_days   days to add
  1533.      * @param int    $pn_day    the day of the month, default is current local
  1534.      *                            day
  1535.      * @param int    $pn_month  the month, default is current local month
  1536.      * @param int    $pn_year   the year in four digit format, default is
  1537.      *                            current local year
  1538.      * @param string $ps_format string specifying how to format the output
  1539.      *
  1540.      * @return   string     the date in the desired format
  1541.      * @access   public
  1542.      * @static
  1543.      * @since    Method available since Release 1.5.0
  1544.      */
  1545.     function addDays($pn_days,
  1546.                      $pn_day,
  1547.                      $pn_month,
  1548.                      $pn_year,
  1549.                      $ps_format = DATE_CALC_FORMAT)
  1550.     {
  1551.         if (is_null($pn_year)) {
  1552.             $pn_year Date_Calc::dateNow('%Y');
  1553.         }
  1554.         if (empty($pn_month)) {
  1555.             $pn_month Date_Calc::dateNow('%m');
  1556.         }
  1557.         if (empty($pn_day)) {
  1558.             $pn_day Date_Calc::dateNow('%d');
  1559.         }
  1560.  
  1561.         if ($pn_days == 0)
  1562.             return Date_Calc::dateFormat($pn_day,
  1563.                                          $pn_month,
  1564.                                          $pn_year,
  1565.                                          $ps_format);
  1566.  
  1567.         return Date_Calc::daysToDate(Date_Calc::dateToDays($pn_day,
  1568.                                                            $pn_month,
  1569.                                                            $pn_year+
  1570.                                      $pn_days,
  1571.                                      $ps_format);
  1572.     }
  1573.  
  1574.  
  1575.     // }}}
  1576.     // {{{ getFirstDayOfMonth()
  1577.  
  1578.     /**
  1579.      * Returns first day of the specified month of specified year as integer
  1580.      *
  1581.      * @param int $pn_month the month
  1582.      * @param int $pn_year  the year (using 'Astronomical' year numbering)
  1583.      *
  1584.      * @return   int        number of first day of month
  1585.      * @access   public
  1586.      * @static
  1587.      * @since    Method available since Release 1.5.0
  1588.      */
  1589.     function getFirstDayOfMonth($pn_month$pn_year)
  1590.     {
  1591.         return 1;
  1592.     }
  1593.  
  1594.  
  1595.     // }}}
  1596.     // {{{ getLastDayOfMonth()
  1597.  
  1598.     /**
  1599.      * Returns last day of the specified month of specified year as integer
  1600.      *
  1601.      * @param int $pn_month the month
  1602.      * @param int $pn_year  the year (using 'Astronomical' year numbering)
  1603.      *
  1604.      * @return   int        number of last day of month
  1605.      * @access   public
  1606.      * @static
  1607.      * @since    Method available since Release 1.5.0
  1608.      */
  1609.     function getLastDayOfMonth($pn_month$pn_year)
  1610.     {
  1611.         return Date_Calc::daysInMonth($pn_month$pn_year);
  1612.     }
  1613.  
  1614.  
  1615.     // }}}
  1616.     // {{{ firstDayOfMonth()
  1617.  
  1618.     /**
  1619.      * Returns the Julian Day of the first day of the month of the specified
  1620.      * year (i.e. the no of days since 24th November, 4714 B.C.)
  1621.      *
  1622.      * @param int $pn_month the month
  1623.      * @param int $pn_year  the year (using 'Astronomical' year numbering)
  1624.      *
  1625.      * @return   integer    the number of days since 24th November, 4714 B.C.
  1626.      * @access   public
  1627.      * @static
  1628.      * @since    Method available since Release 1.5.0
  1629.      */
  1630.     function firstDayOfMonth($pn_month$pn_year)
  1631.     {
  1632.         return Date_Calc::dateToDays(Date_Calc::getFirstDayOfMonth($pn_month,
  1633.                                                                    $pn_year),
  1634.                                      $pn_month,
  1635.                                      $pn_year);
  1636.     }
  1637.  
  1638.  
  1639.     // }}}
  1640.     // {{{ lastDayOfMonth()
  1641.  
  1642.     /**
  1643.      * Returns the Julian Day of the last day of the month of the specified
  1644.      * year (i.e. the no of days since 24th November, 4714 B.C.)
  1645.      *
  1646.      * @param int $pn_month the month
  1647.      * @param int $pn_year  the year (using 'Astronomical' year numbering)
  1648.      *
  1649.      * @return   integer    the number of days since 24th November, 4714 B.C.
  1650.      * @access   public
  1651.      * @static
  1652.      * @since    Method available since Release 1.5.0
  1653.      */
  1654.     function lastDayOfMonth($pn_month$pn_year)
  1655.     {
  1656.         list($hn_nmyear$hn_nextmonthDate_Calc::nextMonth($pn_month,
  1657.                                                                $pn_year);
  1658.         return Date_Calc::firstDayOfMonth($hn_nextmonth$hn_nmyear- 1;
  1659.     }
  1660.  
  1661.  
  1662.     // }}}
  1663.     // {{{ getFirstMonthOfYear()
  1664.  
  1665.     /**
  1666.      * Returns first month of specified year as integer
  1667.      *
  1668.      * @param int $pn_year the year (using 'Astronomical' year numbering)
  1669.      *
  1670.      * @return   int        number of first month of year
  1671.      * @access   public
  1672.      * @static
  1673.      * @since    Method available since Release 1.5.0
  1674.      */
  1675.     function getFirstMonthOfYear($pn_year)
  1676.     {
  1677.         $ha_months Date_Calc::getMonths($pn_year);
  1678.         return $ha_months[0];
  1679.     }
  1680.  
  1681.  
  1682.     // }}}
  1683.     // {{{ firstDayOfYear()
  1684.  
  1685.     /**
  1686.      * Returns the Julian Day of the first day of the year (i.e. the no of
  1687.      * days since 24th November, 4714 B.C.)
  1688.      *
  1689.      * @param int $pn_year the year (using 'Astronomical' year numbering)
  1690.      *
  1691.      * @return   integer    the number of days since 24th November, 4714 B.C.
  1692.      * @access   public
  1693.      * @static
  1694.      * @since    Method available since Release 1.5.0
  1695.      */
  1696.     function firstDayOfYear($pn_year)
  1697.     {
  1698.         return Date_Calc::firstDayOfMonth(Date_Calc::getFirstMonthOfYear($pn_year),
  1699.                                           $pn_year);
  1700.     }
  1701.  
  1702.  
  1703.     // }}}
  1704.     // {{{ lastDayOfYear()
  1705.  
  1706.     /**
  1707.      * Returns the Julian Day of the last day of the year (i.e. the no of
  1708.      * days since 24th November, 4714 B.C.)
  1709.      *
  1710.      * @param int $pn_year the year (using 'Astronomical' year numbering)
  1711.      *
  1712.      * @return   integer    the number of days since 24th November, 4714 B.C.
  1713.      * @access   public
  1714.      * @static
  1715.      * @since    Method available since Release 1.5.0
  1716.      */
  1717.     function lastDayOfYear($pn_year)
  1718.     {
  1719.         return Date_Calc::firstDayOfYear($pn_year + 1- 1;
  1720.     }
  1721.  
  1722.  
  1723.     // }}}
  1724.     // {{{ dateToDaysJulian()
  1725.  
  1726.     /**
  1727.      * Converts a date in the proleptic Julian calendar to the no of days
  1728.      * since 1st January, 4713 B.C.
  1729.      *
  1730.      * Returns the no of days since Monday, 1st January, 4713 B.C. in the
  1731.      * proleptic Julian calendar (which is 1st January, -4712 using
  1732.      * 'Astronomical' year numbering, and 24th November, 4713 B.C. in the
  1733.      * proleptic Gregorian calendar).  This is also the first day of the 'Julian
  1734.      * Period' proposed by Joseph Scaliger in 1583, and the number of days
  1735.      * since this date is known as the 'Julian Day'.  (It is not directly
  1736.      * to do with the Julian calendar, although this is where the name
  1737.      * is derived from.)
  1738.      *
  1739.      * The algorithm is valid for all years (positive and negative), and
  1740.      * also for years preceding 4713 B.C.
  1741.      *
  1742.      * @param int $day   the day of the month
  1743.      * @param int $month the month
  1744.      * @param int $year  the year (using 'Astronomical' year numbering)
  1745.      *
  1746.      * @return   int        the number of days since 1st January, 4713 B.C.
  1747.      * @access   public
  1748.      * @static
  1749.      * @since    Method available since Release 1.5.0
  1750.      */
  1751.     function dateToDaysJulian($day$month$year)
  1752.     {
  1753.         if ($month > 2{
  1754.             // March = 0, April = 1, ..., December = 9,
  1755.             // January = 10, February = 11
  1756.             $month -= 3;
  1757.         else {
  1758.             $month += 9;
  1759.             --$year;
  1760.         }
  1761.  
  1762.         $hb_negativeyear $year < 0;
  1763.  
  1764.         if ($hb_negativeyear{
  1765.             // Subtract 1 because year 0 is a leap year;
  1766.             // And N.B. that we must treat the leap years as occurring
  1767.             // one year earlier than they do, because for the purposes
  1768.             // of calculation, the year starts on 1st March:
  1769.             //
  1770.             return intval((1461 * $year + 1/ 4+
  1771.                    intval((153 * $month + 2/ 5+
  1772.                    $day + 1721116;
  1773.         else {
  1774.             return intval(1461 * $year / 4+
  1775.                    floor((153 * $month + 2/ 5+
  1776.                    $day + 1721117;
  1777.         }
  1778.     }
  1779.  
  1780.  
  1781.     // }}}
  1782.     // {{{ daysToDateJulian()
  1783.  
  1784.     /**
  1785.      * Converts no of days since 1st January, 4713 B.C. (in the proleptic
  1786.      * Julian calendar, which is year -4712 using 'Astronomical' year
  1787.      * numbering) to Julian calendar date
  1788.      *
  1789.      * Returned date belongs to the proleptic Julian calendar, using
  1790.      * 'Astronomical' year numbering.
  1791.      *
  1792.      * @param int    $days   the number of days since 1st January, 4713 B.C.
  1793.      * @param string $format the string indicating how to format the output
  1794.      *
  1795.      * @return   string     the date in the desired format
  1796.      * @access   public
  1797.      * @static
  1798.      * @since    Method available since Release 1.5.0
  1799.      */
  1800.     function daysToDateJulian($days$format = DATE_CALC_FORMAT)
  1801.     {
  1802.         $days intval($days);
  1803.  
  1804.         $days -= 1721117;
  1805.         $days  floor(4 * $days - 1);
  1806.         $day   floor($days / 4);
  1807.  
  1808.         $year floor((4 * $day +  3/ 1461);
  1809.         $day  floor(4 * $day +  3 - 1461 * $year);
  1810.         $day  floor(($day +  4/ 4);
  1811.  
  1812.         $month floor((5 * $day - 3/ 153);
  1813.         $day   floor(5 * $day - 3 - 153 * $month);
  1814.         $day   floor(($day +  5/  5);
  1815.  
  1816.         if ($month < 10{
  1817.             $month +=3;
  1818.         else {
  1819.             $month -=9;
  1820.             ++$year;
  1821.         }
  1822.  
  1823.         return Date_Calc::dateFormat($day$month$year$format);
  1824.     }
  1825.  
  1826.  
  1827.     // }}}
  1828.     // {{{ isoWeekDate()
  1829.  
  1830.     /**
  1831.      * Returns array defining the 'ISO Week Date' as defined in ISO 8601
  1832.      *
  1833.      * Expects a date in the proleptic Gregorian calendar using 'Astronomical'
  1834.      * year numbering, that is, with a year 0.  Algorithm is valid for all
  1835.      * years (positive and negative).
  1836.      *
  1837.      * N.B. the ISO week day no for Sunday is defined as 7, whereas this
  1838.      * class and its related functions defines Sunday as 0.
  1839.      *
  1840.      * @param int $pn_day   the day of the month
  1841.      * @param int $pn_month the month
  1842.      * @param int $pn_year  the year
  1843.      *
  1844.      * @return   array      array of ISO Year, ISO Week No, ISO Day No as
  1845.      *                        integers
  1846.      * @access   public
  1847.      * @static
  1848.      * @since    Method available since Release 1.5.0
  1849.      */
  1850.     function isoWeekDate($pn_day = 0$pn_month = 0$pn_year = null)
  1851.     {
  1852.         if (is_null($pn_year)) {
  1853.             $pn_year Date_Calc::dateNow('%Y');
  1854.         }
  1855.         if (empty($pn_month)) {
  1856.             $pn_month Date_Calc::dateNow('%m');
  1857.         }
  1858.         if (empty($pn_day)) {
  1859.             $pn_day Date_Calc::dateNow('%d');
  1860.         }
  1861.  
  1862.         $hn_jd Date_Calc::dateToDays($pn_day$pn_month$pn_year);
  1863.         $hn_wd Date_Calc::daysToDayOfWeek($hn_jd);
  1864.         if ($hn_wd == 0)
  1865.             $hn_wd = 7;
  1866.  
  1867.         $hn_jd1 Date_Calc::firstDayOfYear($pn_year);
  1868.         $hn_day $hn_jd $hn_jd1 + 1;
  1869.  
  1870.         if ($hn_wd <= $hn_jd Date_Calc::lastDayOfYear($pn_year+ 3{
  1871.             // ISO week is the first week of the next ISO year:
  1872.             //
  1873.             $hn_year    $pn_year + 1;
  1874.             $hn_isoweek = 1;
  1875.         else {
  1876.             switch ($hn_wd1 Date_Calc::daysToDayOfWeek($hn_jd1)) {
  1877.             case 1:
  1878.             case 2:
  1879.             case 3:
  1880.             case 4:
  1881.                 // Monday - Thursday:
  1882.                 //
  1883.                 $hn_year    $pn_year;
  1884.                 $hn_isoweek floor(($hn_day $hn_wd1 - 2/ 7+ 1;
  1885.                 break;
  1886.             case 0:
  1887.                 $hn_wd1 = 7;
  1888.             case 5:
  1889.             case 6:
  1890.                 // Friday - Sunday:
  1891.                 //
  1892.                 if ($hn_day <= 8 - $hn_wd1{
  1893.                     // ISO week is the last week of the previous ISO year:
  1894.                     //
  1895.                     list($hn_year$hn_lastmonth$hn_lastday=
  1896.                         explode(" ",
  1897.                                 Date_Calc::daysToDate($hn_jd1 - 1"%Y %m %d"));
  1898.                     list($hn_year$hn_isoweek$hn_pisoday=
  1899.                         Date_Calc::isoWeekDate($hn_lastday,
  1900.                                                $hn_lastmonth,
  1901.                                                $hn_year);
  1902.                 else {
  1903.                     $hn_year    $pn_year;
  1904.                     $hn_isoweek floor(($hn_day $hn_wd1 - 9/ 7+ 1;
  1905.                 }
  1906.  
  1907.                 break;
  1908.             }
  1909.         }
  1910.  
  1911.         return array((int) $hn_year(int) $hn_isoweek(int) $hn_wd);
  1912.     }
  1913.  
  1914.  
  1915.     // }}}
  1916.     // {{{ gregorianToISO()
  1917.  
  1918.     /**
  1919.      * Converts from Gregorian Year-Month-Day to ISO Year-WeekNumber-WeekDay
  1920.      *
  1921.      * Uses ISO 8601 definitions.
  1922.      *
  1923.      * @param int $day   the day of the month
  1924.      * @param int $month the month
  1925.      * @param int $year  the year.  Use the complete year instead of the
  1926.      *                     abbreviated version.  E.g. use 2005, not 05.
  1927.      *
  1928.      * @return   string     the date in ISO Year-WeekNumber-WeekDay format
  1929.      * @access   public
  1930.      * @static
  1931.      */
  1932.     function gregorianToISO($day$month$year)
  1933.     {
  1934.         list($yearnumber$weeknumber$weekday=
  1935.             Date_Calc::isoWeekDate($day$month$year);
  1936.         return sprintf("%04d"$yearnumber.
  1937.                        '-' .
  1938.                        sprintf("%02d"$weeknumber.
  1939.                        '-' .
  1940.                        $weekday;
  1941.     }
  1942.  
  1943.  
  1944.     // }}}
  1945.     // {{{ weekOfYear4th()
  1946.  
  1947.     /**
  1948.      * Returns week of the year counting week 1 as the week that contains 4th
  1949.      * January
  1950.      *
  1951.      * Week 1 is determined to be the week that includes the 4th January, and
  1952.      * therefore can be defined as the first week of the year that has at least
  1953.      * 4 days.  The previous week is counted as week 52 or 53 of the previous
  1954.      * year.  Note that this definition depends on which day is the first day of
  1955.      * the week, and that if this is not passed as the '$pn_firstdayofweek'
  1956.      * parameter, the default is assumed.
  1957.      *
  1958.      * Note also that the last day week of the year is likely to extend into
  1959.      * the following year, except in the case that the last day of the week
  1960.      * falls on 31st December.
  1961.      *
  1962.      * Also note that this is very similar to the ISO week returned by
  1963.      * 'isoWeekDate()', the difference being that the ISO week always has
  1964.      * 7 days, and if the 4th of January is a Friday, for example,
  1965.      * ISO week 1 would start on Monday, 31st December in the previous year,
  1966.      * whereas the week defined by this function would start on 1st January,
  1967.      * but would be only 6 days long.  Of course you can also set the day
  1968.      * of the week, whereas the ISO week starts on a Monday by definition.
  1969.      *
  1970.      * Returned week is an integer from 1 to 53.
  1971.      *
  1972.      * @param int $pn_day            the day of the month, default is current
  1973.      *                                 local day
  1974.      * @param int $pn_month          the month, default is current local month
  1975.      * @param int $pn_year           the year in four digit format, default is
  1976.      *                                 current local year
  1977.      * @param int $pn_firstdayofweek optional integer specifying the first day
  1978.      *                                 of the week
  1979.      *
  1980.      * @return   array      array of year, week no as integers
  1981.      * @access   public
  1982.      * @static
  1983.      * @since    Method available since Release 1.5.0
  1984.      */
  1985.     function weekOfYear4th($pn_day = 0,
  1986.                            $pn_month = 0,
  1987.                            $pn_year = null,
  1988.                            $pn_firstdayofweek = DATE_CALC_BEGIN_WEEKDAY)
  1989.     {
  1990.         if (is_null($pn_year)) {
  1991.             $pn_year Date_Calc::dateNow('%Y');
  1992.         }
  1993.         if (empty($pn_month)) {
  1994.             $pn_month Date_Calc::dateNow('%m');
  1995.         }
  1996.         if (empty($pn_day)) {
  1997.             $pn_day Date_Calc::dateNow('%d');
  1998.         }
  1999.  
  2000.         $hn_wd1  Date_Calc::daysToDayOfWeek(Date_Calc::firstDayOfYear($pn_year));
  2001.         $hn_day  Date_Calc::dayOfYear($pn_day$pn_month$pn_year);
  2002.         $hn_week floor(($hn_day +
  2003.                           (10 + $hn_wd1 $pn_firstdayofweek% 7 +
  2004.                           3/ 7);
  2005.  
  2006.         if ($hn_week > 0{
  2007.             $hn_year $pn_year;
  2008.         else {
  2009.             // Week number is the last week of the previous year:
  2010.             //
  2011.             list($hn_year$hn_lastmonth$hn_lastday=
  2012.                 explode(" ",
  2013.                         Date_Calc::daysToDate(Date_Calc::lastDayOfYear($pn_year - 1),
  2014.                                               "%Y %m %d"));
  2015.             list($hn_year$hn_week=
  2016.                 Date_Calc::weekOfYear4th($hn_lastday,
  2017.                                          $hn_lastmonth,
  2018.                                          $hn_year,
  2019.                                          $pn_firstdayofweek);
  2020.         }
  2021.  
  2022.         return array((int) $hn_year(int) $hn_week);
  2023.     }
  2024.  
  2025.  
  2026.     // }}}
  2027.     // {{{ weekOfYear7th()
  2028.  
  2029.     /**
  2030.      * Returns week of the year counting week 1 as the week that contains 7th
  2031.      * January
  2032.      *
  2033.      * Week 1 is determined to be the week that includes the 7th January, and
  2034.      * therefore can be defined as the first full week of the year.  The
  2035.      * previous week is counted as week 52 or 53 of the previous year.  Note
  2036.      * that this definition depends on which day is the first day of the week,
  2037.      * and that if this is not passed as the '$pn_firstdayofweek' parameter, the
  2038.      * default is assumed.
  2039.      *
  2040.      * Note also that the last day week of the year is likely to extend into
  2041.      * the following year, except in the case that the last day of the week
  2042.      * falls on 31st December.
  2043.      *
  2044.      * Returned week is an integer from 1 to 53.
  2045.      *
  2046.      * @param int $pn_day            the day of the month, default is current
  2047.      *                                 local day
  2048.      * @param int $pn_month          the month, default is current local month
  2049.      * @param int $pn_year           the year in four digit format, default is
  2050.      *                                 current local year
  2051.      * @param int $pn_firstdayofweek optional integer specifying the first day
  2052.      *                                 of the week
  2053.      *
  2054.      * @return   array      array of year, week no as integers
  2055.      * @access   public
  2056.      * @static
  2057.      * @since    Method available since Release 1.5.0
  2058.      */
  2059.     function weekOfYear7th($pn_day = 0,
  2060.                            $pn_month = 0,
  2061.                            $pn_year = null,
  2062.                            $pn_firstdayofweek = DATE_CALC_BEGIN_WEEKDAY)
  2063.     {
  2064.         if (is_null($pn_year)) {
  2065.             $pn_year Date_Calc::dateNow('%Y');
  2066.         }
  2067.         if (empty($pn_month)) {
  2068.             $pn_month Date_Calc::dateNow('%m');
  2069.         }
  2070.         if (empty($pn_day)) {
  2071.             $pn_day Date_Calc::dateNow('%d');
  2072.         }
  2073.  
  2074.         $hn_wd1  Date_Calc::daysToDayOfWeek(Date_Calc::firstDayOfYear($pn_year));
  2075.         $hn_day  Date_Calc::dayOfYear($pn_day$pn_month$pn_year);
  2076.         $hn_week floor(($hn_day (6 + $hn_wd1 $pn_firstdayofweek% 7/ 7);
  2077.  
  2078.         if ($hn_week > 0{
  2079.             $hn_year $pn_year;
  2080.         else {
  2081.             // Week number is the last week of the previous ISO year:
  2082.             //
  2083.             list($hn_year$hn_lastmonth$hn_lastdayexplode(" "Date_Calc::daysToDate(Date_Calc::lastDayOfYear($pn_year - 1)"%Y %m %d"));
  2084.             list($hn_year$hn_weekDate_Calc::weekOfYear7th($hn_lastday$hn_lastmonth$hn_year$pn_firstdayofweek);
  2085.         }
  2086.  
  2087.         return array((int) $hn_year(int) $hn_week);
  2088.     }
  2089.  
  2090.  
  2091.     // }}}
  2092.     // {{{ dateSeason()
  2093.  
  2094.     /**
  2095.      * Determines julian date of the given season
  2096.      *
  2097.      * Adapted from previous work in Java by James Mark Hamilton.
  2098.      *
  2099.      * @param string $season the season to get the date for: VERNALEQUINOX,
  2100.      *                         SUMMERSOLSTICE, AUTUMNALEQUINOX,
  2101.      *                         or WINTERSOLSTICE
  2102.      * @param string $year   the year in four digit format.  Must be between
  2103.      *                         -1000 B.C. and 3000 A.D.
  2104.      *
  2105.      * @return   float      the julian date the season starts on
  2106.      * @access   public
  2107.      * @static
  2108.      */
  2109.     function dateSeason($season$year = 0)
  2110.     {
  2111.         if ($year == ''{
  2112.             $year Date_Calc::dateNow('%Y');
  2113.         }
  2114.         if (($year >= -1000&& ($year <= 1000)) {
  2115.             $y $year / 1000.0;
  2116.             switch ($season{
  2117.             case 'VERNALEQUINOX':
  2118.                 $juliandate (((((((-0.00071 * $y- 0.00111$y+ 0.06134$y+ 365242.1374$y+ 1721139.29189;
  2119.                 break;
  2120.             case 'SUMMERSOLSTICE':
  2121.                 $juliandate (((((((0.00025 * $y+ 0.00907$y- 0.05323$y+ 365241.72562$y+ 1721233.25401;
  2122.                 break;
  2123.             case 'AUTUMNALEQUINOX':
  2124.                 $juliandate (((((((0.00074 * $y- 0.00297$y- 0.11677$y+ 365242.49558$y+ 1721325.70455;
  2125.                 break;
  2126.             case 'WINTERSOLSTICE':
  2127.             default:
  2128.                 $juliandate (((((((-0.00006 * $y- 0.00933$y- 0.00769$y+ 365242.88257$y+ 1721414.39987;
  2129.             }
  2130.         elseif (($year > 1000&& ($year <= 3000)) {
  2131.             $y ($year - 2000/ 1000;
  2132.             switch ($season{
  2133.             case 'VERNALEQUINOX':
  2134.                 $juliandate (((((((-0.00057 * $y- 0.00411$y+ 0.05169$y+ 365242.37404$y+ 2451623.80984;
  2135.                 break;
  2136.             case 'SUMMERSOLSTICE':
  2137.                 $juliandate (((((((-0.0003 * $y+ 0.00888$y+ 0.00325$y+ 365241.62603$y+ 2451716.56767;
  2138.                 break;
  2139.             case 'AUTUMNALEQUINOX':
  2140.                 $juliandate (((((((0.00078 * $y+ 0.00337$y- 0.11575$y+ 365242.01767$y+ 2451810.21715;
  2141.                 break;
  2142.             case 'WINTERSOLSTICE':
  2143.             default:
  2144.                 $juliandate (((((((0.00032 * $y- 0.00823$y- 0.06223$y+ 365242.74049$y+ 2451900.05952;
  2145.             }
  2146.         }
  2147.         return $juliandate;
  2148.     }
  2149.  
  2150.  
  2151.     // }}}
  2152.     // {{{ dayOfYear()
  2153.  
  2154.     /**
  2155.      * Returns number of days since 31 December of year before given date
  2156.      *
  2157.      * @param int $pn_day   the day of the month, default is current local day
  2158.      * @param int $pn_month the month, default is current local month
  2159.      * @param int $pn_year  the year in four digit format, default is current
  2160.      *                        local year
  2161.      *
  2162.      * @return   int 
  2163.      * @access   public
  2164.      * @static
  2165.      * @since    Method available since Release 1.5.0
  2166.      */
  2167.     function dayOfYear($pn_day = 0$pn_month = 0$pn_year = null)
  2168.     {
  2169.         if (is_null($pn_year)) {
  2170.             $pn_year Date_Calc::dateNow('%Y');
  2171.         }
  2172.         if (empty($pn_month)) {
  2173.             $pn_month Date_Calc::dateNow('%m');
  2174.         }
  2175.         if (empty($pn_day)) {
  2176.             $pn_day Date_Calc::dateNow('%d');
  2177.         }
  2178.  
  2179.         $hn_jd  Date_Calc::dateToDays($pn_day$pn_month$pn_year);
  2180.         $hn_jd1 Date_Calc::firstDayOfYear($pn_year);
  2181.         return $hn_jd $hn_jd1 + 1;
  2182.     }
  2183.  
  2184.  
  2185.     // }}}
  2186.     // {{{ julianDate()
  2187.  
  2188.     /**
  2189.      * Returns number of days since 31 December of year before given date
  2190.      *
  2191.      * @param int $pn_day   the day of the month, default is current local day
  2192.      * @param int $pn_month the month, default is current local month
  2193.      * @param int $pn_year  the year in four digit format, default is current
  2194.      *                        local year
  2195.      *
  2196.      * @return     int 
  2197.      * @access     public
  2198.      * @static
  2199.      * @deprecated Method deprecated in Release 1.5.0
  2200.      */
  2201.     function julianDate($pn_day = 0$pn_month = 0$pn_year = null)
  2202.     {
  2203.         return Date_Calc::dayOfYear($pn_day$pn_month$pn_year);
  2204.     }
  2205.  
  2206.  
  2207.     // }}}
  2208.     // {{{ getWeekdayFullname()
  2209.  
  2210.     /**
  2211.      * Returns the full weekday name for the given date
  2212.      *
  2213.      * @param int $pn_day   the day of the month, default is current local day
  2214.      * @param int $pn_month the month, default is current local month
  2215.      * @param int $pn_year  the year in four digit format, default is current
  2216.      *                        local year
  2217.      *
  2218.      * @return   string     the full name of the day of the week
  2219.      * @access   public
  2220.      * @static
  2221.      */
  2222.     function getWeekdayFullname($pn_day = 0$pn_month = 0$pn_year = null)
  2223.     {
  2224.         if (is_null($pn_year)) {
  2225.             $pn_year Date_Calc::dateNow('%Y');
  2226.         }
  2227.         if (empty($pn_month)) {
  2228.             $pn_month Date_Calc::dateNow('%m');
  2229.         }
  2230.         if (empty($pn_day)) {
  2231.             $pn_day Date_Calc::dateNow('%d');
  2232.         }
  2233.  
  2234.         $weekday_names Date_Calc::getWeekDays();
  2235.         $weekday       Date_Calc::dayOfWeek($pn_day$pn_month$pn_year);
  2236.         return $weekday_names[$weekday];
  2237.     }
  2238.  
  2239.  
  2240.     // }}}
  2241.     // {{{ getWeekdayAbbrname()
  2242.  
  2243.     /**
  2244.      * Returns the abbreviated weekday name for the given date
  2245.      *
  2246.      * @param int $pn_day   the day of the month, default is current local day
  2247.      * @param int $pn_month the month, default is current local month
  2248.      * @param int $pn_year  the year in four digit format, default is current
  2249.      *                        local year
  2250.      * @param int $length   the length of abbreviation
  2251.      *
  2252.      * @return   string     the abbreviated name of the day of the week
  2253.      * @access   public
  2254.      * @static
  2255.      * @see      Date_Calc::getWeekdayFullname()
  2256.      */
  2257.     function getWeekdayAbbrname($pn_day = 0,
  2258.                                 $pn_month = 0,
  2259.                                 $pn_year = null,
  2260.                                 $length = 3)
  2261.     {
  2262.         if (is_null($pn_year)) {
  2263.             $pn_year Date_Calc::dateNow('%Y');
  2264.         }
  2265.         if (empty($pn_month)) {
  2266.             $pn_month Date_Calc::dateNow('%m');
  2267.         }
  2268.         if (empty($pn_day)) {
  2269.             $pn_day Date_Calc::dateNow('%d');
  2270.         }
  2271.  
  2272.         $weekday_names Date_Calc::getWeekDays(true);
  2273.         $weekday       Date_Calc::dayOfWeek($pn_day$pn_month$pn_year);
  2274.         return $weekday_names[$weekday];
  2275.     }
  2276.  
  2277.  
  2278.     // }}}
  2279.     // {{{ getMonthFullname()
  2280.  
  2281.     /**
  2282.      * Returns the full month name for the given month
  2283.      *
  2284.      * @param int $month the month
  2285.      *
  2286.      * @return   string     the full name of the month
  2287.      * @access   public
  2288.      * @static
  2289.      */
  2290.     function getMonthFullname($month)
  2291.     {
  2292.         $month = (int)$month;
  2293.         if (empty($month)) {
  2294.             $month = (int)Date_Calc::dateNow('%m');
  2295.         }
  2296.  
  2297.         $month_names Date_Calc::getMonthNames();
  2298.         return $month_names[$month];
  2299.     }
  2300.  
  2301.  
  2302.     // }}}
  2303.     // {{{ getMonthAbbrname()
  2304.  
  2305.     /**
  2306.      * Returns the abbreviated month name for the given month
  2307.      *
  2308.      * @param int $month  the month
  2309.      * @param int $length the length of abbreviation
  2310.      *
  2311.      * @return   string     the abbreviated name of the month
  2312.      * @access   public
  2313.      * @static
  2314.      * @see      Date_Calc::getMonthFullname
  2315.      */
  2316.     function getMonthAbbrname($month$length = 3)
  2317.     {
  2318.         $month = (int)$month;
  2319.         if (empty($month)) {
  2320.             $month Date_Calc::dateNow('%m');
  2321.         }
  2322.  
  2323.         $month_names Date_Calc::getMonthNames(true);
  2324.         return $month_names[$month];
  2325.     }
  2326.  
  2327.  
  2328.     // }}}
  2329.     // {{{ getMonthFromFullname()
  2330.  
  2331.     /**
  2332.      * Returns the numeric month from the month name or an abreviation
  2333.      *
  2334.      * Both August and Aug would return 8.
  2335.      *
  2336.      * @param string $month the name of the month to examine.
  2337.      *                        Case insensitive.
  2338.      *
  2339.      * @return   int        the month's number
  2340.      * @access   public
  2341.      * @static
  2342.      */
  2343.     function getMonthFromFullName($month)
  2344.     {
  2345.         $month  strtolower($month);
  2346.         $months Date_Calc::getMonthNames();
  2347.         while (list($id$nameeach($months)) {
  2348.             if (ereg($monthstrtolower($name))) {
  2349.                 return $id;
  2350.             }
  2351.         }
  2352.         return&nbs