2 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
7 * Calculates, manipulates and retrieves dates
9 * It does not rely on 32-bit system time stamps, so it works dates
10 * before 1970 and after 2038.
12 * PHP versions 4 and 5
16 * Copyright (c) 1999-2007 Monte Ohrt, Pierre-Alain Joye, Daniel Convissor,
18 * All rights reserved.
20 * Redistribution and use in source and binary forms, with or without
21 * modification, are permitted under the terms of the BSD License.
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.
36 * @category Date and Time
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
46 * @link http://pear.php.net/package/Date
47 * @since File available since Release 1.2
56 require_once 'PEAR.php';
59 // {{{ General constants:
61 if (!defined('DATE_CALC_BEGIN_WEEKDAY')) {
63 * Defines what day starts the week
65 * Monday (1) is the international standard.
66 * Redefine this to 0 if you want weeks to begin on Sunday.
68 define('DATE_CALC_BEGIN_WEEKDAY', 1);
71 if (!defined('DATE_CALC_FORMAT')) {
73 * The default value for each method's $format parameter
75 * The default is '%Y%m%d'. To override this default, define
76 * this constant before including Calc.php.
78 * @since Constant available since Release 1.4.4
80 define('DATE_CALC_FORMAT', '%Y%m%d');
84 // {{{ Date precision constants (used in 'round()' and 'trunc()'):
86 define('DATE_PRECISION_YEAR', -2);
87 define('DATE_PRECISION_MONTH', -1);
88 define('DATE_PRECISION_DAY', 0);
89 define('DATE_PRECISION_HOUR', 1);
90 define('DATE_PRECISION_10MINUTES', 2);
91 define('DATE_PRECISION_MINUTE', 3);
92 define('DATE_PRECISION_10SECONDS', 4);
93 define('DATE_PRECISION_SECOND', 5);
97 // {{{ Class: Date_Calc
100 * Calculates, manipulates and retrieves dates
102 * It does not rely on 32-bit system time stamps, so it works dates
103 * before 1970 and after 2038.
105 * @category Date and Time
107 * @author Monte Ohrt <monte@ispi.net>
108 * @author Daniel Convissor <danielc@php.net>
109 * @author C.A. Woodcock <c01234@netcomuk.co.uk>
110 * @copyright 1999-2007 Monte Ohrt, Pierre-Alain Joye, Daniel Convissor, C.A. Woodcock
111 * @license http://www.opensource.org/licenses/bsd-license.php
113 * @version Release: 1.5.0a1
114 * @link http://pear.php.net/package/Date
115 * @since Class available since Release 1.2
123 * Formats the date in the given format, much like
124 * {@link http://www.php.net/strftime strftime()}
126 * This function is used to alleviate the problem with 32-bit numbers for
127 * dates pre 1970 or post 2038, as strftime() has on most systems.
128 * Most of the formatting options are compatible.
130 * Formatting options:
132 * - <b>%a</b> - abbreviated weekday name (Sun, Mon, Tue)
133 * - <b>%A</b> - full weekday name (Sunday, Monday, Tuesday)
134 * - <b>%b</b> - abbreviated month name (Jan, Feb, Mar)
135 * - <b>%B</b> - full month name (January, February, March)
136 * - <b>%d</b> - day of month (range 00 to 31)
137 * - <b>%e</b> - day of month, single digit (range 0 to 31)
138 * - <b>%E</b> - number of days since unspecified epoch (integer).
139 * ('<b>%E</b>' is useful for passing a date in a URL as an
140 * integer value. Then simply use {@link Date_Calc::daysToDate()}
141 * to convert back to a date.)
142 * - <b>%j</b> - day of year (range 001 to 366)
143 * - <b>%m</b> - month as decimal number (range 1 to 12)
144 * - <b>%n</b> - newline character (\n)
145 * - <b>%t</b> - tab character (\t)
146 * - <b>%w</b> - weekday as decimal (0 = Sunday)
147 * - <b>%U</b> - week number of current year, first sunday as first week
148 * - <b>%y</b> - year as decimal (range 00 to 99)
149 * - <b>%Y</b> - year as decimal including century (range 0000 to 9999)
150 * - <b>%%</b> - literal '%'
152 * @param int $day the day of the month
153 * @param int $month the month
154 * @param int $year the year. Use the complete year instead of the
155 * abbreviated version. E.g. use 2005, not 05.
156 * @param string $format the format string
158 * @return string the date in the desired format
162 public function dateFormat($day, $month, $year, $format)
164 if (!Date_Calc::isValidDate($day, $month, $year)) {
165 $year = Date_Calc::dateNow('%Y');
166 $month = Date_Calc::dateNow('%m');
167 $day = Date_Calc::dateNow('%d');
172 for ($strpos = 0; $strpos < strlen($format); $strpos++) {
173 $char = substr($format, $strpos, 1);
175 $nextchar = substr($format, $strpos + 1, 1);
178 $output .= Date_Calc::getWeekdayAbbrname($day, $month, $year);
181 $output .= Date_Calc::getWeekdayFullname($day, $month, $year);
184 $output .= Date_Calc::getMonthAbbrname($month);
187 $output .= Date_Calc::getMonthFullname($month);
190 $output .= sprintf('%02d', $day);
196 $output .= Date_Calc::dateToDays($day, $month, $year);
199 $output .= Date_Calc::dayOfYear($day, $month, $year);
202 $output .= sprintf('%02d', $month);
211 $output .= Date_Calc::dayOfWeek($day, $month, $year);
214 $output .= Date_Calc::weekOfYear($day, $month, $year);
219 ($year < 0 ? '3' : '2') .
227 ($year < 0 ? '5' : '4') .
236 $output .= $char . $nextchar;
251 * Returns the current local date
253 * NOTE: This function retrieves the local date using
254 * {@link http://www.php.net/strftime strftime()}, which may or may
255 * not be 32-bit safe on your system.
257 * @param string $format the string indicating how to format the output
259 * @return string the current date in the specified format
263 public function dateNow($format = DATE_CALC_FORMAT)
265 return strftime($format, time());
273 * Returns the current local year in format CCYY
275 * @return string the current year in four digit format
279 public function getYear()
281 return Date_Calc::dateNow('%Y');
289 * Returns the current local month in format MM
291 * @return string the current month in two digit format
295 public function getMonth()
297 return Date_Calc::dateNow('%m');
305 * Returns the current local day in format DD
307 * @return string the current day of the month in two digit format
311 public function getDay()
313 return Date_Calc::dateNow('%d');
318 // {{{ defaultCentury()
321 * Turns a two digit year into a four digit year
323 * Return value depends on current year; the century chosen
324 * will be the one which forms the year that is closest
325 * to the current year. If the two possibilities are
326 * equidistant to the current year (i.e. 50 years in the past
327 * and 50 years in the future), then the past year is chosen.
329 * For example, if the current year is 2007:
330 * - <b>"03"</b> - returns 2003
331 * - <b>"09"</b> - returns 2009
332 * - <b>"56"</b> - returns 2056 (closer to 2007 than 1956)
333 * - <b>"57"</b> - returns 1957 (1957 and 2007 are equidistant,
334 * so previous century chosen)
335 * - <b>"58"</b> - returns 1958
337 * @param int $year the 2 digit year
339 * @return int the 4 digit year
343 public function defaultCentury($year)
345 $hn_century = intval(($hn_currentyear = date("Y")) / 100);
346 $hn_currentyear = $hn_currentyear % 100;
348 if ($year < 0 || $year >= 100) {
352 if ($year - $hn_currentyear < -50) {
353 return ($hn_century + 1) * 100 + $year;
354 } elseif ($year - $hn_currentyear < 50) {
355 return $hn_century * 100 + $year;
357 return ($hn_century - 1) * 100 + $year;
363 // {{{ getSecondsInYear()
366 * Returns the total number of seconds in the given year
368 * This takes into account leap seconds.
370 * @param int $pn_year the year in four digit format
375 * @since Method available since Release 1.5.0
377 public function getSecondsInYear($pn_year)
379 $pn_year = intval($pn_year);
381 static $ha_leapseconds;
382 if (!isset($ha_leapseconds)) {
383 $ha_leapseconds = array(1972 => 2,
407 $ret = Date_Calc::daysInYear($pn_year) * 86400;
409 if (isset($ha_leapseconds[$pn_year])) {
410 return $ret + $ha_leapseconds[$pn_year];
418 // {{{ getSecondsInMonth()
421 * Returns the total number of seconds in the given month
423 * This takes into account leap seconds.
425 * @param int $pn_month the month
426 * @param int $pn_year the year in four digit format
431 * @since Method available since Release 1.5.0
433 public function getSecondsInMonth($pn_month, $pn_year)
435 $pn_month = intval($pn_month);
436 $pn_year = intval($pn_year);
438 static $ha_leapseconds;
439 if (!isset($ha_leapseconds)) {
440 $ha_leapseconds = array(1972 => array(6 => 1,
442 1973 => array(12 => 1),
443 1974 => array(12 => 1),
444 1975 => array(12 => 1),
445 1976 => array(12 => 1),
446 1977 => array(12 => 1),
447 1978 => array(12 => 1),
448 1979 => array(12 => 1),
449 1981 => array(6 => 1),
450 1982 => array(6 => 1),
451 1983 => array(6 => 1),
452 1985 => array(6 => 1),
453 1987 => array(12 => 1),
454 1989 => array(12 => 1),
455 1990 => array(12 => 1),
456 1992 => array(6 => 1),
457 1993 => array(6 => 1),
458 1994 => array(6 => 1),
459 1995 => array(12 => 1),
460 1997 => array(6 => 1),
461 1998 => array(12 => 1),
462 2005 => array(12 => 1));
465 $ret = Date_Calc::daysInMonth($pn_month, $pn_year) * 86400;
467 if (isset($ha_leapseconds[$pn_year][$pn_month])) {
468 return $ret + $ha_leapseconds[$pn_year][$pn_month];
476 // {{{ getSecondsInDay()
479 * Returns the total number of seconds in the day of the given date
481 * This takes into account leap seconds.
483 * @param int $pn_day the day of the month
484 * @param int $pn_month the month
485 * @param int $pn_year the year in four digit format
490 * @since Method available since Release 1.5.0
492 public function getSecondsInDay($pn_day, $pn_month, $pn_year)
494 // Note to developers:
496 // The leap seconds listed here are a matter of historical fact,
497 // that is, it is known on which exact day they occurred.
498 // However, the implementation of the class as a whole depends
499 // on the fact that they always occur at the end of the month
500 // (although it is assumed that they could occur in any month,
501 // even though practically they only occur in June or December).
503 // Do not define a leap second on a day of the month other than
504 // the last day without altering the implementation of the
505 // functions that depend on this one.
507 // It is possible, though, to define an un-leap second (i.e. a skipped
508 // second (I do not know what they are called), or a number of
509 // consecutive leap seconds).
511 $pn_day = intval($pn_day);
512 $pn_month = intval($pn_month);
513 $pn_year = intval($pn_year);
515 static $ha_leapseconds;
516 if (!isset($ha_leapseconds)) {
517 $ha_leapseconds = array(1972 => array(6 => array(30 => 1),
518 12 => array(31 => 1)),
519 1973 => array(12 => array(31 => 1)),
520 1974 => array(12 => array(31 => 1)),
521 1975 => array(12 => array(31 => 1)),
522 1976 => array(12 => array(31 => 1)),
523 1977 => array(12 => array(31 => 1)),
524 1978 => array(12 => array(31 => 1)),
525 1979 => array(12 => array(31 => 1)),
526 1981 => array(6 => array(30 => 1)),
527 1982 => array(6 => array(30 => 1)),
528 1983 => array(6 => array(30 => 1)),
529 1985 => array(6 => array(30 => 1)),
530 1987 => array(12 => array(31 => 1)),
531 1989 => array(12 => array(31 => 1)),
532 1990 => array(12 => array(31 => 1)),
533 1992 => array(6 => array(30 => 1)),
534 1993 => array(6 => array(30 => 1)),
535 1994 => array(6 => array(30 => 1)),
536 1995 => array(12 => array(31 => 1)),
537 1997 => array(6 => array(30 => 1)),
538 1998 => array(12 => array(31 => 1)),
539 2005 => array(12 => array(31 => 1)));
542 if (isset($ha_leapseconds[$pn_year][$pn_month][$pn_day])) {
543 return 86400 + $ha_leapseconds[$pn_year][$pn_month][$pn_day];
551 // {{{ getSecondsInHour()
554 * Returns the total number of seconds in the hour of the given date
556 * This takes into account leap seconds.
558 * @param int $pn_day the day of the month
559 * @param int $pn_month the month
560 * @param int $pn_year the year in four digit format
561 * @param int $pn_hour the hour
567 public function getSecondsInHour($pn_day, $pn_month, $pn_year, $pn_hour)
572 return Date_Calc::getSecondsInDay($pn_day, $pn_month, $pn_year) -
579 // {{{ getSecondsInMinute()
582 * Returns the total number of seconds in the minute of the given hour
584 * This takes into account leap seconds.
586 * @param int $pn_day the day of the month
587 * @param int $pn_month the month
588 * @param int $pn_year the year in four digit format
589 * @param int $pn_hour the hour
590 * @param int $pn_minute the minute
595 * @since Method available since Release 1.5.0
597 public function getSecondsInMinute(
605 if ($pn_hour < 23 || $pn_minute < 59) {
608 return Date_Calc::getSecondsInDay($pn_day, $pn_month, $pn_year) -
615 // {{{ secondsPastMidnight()
618 * Returns the no of seconds since midnight (0-86399)
620 * @param int $pn_hour the hour of the day
621 * @param int $pn_minute the minute
622 * @param mixed $pn_second the second as integer or float
624 * @return mixed integer or float from 0-86399
627 * @since Method available since Release 1.5.0
629 public function secondsPastMidnight($pn_hour, $pn_minute, $pn_second)
631 return 3600 * $pn_hour + 60 * $pn_minute + $pn_second;
636 // {{{ secondsPastMidnightToTime()
639 * Returns the time as an array (i.e. hour, minute, second)
641 * @param mixed $pn_seconds the no of seconds since midnight (0-86399)
643 * @return mixed array of hour, minute (both as integers), second (as
644 * integer or float, depending on parameter)
647 * @since Method available since Release 1.5.0
649 public function secondsPastMidnightToTime($pn_seconds)
651 if ($pn_seconds >= 86400) {
652 return array(23, 59, $pn_seconds - 86340);
655 $hn_hour = intval($pn_seconds / 3600);
656 $hn_minute = intval(($pn_seconds - $hn_hour * 3600) / 60);
657 $hn_second = is_float($pn_seconds) ?
658 fmod($pn_seconds, 60) :
661 return array($hn_hour, $hn_minute, $hn_second);
666 // {{{ secondsPastTheHour()
669 * Returns the no of seconds since the last hour o'clock (0-3599)
671 * @param int $pn_minute the minute
672 * @param mixed $pn_second the second as integer or float
674 * @return mixed integer or float from 0-3599
677 * @since Method available since Release 1.5.0
679 public function secondsPastTheHour($pn_minute, $pn_second)
681 return 60 * $pn_minute + $pn_second;
689 * Returns the date the specified no of hours from the given date
691 * To subtract hours use a negative value for the '$pn_hours' parameter
693 * @param int $pn_hours hours to add
694 * @param int $pn_day the day of the month
695 * @param int $pn_month the month
696 * @param int $pn_year the year
697 * @param int $pn_hour the hour
699 * @return array array of year, month, day, hour
702 * @since Method available since Release 1.5.0
704 public function addHours($pn_hours, $pn_day, $pn_month, $pn_year, $pn_hour)
706 if ($pn_hours == 0) {
707 return array((int)$pn_year,
713 $hn_days = intval($pn_hours / 24);
714 $hn_hour = $pn_hour + $pn_hours % 24;
716 if ($hn_hour >= 24) {
719 } elseif ($hn_hour < 0) {
726 $hn_month = $pn_month;
729 list($hn_year, $hn_month, $hn_day) =
742 return array((int)$hn_year, (int)$hn_month, (int)$hn_day, $hn_hour);
750 * Returns the date the specified no of minutes from the given date
752 * To subtract minutes use a negative value for the '$pn_minutes' parameter
754 * @param int $pn_minutes minutes to add
755 * @param int $pn_day the day of the month
756 * @param int $pn_month the month
757 * @param int $pn_year the year
758 * @param int $pn_hour the hour
759 * @param int $pn_minute the minute
761 * @return array array of year, month, day, hour, minute
764 * @since Method available since Release 1.5.0
766 public function addMinutes(
775 if ($pn_minutes == 0) {
776 return array((int)$pn_year,
783 $hn_hours = intval($pn_minutes / 60);
784 $hn_minute = $pn_minute + $pn_minutes % 60;
786 if ($hn_minute >= 60) {
789 } elseif ($hn_minute < 0) {
794 if ($hn_hours == 0) {
796 $hn_month = $pn_month;
800 list($hn_year, $hn_month, $hn_day, $hn_hour) =
810 return array($hn_year, $hn_month, $hn_day, $hn_hour, $hn_minute);
818 * Returns the date the specified no of seconds from the given date
820 * If leap seconds are specified to be counted, the passed time must be UTC.
821 * To subtract seconds use a negative value for the '$pn_seconds' parameter.
823 * N.B. the return type of the second part of the date is float if
824 * either '$pn_seconds' or '$pn_second' is a float; otherwise, it
827 * @param mixed $pn_seconds seconds to add as integer or float
828 * @param int $pn_day the day of the month
829 * @param int $pn_month the month
830 * @param int $pn_year the year
831 * @param int $pn_hour the hour
832 * @param int $pn_minute the minute
833 * @param mixed $pn_second the second as integer or float
834 * @param bool $pb_countleap whether to count leap seconds (defaults to
835 * DATE_COUNT_LEAP_SECONDS)
837 * @return array array of year, month, day, hour, minute, second
840 * @since Method available since Release 1.5.0
842 public function addSeconds(
850 $pb_countleap = DATE_COUNT_LEAP_SECONDS
853 if ($pn_seconds == 0) {
854 return array((int)$pn_year,
863 $hn_seconds = $pn_seconds;
865 $hn_day = (int)$pn_day;
866 $hn_month = (int)$pn_month;
867 $hn_year = (int)$pn_year;
868 $hn_hour = (int)$pn_hour;
869 $hn_minute = (int)$pn_minute;
870 $hn_second = $pn_second;
872 $hn_days = Date_Calc::dateToDays(
877 $hn_secondsofmonth = 86400 * ($hn_days -
878 Date_Calc::firstDayOfMonth(
882 Date_Calc::secondsPastMidnight(
888 if ($hn_seconds > 0) {
889 // Advance to end of month:
891 if ($hn_secondsofmonth != 0 &&
892 $hn_secondsofmonth + $hn_seconds >=
893 ($hn_secondsinmonth =
894 Date_Calc::getSecondsInMonth($hn_month, $hn_year))) {
895 $hn_seconds -= $hn_secondsinmonth - $hn_secondsofmonth;
896 $hn_secondsofmonth = 0;
897 list($hn_year, $hn_month) =
898 Date_Calc::nextMonth($hn_month, $hn_year);
899 $hn_day = Date_Calc::getFirstDayOfMonth(
903 $hn_hour = $hn_minute = $hn_second = 0;
906 // Advance to end of year:
908 if ($hn_secondsofmonth == 0 &&
909 $hn_month != Date_Calc::getFirstMonthOfYear($hn_year)) {
910 while ($hn_year == $pn_year &&
911 $hn_seconds >= ($hn_secondsinmonth =
912 Date_Calc::getSecondsInMonth(
916 $hn_seconds -= $hn_secondsinmonth;
917 list($hn_year, $hn_month) =
918 Date_Calc::nextMonth($hn_month, $hn_year);
919 $hn_day = Date_Calc::getFirstDayOfMonth(
926 if ($hn_secondsofmonth == 0) {
929 if ($hn_month == Date_Calc::getFirstMonthOfYear($hn_year)) {
930 while ($hn_seconds >= ($hn_secondsinyear =
931 Date_Calc::getSecondsInYear($hn_year))) {
932 $hn_seconds -= $hn_secondsinyear;
933 $hn_month = Date_Calc::getFirstMonthOfYear(++$hn_year);
934 $hn_day = Date_Calc::getFirstDayOfMonth(
943 while ($hn_seconds >= ($hn_secondsinmonth =
944 Date_Calc::getSecondsInMonth($hn_month, $hn_year))) {
945 $hn_seconds -= $hn_secondsinmonth;
946 list($hn_year, $hn_month) =
947 Date_Calc::nextMonth($hn_month, $hn_year);
948 $hn_day = Date_Calc::getFirstDayOfMonth($hn_month, $hn_year);
953 // (if $hn_seconds < 0)
955 // Go back to start of month:
957 if ($hn_secondsofmonth != 0 &&
958 -$hn_seconds >= $hn_secondsofmonth) {
959 $hn_seconds += $hn_secondsofmonth;
960 $hn_secondsofmonth = 0;
961 $hn_day = Date_Calc::getFirstDayOfMonth(
965 $hn_hour = $hn_minute = $hn_second = 0;
968 // Go back to start of year:
970 if ($hn_secondsofmonth == 0) {
972 Date_Calc::getFirstMonthOfYear($hn_year)) {
973 list($hn_year, $hn_prevmonth) =
974 Date_Calc::prevMonth($hn_month, $hn_year);
976 if (-$hn_seconds >= ($hn_secondsinmonth =
977 Date_Calc::getSecondsInMonth(
981 $hn_seconds += $hn_secondsinmonth;
982 $hn_month = $hn_prevmonth;
983 $hn_day = Date_Calc::getFirstDayOfMonth(
993 if ($hn_secondsofmonth == 0) {
996 if ($hn_month == Date_Calc::getFirstMonthOfYear($hn_year)) {
997 while (-$hn_seconds >= ($hn_secondsinyear =
998 Date_Calc::getSecondsInYear($hn_year - 1))) {
999 $hn_seconds += $hn_secondsinyear;
1000 $hn_month = Date_Calc::getFirstMonthOfYear(--$hn_year);
1001 $hn_day = Date_Calc::getFirstDayOfMonth(
1010 list($hn_pmyear, $hn_prevmonth) =
1011 Date_Calc::prevMonth($hn_month, $hn_year);
1012 while (-$hn_seconds >= ($hn_secondsinmonth =
1013 Date_Calc::getSecondsInMonth(
1017 $hn_seconds += $hn_secondsinmonth;
1018 $hn_year = $hn_pmyear;
1019 $hn_month = $hn_prevmonth;
1020 $hn_day = Date_Calc::getFirstDayOfMonth(
1024 list($hn_pmyear, $hn_prevmonth) =
1025 Date_Calc::prevMonth($hn_month, $hn_year);
1030 if ($hn_seconds < 0 && $hn_secondsofmonth == 0) {
1031 list($hn_year, $hn_month) =
1032 Date_Calc::prevMonth($hn_month, $hn_year);
1033 $hn_day = Date_Calc::getFirstDayOfMonth($hn_month, $hn_year);
1034 $hn_seconds += Date_Calc::getSecondsInMonth($hn_month, $hn_year);
1037 $hn_seconds += Date_Calc::secondsPastMidnight(
1042 if ($hn_seconds < 0) {
1043 $hn_daysadd = intval($hn_seconds / 86400) - 1;
1044 } elseif ($hn_seconds < 86400) {
1047 $hn_daysadd = intval($hn_seconds / 86400) - 1;
1050 if ($hn_daysadd != 0) {
1051 list($hn_year, $hn_month, $hn_day) =
1062 $hn_seconds -= $hn_daysadd * 86400;
1065 $hn_secondsinday = Date_Calc::getSecondsInDay(
1070 if ($hn_seconds >= $hn_secondsinday) {
1071 list($hn_year, $hn_month, $hn_day) =
1082 $hn_seconds -= $hn_secondsinday;
1085 list($hn_hour, $hn_minute, $hn_second) =
1086 Date_Calc::secondsPastMidnightToTime($hn_seconds);
1088 return array((int)$hn_year,
1095 // Assume every day has 86400 seconds exactly (ignore leap seconds):
1097 $hn_minutes = intval($pn_seconds / 60);
1099 if (is_float($pn_seconds)) {
1100 $hn_second = $pn_second + fmod($pn_seconds, 60);
1102 $hn_second = $pn_second + $pn_seconds % 60;
1105 if ($hn_second >= 60) {
1108 } elseif ($hn_second < 0) {
1113 if ($hn_minutes == 0) {
1114 $hn_year = $pn_year;
1115 $hn_month = $pn_month;
1117 $hn_hour = $pn_hour;
1118 $hn_minute = $pn_minute;
1120 list($hn_year, $hn_month, $hn_day, $hn_hour, $hn_minute) =
1121 Date_Calc::addMinutes(
1131 return array($hn_year,
1145 * Converts a date in the proleptic Gregorian calendar to the no of days
1146 * since 24th November, 4714 B.C.
1148 * Returns the no of days since Monday, 24th November, 4714 B.C. in the
1149 * proleptic Gregorian calendar (which is 24th November, -4713 using
1150 * 'Astronomical' year numbering, and 1st January, 4713 B.C. in the
1151 * proleptic Julian calendar). This is also the first day of the 'Julian
1152 * Period' proposed by Joseph Scaliger in 1583, and the number of days
1153 * since this date is known as the 'Julian Day'. (It is not directly
1154 * to do with the Julian calendar, although this is where the name
1157 * The algorithm is valid for all years (positive and negative), and
1158 * also for years preceding 4714 B.C.
1160 * @param int $day the day of the month
1161 * @param int $month the month
1162 * @param int $year the year (using 'Astronomical' year numbering)
1164 * @return int the number of days since 24th November, 4714 B.C.
1168 public function dateToDays($day, $month, $year)
1171 // March = 0, April = 1, ..., December = 9,
1172 // January = 10, February = 11
1179 $hb_negativeyear = $year < 0;
1180 $century = intval($year / 100);
1181 $year = $year % 100;
1183 if ($hb_negativeyear) {
1184 // Subtract 1 because year 0 is a leap year;
1185 // And N.B. that we must treat the leap years as occurring
1186 // one year earlier than they do, because for the purposes
1187 // of calculation, the year starts on 1st March:
1189 return intval((14609700 * $century + ($year == 0 ? 1 : 0)) / 400) +
1190 intval((1461 * $year + 1) / 4) +
1191 intval((153 * $month + 2) / 5) +
1194 return intval(146097 * $century / 4) +
1195 intval(1461 * $year / 4) +
1196 intval((153 * $month + 2) / 5) +
1206 * Converts no of days since 24th November, 4714 B.C. (in the proleptic
1207 * Gregorian calendar, which is year -4713 using 'Astronomical' year
1208 * numbering) to Gregorian calendar date
1210 * Returned date belongs to the proleptic Gregorian calendar, using
1211 * 'Astronomical' year numbering.
1213 * The algorithm is valid for all years (positive and negative), and
1214 * also for years preceding 4714 B.C. (i.e. for negative 'Julian Days'),
1215 * and so the only limitation is platform-dependent (for 32-bit systems
1216 * the maximum year would be something like about 1,465,190 A.D.).
1218 * N.B. Monday, 24th November, 4714 B.C. is Julian Day '0'.
1220 * @param int $days the number of days since 24th November, 4714 B.C.
1221 * @param string $format the string indicating how to format the output
1223 * @return string the date in the desired format
1227 public function daysToDate($days, $format = DATE_CALC_FORMAT)
1229 $days = intval($days);
1232 $century = floor((4 * $days - 1) / 146097);
1233 $days = floor(4 * $days - 1 - 146097 * $century);
1234 $day = floor($days / 4);
1236 $year = floor((4 * $day + 3) / 1461);
1237 $day = floor(4 * $day + 3 - 1461 * $year);
1238 $day = floor(($day + 4) / 4);
1240 $month = floor((5 * $day - 3) / 153);
1241 $day = floor(5 * $day - 3 - 153 * $month);
1242 $day = floor(($day + 5) / 5);
1244 $year = $century * 100 + $year;
1252 return Date_Calc::dateFormat($day, $month, $year, $format);
1260 * Returns array of the month numbers, in order, for the given year
1262 * @param int $pn_year the year (using 'Astronomical' year numbering)
1264 * @return array array of integer month numbers, in order
1267 * @since Method available since Release 1.5.0
1269 public function getMonths($pn_year)
1271 // N.B. Month numbers can be skipped but not duplicated:
1273 return array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);
1278 // {{{ getMonthNames()
1281 * Returns an array of month names
1283 * Used to take advantage of the setlocale function to return
1284 * language specific month names.
1286 * TODO: cache values to some global array to avoid performance
1287 * hits when called more than once.
1289 * @param int $pb_abbreviated whether to return the abbreviated form of the
1292 * @return array associative array of integer month numbers, in
1293 * order, to month names
1297 public function getMonthNames($pb_abbreviated = false)
1300 foreach (Date_Calc::getMonths(2001) as $i) {
1301 $ret[$i] = strftime(
1302 $pb_abbreviated ? '%b' : '%B',
1303 mktime(0, 0, 0, $i, 1, 2001)
1314 * Returns month and year of previous month
1316 * @param int $pn_month the month
1317 * @param int $pn_year the year (using 'Astronomical' year numbering)
1319 * @return array array of year, month as integers
1322 * @since Method available since Release 1.5.0
1324 public function prevMonth($pn_month, $pn_year)
1326 $ha_months = Date_Calc::getMonths($pn_year);
1327 $hn_monthkey = array_search($pn_month, $ha_months);
1328 if (array_key_exists($hn_monthkey - 1, $ha_months)) {
1329 return array((int)$pn_year, $ha_months[$hn_monthkey - 1]);
1331 $ha_months = Date_Calc::getMonths($pn_year - 1);
1332 return array($pn_year - 1, end($ha_months));
1341 * Returns month and year of next month
1343 * @param int $pn_month the month
1344 * @param int $pn_year the year (using 'Astronomical' year numbering)
1346 * @return array array of year, month as integers
1349 * @since Method available since Release 1.5.0
1351 public function nextMonth($pn_month, $pn_year)
1353 $ha_months = Date_Calc::getMonths($pn_year);
1354 $hn_monthkey = array_search($pn_month, $ha_months);
1355 if (array_key_exists($hn_monthkey + 1, $ha_months)) {
1356 return array((int)$pn_year, $ha_months[$hn_monthkey + 1]);
1358 $ha_months = Date_Calc::getMonths($pn_year + 1);
1359 return array($pn_year + 1, $ha_months[0]);
1365 // {{{ addMonthsToDays()
1368 * Returns 'Julian Day' of the date the specified no of months
1369 * from the given date
1371 * To subtract months use a negative value for the '$pn_months'
1374 * @param int $pn_months months to add
1375 * @param int $pn_days 'Julian Day', i.e. the no of days since 1st
1376 * January, 4713 B.C.
1378 * @return int 'Julian Day', i.e. the no of days since 1st January,
1382 * @since Method available since Release 1.5.0
1384 public function addMonthsToDays($pn_months, $pn_days)
1386 if ($pn_months == 0) {
1387 return (int)$pn_days;
1390 list($hn_year, $hn_month, $hn_day) =
1391 explode(" ", Date_Calc::daysToDate($pn_days, "%Y %m %d"));
1393 $hn_retmonth = $hn_month + $pn_months % 12;
1394 $hn_retyear = $hn_year + intval($pn_months / 12);
1395 if ($hn_retmonth < 1) {
1398 } elseif ($hn_retmonth > 12) {
1403 if (Date_Calc::isValidDate($hn_day, $hn_retmonth, $hn_retyear)) {
1404 return Date_Calc::dateToDays($hn_day, $hn_retmonth, $hn_retyear);
1407 // Calculate days since first of month:
1409 $hn_dayoffset = $pn_days -
1410 Date_Calc::firstDayOfMonth($hn_month, $hn_year);
1412 $hn_retmonthfirstday = Date_Calc::firstDayOfMonth(
1416 $hn_retmonthlastday = Date_Calc::lastDayOfMonth(
1421 if ($hn_dayoffset > $hn_retmonthlastday - $hn_retmonthfirstday) {
1422 return $hn_retmonthlastday;
1424 return $hn_retmonthfirstday + $hn_dayoffset;
1433 * Returns the date the specified no of months from the given date
1435 * To subtract months use a negative value for the '$pn_months'
1438 * @param int $pn_months months to add
1439 * @param int $pn_day the day of the month, default is current local
1441 * @param int $pn_month the month, default is current local month
1442 * @param int $pn_year the year in four digit format, default is
1443 * current local year
1444 * @param string $ps_format string specifying how to format the output
1446 * @return string the date in the desired format
1449 * @since Method available since Release 1.5.0
1451 public function addMonths(
1456 $ps_format = DATE_CALC_FORMAT
1459 if (is_null($pn_year)) {
1460 $pn_year = Date_Calc::dateNow('%Y');
1462 if (empty($pn_month)) {
1463 $pn_month = Date_Calc::dateNow('%m');
1465 if (empty($pn_day)) {
1466 $pn_day = Date_Calc::dateNow('%d');
1469 if ($pn_months == 0) {
1470 return Date_Calc::dateFormat(
1478 $hn_days = Date_Calc::dateToDays($pn_day, $pn_month, $pn_year);
1479 return Date_Calc::daysToDate(
1480 Date_Calc::addMonthsToDays(
1490 // {{{ addYearsToDays()
1493 * Returns 'Julian Day' of the date the specified no of years
1494 * from the given date
1496 * To subtract years use a negative value for the '$pn_years'
1499 * @param int $pn_years years to add
1500 * @param int $pn_days 'Julian Day', i.e. the no of days since 1st January,
1503 * @return int 'Julian Day', i.e. the no of days since 1st January,
1507 * @since Method available since Release 1.5.0
1509 public function addYearsToDays($pn_years, $pn_days)
1511 if ($pn_years == 0) {
1512 return (int)$pn_days;
1515 list($hn_year, $hn_month, $hn_day) =
1516 explode(" ", Date_Calc::daysToDate($pn_days, "%Y %m %d"));
1518 $hn_retyear = $hn_year + $pn_years;
1519 if (Date_Calc::isValidDate($hn_day, $hn_month, $hn_retyear)) {
1520 return Date_Calc::dateToDays($hn_day, $hn_month, $hn_retyear);
1523 $ha_months = Date_Calc::getMonths($hn_retyear);
1524 if (in_array($hn_month, $ha_months)) {
1525 $hn_retmonth = $hn_month;
1527 // Calculate days since first of month:
1529 $hn_dayoffset = $pn_days - Date_Calc::firstDayOfMonth(
1534 $hn_retmonthfirstday = Date_Calc::firstDayOfMonth(
1538 $hn_retmonthlastday = Date_Calc::lastDayOfMonth(
1543 if ($hn_dayoffset > $hn_retmonthlastday - $hn_retmonthfirstday) {
1544 return $hn_retmonthlastday;
1546 return $hn_retmonthfirstday + $hn_dayoffset;
1549 // Calculate days since first of year:
1551 $hn_dayoffset = $pn_days - Date_Calc::firstDayOfYear($hn_year);
1553 $hn_retyearfirstday = Date_Calc::firstDayOfYear($hn_retyear);
1554 $hn_retyearlastday = Date_Calc::lastDayOfYear($hn_retyear);
1556 if ($hn_dayoffset > $hn_retyearlastday - $hn_retyearfirstday) {
1557 return $hn_retyearlastday;
1559 return $hn_retyearfirstday + $hn_dayoffset;
1569 * Returns the date the specified no of years from the given date
1571 * To subtract years use a negative value for the '$pn_years'
1574 * @param int $pn_years years to add
1575 * @param int $pn_day the day of the month, default is current local
1577 * @param int $pn_month the month, default is current local month
1578 * @param int $pn_year the year in four digit format, default is
1579 * current local year
1580 * @param string $ps_format string specifying how to format the output
1582 * @return string the date in the desired format
1585 * @since Method available since Release 1.5.0
1587 public function addYears(
1592 $ps_format = DATE_CALC_FORMAT
1595 if (is_null($pn_year)) {
1596 $pn_year = Date_Calc::dateNow('%Y');
1598 if (empty($pn_month)) {
1599 $pn_month = Date_Calc::dateNow('%m');
1601 if (empty($pn_day)) {
1602 $pn_day = Date_Calc::dateNow('%d');
1605 if ($pn_years == 0) {
1606 return Date_Calc::dateFormat(
1614 $hn_days = Date_Calc::dateToDays($pn_day, $pn_month, $pn_year);
1615 return Date_Calc::daysToDate(
1616 Date_Calc::addYearsToDays(
1629 * Returns the date the specified no of days from the given date
1631 * To subtract days use a negative value for the '$pn_days' parameter
1633 * @param int $pn_days days to add
1634 * @param int $pn_day the day of the month, default is current local
1636 * @param int $pn_month the month, default is current local month
1637 * @param int $pn_year the year in four digit format, default is
1638 * current local year
1639 * @param string $ps_format string specifying how to format the output
1641 * @return string the date in the desired format
1644 * @since Method available since Release 1.5.0
1646 public function addDays(
1651 $ps_format = DATE_CALC_FORMAT
1654 if (is_null($pn_year)) {
1655 $pn_year = Date_Calc::dateNow('%Y');
1657 if (empty($pn_month)) {
1658 $pn_month = Date_Calc::dateNow('%m');
1660 if (empty($pn_day)) {
1661 $pn_day = Date_Calc::dateNow('%d');
1664 if ($pn_days == 0) {
1665 return Date_Calc::dateFormat(
1673 return Date_Calc::daysToDate(
1674 Date_Calc::dateToDays(
1686 // {{{ getFirstDayOfMonth()
1689 * Returns first day of the specified month of specified year as integer
1691 * @param int $pn_month the month
1692 * @param int $pn_year the year (using 'Astronomical' year numbering)
1694 * @return int number of first day of month
1697 * @since Method available since Release 1.5.0
1699 public function getFirstDayOfMonth($pn_month, $pn_year)
1706 // {{{ getLastDayOfMonth()
1709 * Returns last day of the specified month of specified year as integer
1711 * @param int $pn_month the month
1712 * @param int $pn_year the year (using 'Astronomical' year numbering)
1714 * @return int number of last day of month
1717 * @since Method available since Release 1.5.0
1719 public function getLastDayOfMonth($pn_month, $pn_year)
1721 return Date_Calc::daysInMonth($pn_month, $pn_year);
1726 // {{{ firstDayOfMonth()
1729 * Returns the Julian Day of the first day of the month of the specified
1730 * year (i.e. the no of days since 24th November, 4714 B.C.)
1732 * @param int $pn_month the month
1733 * @param int $pn_year the year (using 'Astronomical' year numbering)
1735 * @return integer the number of days since 24th November, 4714 B.C.
1738 * @since Method available since Release 1.5.0
1740 public function firstDayOfMonth($pn_month, $pn_year)
1742 return Date_Calc::dateToDays(
1743 Date_Calc::getFirstDayOfMonth(
1754 // {{{ lastDayOfMonth()
1757 * Returns the Julian Day of the last day of the month of the specified
1758 * year (i.e. the no of days since 24th November, 4714 B.C.)
1760 * @param int $pn_month the month
1761 * @param int $pn_year the year (using 'Astronomical' year numbering)
1763 * @return integer the number of days since 24th November, 4714 B.C.
1766 * @since Method available since Release 1.5.0
1768 public function lastDayOfMonth($pn_month, $pn_year)
1770 list($hn_nmyear, $hn_nextmonth) = Date_Calc::nextMonth(
1774 return Date_Calc::firstDayOfMonth($hn_nextmonth, $hn_nmyear) - 1;
1779 // {{{ getFirstMonthOfYear()
1782 * Returns first month of specified year as integer
1784 * @param int $pn_year the year (using 'Astronomical' year numbering)
1786 * @return int number of first month of year
1789 * @since Method available since Release 1.5.0
1791 public function getFirstMonthOfYear($pn_year)
1793 $ha_months = Date_Calc::getMonths($pn_year);
1794 return $ha_months[0];
1799 // {{{ firstDayOfYear()
1802 * Returns the Julian Day of the first day of the year (i.e. the no of
1803 * days since 24th November, 4714 B.C.)
1805 * @param int $pn_year the year (using 'Astronomical' year numbering)
1807 * @return integer the number of days since 24th November, 4714 B.C.
1810 * @since Method available since Release 1.5.0
1812 public function firstDayOfYear($pn_year)
1814 return Date_Calc::firstDayOfMonth(
1815 Date_Calc::getFirstMonthOfYear($pn_year),
1822 // {{{ lastDayOfYear()
1825 * Returns the Julian Day of the last day of the year (i.e. the no of
1826 * days since 24th November, 4714 B.C.)
1828 * @param int $pn_year the year (using 'Astronomical' year numbering)
1830 * @return integer the number of days since 24th November, 4714 B.C.
1833 * @since Method available since Release 1.5.0
1835 public function lastDayOfYear($pn_year)
1837 return Date_Calc::firstDayOfYear($pn_year + 1) - 1;
1842 // {{{ dateToDaysJulian()
1845 * Converts a date in the proleptic Julian calendar to the no of days
1846 * since 1st January, 4713 B.C.
1848 * Returns the no of days since Monday, 1st January, 4713 B.C. in the
1849 * proleptic Julian calendar (which is 1st January, -4712 using
1850 * 'Astronomical' year numbering, and 24th November, 4713 B.C. in the
1851 * proleptic Gregorian calendar). This is also the first day of the 'Julian
1852 * Period' proposed by Joseph Scaliger in 1583, and the number of days
1853 * since this date is known as the 'Julian Day'. (It is not directly
1854 * to do with the Julian calendar, although this is where the name
1857 * The algorithm is valid for all years (positive and negative), and
1858 * also for years preceding 4713 B.C.
1860 * @param int $day the day of the month
1861 * @param int $month the month
1862 * @param int $year the year (using 'Astronomical' year numbering)
1864 * @return int the number of days since 1st January, 4713 B.C.
1867 * @since Method available since Release 1.5.0
1869 public function dateToDaysJulian($day, $month, $year)
1872 // March = 0, April = 1, ..., December = 9,
1873 // January = 10, February = 11
1880 $hb_negativeyear = $year < 0;
1882 if ($hb_negativeyear) {
1883 // Subtract 1 because year 0 is a leap year;
1884 // And N.B. that we must treat the leap years as occurring
1885 // one year earlier than they do, because for the purposes
1886 // of calculation, the year starts on 1st March:
1888 return intval((1461 * $year + 1) / 4) +
1889 intval((153 * $month + 2) / 5) +
1892 return intval(1461 * $year / 4) +
1893 floor((153 * $month + 2) / 5) +
1900 // {{{ daysToDateJulian()
1903 * Converts no of days since 1st January, 4713 B.C. (in the proleptic
1904 * Julian calendar, which is year -4712 using 'Astronomical' year
1905 * numbering) to Julian calendar date
1907 * Returned date belongs to the proleptic Julian calendar, using
1908 * 'Astronomical' year numbering.
1910 * @param int $days the number of days since 1st January, 4713 B.C.
1911 * @param string $format the string indicating how to format the output
1913 * @return string the date in the desired format
1916 * @since Method available since Release 1.5.0
1918 public function daysToDateJulian($days, $format = DATE_CALC_FORMAT)
1920 $days = intval($days);
1923 $days = floor(4 * $days - 1);
1924 $day = floor($days / 4);
1926 $year = floor((4 * $day + 3) / 1461);
1927 $day = floor(4 * $day + 3 - 1461 * $year);
1928 $day = floor(($day + 4) / 4);
1930 $month = floor((5 * $day - 3) / 153);
1931 $day = floor(5 * $day - 3 - 153 * $month);
1932 $day = floor(($day + 5) / 5);
1941 return Date_Calc::dateFormat($day, $month, $year, $format);
1946 // {{{ isoWeekDate()
1949 * Returns array defining the 'ISO Week Date' as defined in ISO 8601
1951 * Expects a date in the proleptic Gregorian calendar using 'Astronomical'
1952 * year numbering, that is, with a year 0. Algorithm is valid for all
1953 * years (positive and negative).
1955 * N.B. the ISO week day no for Sunday is defined as 7, whereas this
1956 * class and its related functions defines Sunday as 0.
1958 * @param int $pn_day the day of the month
1959 * @param int $pn_month the month
1960 * @param int $pn_year the year
1962 * @return array array of ISO Year, ISO Week No, ISO Day No as
1966 * @since Method available since Release 1.5.0
1968 public function isoWeekDate($pn_day = 0, $pn_month = 0, $pn_year = null)
1970 if (is_null($pn_year)) {
1971 $pn_year = Date_Calc::dateNow('%Y');
1973 if (empty($pn_month)) {
1974 $pn_month = Date_Calc::dateNow('%m');
1976 if (empty($pn_day)) {
1977 $pn_day = Date_Calc::dateNow('%d');
1980 $hn_jd = Date_Calc::dateToDays($pn_day, $pn_month, $pn_year);
1981 $hn_wd = Date_Calc::daysToDayOfWeek($hn_jd);
1986 $hn_jd1 = Date_Calc::firstDayOfYear($pn_year);
1987 $hn_day = $hn_jd - $hn_jd1 + 1;
1989 if ($hn_wd <= $hn_jd - Date_Calc::lastDayOfYear($pn_year) + 3) {
1990 // ISO week is the first week of the next ISO year:
1992 $hn_year = $pn_year + 1;
1995 switch ($hn_wd1 = Date_Calc::daysToDayOfWeek($hn_jd1)) {
2000 // Monday - Thursday:
2002 $hn_year = $pn_year;
2003 $hn_isoweek = floor(($hn_day + $hn_wd1 - 2) / 7) + 1;
2012 if ($hn_day <= 8 - $hn_wd1) {
2013 // ISO week is the last week of the previous ISO year:
2015 list($hn_year, $hn_lastmonth, $hn_lastday) =
2018 Date_Calc::daysToDate($hn_jd1 - 1, "%Y %m %d")
2020 list($hn_year, $hn_isoweek, $hn_pisoday) =
2021 Date_Calc::isoWeekDate(
2027 $hn_year = $pn_year;
2028 $hn_isoweek = floor(($hn_day + $hn_wd1 - 9) / 7) + 1;
2035 return array((int)$hn_year, (int)$hn_isoweek, (int)$hn_wd);
2040 // {{{ gregorianToISO()
2043 * Converts from Gregorian Year-Month-Day to ISO Year-WeekNumber-WeekDay
2045 * Uses ISO 8601 definitions.
2047 * @param int $day the day of the month
2048 * @param int $month the month
2049 * @param int $year the year. Use the complete year instead of the
2050 * abbreviated version. E.g. use 2005, not 05.
2052 * @return string the date in ISO Year-WeekNumber-WeekDay format
2056 public function gregorianToISO($day, $month, $year)
2058 list($yearnumber, $weeknumber, $weekday) =
2059 Date_Calc::isoWeekDate($day, $month, $year);
2060 return sprintf("%04d", $yearnumber) .
2062 sprintf("%02d", $weeknumber) .
2069 // {{{ weekOfYear4th()
2072 * Returns week of the year counting week 1 as the week that contains 4th
2075 * Week 1 is determined to be the week that includes the 4th January, and
2076 * therefore can be defined as the first week of the year that has at least
2077 * 4 days. The previous week is counted as week 52 or 53 of the previous
2078 * year. Note that this definition depends on which day is the first day of
2079 * the week, and that if this is not passed as the '$pn_firstdayofweek'
2080 * parameter, the default is assumed.
2082 * Note also that the last day week of the year is likely to extend into
2083 * the following year, except in the case that the last day of the week
2084 * falls on 31st December.
2086 * Also note that this is very similar to the ISO week returned by
2087 * {@link Date::isoWeekDate()}, the difference being that the ISO week
2088 * always has 7 days, and if the 4th of January is a Friday, for example,
2089 * ISO week 1 would start on Monday, 31st December in the previous year,
2090 * whereas the week defined by this function would start on 1st January,
2091 * but would be only 6 days long. Of course you can also set the day
2092 * of the week, whereas the ISO week starts on a Monday by definition.
2094 * Returned week is an integer from 1 to 53.
2096 * @param int $pn_day the day of the month, default is current
2098 * @param int $pn_month the month, default is current local month
2099 * @param int $pn_year the year in four digit format, default is
2100 * current local year
2101 * @param int $pn_firstdayofweek optional integer specifying the first day
2104 * @return array array of year, week no as integers
2107 * @since Method available since Release 1.5.0
2109 public function weekOfYear4th(
2113 $pn_firstdayofweek = DATE_CALC_BEGIN_WEEKDAY
2116 if (is_null($pn_year)) {
2117 $pn_year = Date_Calc::dateNow('%Y');
2119 if (empty($pn_month)) {
2120 $pn_month = Date_Calc::dateNow('%m');
2122 if (empty($pn_day)) {
2123 $pn_day = Date_Calc::dateNow('%d');
2126 $hn_wd1 = Date_Calc::daysToDayOfWeek(Date_Calc::firstDayOfYear($pn_year));
2127 $hn_day = Date_Calc::dayOfYear($pn_day, $pn_month, $pn_year);
2128 $hn_week = floor(($hn_day +
2129 (10 + $hn_wd1 - $pn_firstdayofweek) % 7 +
2133 $hn_year = $pn_year;
2135 // Week number is the last week of the previous year:
2137 list($hn_year, $hn_lastmonth, $hn_lastday) =
2140 Date_Calc::daysToDate(
2141 Date_Calc::lastDayOfYear($pn_year - 1),
2145 list($hn_year, $hn_week) =
2146 Date_Calc::weekOfYear4th(
2154 return array((int)$hn_year, (int)$hn_week);
2159 // {{{ weekOfYear7th()
2162 * Returns week of the year counting week 1 as the week that contains 7th
2165 * Week 1 is determined to be the week that includes the 7th January, and
2166 * therefore can be defined as the first full week of the year. The
2167 * previous week is counted as week 52 or 53 of the previous year. Note
2168 * that this definition depends on which day is the first day of the week,
2169 * and that if this is not passed as the '$pn_firstdayofweek' parameter, the
2170 * default is assumed.
2172 * Note also that the last day week of the year is likely to extend into
2173 * the following year, except in the case that the last day of the week
2174 * falls on 31st December.
2176 * Returned week is an integer from 1 to 53.
2178 * @param int $pn_day the day of the month, default is current
2180 * @param int $pn_month the month, default is current local month
2181 * @param int $pn_year the year in four digit format, default is
2182 * current local year
2183 * @param int $pn_firstdayofweek optional integer specifying the first day
2186 * @return array array of year, week no as integers
2189 * @since Method available since Release 1.5.0
2191 public function weekOfYear7th(
2195 $pn_firstdayofweek = DATE_CALC_BEGIN_WEEKDAY
2198 if (is_null($pn_year)) {
2199 $pn_year = Date_Calc::dateNow('%Y');
2201 if (empty($pn_month)) {
2202 $pn_month = Date_Calc::dateNow('%m');
2204 if (empty($pn_day)) {
2205 $pn_day = Date_Calc::dateNow('%d');
2208 $hn_wd1 = Date_Calc::daysToDayOfWeek(Date_Calc::firstDayOfYear($pn_year));
2209 $hn_day = Date_Calc::dayOfYear($pn_day, $pn_month, $pn_year);
2210 $hn_week = floor(($hn_day + (6 + $hn_wd1 - $pn_firstdayofweek) % 7) / 7);
2213 $hn_year = $pn_year;
2215 // Week number is the last week of the previous ISO year:
2217 list($hn_year, $hn_lastmonth, $hn_lastday) = explode(" ", Date_Calc::daysToDate(Date_Calc::lastDayOfYear($pn_year - 1), "%Y %m %d"));
2218 list($hn_year, $hn_week) = Date_Calc::weekOfYear7th($hn_lastday, $hn_lastmonth, $hn_year, $pn_firstdayofweek);
2221 return array((int)$hn_year, (int)$hn_week);
2229 * Determines julian date of the given season
2231 * @param string $season the season to get the date for: VERNALEQUINOX,
2232 * SUMMERSOLSTICE, AUTUMNALEQUINOX,
2234 * @param string $year the year in four digit format. Must be between
2235 * -1000 B.C. and 3000 A.D.
2237 * @return float the julian date the season starts on
2241 public function dateSeason($season, $year = 0)
2244 $year = Date_Calc::dateNow('%Y');
2246 if (($year >= -1000) && ($year <= 1000)) {
2247 $y = $year / 1000.0;
2249 case 'VERNALEQUINOX':
2250 $juliandate = (((((((-0.00071 * $y) - 0.00111) * $y) + 0.06134) * $y) + 365242.1374) * $y) + 1721139.29189;
2252 case 'SUMMERSOLSTICE':
2253 $juliandate = (((((((0.00025 * $y) + 0.00907) * $y) - 0.05323) * $y) + 365241.72562) * $y) + 1721233.25401;
2255 case 'AUTUMNALEQUINOX':
2256 $juliandate = (((((((0.00074 * $y) - 0.00297) * $y) - 0.11677) * $y) + 365242.49558) * $y) + 1721325.70455;
2258 case 'WINTERSOLSTICE':
2260 $juliandate = (((((((-0.00006 * $y) - 0.00933) * $y) - 0.00769) * $y) + 365242.88257) * $y) + 1721414.39987;
2262 } elseif (($year > 1000) && ($year <= 3000)) {
2263 $y = ($year - 2000) / 1000;
2265 case 'VERNALEQUINOX':
2266 $juliandate = (((((((-0.00057 * $y) - 0.00411) * $y) + 0.05169) * $y) + 365242.37404) * $y) + 2451623.80984;
2268 case 'SUMMERSOLSTICE':
2269 $juliandate = (((((((-0.0003 * $y) + 0.00888) * $y) + 0.00325) * $y) + 365241.62603) * $y) + 2451716.56767;
2271 case 'AUTUMNALEQUINOX':
2272 $juliandate = (((((((0.00078 * $y) + 0.00337) * $y) - 0.11575) * $y) + 365242.01767) * $y) + 2451810.21715;
2274 case 'WINTERSOLSTICE':
2276 $juliandate = (((((((0.00032 * $y) - 0.00823) * $y) - 0.06223) * $y) + 365242.74049) * $y) + 2451900.05952;
2287 * Returns number of days since 31 December of year before given date
2289 * @param int $pn_day the day of the month, default is current local day
2290 * @param int $pn_month the month, default is current local month
2291 * @param int $pn_year the year in four digit format, default is current
2297 * @since Method available since Release 1.5.0
2299 public function dayOfYear($pn_day = 0, $pn_month = 0, $pn_year = null)
2301 if (is_null($pn_year)) {
2302 $pn_year = Date_Calc::dateNow('%Y');
2304 if (empty($pn_month)) {
2305 $pn_month = Date_Calc::dateNow('%m');
2307 if (empty($pn_day)) {
2308 $pn_day = Date_Calc::dateNow('%d');
2311 $hn_jd = Date_Calc::dateToDays($pn_day, $pn_month, $pn_year);
2312 $hn_jd1 = Date_Calc::firstDayOfYear($pn_year);
2313 return $hn_jd - $hn_jd1 + 1;
2321 * Returns number of days since 31 December of year before given date
2323 * @param int $pn_day the day of the month, default is current local day
2324 * @param int $pn_month the month, default is current local month
2325 * @param int $pn_year the year in four digit format, default is current
2331 * @deprecated Method deprecated in Release 1.5.0
2333 public function julianDate($pn_day = 0, $pn_month = 0, $pn_year = null)
2335 return Date_Calc::dayOfYear($pn_day, $pn_month, $pn_year);
2340 // {{{ getWeekdayFullname()
2343 * Returns the full weekday name for the given date
2345 * @param int $pn_day the day of the month, default is current local day
2346 * @param int $pn_month the month, default is current local month
2347 * @param int $pn_year the year in four digit format, default is current
2350 * @return string the full name of the day of the week
2354 public function getWeekdayFullname($pn_day = 0, $pn_month = 0, $pn_year = null)
2356 if (is_null($pn_year)) {
2357 $pn_year = Date_Calc::dateNow('%Y');
2359 if (empty($pn_month)) {
2360 $pn_month = Date_Calc::dateNow('%m');
2362 if (empty($pn_day)) {
2363 $pn_day = Date_Calc::dateNow('%d');
2366 $weekday_names = Date_Calc::getWeekDays();
2367 $weekday = Date_Calc::dayOfWeek($pn_day, $pn_month, $pn_year);
2368 return $weekday_names[$weekday];
2373 // {{{ getWeekdayAbbrname()
2376 * Returns the abbreviated weekday name for the given date
2378 * @param int $pn_day the day of the month, default is current local day
2379 * @param int $pn_month the month, default is current local month
2380 * @param int $pn_year the year in four digit format, default is current
2382 * @param int $length the length of abbreviation
2384 * @return string the abbreviated name of the day of the week
2387 * @see Date_Calc::getWeekdayFullname()
2389 public function getWeekdayAbbrname(
2396 if (is_null($pn_year)) {
2397 $pn_year = Date_Calc::dateNow('%Y');
2399 if (empty($pn_month)) {
2400 $pn_month = Date_Calc::dateNow('%m');
2402 if (empty($pn_day)) {
2403 $pn_day = Date_Calc::dateNow('%d');
2406 $weekday_names = Date_Calc::getWeekDays(true);
2407 $weekday = Date_Calc::dayOfWeek($pn_day, $pn_month, $pn_year);
2408 return $weekday_names[$weekday];
2413 // {{{ getMonthFullname()
2416 * Returns the full month name for the given month
2418 * @param int $month the month
2420 * @return string the full name of the month
2424 public function getMonthFullname($month)
2426 $month = (int)$month;
2427 if (empty($month)) {
2428 $month = (int)Date_Calc::dateNow('%m');
2431 $month_names = Date_Calc::getMonthNames();
2432 return $month_names[$month];
2437 // {{{ getMonthAbbrname()
2440 * Returns the abbreviated month name for the given month
2442 * @param int $month the month
2443 * @param int $length the length of abbreviation
2445 * @return string the abbreviated name of the month
2448 * @see Date_Calc::getMonthFullname
2450 public function getMonthAbbrname($month, $length = 3)
2452 $month = (int)$month;
2453 if (empty($month)) {
2454 $month = Date_Calc::dateNow('%m');
2457 $month_names = Date_Calc::getMonthNames(true);
2458 return $month_names[$month];
2463 // {{{ getMonthFromFullname()
2466 * Returns the numeric month from the month name or an abreviation
2468 * Both August and Aug would return 8.
2470 * @param string $month the name of the month to examine.
2473 * @return int the month's number
2477 public function getMonthFromFullName($month)
2479 $month = strtolower($month);
2480 $months = Date_Calc::getMonthNames();
2481 while (list($id, $name) = each($months)) {
2482 if (preg_match('/' . $month . '/', strtolower($name))) {
2491 // {{{ getWeekDays()
2494 * Returns an array of week day names
2496 * Used to take advantage of the setlocale function to return language
2497 * specific week days.
2499 * @param int $pb_abbreviated whether to return the abbreviated form of the
2502 * @return array an array of week-day names
2506 public function getWeekDays($pb_abbreviated = false)
2508 for ($i = 0; $i < 7; $i++) {
2509 $weekdays[$i] = strftime(
2510 $pb_abbreviated ? '%a' : '%A',
2511 mktime(0, 0, 0, 1, $i, 2001)
2519 // {{{ daysToDayOfWeek()
2522 * Returns day of week for specified 'Julian Day'
2524 * The algorithm is valid for all years (positive and negative), and
2525 * also for years preceding 4714 B.C. (i.e. for negative 'Julian Days'),
2526 * and so the only limitation is platform-dependent (for 32-bit systems
2527 * the maximum year would be something like about 1,465,190 A.D.).
2529 * N.B. Monday, 24th November, 4714 B.C. is Julian Day '0'.
2531 * @param int $pn_days the number of days since 24th November, 4714 B.C.
2533 * @return int integer from 0 to 7 where 0 represents Sunday
2536 * @since Method available since Release 1.5.0
2538 public function daysToDayOfWeek($pn_days)
2540 // On Julian day 0 the day is Monday (PHP day 1):
2542 $ret = ($pn_days + 1) % 7;
2543 return $ret < 0 ? $ret + 7 : $ret;
2551 * Returns day of week for given date (0 = Sunday)
2553 * The algorithm is valid for all years (positive and negative).
2555 * @param int $day the day of the month, default is current local day
2556 * @param int $month the month, default is current local month
2557 * @param int $year the year in four digit format, default is current
2560 * @return int the number of the day in the week
2564 public function dayOfWeek($day = null, $month = null, $year = null)
2566 if (is_null($year)) {
2567 $year = Date_Calc::dateNow('%Y');
2569 if (empty($month)) {
2570 $month = Date_Calc::dateNow('%m');
2573 $day = Date_Calc::dateNow('%d');
2576 // if ($month <= 2) {
2582 // intval((13 * $month + 3) / 5) +
2584 // floor($year / 4) -
2585 // floor($year / 100) +
2586 // floor($year / 400) +
2589 // return (int) ($wd < 0 ? $wd + 7 : $wd);
2591 return Date_Calc::daysToDayOfWeek(Date_Calc::dateToDays(
2600 // {{{ weekOfYearAbsolute()
2603 * Returns week of the year counting week 1 as 1st-7th January,
2604 * regardless of what day 1st January falls on
2606 * Returned value is an integer from 1 to 53. Week 53 will start on
2607 * 31st December and have only one day, except in a leap year, in
2608 * which it will start a day earlier and contain two days.
2610 * @param int $pn_day the day of the month, default is current local day
2611 * @param int $pn_month the month, default is current local month
2612 * @param int $pn_year the year in four digit format, default is current
2615 * @return int integer from 1 to 53
2618 * @since Method available since Release 1.5.0
2620 public function weekOfYearAbsolute($pn_day = 0, $pn_month = 0, $pn_year = null)
2622 if (is_null($pn_year)) {
2623 $pn_year = Date_Calc::dateNow('%Y');
2625 if (empty($pn_month)) {
2626 $pn_month = Date_Calc::dateNow('%m');
2628 if (empty($pn_day)) {
2629 $pn_day = Date_Calc::dateNow('%d');
2632 $hn_day = Date_Calc::dayOfYear($pn_day, $pn_month, $pn_year);
2633 return intval(($hn_day + 6) / 7);
2638 // {{{ weekOfYear1st()
2641 * Returns week of the year counting week 1 as the week that contains 1st
2644 * Week 1 is determined to be the week that includes the 1st January, even
2645 * if this week extends into the previous year, in which case the week will
2646 * only contain between 1 and 6 days of the current year. Note that this
2647 * definition depends on which day is the first day of the week, and that if
2648 * this is not passed as the '$pn_firstdayofweek' parameter, the default is
2651 * Note also that the last day week of the year is also likely to contain
2652 * less than seven days, except in the case that the last day of the week
2653 * falls on 31st December.
2655 * Returned value is an integer from 1 to 54. The year will only contain
2656 * 54 weeks in the case of a leap year in which 1st January is the last day
2657 * of the week, and 31st December is the first day of the week. In this
2658 * case, both weeks 1 and 54 will contain one day only.
2660 * @param int $pn_day the day of the month, default is current
2662 * @param int $pn_month the month, default is current local month
2663 * @param int $pn_year the year in four digit format, default is
2664 * current local year
2665 * @param int $pn_firstdayofweek optional integer specifying the first day
2668 * @return int integer from 1 to 54
2671 * @since Method available since Release 1.5.0
2673 public function weekOfYear1st(
2677 $pn_firstdayofweek = DATE_CALC_BEGIN_WEEKDAY
2680 if (is_null($pn_year)) {
2681 $pn_year = Date_Calc::dateNow('%Y');
2683 if (empty($pn_month)) {
2684 $pn_month = Date_Calc::dateNow('%m');
2686 if (empty($pn_day)) {
2687 $pn_day = Date_Calc::dateNow('%d');
2690 $hn_wd1 = Date_Calc::daysToDayOfWeek(Date_Calc::firstDayOfYear($pn_year));
2691 $hn_day = Date_Calc::dayOfYear($pn_day, $pn_month, $pn_year);
2692 return floor(($hn_day + (7 + $hn_wd1 - $pn_firstdayofweek) % 7 + 6) / 7);
2700 * Returns week of the year, where first Sunday is first day of first week
2702 * N.B. this function is equivalent to calling:
2704 * <code>Date_Calc::weekOfYear7th($day, $month, $year, 0);</code>
2706 * Returned week is an integer from 1 to 53.
2708 * @param int $pn_day the day of the month, default is current local day
2709 * @param int $pn_month the month, default is current local month
2710 * @param int $pn_year the year in four digit format, default is current
2713 * @return int integer from 1 to 53
2716 * @see Date_Calc::weekOfYear7th
2717 * @deprecated Method deprecated in Release 1.5.0
2719 public function weekOfYear($pn_day = 0, $pn_month = 0, $pn_year = null)
2721 $ha_week = Date_Calc::weekOfYear7th($pn_day, $pn_month, $pn_year, 0);
2727 // {{{ weekOfMonthAbsolute()
2730 * Returns week of the month counting week 1 as 1st-7th of the month,
2731 * regardless of what day the 1st falls on
2733 * Returned value is an integer from 1 to 5. Week 5 will start on
2734 * the 29th of the month and have between 1 and 3 days, except
2735 * in February in a non-leap year, when there will be 4 weeks only.
2737 * @param int $pn_day the day of the month, default is current local day
2739 * @return int integer from 1 to 5
2742 * @since Method available since Release 1.5.0
2744 public function weekOfMonthAbsolute($pn_day = 0)
2746 if (empty($pn_day)) {
2747 $pn_day = Date_Calc::dateNow('%d');
2749 return intval(($pn_day + 6) / 7);
2754 // {{{ weekOfMonth()
2757 * Alias for 'weekOfMonthAbsolute()'
2759 * @param int $pn_day the day of the month, default is current local day
2761 * @return int integer from 1 to 5
2764 * @since Method available since Release 1.5.0
2766 public function weekOfMonth($pn_day = 0)
2768 return Date_Calc::weekOfMonthAbsolute($pn_day);
2773 // {{{ quarterOfYear()
2776 * Returns quarter of the year for given date
2778 * @param int $day the day of the month, default is current local day
2779 * @param int $month the month, default is current local month
2780 * @param int $year the year in four digit format, default is current
2783 * @return int the number of the quarter in the year
2787 public function quarterOfYear($day = 0, $month = 0, $year = null)
2789 if (empty($month)) {
2790 $month = Date_Calc::dateNow('%m');
2792 return intval(($month - 1) / 3 + 1);
2797 // {{{ daysInMonth()
2800 * Returns the number of days in the given month
2802 * @param int $month the month, default is current local month
2803 * @param int $year the year in four digit format, default is current
2806 * @return int the number of days the month has
2810 public function daysInMonth($month = 0, $year = null)
2812 if (is_null($year)) {
2813 $year = Date_Calc::dateNow('%Y');
2815 if (empty($month)) {
2816 $month = Date_Calc::dateNow('%m');
2819 return Date_Calc::lastDayOfMonth($month, $year) -
2820 Date_Calc::firstDayOfMonth($month, $year) +
2829 * Returns the number of days in the given year
2831 * @param int $year the year in four digit format, default is current local
2834 * @return int the number of days the year has
2838 public function daysInYear($year = null)
2840 if (is_null($year)) {
2841 $year = Date_Calc::dateNow('%Y');
2844 return Date_Calc::firstDayOfYear($year + 1) -
2845 Date_Calc::firstDayOfYear($year);
2850 // {{{ weeksInMonth()
2853 * Returns the number of rows on a calendar month
2855 * Useful for determining the number of rows when displaying a typical
2858 * @param int $month the month, default is current local month
2859 * @param int $year the year in four digit format, default is current
2862 * @return int the number of weeks the month has
2866 public function weeksInMonth($month = 0, $year = null)
2868 if (is_null($year)) {
2869 $year = Date_Calc::dateNow('%Y');
2871 if (empty($month)) {
2872 $month = Date_Calc::dateNow('%m');
2874 $FDOM = Date_Calc::firstOfMonthWeekday($month, $year);
2875 if (DATE_CALC_BEGIN_WEEKDAY == 1 && $FDOM == 0) {
2876 $first_week_days = 7 - $FDOM + DATE_CALC_BEGIN_WEEKDAY;
2878 } elseif (DATE_CALC_BEGIN_WEEKDAY == 0 && $FDOM == 6) {
2879 $first_week_days = 7 - $FDOM + DATE_CALC_BEGIN_WEEKDAY;
2882 $first_week_days = DATE_CALC_BEGIN_WEEKDAY - $FDOM;
2885 $first_week_days %= 7;
2886 return ceil((Date_Calc::daysInMonth($month, $year)
2887 - $first_week_days) / 7) + $weeks;
2892 // {{{ getCalendarWeek()
2895 * Return an array with days in week
2897 * @param int $day the day of the month, default is current local day
2898 * @param int $month the month, default is current local month
2899 * @param int $year the year in four digit format, default is current
2901 * @param string $format the string indicating how to format the output
2903 * @return array $week[$weekday]
2907 public function getCalendarWeek(
2911 $format = DATE_CALC_FORMAT
2914 if (is_null($year)) {
2915 $year = Date_Calc::dateNow('%Y');
2917 if (empty($month)) {
2918 $month = Date_Calc::dateNow('%m');
2921 $day = Date_Calc::dateNow('%d');
2924 $week_array = array();
2926 // date for the column of week
2928 $curr_day = Date_Calc::beginOfWeek($day, $month, $year, '%E');
2930 for ($counter = 0; $counter <= 6; $counter++) {
2931 $week_array[$counter] = Date_Calc::daysToDate($curr_day, $format);
2939 // {{{ getCalendarMonth()
2942 * Return a set of arrays to construct a calendar month for the given date
2944 * @param int $month the month, default is current local month
2945 * @param int $year the year in four digit format, default is current
2947 * @param string $format the string indicating how to format the output
2949 * @return array $month[$row][$col]
2953 public function getCalendarMonth(
2956 $format = DATE_CALC_FORMAT
2959 if (is_null($year)) {
2960 $year = Date_Calc::dateNow('%Y');
2962 if (empty($month)) {
2963 $month = Date_Calc::dateNow('%m');
2966 $month_array = array();
2968 // date for the first row, first column of calendar month
2969 if (DATE_CALC_BEGIN_WEEKDAY == 1) {
2970 if (Date_Calc::firstOfMonthWeekday($month, $year) == 0) {
2971 $curr_day = Date_Calc::firstDayOfMonth($month, $year) - 6;
2973 $curr_day = Date_Calc::firstDayOfMonth($month, $year)
2974 - Date_Calc::firstOfMonthWeekday($month, $year) + 1;
2977 $curr_day = (Date_Calc::firstDayOfMonth($month, $year)
2978 - Date_Calc::firstOfMonthWeekday($month, $year));
2981 // number of days in this month
2982 $daysInMonth = Date_Calc::daysInMonth($month, $year);
2984 $weeksInMonth = Date_Calc::weeksInMonth($month, $year);
2985 for ($row_counter = 0; $row_counter < $weeksInMonth; $row_counter++) {
2986 for ($column_counter = 0; $column_counter <= 6; $column_counter++) {
2987 $month_array[$row_counter][$column_counter] =
2988 Date_Calc::daysToDate($curr_day, $format);
2993 return $month_array;
2998 // {{{ getCalendarYear()
3001 * Return a set of arrays to construct a calendar year for the given date
3003 * @param int $year the year in four digit format, default current
3005 * @param string $format the string indicating how to format the output
3007 * @return array $year[$month][$row][$col]
3011 public function getCalendarYear($year = null, $format = DATE_CALC_FORMAT)
3013 if (is_null($year)) {
3014 $year = Date_Calc::dateNow('%Y');
3017 $year_array = array();
3019 for ($curr_month = 0; $curr_month <= 11; $curr_month++) {
3020 $year_array[$curr_month] =
3021 Date_Calc::getCalendarMonth(
3036 * Returns date of day before given date
3038 * @param int $day the day of the month, default is current local day
3039 * @param int $month the month, default is current local month
3040 * @param int $year the year in four digit format, default is current
3042 * @param string $format the string indicating how to format the output
3044 * @return string the date in the desired format
3048 public function prevDay(
3052 $format = DATE_CALC_FORMAT
3055 if (is_null($year)) {
3056 $year = Date_Calc::dateNow('%Y');
3058 if (empty($month)) {
3059 $month = Date_Calc::dateNow('%m');
3062 $day = Date_Calc::dateNow('%d');
3065 return Date_Calc::addDays(-1, $day, $month, $year, $format);
3073 * Returns date of day after given date
3075 * @param int $day the day of the month, default is current local day
3076 * @param int $month the month, default is current local month
3077 * @param int $year the year in four digit format, default is current
3079 * @param string $format the string indicating how to format the output
3081 * @return string the date in the desired format
3085 public function nextDay(
3089 $format = DATE_CALC_FORMAT
3092 if (is_null($year)) {
3093 $year = Date_Calc::dateNow('%Y');
3095 if (empty($month)) {
3096 $month = Date_Calc::dateNow('%m');
3099 $day = Date_Calc::dateNow('%d');
3102 return Date_Calc::addDays(1, $day, $month, $year, $format);
3107 // {{{ prevWeekday()
3110 * Returns date of the previous weekday, skipping from Monday to Friday
3112 * @param int $day the day of the month, default is current local day
3113 * @param int $month the month, default is current local month
3114 * @param int $year the year in four digit format, default is current
3116 * @param string $format the string indicating how to format the output
3118 * @return string the date in the desired format
3122 public function prevWeekday(
3126 $format = DATE_CALC_FORMAT
3129 if (is_null($year)) {
3130 $year = Date_Calc::dateNow('%Y');
3132 if (empty($month)) {
3133 $month = Date_Calc::dateNow('%m');
3136 $day = Date_Calc::dateNow('%d');
3139 $days = Date_Calc::dateToDays($day, $month, $year);
3140 if (Date_Calc::dayOfWeek($day, $month, $year) == 1) {
3142 } elseif (Date_Calc::dayOfWeek($day, $month, $year) == 0) {
3148 return Date_Calc::daysToDate($days, $format);
3153 // {{{ nextWeekday()
3156 * Returns date of the next weekday of given date, skipping from
3159 * @param int $day the day of the month, default is current local day
3160 * @param int $month the month, default is current local month
3161 * @param int $year the year in four digit format, default is current
3163 * @param string $format the string indicating how to format the output
3165 * @return string the date in the desired format
3169 public function nextWeekday(
3173 $format = DATE_CALC_FORMAT
3176 if (is_null($year)) {
3177 $year = Date_Calc::dateNow('%Y');
3179 if (empty($month)) {
3180 $month = Date_Calc::dateNow('%m');
3183 $day = Date_Calc::dateNow('%d');
3186 $days = Date_Calc::dateToDays($day, $month, $year);
3187 if (Date_Calc::dayOfWeek($day, $month, $year) == 5) {
3189 } elseif (Date_Calc::dayOfWeek($day, $month, $year) == 6) {
3195 return Date_Calc::daysToDate($days, $format);
3200 // {{{ daysToPrevDayOfWeek()
3203 * Returns 'Julian Day' of the previous specific day of the week
3204 * from the given date.
3206 * @param int $dow the day of the week (0 = Sunday)
3207 * @param int $days 'Julian Day', i.e. the no of days since 1st
3208 * January, 4713 B.C.
3209 * @param bool $onorbefore if true and days are same, returns current day
3211 * @return int 'Julian Day', i.e. the no of days since 1st January,
3215 * @since Method available since Release 1.5.0
3217 public function daysToPrevDayOfWeek($dow, $days, $onorbefore = false)
3219 $curr_weekday = Date_Calc::daysToDayOfWeek($days);
3220 if ($curr_weekday == $dow) {
3226 } elseif ($curr_weekday < $dow) {
3227 return $days - 7 + $dow - $curr_weekday;
3229 return $days - $curr_weekday + $dow;
3235 // {{{ prevDayOfWeek()
3238 * Returns date of the previous specific day of the week
3239 * from the given date
3241 * @param int $dow the day of the week (0 = Sunday)
3242 * @param int $day the day of the month, default is current local
3244 * @param int $month the month, default is current local month
3245 * @param int $year the year in four digit format, default is
3246 * current local year
3247 * @param string $format the string indicating how to format the output
3248 * @param bool $onorbefore if true and days are same, returns current day
3250 * @return string the date in the desired format
3254 public function prevDayOfWeek(
3259 $format = DATE_CALC_FORMAT,
3263 if (is_null($year)) {
3264 $year = Date_Calc::dateNow('%Y');
3266 if (empty($month)) {
3267 $month = Date_Calc::dateNow('%m');
3270 $day = Date_Calc::dateNow('%d');
3273 $days = Date_Calc::dateToDays($day, $month, $year);
3274 $days = Date_Calc::daysToPrevDayOfWeek($dow, $days, $onorbefore);
3275 return Date_Calc::daysToDate($days, $format);
3280 // {{{ daysToNextDayOfWeek()
3283 * Returns 'Julian Day' of the next specific day of the week
3284 * from the given date.
3286 * @param int $dow the day of the week (0 = Sunday)
3287 * @param int $days 'Julian Day', i.e. the no of days since 1st
3288 * January, 4713 B.C.
3289 * @param bool $onorafter if true and days are same, returns current day
3291 * @return int 'Julian Day', i.e. the no of days since 1st January,
3295 * @since Method available since Release 1.5.0
3297 public function daysToNextDayOfWeek($dow, $days, $onorafter = false)
3299 $curr_weekday = Date_Calc::daysToDayOfWeek($days);
3300 if ($curr_weekday == $dow) {
3306 } elseif ($curr_weekday > $dow) {
3307 return $days + 7 - $curr_weekday + $dow;
3309 return $days + $dow - $curr_weekday;
3315 // {{{ nextDayOfWeek()
3318 * Returns date of the next specific day of the week
3319 * from the given date
3321 * @param int $dow the day of the week (0 = Sunday)
3322 * @param int $day the day of the month, default is current local
3324 * @param int $month the month, default is current local month
3325 * @param int $year the year in four digit format, default is
3326 * current local year
3327 * @param string $format the string indicating how to format the output
3328 * @param bool $onorafter if true and days are same, returns current day
3330 * @return string the date in the desired format
3334 public function nextDayOfWeek(
3339 $format = DATE_CALC_FORMAT,
3343 if (is_null($year)) {
3344 $year = Date_Calc::dateNow('%Y');
3346 if (empty($month)) {
3347 $month = Date_Calc::dateNow('%m');
3350 $day = Date_Calc::dateNow('%d');
3353 $days = Date_Calc::dateToDays($day, $month, $year);
3354 $days = Date_Calc::daysToNextDayOfWeek($dow, $days, $onorafter);
3355 return Date_Calc::daysToDate($days, $format);
3360 // {{{ prevDayOfWeekOnOrBefore()
3363 * Returns date of the previous specific day of the week
3364 * on or before the given date
3366 * @param int $dow the day of the week (0 = Sunday)
3367 * @param int $day the day of the month, default is current local day
3368 * @param int $month the month, default is current local month
3369 * @param int $year the year in four digit format, default is current
3371 * @param string $format the string indicating how to format the output
3373 * @return string the date in the desired format
3377 public function prevDayOfWeekOnOrBefore(
3382 $format = DATE_CALC_FORMAT
3385 return Date_Calc::prevDayOfWeek(
3397 // {{{ nextDayOfWeekOnOrAfter()
3400 * Returns date of the next specific day of the week
3401 * on or after the given date
3403 * @param int $dow the day of the week (0 = Sunday)
3404 * @param int $day the day of the month, default is current local day
3405 * @param int $month the month, default is current local month
3406 * @param int $year the year in four digit format, default is current
3408 * @param string $format the string indicating how to format the output
3410 * @return string the date in the desired format
3414 public function nextDayOfWeekOnOrAfter(
3419 $format = DATE_CALC_FORMAT
3422 return Date_Calc::nextDayOfWeek(
3434 // {{{ beginOfWeek()
3437 * Find the month day of the beginning of week for given date,
3438 * using {@link DATE_CALC_BEGIN_WEEKDAY}
3440 * Can return weekday of prev month.
3442 * @param int $day the day of the month, default is current local day
3443 * @param int $month the month, default is current local month
3444 * @param int $year the year in four digit format, default is current
3446 * @param string $format the string indicating how to format the output
3448 * @return string the date in the desired format
3452 public function beginOfWeek(
3456 $format = DATE_CALC_FORMAT
3459 if (is_null($year)) {
3460 $year = Date_Calc::dateNow('%Y');
3462 if (empty($month)) {
3463 $month = Date_Calc::dateNow('%m');
3466 $day = Date_Calc::dateNow('%d');
3469 $hn_days = Date_Calc::dateToDays($day, $month, $year);
3470 $this_weekday = Date_Calc::daysToDayOfWeek($hn_days);
3471 $interval = (7 - DATE_CALC_BEGIN_WEEKDAY + $this_weekday) % 7;
3472 return Date_Calc::daysToDate($hn_days - $interval, $format);
3480 * Find the month day of the end of week for given date,
3481 * using {@link DATE_CALC_BEGIN_WEEKDAY}
3483 * Can return weekday of following month.
3485 * @param int $day the day of the month, default is current local day
3486 * @param int $month the month, default is current local month
3487 * @param int $year the year in four digit format, default is current
3489 * @param string $format the string indicating how to format the output
3491 * @return string the date in the desired format
3495 public function endOfWeek(
3499 $format = DATE_CALC_FORMAT
3502 if (is_null($year)) {
3503 $year = Date_Calc::dateNow('%Y');
3505 if (empty($month)) {
3506 $month = Date_Calc::dateNow('%m');
3509 $day = Date_Calc::dateNow('%d');
3512 $hn_days = Date_Calc::dateToDays($day, $month, $year);
3513 $this_weekday = Date_Calc::daysToDayOfWeek($hn_days);
3514 $interval = (6 + DATE_CALC_BEGIN_WEEKDAY - $this_weekday) % 7;
3515 return Date_Calc::daysToDate($hn_days + $interval, $format);
3520 // {{{ beginOfPrevWeek()
3523 * Find the month day of the beginning of week before given date,
3524 * using {@link DATE_CALC_BEGIN_WEEKDAY}
3526 * Can return weekday of prev month.
3528 * @param int $day the day of the month, default is current local day
3529 * @param int $month the month, default is current local month
3530 * @param int $year the year in four digit format, default is current
3532 * @param string $format the string indicating how to format the output
3534 * @return string the date in the desired format
3538 public function beginOfPrevWeek(
3542 $format = DATE_CALC_FORMAT
3545 if (is_null($year)) {
3546 $year = Date_Calc::dateNow('%Y');
3548 if (empty($month)) {
3549 $month = Date_Calc::dateNow('%m');
3552 $day = Date_Calc::dateNow('%d');
3555 list($hn_pwyear, $hn_pwmonth, $hn_pwday) =
3556 explode(" ", Date_Calc::daysToDate(
3557 Date_Calc::dateToDays(
3564 return Date_Calc::beginOfWeek(
3574 // {{{ beginOfNextWeek()
3577 * Find the month day of the beginning of week after given date,
3578 * using {@link DATE_CALC_BEGIN_WEEKDAY}
3580 * Can return weekday of prev month.
3582 * @param int $day the day of the month, default is current local day
3583 * @param int $month the month, default is current local month
3584 * @param int $year the year in four digit format, default is current
3586 * @param string $format the string indicating how to format the output
3588 * @return string the date in the desired format
3592 public function beginOfNextWeek(
3596 $format = DATE_CALC_FORMAT
3599 if (is_null($year)) {
3600 $year = Date_Calc::dateNow('%Y');
3602 if (empty($month)) {
3603 $month = Date_Calc::dateNow('%m');
3606 $day = Date_Calc::dateNow('%d');
3609 list($hn_pwyear, $hn_pwmonth, $hn_pwday) =
3612 Date_Calc::daysToDate(
3613 Date_Calc::dateToDays(
3621 return Date_Calc::beginOfWeek(
3631 // {{{ beginOfMonth()
3634 * Return date of first day of month of given date
3636 * @param int $month the month, default is current local month
3637 * @param int $year the year in four digit format, default is current
3639 * @param string $format the string indicating how to format the output
3641 * @return string the date in the desired format
3644 * @see Date_Calc::beginOfMonthBySpan()
3645 * @deprecated Method deprecated in Release 1.4.4
3647 public function beginOfMonth($month = 0, $year = null, $format = DATE_CALC_FORMAT)
3649 if (is_null($year)) {
3650 $year = Date_Calc::dateNow('%Y');
3652 if (empty($month)) {
3653 $month = Date_Calc::dateNow('%m');
3656 return Date_Calc::dateFormat(
3657 Date_Calc::getFirstDayOfMonth(
3672 * Return date of last day of month of given date
3674 * @param int $month the month, default is current local month
3675 * @param int $year the year in four digit format, default is current
3677 * @param string $format the string indicating how to format the output
3679 * @return string the date in the desired format
3682 * @see Date_Calc::beginOfMonthBySpan()
3683 * @since Method available since Release 1.5.0
3684 * @deprecated Method deprecated in Release 1.5.0
3686 public function endOfMonth($month = 0, $year = null, $format = DATE_CALC_FORMAT)
3688 if (is_null($year)) {
3689 $year = Date_Calc::dateNow('%Y');
3691 if (empty($month)) {
3692 $month = Date_Calc::dateNow('%m');
3695 return Date_Calc::daysToDate(
3696 Date_Calc::lastDayOfMonth($month, $year),
3703 // {{{ beginOfPrevMonth()
3706 * Returns date of the first day of previous month of given date
3708 * @param mixed $dummy irrelevant parameter
3709 * @param int $month the month, default is current local month
3710 * @param int $year the year in four digit format, default is current
3712 * @param string $format the string indicating how to format the output
3714 * @return string the date in the desired format
3717 * @see Date_Calc::beginOfMonthBySpan()
3718 * @deprecated Method deprecated in Release 1.4.4
3720 public function beginOfPrevMonth(
3724 $format = DATE_CALC_FORMAT
3727 if (is_null($year)) {
3728 $year = Date_Calc::dateNow('%Y');
3730 if (empty($month)) {
3731 $month = Date_Calc::dateNow('%m');
3734 list($hn_pmyear, $hn_prevmonth) = Date_Calc::prevMonth($month, $year);
3735 return Date_Calc::dateFormat(
3736 Date_Calc::getFirstDayOfMonth(
3748 // {{{ endOfPrevMonth()
3751 * Returns date of the last day of previous month for given date
3753 * @param mixed $dummy irrelevant parameter
3754 * @param int $month the month, default is current local month
3755 * @param int $year the year in four digit format, default is current
3757 * @param string $format the string indicating how to format the output
3759 * @return string the date in the desired format
3762 * @see Date_Calc::endOfMonthBySpan()
3763 * @deprecated Method deprecated in Release 1.4.4
3765 public function endOfPrevMonth(
3769 $format = DATE_CALC_FORMAT
3772 if (is_null($year)) {
3773 $year = Date_Calc::dateNow('%Y');
3775 if (empty($month)) {
3776 $month = Date_Calc::dateNow('%m');
3779 return Date_Calc::daysToDate(
3780 Date_Calc::firstDayOfMonth(
3790 // {{{ beginOfNextMonth()
3793 * Returns date of begin of next month of given date
3795 * @param mixed $dummy irrelevant parameter
3796 * @param int $month the month, default is current local month
3797 * @param int $year the year in four digit format, default is current
3799 * @param string $format the string indicating how to format the output
3801 * @return string the date in the desired format
3804 * @see Date_Calc::beginOfMonthBySpan()
3805 * @deprecated Method deprecated in Release 1.4.4
3807 public function beginOfNextMonth(
3811 $format = DATE_CALC_FORMAT
3814 if (is_null($year)) {
3815 $year = Date_Calc::dateNow('%Y');
3817 if (empty($month)) {
3818 $month = Date_Calc::dateNow('%m');
3821 list($hn_nmyear, $hn_nextmonth) = Date_Calc::nextMonth($month, $year);
3822 return Date_Calc::dateFormat(
3823 Date_Calc::getFirstDayOfMonth(
3835 // {{{ endOfNextMonth()
3838 * Returns date of the last day of next month of given date
3840 * @param mixed $dummy irrelevant parameter
3841 * @param int $month the month, default is current local month
3842 * @param int $year the year in four digit format, default is current
3844 * @param string $format the string indicating how to format the output
3846 * @return string the date in the desired format
3849 * @see Date_Calc::endOfMonthBySpan()
3850 * @deprecated Method deprecated in Release 1.4.4
3852 public function endOfNextMonth(
3856 $format = DATE_CALC_FORMAT
3859 if (is_null($year)) {
3860 $year = Date_Calc::dateNow('%Y');
3862 if (empty($month)) {
3863 $month = Date_Calc::dateNow('%m');
3866 list($hn_nmyear, $hn_nextmonth) = Date_Calc::nextMonth($month, $year);
3867 return Date_Calc::daysToDate(
3868 Date_Calc::lastDayOfMonth(
3878 // {{{ beginOfMonthBySpan()
3881 * Returns date of the first day of the month in the number of months
3882 * from the given date
3884 * @param int $months the number of months from the date provided.
3885 * Positive numbers go into the future.
3886 * Negative numbers go into the past.
3887 * Nought is the month presented in $month.
3888 * @param string $month the month, default is current local month
3889 * @param string $year the year in four digit format, default is the
3890 * current local year
3891 * @param string $format the string indicating how to format the output
3893 * @return string the date in the desired format
3896 * @since Method available since Release 1.4.4
3898 public function beginOfMonthBySpan(
3902 $format = DATE_CALC_FORMAT
3905 if (is_null($year)) {
3906 $year = Date_Calc::dateNow('%Y');
3908 if (empty($month)) {
3909 $month = Date_Calc::dateNow('%m');
3912 return Date_Calc::addMonths(
3914 Date_Calc::getFirstDayOfMonth($month, $year),
3923 // {{{ endOfMonthBySpan()
3926 * Returns date of the last day of the month in the number of months
3927 * from the given date
3929 * @param int $months the number of months from the date provided.
3930 * Positive numbers go into the future.
3931 * Negative numbers go into the past.
3932 * Nought is the month presented in $month.
3933 * @param string $month the month, default is current local month
3934 * @param string $year the year in four digit format, default is the
3935 * current local year
3936 * @param string $format the string indicating how to format the output
3938 * @return string the date in the desired format
3941 * @since Method available since Release 1.4.4
3943 public function endOfMonthBySpan(
3947 $format = DATE_CALC_FORMAT
3950 if (is_null($year)) {
3951 $year = Date_Calc::dateNow('%Y');
3953 if (empty($month)) {
3954 $month = Date_Calc::dateNow('%m');
3957 $hn_days = Date_Calc::addMonthsToDays(
3959 Date_Calc::firstDayOfMonth($month, $year)
3961 return Date_Calc::daysToDate($hn_days, $format);
3966 // {{{ firstOfMonthWeekday()
3969 * Find the day of the week for the first of the month of given date
3971 * @param int $month the month, default is current local month
3972 * @param int $year the year in four digit format, default is current
3975 * @return int number of weekday for the first day, 0=Sunday
3979 public function firstOfMonthWeekday($month = 0, $year = null)
3981 if (is_null($year)) {
3982 $year = Date_Calc::dateNow('%Y');
3984 if (empty($month)) {
3985 $month = Date_Calc::dateNow('%m');
3987 return Date_Calc::daysToDayOfWeek(Date_Calc::firstDayOfMonth(
3995 // {{{ nWeekdayOfMonth()
3998 * Calculates the date of the Nth weekday of the month,
3999 * such as the second Saturday of January 2000
4001 * @param int $week the number of the week to get
4002 * (1 to 5. Also can be 'last'.)
4003 * @param int $dow the day of the week (0 = Sunday)
4004 * @param int $month the month
4005 * @param int $year the year. Use the complete year instead of the
4006 * abbreviated version. E.g. use 2005, not 05.
4007 * @param string $format the string indicating how to format the output
4009 * @return string the date in the desired format
4013 public function nWeekDayOfMonth(
4018 $format = DATE_CALC_FORMAT
4021 if ((is_numeric($week) && ($week < 1 || $week > 5)) ||
4022 (!is_numeric($week) && $week != "last")
4024 return PEAR::raiseError("Invalid week value '$week', only 1-5 or 'last' accepted");
4027 if ($dow < 0 || $dow > 6) {
4028 return PEAR::raiseError("Invalid dow value '$dow', only 0-6 accepted");
4031 if ($month < 1 || $month > 12) {
4032 return PEAR::raiseError("Invalid month value '$month'");
4035 if (is_numeric($week)) {
4036 // the weekday of first day of month "1"
4037 $DOW1 = Date_Calc::dayOfWeek(1, $month, $year);
4040 $sunday = ($week - 1) * 7 + 1;
4042 $sunday += (7 - $DOW1);
4045 // adjust the sunday with dow addition
4046 $wdate = $sunday + $dow;
4047 if ($wdate > Date_Calc::daysInMonth($month, $year)) {
4050 return Date_Calc::dateFormat($wdate, $month, $year, $format);
4052 } elseif ($week == 'last' && $dow < 7) {
4053 $lastday = Date_Calc::daysInMonth($month, $year);
4054 $lastdow = Date_Calc::dayOfWeek($lastday, $month, $year);
4055 $diff = $dow - $lastdow;
4057 return Date_Calc::dateFormat(
4058 $lastday - (7 - $diff),
4064 return Date_Calc::dateFormat(
4078 // {{{ isValidDate()
4081 * Returns true for valid date, false for invalid date
4083 * Uses the proleptic Gregorian calendar, with the year 0 (1 B.C.)
4084 * assumed to be valid and also assumed to be a leap year.
4086 * @param int $day the day of the month
4087 * @param int $month the month
4088 * @param int $year the year. Use the complete year instead of the
4089 * abbreviated version. E.g. use 2005, not 05.
4095 public function isValidDate($day, $month, $year)
4097 if ($day < 1 || $month < 1 || $month > 12) {
4101 if (Date_Calc::isLeapYearGregorian($year)) {
4106 } elseif ($month == 4 || $month == 6 || $month == 9 || $month == 11) {
4115 // {{{ isLeapYearGregorian()
4118 * Returns true for a leap year, else false
4120 * Uses the proleptic Gregorian calendar. The year 0 (1 B.C.) is
4121 * assumed in this algorithm to be a leap year. The function is
4122 * valid for all years, positive and negative.
4124 * @param int $year the year. Use the complete year instead of the
4125 * abbreviated version. E.g. use 2005, not 05.
4130 * @since Method available since Release 1.5.0
4132 public function isLeapYearGregorian($year = null)
4134 if (is_null($year)) {
4135 $year = Date_Calc::dateNow('%Y');
4137 return (($year % 4 == 0) &&
4138 ($year % 100 != 0)) ||
4144 // {{{ isLeapYearJulian()
4147 * Returns true for a leap year, else false
4149 * Uses the proleptic Julian calendar. The year 0 (1 B.C.) is
4150 * assumed in this algorithm to be a leap year. The function is
4151 * valid for all years, positive and negative.
4153 * @param int $year the year. Use the complete year instead of the
4154 * abbreviated version. E.g. use 2005, not 05.
4159 * @since Method available since Release 1.5.0
4161 public function isLeapYearJulian($year = null)
4163 if (is_null($year)) {
4164 $year = Date_Calc::dateNow('%Y');
4166 return $year % 4 == 0;
4174 * Returns true for a leap year, else false
4176 * @param int $year the year. Use the complete year instead of the
4177 * abbreviated version. E.g. use 2005, not 05.
4183 public function isLeapYear($year = null)
4185 if (is_null($year)) {
4186 $year = Date_Calc::dateNow('%Y');
4189 // pre Gregorio XIII - 1582
4190 return Date_Calc::isLeapYearJulian($year);
4192 // post Gregorio XIII - 1582
4193 return Date_Calc::isLeapYearGregorian($year);
4199 // {{{ isFutureDate()
4202 * Determines if given date is a future date from now
4204 * @param int $day the day of the month
4205 * @param int $month the month
4206 * @param int $year the year. Use the complete year instead of the
4207 * abbreviated version. E.g. use 2005, not 05.
4213 public function isFutureDate($day, $month, $year)
4215 $this_year = Date_Calc::dateNow('%Y');
4216 $this_month = Date_Calc::dateNow('%m');
4217 $this_day = Date_Calc::dateNow('%d');
4219 if ($year > $this_year) {
4221 } elseif ($year == $this_year) {
4222 if ($month > $this_month) {
4224 } elseif ($month == $this_month) {
4225 if ($day > $this_day) {
4238 * Determines if given date is a past date from now
4240 * @param int $day the day of the month
4241 * @param int $month the month
4242 * @param int $year the year. Use the complete year instead of the
4243 * abbreviated version. E.g. use 2005, not 05.
4249 public function isPastDate($day, $month, $year)
4251 $this_year = Date_Calc::dateNow('%Y');
4252 $this_month = Date_Calc::dateNow('%m');
4253 $this_day = Date_Calc::dateNow('%d');
4255 if ($year < $this_year) {
4257 } elseif ($year == $this_year) {
4258 if ($month < $this_month) {
4260 } elseif ($month == $this_month) {
4261 if ($day < $this_day) {
4274 * Returns number of days between two given dates
4276 * @param int $day1 the day of the month
4277 * @param int $month1 the month
4278 * @param int $year1 the year. Use the complete year instead of the
4279 * abbreviated version. E.g. use 2005, not 05.
4280 * @param int $day2 the day of the month
4281 * @param int $month2 the month
4282 * @param int $year2 the year. Use the complete year instead of the
4283 * abbreviated version. E.g. use 2005, not 05.
4285 * @return int the absolute number of days between the two dates.
4286 * If an error occurs, -1 is returned.
4290 public function dateDiff($day1, $month1, $year1, $day2, $month2, $year2)
4292 if (!Date_Calc::isValidDate($day1, $month1, $year1)) {
4295 if (!Date_Calc::isValidDate($day2, $month2, $year2)) {
4298 return abs(Date_Calc::dateToDays($day1, $month1, $year1)
4299 - Date_Calc::dateToDays($day2, $month2, $year2));
4304 // {{{ compareDates()
4307 * Compares two dates
4309 * @param int $day1 the day of the month
4310 * @param int $month1 the month
4311 * @param int $year1 the year. Use the complete year instead of the
4312 * abbreviated version. E.g. use 2005, not 05.
4313 * @param int $day2 the day of the month
4314 * @param int $month2 the month
4315 * @param int $year2 the year. Use the complete year instead of the
4316 * abbreviated version. E.g. use 2005, not 05.
4318 * @return int 0 if the dates are equal. 1 if date 1 is later, -1
4319 * if date 1 is earlier.
4323 public static function compareDates($day1, $month1, $year1, $day2, $month2, $year2)
4325 $ndays1 = Date_Calc::dateToDays($day1, $month1, $year1);
4326 $ndays2 = Date_Calc::dateToDays($day2, $month2, $year2);
4327 if ($ndays1 == $ndays2) {
4330 return ($ndays1 > $ndays2) ? 1 : -1;
4338 * Rounds the date according to the specified precision
4340 * The precision parameter must be one of the following constants:
4342 * - {@link DATE_PRECISION_YEAR}
4343 * - {@link DATE_PRECISION_MONTH}
4344 * - {@link DATE_PRECISION_DAY}
4345 * - {@link DATE_PRECISION_HOUR}
4346 * - {@link DATE_PRECISION_10MINUTES}
4347 * - {@link DATE_PRECISION_MINUTE}
4348 * - {@link DATE_PRECISION_10SECONDS}
4349 * - {@link DATE_PRECISION_SECOND}
4351 * The precision can also be specified as an integral offset from
4352 * one of these constants, where the offset reflects a precision
4353 * of 10 to the power of the offset greater than the constant.
4356 * - <b>(DATE_PRECISION_YEAR - 1)</b> rounds the date to the nearest 10
4358 * - <b>(DATE_PRECISION_YEAR - 3)</b> rounds the date to the nearest 1000
4360 * - <b>(DATE_PRECISION_SECOND + 1)</b> rounds the date to 1 decimal
4362 * - <b>(DATE_PRECISION_SECOND + 1)</b> rounds the date to 3 decimal
4363 * points of a second
4364 * - <b>(DATE_PRECISION_SECOND + 1)</b> rounds the date to the nearest 10
4365 * seconds (thus it is equivalent to
4366 * <b>DATE_PRECISION_10SECONDS</b>)
4368 * N.B. This function requires a time in UTC if both the precision is at
4369 * least DATE_PRECISION_SECOND and leap seconds are being counted, otherwise
4370 * any local time is acceptable.
4372 * @param int $pn_precision a 'DATE_PRECISION_*' constant (defaults to
4373 * {@link DATE_PRECISION_DAY})
4374 * @param int $pn_day the day of the month
4375 * @param int $pn_month the month
4376 * @param int $pn_year the year
4377 * @param int $pn_hour the hour
4378 * @param int $pn_minute the minute
4379 * @param mixed $pn_second the second as integer or float
4380 * @param bool $pb_countleap whether to count leap seconds (defaults to
4381 * {@link DATE_COUNT_LEAP_SECONDS})
4383 * @return array array of year, month, day, hour, minute, second
4386 * @since Method available since Release 1.5.0
4388 public function round(
4396 $pb_countleap = DATE_COUNT_LEAP_SECONDS
4399 if ($pn_precision <= DATE_PRECISION_YEAR) {
4406 if ($pn_precision < DATE_PRECISION_YEAR) {
4407 $hn_year = round($pn_year, $pn_precision - DATE_PRECISION_YEAR);
4411 $hn_midyear = (Date_Calc::firstDayOfYear($pn_year + 1) -
4412 Date_Calc::firstDayOfYear($pn_year)) / 2;
4413 if (($hn_days = Date_Calc::dayOfYear(
4419 $hn_year = $pn_year;
4420 } elseif ($hn_days >= $hn_midyear) {
4423 $hn_year = $pn_year + 1;
4425 // Take time into account:
4427 $hn_partday = Date_Calc::secondsPastMidnight(
4433 if ($hn_partday >= $hn_midyear - $hn_days) {
4436 $hn_year = $pn_year + 1;
4438 $hn_year = $pn_year;
4442 } elseif ($pn_precision == DATE_PRECISION_MONTH) {
4443 $hn_year = $pn_year;
4449 $hn_firstofmonth = Date_Calc::firstDayOfMonth($pn_month, $pn_year);
4450 $hn_midmonth = (Date_Calc::lastDayOfMonth($pn_month, $pn_year) +
4452 $hn_firstofmonth) / 2;
4453 if (($hn_days = Date_Calc::dateToDays(
4458 $hn_firstofmonth) <= $hn_midmonth - 1) {
4459 $hn_month = $pn_month;
4460 } elseif ($hn_days >= $hn_midmonth) {
4463 list($hn_year, $hn_month) = Date_Calc::nextMonth(
4468 // Take time into account:
4470 $hn_partday = Date_Calc::secondsPastMidnight(
4476 if ($hn_partday >= $hn_midmonth - $hn_days) {
4479 list($hn_year, $hn_month) = Date_Calc::nextMonth(
4484 $hn_month = $pn_month;
4487 } elseif ($pn_precision == DATE_PRECISION_DAY) {
4488 $hn_year = $pn_year;
4489 $hn_month = $pn_month;
4494 if (Date_Calc::secondsPastMidnight(
4501 list($hn_year, $hn_month, $hn_day) =
4502 explode(" ", Date_Calc::nextDay(
4511 } elseif ($pn_precision == DATE_PRECISION_HOUR) {
4512 $hn_year = $pn_year;
4513 $hn_month = $pn_month;
4518 if (Date_Calc::secondsPastTheHour($pn_minute, $pn_second) >= 1800) {
4521 list($hn_year, $hn_month, $hn_day, $hn_hour) =
4522 Date_Calc::addHours(
4530 $hn_hour = $pn_hour;
4532 } elseif ($pn_precision <= DATE_PRECISION_MINUTE) {
4533 $hn_year = $pn_year;
4534 $hn_month = $pn_month;
4536 $hn_hour = $pn_hour;
4539 if ($pn_precision < DATE_PRECISION_MINUTE) {
4542 $pn_precision - DATE_PRECISION_MINUTE
4547 if ($pn_second >= 30) {
4555 Date_Calc::addMinutes(
4564 $hn_minute = $pn_minute;
4568 // Precision is at least (DATE_PRECISION_SECOND - 1):
4570 $hn_year = $pn_year;
4571 $hn_month = $pn_month;
4573 $hn_hour = $pn_hour;
4574 $hn_minute = $pn_minute;
4578 $pn_precision - DATE_PRECISION_SECOND
4581 if (fmod($hn_second, 1) == 0.0) {
4582 $hn_second = (int)$hn_second;
4584 if ($hn_second != intval($pn_second)) {
4591 Date_Calc::addSeconds(
4592 $hn_second - intval($pn_second),
4600 DATE_PRECISION_SECOND &&
4604 // (N.B. if rounded to nearest 10 seconds,
4605 // user does not expect seconds to be '60')
4610 return array((int)$hn_year,
4620 // {{{ roundSeconds()
4623 * Rounds seconds up or down to the nearest specified unit
4625 * @param int $pn_precision number of digits after the decimal point
4626 * @param int $pn_day the day of the month
4627 * @param int $pn_month the month
4628 * @param int $pn_year the year
4629 * @param int $pn_hour the hour
4630 * @param int $pn_minute the minute
4631 * @param mixed $pn_second the second as integer or float
4632 * @param bool $pb_countleap whether to count leap seconds (defaults to
4633 * DATE_COUNT_LEAP_SECONDS)
4635 * @return array array of year, month, day, hour, minute, second
4638 * @since Method available since Release 1.5.0
4640 public function roundSeconds(
4648 $pb_countleap = DATE_COUNT_LEAP_SECONDS
4651 return Date_Calc::round(
4652 DATE_PRECISION_SECOND + $pn_precision,
4664 // {{{ isoWeekToDate()
4667 * Converts the Week number and Day-of-Week to Date
4669 * Calculation algorithm taken from
4670 * {@link http://www.merlyn.demon.co.uk/weekcalc.htm}.
4672 * @param int $dow day of week from 1 (Monday) to 7 (Sunday)
4673 * @param int $week number of week from 1 to 53
4674 * @param int $year four digits of year
4675 * @param string $format the output format
4677 * @return string formatted date
4680 * @since Method available since Release 1.5.0a2
4682 public function isoWeekToDate($dow, $week, $year, $format = DATE_CALC_FORMAT)
4684 // validates the week number
4685 list(, $nweeks) = Date_Calc::isoWeekDate(28, 12, $year);
4686 if ($week > $nweeks) {
4687 return PEAR::raiseError(
4688 "ISO week number for $year cannot be greater than $nweeks",
4689 DATE_ERROR_INVALIDDATE
4693 // validates the day of week
4694 if ($dow < 1 || $dow > 7) {
4695 return PEAR::raiseError(
4696 "ISO day of week must be between 1 and 7",
4697 DATE_ERROR_INVALIDDATE
4701 // finds the day of week of January 4th.
4702 $jan4th = Date_Calc::dayOfWeek(4, 1, $year);
4707 // offset to the monday of that week
4708 $offset = -($jan4th - 1);
4710 // increment the days starting from january 4th.
4711 $days = Date_Calc::dateToDays(1, 1, $year) + $offset + 7 * ($week - 1) + ($dow - 1) + 3;
4713 return Date_Calc::daysToDate($days, $format);
4726 * c-hanging-comment-ender-p: nil