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

Source for file BitDate.php

Documentation is available at BitDate.php

  1. <?php
  2. /**
  3.  * Date Handling Class
  4.  *
  5.  * @package kernel
  6.  * @version $Header$
  7.  *
  8.  *  Created by: Jeremy Jongsma (jjongsma@tickchat.com)
  9.  *  Created on: Sat Jul 26 11:51:31 CDT 2003
  10.  */
  11.  
  12. /**
  13.  * BitDate
  14.  *
  15.  * This class takes care of all time/date conversions for
  16.  * storing dates in the DB and displaying dates to the user.
  17.  *
  18.  * The objectives are:
  19.  *  - Dates will always stored in UTC in the database
  20.  *  - Display dates will be computed based on the preferred
  21.  *    display offset specified in the constructor
  22.  *
  23.  * @package kernel
  24.  *
  25.  * @todo As of 1.7, dates are still stored in server local time.
  26.  *  This should be changed for 1.7.1 (requires many module changes).
  27.  */
  28. class BitDate {
  29.     /**
  30.      * UTC offset to use for display
  31.      * @var int 
  32.      */
  33.     var $display_offset;
  34.  
  35.     /**
  36.      * Current UTC offset of server
  37.      * @var int 
  38.      */
  39.     var $server_offset;
  40.  
  41.     /**
  42.      * Default constructor
  43.      * @param int desired offset for date display, in minutes
  44.      */
  45.     function BitDate($_display_offset = 0) {
  46.         if ( version_compare( phpversion(), "5.1.0", ">=" ) ) {
  47.             date_default_timezone_set( @date_default_timezone_get() );
  48.         }
  49.         $this->display_offset = $_display_offset;
  50.         $this->server_offset = mktime(0,0,0,1,2,1970) - gmmktime(0,0,0,1,2,1970);
  51.     }
  52.  
  53.     /**
  54.      * Retrieves the user's preferred offset for displaying dates.
  55.      *
  56.      * @param int the logged-in user.
  57.      * @return int the preferred offset to UTC or 0 for straight UTC display
  58.      */
  59.     function get_display_offset($_user = false) {
  60.         global $gBitUser;
  61.  
  62.         // Cache preference from DB
  63.         $display_tz = "UTC";
  64.  
  65.         // Default to UTC get_display_offset
  66.         $this->display_offset = 0;
  67.  
  68.         // Load pref from DB if cache is empty
  69.         $display_tz = $gBitUser->getPreference('site_display_utc', "Local");
  70.  
  71.         // Recompute offset each request in case DST kicked in
  72.         if ( $display_tz == "Local" && isset($_COOKIE["tz_offset"]))
  73.             $this->display_offset = intval($_COOKIE["tz_offset"]);
  74.         else if ( $display_tz == "Fixed" )
  75.             $this->display_offset = $gBitUser->getPreference( 'site_display_timezone', 0 ); 
  76.             if ( version_compare( phpversion(), "5.1.0", ">=" ) and !is_numeric( $this->display_offset ) ) {
  77.                 $dateTimeZoneUser = new DateTimeZone( $this->display_offset );
  78.                 $dtNow = new DateTime( "now" );
  79.                 $this->display_offset = $dateTimeZoneUser->getOffset( $dtNow );
  80.             }
  81.         return $this->display_offset;
  82.     }
  83.  
  84.     /**
  85.      * Convert a UTC timestamp to the preferred display offset.
  86.      * @param timestamp ISO format date
  87.      *     yYYY-mM-dD hH:mM:sS.s ( Lower case letters optional, but should be 0 )
  88.      * @return int Seconds count based on 1st Jan 1970<br>
  89.      */
  90.     function getDisplayDateFromUTC($_timestamp) {
  91.         global $gBitUser;
  92.         
  93.         if ( $gBitUser->getPreference('site_display_utc', "Local") == "Fixed" && class_exists( 'DateTime' ) ) {
  94.             date_default_timezone_set( $gBitUser->getPreference( 'site_display_timezone', 'UTC' ) );
  95.             if ( is_numeric( $_timestamp )) {
  96.                 $dateTimeUser = new DateTime( '@'.$_timestamp );
  97.             } else  {
  98.                 $dateTimeUser = new DateTime( $_timestamp );
  99.             }
  100.             $dateTimeUserZone = new DateTimeZone( $gBitUser->getPreference( 'site_display_timezone', 'UTC' ) );
  101.             return strtotime( $dateTimeUser->format(DATE_ATOM) ) + timezone_offset_get( $dateTimeUserZone, $dateTimeUser );
  102.         } else {
  103.             return $this->getTimestampFromISO($_timestamp) + $this->display_offset;
  104.         }
  105.     }
  106.  
  107.     /**
  108.      * Convert a display-offset timestamp to UTC.
  109.      * @param timestamp ISO format date
  110.      *     yYYY-mM-dD hH:mM:sS.s ( Lower case letters optional, but should be 0 )
  111.      * @return int Seconds count based on 1st Jan 1970<br>
  112.      */
  113.     function getUTCFromDisplayDate($_timestamp) {
  114.         global $gBitUser;
  115.         
  116.         if ( $gBitUser->getPreference('site_display_utc', "Local") == "Fixed" ) {
  117.             date_default_timezone_set( $gBitUser->getPreference( 'site_display_timezone', 'UTC' ) );
  118.             if ( is_numeric( $_timestamp )) {
  119.                 $dateTimeUser = new DateTime( '@'.$_timestamp );
  120.             } else  {
  121.                 $dateTimeUser = new DateTime( $_timestamp );
  122.             }
  123.             $dateTimeUserZone = new DateTimeZone( $gBitUser->getPreference( 'site_display_timezone', 'UTC' ) );
  124.             return strtotime( $dateTimeUser->format(DATE_ATOM) ) - timezone_offset_get( $dateTimeUserZone, $dateTimeUser );
  125.         } else {
  126.             return $this->getTimestampFromISO($_timestamp) - $this->display_offset;
  127.         }
  128.     }
  129.  
  130.     /**
  131.      * Convert a UTC timestamp to the local server time.
  132.      * @param  timestamp UTC timestamp to convert.
  133.      * @return timestamp Server timestamp.
  134.      */
  135.     function getServerDateFromUTC($_timestamp) {
  136.         return $this->getTimestampFromISO($_timestamp) + $this->server_offset;
  137.     }
  138.  
  139.     /**
  140.      * Convert a local server timestamp to UTC.
  141.      * @param  timestamp Server timestamp to convert.
  142.      * @return timestamp UTC timestamp.
  143.      */
  144.     function getUTCFromServerDate($_timestamp) {
  145.         return $this->getTimestampFromISO($_timestamp) - $this->server_offset;
  146.     }
  147.  
  148.     /**
  149.      * Retrieve a current UTC timestamp as Unix epoch.
  150.      * @return int Unix epoch
  151.      */
  152.     function getUTCTime() {
  153.         return time();
  154.     }
  155.  
  156.     /**
  157.      * Retrieve a current UTC Timestamp as an ISO formated date/time.
  158.      * @return string Current ISO formated date/time
  159.      */
  160.     function getUTCTimestamp() {
  161.         return $this->date("Y-m-d H:i:s",time(),true);
  162.     }
  163.  
  164.     /**
  165.      * Retrieve a current UTC Date as an ISO formated date
  166.      * @return string Current ISO formated date
  167.      */
  168.     function getUTCDate() {
  169.         return $this->date("Y-m-d",time(),true);
  170.     }
  171.  
  172.     /**
  173.      * Get the name of the current timezone.
  174.      * Currently, only "UTC" or an empty string (Local).
  175.      * @return string Current timezone
  176.      */
  177.     function getTzName() {
  178.         if ($this->display_offset == 0)
  179.             return "UTC";
  180.         else
  181.             return "";
  182.     }
  183.  
  184.     /**
  185.      * Convert ISO date to numberic timestamp.
  186.      *
  187.      * @param string ISO format date
  188.      *     yYYY-mM-dD hH:mM:sS.s ( Lower case letters optional, but should be 0 )
  189.      * @return int Seconds count based on 1st Jan 1970<br>
  190.      *  returns $iso_date if it is a number, or 0 if format invalid
  191.      */
  192.     function getTimestampFromISO( $iso_date, $reverse = false ) {
  193.         $ret = 0;
  194.         if ( is_numeric($iso_date) ) { 
  195.             $ret = $iso_date;
  196.         } else if ( $reverse ) {
  197.             // Input d.m.y, h:m:s
  198.             if (preg_match(
  199.                 "|^([0-9]{1,2})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{3,4}), ?(([0-9]{1,2}):?([0-9]{1,2}):?([0-9\.]{1,8}))?|",
  200.                 ($iso_date), $rr)) {
  201.                     if (!isset($rr[5])) $ret = $this->gmmktime(0,0,0,$rr[2],$rr[1],$rr[3]);
  202.                     else $ret = @$this->gmmktime($rr[5],$rr[6],$rr[7],$rr[2],$rr[1],$rr[3]);
  203.                 }
  204.         } else {    
  205.                 // Input y.m.d h:m:s
  206.                 if (preg_match(
  207.                     "|^([0-9]{3,4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})[ -]?(([0-9]{1,2}):?([0-9]{1,2}):?([0-9\.]{1,4}))?|",
  208.                     ($iso_date), $rr)) {
  209.                         if (!isset($rr[5])) $ret = $this->gmmktime(0,0,0,$rr[2],$rr[3],$rr[1]);
  210.                         else $ret = @$this->gmmktime($rr[5],$rr[6],$rr[7],$rr[2],$rr[3],$rr[1]);
  211.             }
  212.         }
  213.         return $ret;
  214.     }
  215.  
  216.     /**
  217.      * Returns day of week, 0 = Sunday,... 6=Saturday.
  218.      * Algorithm from PEAR::Date_Calc
  219.      * @param int 
  220.      * @param int 
  221.      * @param int 
  222.      * @return int 
  223.      */
  224.     function dayOfWeek($year, $month, $day)
  225.     {
  226.     /*
  227.     Pope Gregory removed 10 days - October 5 to October 14 - from the year 1582 and
  228.     proclaimed that from that time onwards 3 days would be dropped from the calendar
  229.     every 400 years.
  230.  
  231.     Thursday, October 4, 1582 (Julian) was followed immediately by Friday, October 15, 1582 (Gregorian).
  232.     */
  233.         if ($year <= 1582) {
  234.             if ($year < 1582 ||
  235.                 ($year == 1582 && ($month < 10 || ($month == 10 && $day < 15)))) $greg_correction = 3;
  236.              else
  237.                 $greg_correction = 0;
  238.         } else
  239.             $greg_correction = 0;
  240.  
  241.         if($month > 2)
  242.             $month -= 2;
  243.         else {
  244.             $month += 10;
  245.             $year--;
  246.         }
  247.  
  248.         $day =  floor((13 * $month - 1) / 5) +
  249.             $day + ($year % 100) +
  250.             floor(($year % 100) / 4) +
  251.             floor(($year / 100) / 4) - 2 *
  252.             floor($year / 100) + 77 + $greg_correction;
  253.  
  254.         return $day - 7 * floor($day / 7);
  255.     }
  256.  
  257.     /**
  258.      *    Returns week of year, 1 = first week of year.
  259.      *    Algorithm from PEAR::Date_Calc
  260.      * This needs to be checked out for both start day and early date rules
  261.      * @param int 
  262.      * @param int 
  263.      * @param int 
  264.      * @return int 
  265.      */
  266.     function weekOfYear($year, $month, $day)
  267.     {
  268.         $iso    = $this->gregorianToISO($year, $month, $day);
  269.         $parts  = explode('-',$iso);
  270.         $week_number = intval($parts[1]);
  271.         if ( $week_number == 0 ) $week_number = 53;
  272.         return $week_number;
  273.     }
  274.  
  275.     /**
  276.      * Checks for leap year, returns true if it is. No 2-digit year check. Also
  277.      * handles julian calendar correctly.
  278.      * @param int 
  279.      * @return boolean 
  280.      */
  281.     function _is_leap_year($year)
  282.     {
  283.         if ($year % 4 != 0) return false;
  284.  
  285.         if ($year % 400 == 0) {
  286.             return true;
  287.         // if gregorian calendar (>1582), century not-divisible by 400 is not leap
  288.         } else if ($year > 1582 && $year % 100 == 0 ) {
  289.             return false;
  290.         }
  291.  
  292.         return true;
  293.     }
  294.  
  295.     /**
  296.      * checks for leap year, returns true if it is. Has 2-digit year check
  297.      * @param int 
  298.      * @return boolean 
  299.      */
  300.     function is_leap_year($year)
  301.     {
  302.         return  $this->_is_leap_year($this->year_digit_check($year));
  303.     }
  304.  
  305.     /**
  306.      * Fix 2-digit years. Works for any century.
  307.      * Assumes that if 2-digit is more than 30 years in future, then previous century.
  308.      * @todo This needs to be disabled when dates prior to 100AD are required in ISO format
  309.      * @param int 
  310.      * @return int 
  311.      */
  312.     function year_digit_check($y)
  313.     {
  314.         if ($y < 100) {
  315.  
  316.             $yr = (integer) date("Y");
  317.             $century = (integer) ($yr /100);
  318.  
  319.             if ($yr%100 > 50) {
  320.                 $c1 = $century + 1;
  321.                 $c0 = $century;
  322.             } else {
  323.                 $c1 = $century;
  324.                 $c0 = $century - 1;
  325.             }
  326.             $c1 *= 100;
  327.             // if 2-digit year is less than 30 years in future, set it to this century
  328.             // otherwise if more than 30 years in future, then we set 2-digit year to the prev century.
  329.             if (($y + $c1) < $yr+30) $y = $y + $c1;
  330.             else $y = $y + $c0*100;
  331.         }
  332.         return $y;
  333.     }
  334.  
  335.     /**
  336.      *Returns an array with date info.
  337.      * @param boolean 
  338.      * @param boolean 
  339.      * @return array 
  340.      */
  341.     function getDate($d=false,$fast=false)
  342.     {
  343.         if ($d === false) return $this->getdate();
  344.         if ((abs($d) <= 0x7FFFFFFF)) { // check if number in 32-bit signed range
  345.             if (!defined('ADODB_NO_NEGATIVE_TS') || $d >= 0) // if windows, must be +ve integer
  346.                 return @$this->_getDate($d);
  347.         }
  348.         return $this->_getDate($d,$fast);
  349.     }
  350.  
  351.     /*
  352.      * generate $YRS table for _adodb_getdate()
  353.      *
  354.     function _date_gentable($out=true)
  355.     {
  356.  
  357.         for ($i=1970; $i >= 1600; $i-=10) {
  358.             $s = adodb_gmmktime(0,0,0,1,1,$i);
  359.             echo "$i => $s,<br>";
  360.         }
  361.     }
  362.     adodb_date_gentable();
  363.  
  364.     for ($i=1970; $i > 1500; $i--) {
  365.  
  366.     echo "<hr>$i ";
  367.         adodb_date_test_date($i,1,1);
  368.     }
  369.  
  370.     */
  371.  
  372.     /**
  373.      * Low-level function that returns the getdate() array. We have a special
  374.      * $fast flag, which if set to true, will return fewer array values,
  375.      * and is much faster as it does not calculate dow, etc.
  376.      * @param int Date to be converted in Unix epochs
  377.      * @param boolean Return short format array ( less weekday and month )
  378.      * @param boolean Ignore timezone
  379.      * @return array 
  380.      */
  381.     function _getDate($origd=false,$fast=false,$is_gmt=false)
  382.     {
  383.         static $YRS;
  384.  
  385.         $d =  $origd - ($is_gmt ? 0 : adodb_get_gmt_diff(false,false,false));
  386.  
  387.         $_day_power = 86400;
  388.         $_hour_power = 3600;
  389.         $_min_power = 60;
  390.  
  391.         if ($d < -12219321600) $d -= 86400*10; // if 15 Oct 1582 or earlier, gregorian correction
  392.  
  393.         $_month_table_normal = array("",31,28,31,30,31,30,31,31,30,31,30,31);
  394.         $_month_table_leaf = array("",31,29,31,30,31,30,31,31,30,31,30,31);
  395.  
  396.         $d366 = $_day_power * 366;
  397.         $d365 = $_day_power * 365;
  398.  
  399.         if ($d < 0) {
  400.  
  401.             if (empty($YRS)) $YRS = array(
  402.                 1970 => 0,
  403.                 1960 => -315619200,
  404.                 1950 => -631152000,
  405.                 1940 => -946771200,
  406.                 1930 => -1262304000,
  407.                 1920 => -1577923200,
  408.                 1910 => -1893456000,
  409.                 1900 => -2208988800,
  410.                 1890 => -2524521600,
  411.                 1880 => -2840140800,
  412.                 1870 => -3155673600,
  413.                 1860 => -3471292800,
  414.                 1850 => -3786825600,
  415.                 1840 => -4102444800,
  416.                 1830 => -4417977600,
  417.                 1820 => -4733596800,
  418.                 1810 => -5049129600,
  419.                 1800 => -5364662400,
  420.                 1790 => -5680195200,
  421.                 1780 => -5995814400,
  422.                 1770 => -6311347200,
  423.                 1760 => -6626966400,
  424.                 1750 => -6942499200,
  425.                 1740 => -7258118400,
  426.                 1730 => -7573651200,
  427.                 1720 => -7889270400,
  428.                 1710 => -8204803200,
  429.                 1700 => -8520336000,
  430.                 1690 => -8835868800,
  431.                 1680 => -9151488000,
  432.                 1670 => -9467020800,
  433.                 1660 => -9782640000,
  434.                 1650 => -10098172800,
  435.                 1640 => -10413792000,
  436.                 1630 => -10729324800,
  437.                 1620 => -11044944000,
  438.                 1610 => -11360476800,
  439.                 1600 => -11676096000);
  440.  
  441.             if ($is_gmt) $origd = $d;
  442.             // The valid range of a 32bit signed timestamp is typically from
  443.             // Fri, 13 Dec 1901 20:45:54 GMT to Tue, 19 Jan 2038 03:14:07 GMT
  444.             //
  445.  
  446.             $lastsecs = 0;
  447.             $lastyear = 1970;
  448.             foreach($YRS as $year => $secs) {
  449.                 if ($d >= $secs) {
  450.                     $a = $lastyear;
  451.                     break;
  452.                 }
  453.                 $lastsecs = $secs;
  454.                 $lastyear = $year;
  455.             }
  456.  
  457.             $d -= $lastsecs;
  458.             if (!isset($a)) $a = $lastyear;
  459.  
  460.             for (; --$a >= 0;) {
  461.                 $lastd = $d;
  462.  
  463.                 if ($leaf = _adodb_is_leap_year($a)) $d += $d366;
  464.                 else $d += $d365;
  465.  
  466.                 if ($d >= 0) {
  467.                     $year = $a;
  468.                     break;
  469.                 }
  470.             }
  471.  
  472.             $secsInYear = 86400 * ($leaf ? 366 : 365) + $lastd;
  473.  
  474.             $d = $lastd;
  475.             $mtab = ($leaf) ? $_month_table_leaf : $_month_table_normal;
  476.             for ($a = 13 ; --$a > 0;) {
  477.                 $lastd = $d;
  478.                 $d += $mtab[$a] * $_day_power;
  479.                 if ($d >= 0) {
  480.                     $month = $a;
  481.                     $ndays = $mtab[$a];
  482.                     break;
  483.                 }
  484.             }
  485.  
  486.             $d = $lastd;
  487.             $day = $ndays + ceil(($d+1) / ($_day_power));
  488.  
  489.             $d += ($ndays - $day+1)* $_day_power;
  490.             $hour = floor($d/$_hour_power);
  491.  
  492.         } else {
  493.             for ($a = 1970 ;; $a++) {
  494.                 $lastd = $d;
  495.  
  496.                 if ($leaf = _adodb_is_leap_year($a)) $d -= $d366;
  497.                 else $d -= $d365;
  498.                 if ($d < 0) {
  499.                     $year = $a;
  500.                     break;
  501.                 }
  502.             }
  503.             $secsInYear = $lastd;
  504.             $d = $lastd;
  505.             $mtab = ($leaf) ? $_month_table_leaf : $_month_table_normal;
  506.             for ($a = 1 ; $a <= 12; $a++) {
  507.                 $lastd = $d;
  508.                 $d -= $mtab[$a] * $_day_power;
  509.                 if ($d < 0) {
  510.                     $month = $a;
  511.                     $ndays = $mtab[$a];
  512.                     break;
  513.                 }
  514.             }
  515.             $d = $lastd;
  516.             $day = ceil(($d+1) / $_day_power);
  517.             $d = $d - ($day-1) * $_day_power;
  518.             $hour = floor($d /$_hour_power);
  519.         }
  520.  
  521.         $d -= $hour * $_hour_power;
  522.         $min = floor($d/$_min_power);
  523.         $secs = $d - $min * $_min_power;
  524.         if ($fast) {
  525.             return array(
  526.             'seconds' => $secs,
  527.             'minutes' => $min,
  528.             'hours' => $hour,
  529.             'mday' => $day,
  530.             'mon' => $month,
  531.             'year' => $year,
  532.             'yday' => floor($secsInYear/$_day_power),
  533.             'leap' => $leaf,
  534.             'ndays' => $ndays
  535.             );
  536.         }
  537.  
  538.  
  539.         $dow = adodb_dow($year,$month,$day);
  540.  
  541.         return array(
  542.             'seconds' => $secs,
  543.             'minutes' => $min,
  544.             'hours' => $hour,
  545.             'mday' => $day,
  546.             'wday' => $dow,
  547.             'mon' => $month,
  548.             'year' => $year,
  549.             'yday' => floor($secsInYear/$_day_power),
  550.             'weekday' => gmdate('l',$_day_power*(3+$dow)),
  551.             'month' => gmdate('F',mktime(0,0,0,$month,2,1971)),
  552.             0 => $origd
  553.         );
  554.     }
  555.  
  556.     /*
  557.      * Accepts unix timestamp and iso date format
  558.      * ISO format date is converted into unix timestamp before calling date()
  559.      * @param string Format of date output
  560.      * @param int/string Date to be converted
  561.      * @param boolean Ignore timezone
  562.      * @return string In the format specified by $fmt
  563.      */
  564.     function date2($fmt, $d=false, $is_gmt=false)
  565.     {    if ( is_numeric($d) ) $this->date($fmt,$d,$is_gmt);
  566.  
  567.         if ($d !== false) {
  568.             if (!preg_match(
  569.                 "|^([0-9]{3,4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})[ -]?(([0-9]{1,2}):?([0-9]{1,2}):?([0-9\.]{1,4}))?|",
  570.                 ($d), $rr)) return $this->date($fmt,false,$is_gmt);
  571.  
  572.             if ($rr[1] <= 100 && $rr[2]<= 1) return adodb_date($fmt,false,$is_gmt);
  573.  
  574.             // h-m-s-MM-DD-YY
  575.             if (!isset($rr[5])) $d = adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1]);
  576.             else $d = @adodb_mktime($rr[5],$rr[6],$rr[7],$rr[2],$rr[3],$rr[1]);
  577.         }
  578.  
  579.         return $this->date($fmt,$d,$is_gmt);
  580.     }
  581.  
  582.  
  583.     /**
  584.      * Return formatted date based on timestamp $d
  585.      * @param string Format of date output
  586.      * @param int Date to be converted
  587.      * @param boolean Ignore timezone
  588.      * @return string In the format specified by $fmt
  589.      */
  590.     function date($fmt,$d=false,$is_gmt=false)
  591.     {
  592.     static $daylight;
  593.         if ($d === false) return ($is_gmt)? @gmdate($fmt): @date($fmt);
  594.             if ((abs($d) <= 0x7FFFFFFF)) { // check if number in 32-bit signed range
  595.                 if (!defined('ADODB_NO_NEGATIVE_TS') || $d >= 0) // if windows, must be +ve integer
  596.                     return ($is_gmt)? @gmdate($fmt,$d): @date($fmt,$d);
  597.         }
  598.         $_day_power = 86400;
  599.  
  600.         $arr = $this->_getdate($d,true,$is_gmt);
  601.  
  602. //        if (!isset($daylight)) $daylight = function_exists('adodb_daylight_sv');
  603. //        if ($daylight) adodb_daylight_sv($arr, $is_gmt);
  604.  
  605.         $year = $arr['year'];
  606.         $month = $arr['mon'];
  607.         $day = $arr['mday'];
  608.         $hour = $arr['hours'];
  609.         $min = $arr['minutes'];
  610.         $secs = $arr['seconds'];
  611.  
  612.         $max = strlen($fmt);
  613.         $dates = '';
  614.  
  615.         /*
  616.             at this point, we have the following integer vars to manipulate:
  617.             $year, $month, $day, $hour, $min, $secs
  618.         */
  619.         for ($i=0; $i < $max; $i++) {
  620.             switch($fmt[$i]) {
  621.             case 'T': $dates .= date('T');break;
  622.             // YEAR
  623.             case 'L': $dates .= $arr['leap'] ? '1' : '0'; break;
  624.             case 'r': // Thu, 21 Dec 2000 16:01:07 +0200
  625.  
  626.                 // 4.3.11 uses '04 Jun 2004'
  627.                 // 4.3.8 uses  ' 4 Jun 2004'
  628.                 $dates .= gmdate('D',$_day_power*(3+$this->dow($year,$month,$day))).', '
  629.                     . ($day<10?'0'.$day:$day) . ' '.date('M',mktime(0,0,0,$month,2,1971)).' '.$year.' ';
  630.  
  631.                 if ($hour < 10) $dates .= '0'.$hour; else $dates .= $hour;
  632.  
  633.                 if ($min < 10) $dates .= ':0'.$min; else $dates .= ':'.$min;
  634.  
  635.                 if ($secs < 10) $dates .= ':0'.$secs; else $dates .= ':'.$secs;
  636.  
  637.                 $gmt = adodb_get_gmt_diff();
  638.                 $dates .= sprintf(' %s%04d',($gmt<0)?'+':'-',abs($gmt)/36); break;
  639.  
  640.             case 'Y': $dates .= $year; break;
  641.             case 'y': $dates .= substr($year,strlen($year)-2,2); break;
  642.             // MONTH
  643.             case 'm': if ($month<10) $dates .= '0'.$month; else $dates .= $month; break;
  644.             case 'Q': $dates .= ($month+3)>>2; break;
  645.             case 'n': $dates .= $month; break;
  646.             case 'M': $dates .= date('M',mktime(0,0,0,$month,2,1971)); break;
  647.             case 'F': $dates .= date('F',mktime(0,0,0,$month,2,1971)); break;
  648.             // DAY
  649.             case 't': $dates .= $arr['ndays']; break;
  650.             case 'z': $dates .= $arr['yday']; break;
  651.             case 'w': $dates .= adodb_dow($year,$month,$day); break;
  652.             case 'l': $dates .= gmdate('l',$_day_power*(3+adodb_dow($year,$month,$day))); break;
  653.             case 'D': $dates .= gmdate('D',$_day_power*(3+adodb_dow($year,$month,$day))); break;
  654.             case 'j': $dates .= $day; break;
  655.             case 'd': if ($day<10) $dates .= '0'.$day; else $dates .= $day; break;
  656.             case 'S':
  657.                 $d10 = $day % 10;
  658.                 if ($d10 == 1) $dates .= 'st';
  659.                 else if ($d10 == 2 && $day != 12) $dates .= 'nd';
  660.                 else if ($d10 == 3) $dates .= 'rd';
  661.                 else $dates .= 'th';
  662.                 break;
  663.  
  664.             // HOUR
  665.             case 'Z':
  666.                 $dates .= ($is_gmt) ? 0 : -adodb_get_gmt_diff(); break;
  667.             case 'O':
  668.                 $gmt = ($is_gmt) ? 0 : adodb_get_gmt_diff();
  669.                 $dates .= sprintf('%s%04d',($gmt<0)?'+':'-',abs($gmt)/36); break;
  670.  
  671.             case 'H':
  672.                 if ($hour < 10) $dates .= '0'.$hour;
  673.                 else $dates .= $hour;
  674.                 break;
  675.             case 'h':
  676.                 if ($hour > 12) $hh = $hour - 12;
  677.                 else {
  678.                     if ($hour == 0) $hh = '12';
  679.                     else $hh = $hour;
  680.                 }
  681.  
  682.                 if ($hh < 10) $dates .= '0'.$hh;
  683.                 else $dates .= $hh;
  684.                 break;
  685.  
  686.             case 'G':
  687.                 $dates .= $hour;
  688.                 break;
  689.  
  690.             case 'g':
  691.                 if ($hour > 12) $hh = $hour - 12;
  692.                 else {
  693.                     if ($hour == 0) $hh = '12';
  694.                     else $hh = $hour;
  695.                 }
  696.                 $dates .= $hh;
  697.                 break;
  698.             // MINUTES
  699.             case 'i': if ($min < 10) $dates .= '0'.$min; else $dates .= $min; break;
  700.             // SECONDS
  701.             case 'U': $dates .= $d; break;
  702.             case 's': if ($secs < 10) $dates .= '0'.$secs; else $dates .= $secs; break;
  703.             // AM/PM
  704.             // Note 00:00 to 11:59 is AM, while 12:00 to 23:59 is PM
  705.             case 'a':
  706.                 if ($hour>=12) $dates .= 'pm';
  707.                 else $dates .= 'am';
  708.                 break;
  709.             case 'A':
  710.                 if ($hour>=12) $dates .= 'PM';
  711.                 else $dates .= 'AM';
  712.                 break;
  713.             default:
  714.                 $dates .= $fmt[$i]; break;
  715.             // ESCAPE
  716.             case "\\":
  717.                 $i++;
  718.                 if ($i < $max) $dates .= $fmt[$i];
  719.                 break;
  720.             }
  721.         }
  722.         return $dates;
  723.     }
  724.  
  725.     /**
  726.      * Returns a timestamp given a GMT/UTC time.
  727.      * @param int Hour
  728.      * @param int Minute
  729.      * @param int Second
  730.      * @param int Month
  731.      * @param int Day
  732.      * @param int Year
  733.      * @param int $is_dst is not implemented and is ignored
  734.      * @return int 
  735.      */
  736.     function gmmktime($hr,$min,$sec,$mon=false,$day=false,$year=false,$is_dst=false)
  737.     {
  738.         return $this->mktime($hr,$min,$sec,$mon,$day,$year,$is_dst,true);
  739.     }
  740.  
  741.     /**
  742.      * Return a timestamp given a local time. Originally by jackbbs.
  743.      * Not a very fast algorithm - O(n) operation. Could be optimized to O(1).
  744.      * @param int Hour
  745.      * @param int Minute
  746.      * @param int Second
  747.      * @param int Month
  748.      * @param int Day
  749.      * @param int Year
  750.      * @param int $is_dst is not implemented and is ignored
  751.      * @return int 
  752.      */
  753.     function mktime($hr,$min,$sec,$mon=false,$day=false,$year=false,$is_dst=false,$is_gmt=false)
  754.     {
  755.         if ($mon === false) {
  756.             return $is_gmt? @gmmktime($hr,$min,$sec): @mktime($hr,$min,$sec);
  757.  
  758. /* Need to check if this can be deleted
  759.             // for windows, we don't check 1970 because with timezone differences,
  760.             // 1 Jan 1970 could generate negative timestamp, which is illegal
  761.             if (1971 < $year && $year < 2038
  762.                 || !defined('ADODB_NO_NEGATIVE_TS') && (1901 < $year && $year < 2038)
  763.                 ) {
  764.                     return $is_gmt ?
  765.                         @gmmktime($hr,$min,$sec,$mon,$day,$year):
  766.                         @mktime($hr,$min,$sec,$mon,$day,$year);
  767.                 }
  768. */
  769.         }
  770.  
  771.         $gmt_different = ($is_gmt) ? 0 : $this->server_offset;
  772.  
  773.         /*
  774.         # disabled because some people place large values in $sec.
  775.         # however we need it for $mon because we use an array...
  776.         $hr = intval($hr);
  777.         $min = intval($min);
  778.         $sec = intval($sec);
  779.         */
  780.         $mon = intval($mon);
  781.         $day = intval($day);
  782.         $year = intval($year);
  783.  
  784.  
  785.         $year = $this->year_digit_check($year);
  786.  
  787.         if ($mon > 12) {
  788.             $y = floor($mon / 12);
  789.             $year += $y;
  790.             $mon -= $y*12;
  791.         }
  792.         else if ( $mon <= 0 ) {
  793.             $mon += 12;
  794.             $year -= 1;
  795.         }
  796.         
  797.         $_day_power = 86400;
  798.         $_hour_power = 3600;
  799.         $_min_power = 60;
  800.  
  801.         $_month_table_normal = array("",31,28,31,30,31,30,31,31,30,31,30,31);
  802.         $_month_table_leaf = array("",31,29,31,30,31,30,31,31,30,31,30,31);
  803.  
  804.         $_total_date = 0;
  805.         if ($year >= 1970) {
  806.             for ($a = 1970 ; $a <= $year; $a++) {
  807.                 $leaf = _adodb_is_leap_year($a);
  808.                 if ($leaf == true) {
  809.                     $loop_table = $_month_table_leaf;
  810.                     $_add_date = 366;
  811.                 } else {
  812.                     $loop_table = $_month_table_normal;
  813.                     $_add_date = 365;
  814.                 }
  815.                 if ($a < $year) {
  816.                     $_total_date += $_add_date;
  817.                 } else {
  818.                     for($b=1;$b<$mon;$b++) {
  819.                         $_total_date += $loop_table[$b];
  820.                     }
  821.                 }
  822.             }
  823.             $_total_date +=$day-1;
  824.             $ret = $_total_date * $_day_power + $hr * $_hour_power + $min * $_min_power + $sec + $gmt_different;
  825.  
  826.         } else {
  827.             for ($a = 1969 ; $a >= $year; $a--) {
  828.                 $leaf = _adodb_is_leap_year($a);
  829.                 if ($leaf == true) {
  830.                     $loop_table = $_month_table_leaf;
  831.                     $_add_date = 366;
  832.                 } else {
  833.                     $loop_table = $_month_table_normal;
  834.                     $_add_date = 365;
  835.                 }
  836.                 if ($a > $year) { $_total_date += $_add_date;
  837.                 } else {
  838.                     for($b=12;$b>$mon;$b--) {
  839.                         $_total_date += $loop_table[$b];
  840.                     }
  841.                 }
  842.             }
  843.             $_total_date += $loop_table[$mon] - $day;
  844.  
  845.             $_day_time = $hr * $_hour_power + $min * $_min_power + $sec;
  846.             $_day_time = $_day_power - $_day_time;
  847.             $ret = -( $_total_date * $_day_power + $_day_time - $gmt_different);
  848.             if ($ret < -12220185600) $ret += 10*86400; // if earlier than 5 Oct 1582 - gregorian correction
  849.             else if ($ret < -12219321600) $ret = -12219321600; // if in limbo, reset to 15 Oct 1582.
  850.         }
  851.         //print " dmy=$day/$mon/$year $hr:$min:$sec => " .$ret;
  852.         return $ret;
  853.     }
  854.  
  855.     function gmstrftime($fmt, $ls=false)
  856.     {
  857.         return strftime($fmt,$ls,true);
  858.     }
  859.  
  860.     function strtotime($time, $now=NULL)
  861.     {
  862.         if($now == NULL) 
  863.             return strtotime($time);
  864.         else
  865.             return strtotime($time, $now);
  866.     }
  867.  
  868.     // hack - convert to adodb_date
  869.     function strftime($fmt, $ls=false,$is_gmt=false)
  870.     {
  871.     global $ADODB_DATE_LOCALE;
  872.  
  873.         if ((abs($ls) <= 0x7FFFFFFF)) { // check if number in 32-bit signed range
  874.             if (!defined('ADODB_NO_NEGATIVE_TS') || $ls >= 0) // if windows, must be +ve integer
  875.                 return ($is_gmt)? @gmstrftime($fmt,$ls): @strftime($fmt,$ls);
  876.         }
  877.  
  878.         if (empty($ADODB_DATE_LOCALE)) {
  879.             $tstr = strtoupper(gmstrftime('%c',31366800)); // 30 Dec 1970, 1 am
  880.             $sep = substr($tstr,2,1);
  881.             $hasAM = strrpos($tstr,'M') !== false;
  882.  
  883.             $ADODB_DATE_LOCALE = array();
  884.             $ADODB_DATE_LOCALE[] =  strncmp($tstr,'30',2) == 0 ? 'd'.$sep.'m'.$sep.'y' : 'm'.$sep.'d'.$sep.'y';
  885.             $ADODB_DATE_LOCALE[]  = ($hasAM) ? 'h:i:s a' : 'H:i:s';
  886.  
  887.         }
  888.         $inpct = false;
  889.         $fmtdate = '';
  890.         for ($i=0,$max = strlen($fmt); $i < $max; $i++) {
  891.             $ch = $fmt[$i];
  892.             if ($ch == '%') {
  893.                 if ($inpct) {
  894.                     $fmtdate .= '%';
  895.                     $inpct = false;
  896.                 } else
  897.                     $inpct = true;
  898.             } else if ($inpct) {
  899.  
  900.                 $inpct = false;
  901.                 switch($ch) {
  902.                 case '0':
  903.                 case '1':
  904.                 case '2':
  905.                 case '3':
  906.                 case '4':
  907.                 case '5':
  908.                 case '6':
  909.                 case '7':
  910.                 case '8':
  911.                 case '9':
  912.                 case 'E':
  913.                 case 'O':
  914.                     /* ignore format modifiers */
  915.                     $inpct = true;
  916.                     break;
  917.  
  918.                 case 'a': $fmtdate .= 'D'; break;
  919.                 case 'A': $fmtdate .= 'l'; break;
  920.                 case 'h':
  921.                 case 'b': $fmtdate .= 'M'; break;
  922.                 case 'B': $fmtdate .= 'F'; break;
  923.                 case 'c': $fmtdate .= $ADODB_DATE_LOCALE[0].$ADODB_DATE_LOCALE[1]; break;
  924.                 case 'C': $fmtdate .= '\C?'; break; // century
  925.                 case 'd': $fmtdate .= 'd'; break;
  926.                 case 'D': $fmtdate .= 'm/d/y'; break;
  927.                 case 'e': $fmtdate .= 'j'; break;
  928.                 case 'g': $fmtdate .= '\g?'; break; //?
  929.                 case 'G': $fmtdate .= '\G?'; break; //?
  930.                 case 'H': $fmtdate .= 'H'; break;
  931.                 case 'I': $fmtdate .= 'h'; break;
  932.                 case 'j': $fmtdate .= '?z'; $parsej = true; break; // wrong as j=1-based, z=0-basd
  933.                 case 'm': $fmtdate .= 'm'; break;
  934.                 case 'M': $fmtdate .= 'i'; break;
  935.                 case 'n': $fmtdate .= "\n"; break;
  936.                 case 'p': $fmtdate .= 'a'; break;
  937.                 case 'r': $fmtdate .= 'h:i:s a'; break;
  938.                 case 'R': $fmtdate .= 'H:i:s'; break;
  939.                 case 'S': $fmtdate .= 's'; break;
  940.                 case 't': $fmtdate .= "\t"; break;
  941.                 case 'T': $fmtdate .= 'H:i:s'; break;
  942.                 case 'u': $fmtdate .= '?u'; $parseu = true; break; // wrong strftime=1-based, date=0-basde
  943.                 case 'U': $fmtdate .= '?U'; $parseU = true; break;// wrong strftime=1-based, date=0-based
  944.                 case 'x': $fmtdate .= $ADODB_DATE_LOCALE[0]; break;
  945.                 case 'X': $fmtdate .= $ADODB_DATE_LOCALE[1]; break;
  946.                 case 'w': $fmtdate .= '?w'; $parseu = true; break; // wrong strftime=1-based, date=0-basde
  947.                 case 'W': $fmtdate .= '?W'; $parseU = true; break;// wrong strftime=1-based, date=0-based
  948.                 case 'y': $fmtdate .= 'y'; break;
  949.                 case 'Y': $fmtdate .= 'Y'; break;
  950.                 case 'Z': $fmtdate .= 'T'; break;
  951.                 }
  952.             } else if (('A' <= ($ch) && ($ch) <= 'Z' ) || ('a' <= ($ch) && ($ch) <= 'z' ))
  953.                 $fmtdate .= "\\".$ch;
  954.             else
  955.                 $fmtdate .= $ch;
  956.         }
  957.         //echo "fmt=",$fmtdate,"<br>";
  958.         if ($ls === false) $ls = time();
  959.         $ret = $this->date($fmtdate, $ls, $is_gmt);
  960.         return $ret;
  961.     }
  962.  
  963.     /**
  964.      * Converts from Gregorian Year-Month-Day to ISO YearNumber-WeekNumber-WeekDay
  965.      *
  966.      * Uses ISO 8601 definitions.
  967.      * Algorithm from Rick McCarty, 1999 at http://personal.ecu.edu/mccartyr/ISOwdALG.txt
  968.      *
  969.      * @param int $year 
  970.      * @param int $month 
  971.      * @param int $day 
  972.      * @return string 
  973.      * @access public
  974.      */
  975.     // Transcribed to PHP by Jesus M. Castagnetto (blame him if it is fubared ;-)
  976.     function gregorianToISO($year, $month, $day) {
  977.         $mnth = array (0,31,59,90,120,151,181,212,243,273,304,334);
  978.         if ($month == 0) {
  979.             $year--;
  980.             $month = 12;
  981.         }
  982.         $y_isleap = $this->is_leap_year($year);
  983.         $y_1_isleap = $this->is_leap_year($year - 1);
  984.  
  985.         $day_of_year_number = $day + $mnth[$month - 1];
  986.         if ($y_isleap && $month > 2) {
  987.             $day_of_year_number++;
  988.         }
  989.         // find Jan 1 weekday (monday = 1, sunday = 7)
  990.         $yy = ($year - 1) % 100;
  991.         $c = ($year - 1) - $yy;
  992.         $g = $yy + intval($yy/4);
  993.         $jan1_weekday = 1 + intval((((($c / 100) % 4) * 5) + $g) % 7);
  994.         // weekday for year-month-day
  995.         $h = $day_of_year_number + ($jan1_weekday - 1) - 1;
  996.         $weekday = 1 + intval(($h - 1) % 7);
  997.         // find if Y M D falls in YearNumber Y-1, WeekNumber 52 or
  998.         if ($day_of_year_number <= (8 - $jan1_weekday) && $jan1_weekday > 4){
  999.             $yearnumber = $year - 1;
  1000.             if ($jan1_weekday == 5 || ($jan1_weekday == 6 && $y_1_isleap)) {
  1001.                 $weeknumber = 53;
  1002.             } else {
  1003.                 $weeknumber = 52;
  1004.             }
  1005.         } else {
  1006.             $yearnumber = $year;
  1007.         }
  1008.         // find if Y M D falls in YearNumber Y+1, WeekNumber 1
  1009.         if ($yearnumber == $year) {
  1010.             if ($y_isleap) {
  1011.                 $i = 366;
  1012.             } else {
  1013.                 $i = 365;
  1014.             }
  1015.             if (($i - $day_of_year_number) < (4 - $weekday)) {
  1016.                 $yearnumber++;
  1017.                 $weeknumber = 1;
  1018.             }
  1019.         }
  1020.         // find if Y M D falls in YearNumber Y, WeekNumber 1 through 53
  1021.         if ($yearnumber == $year) {
  1022.             $j = $day_of_year_number + (7 - $weekday) + ($jan1_weekday - 1);
  1023.             //$weeknumber = intval($j / 7) + 1; // kludge!!! - JMC
  1024.                $weeknumber = intval($j / 7); // kludge!!! - JMC
  1025.             if ($jan1_weekday > 4) {
  1026.                 $weeknumber--;
  1027.             }
  1028.         }
  1029.         // put it all together
  1030.         if ($weeknumber < 10)
  1031.             $weeknumber = '0'.$weeknumber;
  1032.         return "{$yearnumber}-{$weeknumber}-{$weekday}";
  1033.     }
  1034.  
  1035.     /**
  1036.      * Get a list of timezones to be worked with
  1037.      */
  1038.     function get_timezone_list($use_default = false) {
  1039.         static $timezone_options;
  1040.  
  1041.         if (!$timezone_options) {
  1042.             $timezone_options = array();
  1043.  
  1044.             if ($use_default)
  1045.                 $timezone_options['default'] = '-- Use Default Time Zone --';
  1046.  
  1047.             foreach ($GLOBALS['_DATE_TIMEZONE_DATA'] as $tz_key => $tz) {
  1048.                 $offset = $tz['offset'];
  1049.  
  1050.                 $absoffset = abs($offset /= 60000);
  1051.                 $plusminus = $offset < 0 ? '-' : '+';
  1052.                 $gmtoff = sprintf("GMT%1s%02d:%02d", $plusminus, $absoffset / 60, $absoffset - (intval($absoffset / 60) * 60));
  1053.                 $tzlongshort = $tz['longname'] . ' (' . $tz['shortname'] . ')';
  1054.                 $timezone_options[$tz_key] = sprintf('%-28.28s: %-36.36s %s', $tz_key, $tzlongshort, $gmtoff);
  1055.             }
  1056.         }
  1057.  
  1058.         return $timezone_options;
  1059.     }
  1060.  
  1061.     /**
  1062.      * Per http://www.w3.org/TR/NOTE-datetime
  1063.      */
  1064.     function get_iso8601_datetime($timestamp, $user = false) {
  1065.         return $this->strftime('%Y-%m-%dT%H:%M:%S%O', $timestamp, $user);
  1066.     }
  1067.  
  1068.     function get_rfc2822_datetime($timestamp = false, $user = false) {
  1069.         if (!$timestamp)
  1070.             $timestamp = time();
  1071.  
  1072.     # rfc2822 requires dates to be en formatted
  1073.         $saved_locale = @setlocale(0);
  1074.         @setlocale ('en_US');
  1075.     #was return date('D, j M Y H:i:s ', $time) . $this->timezone_offset($time, 'no colon');
  1076.         $rv = $this->strftime('%a, %e %b %Y %H:%M:%S', $timestamp, $user). $this->get_rfc2822_timezone_offset($timestamp, $user);
  1077.  
  1078.     # switch back to the 'saved' locale
  1079.         if ($saved_locale)
  1080.             @setlocale ($saved_locale);
  1081.  
  1082.         return $rv;
  1083.     }
  1084.  
  1085.     function get_rfc2822_timezone_offset($time = false, $no_colon = false, $user = false) {
  1086.         if ($time === false)
  1087.             $time = time();
  1088.  
  1089.         $secs = $this->strftime('%Z', $time, $user);
  1090.  
  1091.         if ($secs < 0) {
  1092.             $sign = '-';
  1093.  
  1094.             $secs = -$secs;
  1095.         } else {
  1096.             $sign = '+';
  1097.         }
  1098.  
  1099.         $colon = $no_colon ? '' : ':';
  1100.         $mins = intval(($secs + 30) / 60);
  1101.  
  1102.         return sprintf("%s%02d%s%02d", $sign, $mins / 60, $colon, $mins % 60);
  1103.     }
  1104.  
  1105.     function set_locale($user = false) {
  1106.         static $locale = false;
  1107.  
  1108.         if (!$locale) {
  1109.             # breaks the RFC 2822 code
  1110.             $locale = @setlocale(LC_TIME, $this->get_locale($user));
  1111.             #print "<pre>set_locale(): locale=$locale\n</pre>";
  1112.         }
  1113.  
  1114.         return $locale;
  1115.     }
  1116.  
  1117.     function daysInMonth( $month, $year ) {
  1118.         switch( $month ) {
  1119.             case 1:
  1120.             case 3:
  1121.             case 5:
  1122.             case 7:
  1123.             case 8:
  1124.             case 10:
  1125.             case 12:
  1126.             case 0: // == 12
  1127.                 return 31;
  1128.  
  1129.             case 4:
  1130.             case 6:
  1131.             case 9:
  1132.             case 11:
  1133.                 return 30;
  1134.  
  1135.             case 2:
  1136.                 return $this->is_leap_year( $year ) ? 29 : 28;
  1137.  
  1138.             default:
  1139.                 assert( FALSE );
  1140.         }
  1141.     }
  1142.  
  1143.     /**
  1144.     * Get a hash of holidays for a given year
  1145.     * @param $pYear the year in question
  1146.     * @param $pCountryCode -- the country in question - only US is supported currently
  1147.     * @return an associative array containing the holidays occuring in the given year they key is a date stamp of the form Y-m-d, the value is the name of the corresponding holiday
  1148.     * @access public
  1149.     ***/
  1150.     static function getHolidays( $pYear=NULL, $pCountryCode='US' ) {
  1151.         $return = array();
  1152.  
  1153.         if( empty( $pYear ) ) {
  1154.             $pYear = date( 'Y' );
  1155.         }
  1156.  
  1157.         switch( $pCountryCode ) {
  1158.             case 'UK':
  1159.                 $return[date( 'Y-m-d', strtotime("-1 week monday", strtotime("1 september $pYear")) + 43200)] = 'Bank Holiday';
  1160.                 break;
  1161.             case 'US':
  1162.             default:
  1163.                 // First off, the simple ones
  1164.                 $return[$pYear . '-01-01'] = 'New Year`s Day';
  1165.                 //$return[$pYear . '-02-14'] = 'Valentine`s Day';
  1166.                 $return[$pYear . '-06-14'] = 'Flag Day';
  1167.                 $return[$pYear . '-07-04'] = 'Independence Day';
  1168.                 $return[$pYear . '-11-11'] = 'Veteran`s Day';
  1169.                 $return[$pYear . '-12-25'] = 'Christmas';
  1170.  
  1171.                 // Martin Luther King, Jr. Day - third Monday in January
  1172.                 $return[date( 'Y-m-d', strtotime( '2 weeks monday', strtotime( "January 1, $pYear" ) ) + 43200 )] = 'Martin Luther King, Jr. Day';
  1173.  
  1174.                 // Presidents` Day - third Monday in February
  1175.                 $return[date( 'Y-m-d', strtotime( '2 weeks monday', strtotime( "February 1, $pYear" ) ) + 43200 )] = 'Presidents` Day';
  1176.  
  1177.                 // Mardi Gras - Tuesday ~47 days before Easter
  1178.                 //$return[date( 'Y-m-d', strtotime( 'last tuesday 46 days ago', easter_date( $pYear ) ) + 43200 )] = 'Mardi Gras';
  1179.  
  1180.                 // Memorial Day - last Monday in May
  1181.                 $return[date( 'Y-m-d', strtotime( '-1 week monday', strtotime( "June 1, $pYear" ) ) + 43200 )] = 'Memorial Day';
  1182.  
  1183.                 // Labor Day - first Monday in September
  1184.                 $return[date( 'Y-m-d', strtotime( 'monday', strtotime( "September 1, $pYear" ) ) + 43200 )] = 'Labor Day';
  1185.  
  1186.                 // Columbus Day - second Monday in October
  1187.                 $return[date( 'Y-m-d', strtotime( '1 week monday', strtotime( "October 1, $pYear" ) ) + 43200 )] = 'Columbus Day';
  1188.  
  1189.                 // Thanksgiving - fourth Thursday in November
  1190.                 $return[date( 'Y-m-d', strtotime( '3 weeks thursday', strtotime( "November 1, $pYear" ) ) + 43200 )] = 'Thanksgiving';
  1191.  
  1192.                 ksort( $return );
  1193.                 break;
  1194.         }
  1195.  
  1196.         // Common to all
  1197.  
  1198.         // Easter - the Sunday after the first full moon which falls on or after the Spring Equinox
  1199.         // thank god PHP has a function for that...
  1200.         $return[date( 'Y-m-d', easter_date( $pYear ) + 43200 )] = 'Easter';
  1201.  
  1202.         return $return;
  1203.  
  1204.     }
  1205.  
  1206.     function calculateTimeZoneDate( $dateTime, $fromTZ, $toTZ, $fromLocation = 'North America', $toLocation = 'GMT' ) {
  1207.  
  1208.         $retval     = $dateTime;
  1209.         $timeStamp  = strtotime( $dateTime );
  1210.  
  1211.         $timeZonesArray = array( 'GMT' => array( 'GMT' => +0 // GMT
  1212.                                                      ),
  1213.                 'North America'  =>  array( 'NST' => -3.5, // Newfoundland Standard Time
  1214.                                             'NDT' => -2.5, // Newfoundland Daylight Time
  1215.                                             'AST' => -4, // Atlantic Standard Time
  1216.                                             'ADT' => -3, // Atlantic Daylight Time
  1217.                                             'EST' => -5, // Eastern Standard Time
  1218.                                             'EDT' => -4, // Eastern Daylight Time
  1219.                                             'CST' => -6, // Central Standard Time
  1220.                                             'CDT' => -5, // Central Daylight Time
  1221.                                             'MST' => -7, // Central Daylight Time
  1222.                                             'MDT' => -6, // Mountain Daylight Time
  1223.                                             'PST' => -8, // Pacific Standard Time
  1224.                                             'PDT' => -7, // Pacific Daylight Time
  1225.                                             'AKST' => -9, // Alaska Standard Time
  1226.                                             'AKDT' => -8, // Alaska Daylight Time
  1227.                                             'HAST' => -10, // Hawaii-Aleutian Standard Time
  1228.                                             'HADT' => -9 // Hawaii-Aleutian Daylight Time
  1229.                                             ),
  1230.                 'Australia'      =>  array( 'NFT' => +11.5, // Norfolk (Island) Time
  1231.                                             'EST' => +10, // Eastern Standard Time
  1232.                                             'EDT' => +11, // Eastern Daylight Time
  1233.                                             'CST' => +9.5, // Central Standard Time
  1234.                                             'CDT' => +10.5, // Central Daylight Time
  1235.                                             'WST' => +8, // Western Standard Time
  1236.                                             'CXT' => +7, // Christmas Island Time
  1237.                                             ),
  1238.                 'Europe'         =>  array( 'GMT' => +0, // Greenwich Mean Time
  1239.                                             'BST' => +1, // British Summer Time
  1240.                                             'IST' => +1, // Irish Summer Time
  1241.                                             'WET' => +0, // Western European Time
  1242.                                             'WEST' => +1, // Western European Summer Time
  1243.                                             'CET' => +1, // Central European Time
  1244.                                             'CEST' => +2, // Central European Summer Time
  1245.                                             'EET' => +2, // Eastern European Time
  1246.                                             'EEST' => +3 // Eastern European Summer Time
  1247.                                             ),
  1248.                 'Military'       =>  array( 'Z' => +0, // Zulu Time Zone
  1249.                                             'Y' => -12, // Yankee Time Zone
  1250.                                             'X' => -11, // X-ray Time Zone
  1251.                                             'W' => -10, // Whiskey Time Zone
  1252.                                             'V' => -9, // Victor Time Zone
  1253.                                             'U' => -8, // Uniform Time Zone
  1254.                                             'T' => -7, // Tango Time Zone
  1255.                                             'S' => -6, // Sierra Time Zone
  1256.                                             'R' => -5, // Romeo Time Zone
  1257.                                             'Q' => -4, // Quebec Time Zone
  1258.                                             'P' => -3, // Papa Time Zone
  1259.                                             'O' => -2, // Oscar Time Zone
  1260.                                             'N' => -1, // November Time Zone
  1261.                                             'A' => +1, // Alpha Time Zone
  1262.                                             'B' => +2, // Bravo Time Zone
  1263.                                             'C' => +3, // Charlie Time Zone
  1264.                                             'D' => +4, // Delta Time Zone
  1265.                                             'E' => +5, // Echo Time Zone
  1266.                                             'F' => +6, // Foxtrot Time Zone
  1267.                                             'G' => +7, // Golf Time Zone
  1268.                                             'H' => +8, // Hotel Time Zone
  1269.                                             'I' => +9, // India Time Zone
  1270.                                             'K' => +10, // Kilo Time Zone
  1271.                                             'L' => +11, // Lima Time Zone
  1272.                                             'M' => +12 // Mike Time Zone
  1273.                                             ));
  1274.  
  1275.             $fromGMTDiff  = $timeZonesArray[$fromLocation][$fromTZ];
  1276.             $toGMTDiff    = $timeZonesArray[$toLocation][$toTZ];
  1277.  
  1278.             if(( '' != trim( $fromGMTDiff )) && ( '' != trim( $toGMTDiff ))) {
  1279.             if( $fromGMTDiff > $toGMTDiff ) {
  1280.                 $netDiff = $fromGMTDiff - $toGMTDiff;
  1281.             } else {
  1282.                 $netDiff = $toGMTDiff - $fromGMTDiff;
  1283.             }
  1284.             $retval = date( 'Y-m-d h:i:sa', ( $timeStamp + ( 3600 * $netDiff )));
  1285.  
  1286.         }
  1287.          return $retval;
  1288.  
  1289.     } // end function calculateTimeZoneDate()
  1290.     
  1291. }
  1292. ?>

Documentation generated on Wed, 29 Jul 2015 13:55:47 +0000 by phpDocumentor 1.5.0-lsces