Blame | Letzte Änderung | Log anzeigen | RSS feed
<?php/*** TDateTimeStamp class file.** COPYRIGHT* (c) 2003-2005 John Lim and released under BSD-style license except for code by* jackbbs, which includes getTimeStamp, getGMTDiff, isLeapYear* and originally found at http://www.php.net/manual/en/function.mktime.php** @author Wei Zhuo <weizhuo[at]gamil[dot]com>* @link http://www.pradosoft.com/* @copyright Copyright © 2005-2008 PradoSoft* @license http://www.pradosoft.com/license/* @version $Id: TDateTimeStamp.php 2488 2008-08-06 01:34:06Z knut $* @package System.Util*//*This code was originally for windows. But apparently this problem happensalso with Linux, RH 7.3 and later!glibc-2.2.5-34 and greater has been changed to return -1 for dates <1970. This used to work. The problem exists with RedHat 7.3 and 8.0echo (mktime(0, 0, 0, 1, 1, 1960)); // prints -1References:http://bugs.php.net/bug.php?id=20048&edit=2http://lists.debian.org/debian-glibc/2002/debian-glibc-200205/msg00010.html*/if (!defined('ADODB_ALLOW_NEGATIVE_TS')&& !defined('ADODB_NO_NEGATIVE_TS')) define('ADODB_NO_NEGATIVE_TS',1);/*** TDateTimeStamp Class** TDateTimeStamp Class is adpated from the ADOdb Date Library,* part of the ADOdb abstraction library* Download: http://phplens.com/phpeverywhere/** http://phplens.com/phpeverywhere/adodb_date_library** PHP native date functions use integer timestamps for computations.* Because of this, dates are restricted to the years 1901-2038 on Unix* and 1970-2038 on Windows due to integer overflow for dates beyond* those years. This library overcomes these limitations by replacing the* native function's signed integers (normally 32-bits) with PHP floating* point numbers (normally 64-bits).** Dates from 100 A.D. to 3000 A.D. and later have been tested. The minimum* is 100 A.D. as <100 will invoke the 2 => 4 digit year conversion.* The maximum is billions of years in the future, but this is a theoretical* limit as the computation of that year would take too long with the* current implementation of {@link getTimeStamp}.** PERFORMANCE* For high speed, this library uses the native date functions where* possible, and only switches to PHP code when the dates fall outside* the 32-bit signed integer range.** @author Wei Zhuo <weizhuo[at]gmail[dot]com>* @version $Id: TDateTimeStamp.php 2488 2008-08-06 01:34:06Z knut $* @package System.Util* @since 3.0.4*/class TDateTimeStamp{protected static $_month_normal = array("",31,28,31,30,31,30,31,31,30,31,30,31);protected static $_month_leaf = array("",31,29,31,30,31,30,31,31,30,31,30,31);/*** Gets day of week, 0 = Sunday,... 6=Saturday.* Algorithm from PEAR::Date_Calc*/public function getDayofWeek($year, $month, $day){/*Pope Gregory removed 10 days - October 5 to October 14 - from the year 1582 andproclaimed that from that time onwards 3 days would be dropped from the calendarevery 400 years.Thursday, October 4, 1582 (Julian) was followed immediately by Friday, October 15, 1582 (Gregorian).*/if ($year <= 1582){if ($year < 1582 ||($year == 1582 && ($month < 10 || ($month == 10 && $day < 15)))){$greg_correction = 3;}else{$greg_correction = 0;}}else{$greg_correction = 0;}if($month > 2)$month -= 2;else{$month += 10;$year--;}$day = floor((13 * $month - 1) / 5) +$day + ($year % 100) +floor(($year % 100) / 4) +floor(($year / 100) / 4) - 2 *floor($year / 100) + 77 + $greg_correction;return $day - 7 * floor($day / 7);}/*** Checks for leap year, returns true if it is. No 2-digit year check. Also* handles julian calendar correctly.* @param float year to check* @return boolean true if is leap year*/public function isLeapYear($year){$year = $this->digitCheck($year);if ($year % 4 != 0)return false;if ($year % 400 == 0)return true;// if gregorian calendar (>1582), century not-divisible by 400 is not leapelse if ($year > 1582 && $year % 100 == 0 )return false;return true;}/*** Fix 2-digit years. Works for any century.* Assumes that if 2-digit is more than 30 years in future, then previous century.* @return integer change two digit year into multiple digits*/protected function digitCheck($y){if ($y < 100){$yr = (integer) date("Y");$century = (integer) ($yr /100);if ($yr%100 > 50) {$c1 = $century + 1;$c0 = $century;} else {$c1 = $century;$c0 = $century - 1;}$c1 *= 100;// if 2-digit year is less than 30 years in future, set it to this century// otherwise if more than 30 years in future, then we set 2-digit year to the prev century.if (($y + $c1) < $yr+30) $y = $y + $c1;else $y = $y + $c0*100;}return $y;}public function get4DigitYear($y){return $this->digitCheck($y);}/*** @return integer get local time zone offset from GMT*/public function getGMTDiff(){static $TZ;if (isset($TZ)) return $TZ;$TZ = mktime(0,0,0,1,2,1970) - gmmktime(0,0,0,1,2,1970);return $TZ;}/*** @return array an array with date info.*/function getDate($d=false,$fast=false){if ($d === false) return getdate();// check if number in 32-bit signed rangeif ((abs($d) <= 0x7FFFFFFF)){if (!defined('ADODB_NO_NEGATIVE_TS') || $d >= 0) // if windows, must be +ve integerreturn @getdate($d);}return $this->_getDateInternal($d);}/*** Low-level function that returns the getdate() array. We have a special* $fast flag, which if set to true, will return fewer array values,* and is much faster as it does not calculate dow, etc.* @param float original date* @param boolean false to compute the day of the week, default is true* @param boolean true to calculate the GMT dates* @return array an array with date info.*/protected function _getDateInternal($origd=false,$fast=true,$is_gmt=false){static $YRS;$d = $origd - ($is_gmt ? 0 : $this->getGMTDiff());$_day_power = 86400;$_hour_power = 3600;$_min_power = 60;if ($d < -12219321600)$d -= 86400*10; // if 15 Oct 1582 or earlier, gregorian correction$_month_table_normal =& self::$_month_normal;$_month_table_leaf = & self::$_month_leaf;$d366 = $_day_power * 366;$d365 = $_day_power * 365;if ($d < 0){if (empty($YRS))$YRS = array(1970 => 0,1960 => -315619200,1950 => -631152000,1940 => -946771200,1930 => -1262304000,1920 => -1577923200,1910 => -1893456000,1900 => -2208988800,1890 => -2524521600,1880 => -2840140800,1870 => -3155673600,1860 => -3471292800,1850 => -3786825600,1840 => -4102444800,1830 => -4417977600,1820 => -4733596800,1810 => -5049129600,1800 => -5364662400,1790 => -5680195200,1780 => -5995814400,1770 => -6311347200,1760 => -6626966400,1750 => -6942499200,1740 => -7258118400,1730 => -7573651200,1720 => -7889270400,1710 => -8204803200,1700 => -8520336000,1690 => -8835868800,1680 => -9151488000,1670 => -9467020800,1660 => -9782640000,1650 => -10098172800,1640 => -10413792000,1630 => -10729324800,1620 => -11044944000,1610 => -11360476800,1600 => -11676096000);if ($is_gmt)$origd = $d;// The valid range of a 32bit signed timestamp is typically from// Fri, 13 Dec 1901 20:45:54 GMT to Tue, 19 Jan 2038 03:14:07 GMT//# old algorithm iterates through all years. new algorithm does it in# 10 year blocks/*# old algofor ($a = 1970 ; --$a >= 0;) {$lastd = $d;if ($leaf = _adodb_is_leap_year($a)) $d += $d366;else $d += $d365;if ($d >= 0) {$year = $a;break;}}*/$lastsecs = 0;$lastyear = 1970;foreach($YRS as $year => $secs){if ($d >= $secs){$a = $lastyear;break;}$lastsecs = $secs;$lastyear = $year;}$d -= $lastsecs;if (!isset($a)) $a = $lastyear;//echo ' yr=',$a,' ', $d,'.';for (; --$a >= 0;){$lastd = $d;if ($leaf = $this->isLeapYear($a))$d += $d366;else$d += $d365;if ($d >= 0){$year = $a;break;}}/**/$secsInYear = 86400 * ($leaf ? 366 : 365) + $lastd;$d = $lastd;$mtab = ($leaf) ? $_month_table_leaf : $_month_table_normal;for ($a = 13 ; --$a > 0;){$lastd = $d;$d += $mtab[$a] * $_day_power;if ($d >= 0){$month = $a;$ndays = $mtab[$a];break;}}$d = $lastd;$day = $ndays + ceil(($d+1) / ($_day_power));$d += ($ndays - $day+1)* $_day_power;$hour = floor($d/$_hour_power);} else {for ($a = 1970 ;; $a++){$lastd = $d;if ($leaf = $this->isLeapYear($a)) $d -= $d366;else $d -= $d365;if ($d < 0){$year = $a;break;}}$secsInYear = $lastd;$d = $lastd;$mtab = ($leaf) ? $_month_table_leaf : $_month_table_normal;for ($a = 1 ; $a <= 12; $a++){$lastd = $d;$d -= $mtab[$a] * $_day_power;if ($d < 0){$month = $a;$ndays = $mtab[$a];break;}}$d = $lastd;$day = ceil(($d+1) / $_day_power);$d = $d - ($day-1) * $_day_power;$hour = floor($d /$_hour_power);}$d -= $hour * $_hour_power;$min = floor($d/$_min_power);$secs = $d - $min * $_min_power;if ($fast){return array('seconds' => $secs,'minutes' => $min,'hours' => $hour,'mday' => $day,'mon' => $month,'year' => $year,'yday' => floor($secsInYear/$_day_power),'leap' => $leaf,'ndays' => $ndays);}$dow = $this->getDayofWeek($year,$month,$day);return array('seconds' => $secs,'minutes' => $min,'hours' => $hour,'mday' => $day,'wday' => $dow,'mon' => $month,'year' => $year,'yday' => floor($secsInYear/$_day_power),'weekday' => gmdate('l',$_day_power*(3+$dow)),'month' => gmdate('F',mktime(0,0,0,$month,2,1971)),0 => $origd);}/*** @return boolean true if valid date, semantic check only.*/public function isValidDate($y,$m,$d){if ($this->isLeapYear($y))$marr =& self::$_month_leaf;else$marr =& self::$_month_normal;if ($m > 12 || $m < 1) return false;if ($d > 31 || $d < 1) return false;if ($marr[$m] < $d) return false;if ($y < 1000 && $y > 3000) return false;return true;}/*** @return string formatted date based on timestamp $d*/function formatDate($fmt,$d=false,$is_gmt=false){if ($d === false)return ($is_gmt)? @gmdate($fmt): @date($fmt);// check if number in 32-bit signed rangeif ((abs($d) <= 0x7FFFFFFF)){// if windows, must be +ve integerif (!defined('ADODB_NO_NEGATIVE_TS') || $d >= 0)return ($is_gmt)? @gmdate($fmt,$d): @date($fmt,$d);}$_day_power = 86400;$arr = $this->getDate($d,true,$is_gmt);$year = $arr['year'];$month = $arr['mon'];$day = $arr['mday'];$hour = $arr['hours'];$min = $arr['minutes'];$secs = $arr['seconds'];$max = strlen($fmt);$dates = '';$isphp5 = PHP_VERSION >= 5;/*at this point, we have the following integer vars to manipulate:$year, $month, $day, $hour, $min, $secs*/for ($i=0; $i < $max; $i++){switch($fmt[$i]){case 'T': $dates .= date('T');break;// YEARcase 'L': $dates .= $arr['leap'] ? '1' : '0'; break;case 'r': // Thu, 21 Dec 2000 16:01:07 +0200// 4.3.11 uses '04 Jun 2004'// 4.3.8 uses ' 4 Jun 2004'$dates .= gmdate('D',$_day_power*(3+$this->getDayOfWeek($year,$month,$day))).', '. ($day<10?'0'.$day:$day) . ' '.date('M',mktime(0,0,0,$month,2,1971)).' '.$year.' ';if ($hour < 10) $dates .= '0'.$hour; else $dates .= $hour;if ($min < 10) $dates .= ':0'.$min; else $dates .= ':'.$min;if ($secs < 10) $dates .= ':0'.$secs; else $dates .= ':'.$secs;$gmt = $this->getGMTDiff();if ($isphp5)$dates .= sprintf(' %s%04d',($gmt<=0)?'+':'-',abs($gmt)/36);else$dates .= sprintf(' %s%04d',($gmt<0)?'+':'-',abs($gmt)/36);break;case 'Y': $dates .= $year; break;case 'y': $dates .= substr($year,strlen($year)-2,2); break;// MONTHcase 'm': if ($month<10) $dates .= '0'.$month; else $dates .= $month; break;case 'Q': $dates .= ($month+3)>>2; break;case 'n': $dates .= $month; break;case 'M': $dates .= date('M',mktime(0,0,0,$month,2,1971)); break;case 'F': $dates .= date('F',mktime(0,0,0,$month,2,1971)); break;// DAYcase 't': $dates .= $arr['ndays']; break;case 'z': $dates .= $arr['yday']; break;case 'w': $dates .= $this->getDayOfWeek($year,$month,$day); break;case 'l': $dates .= gmdate('l',$_day_power*(3+$this->getDayOfWeek($year,$month,$day))); break;case 'D': $dates .= gmdate('D',$_day_power*(3+$this->getDayOfWeek($year,$month,$day))); break;case 'j': $dates .= $day; break;case 'd': if ($day<10) $dates .= '0'.$day; else $dates .= $day; break;case 'S':$d10 = $day % 10;if ($d10 == 1) $dates .= 'st';else if ($d10 == 2 && $day != 12) $dates .= 'nd';else if ($d10 == 3) $dates .= 'rd';else $dates .= 'th';break;// HOURcase 'Z':$dates .= ($is_gmt) ? 0 : -$this->getGMTDiff(); break;case 'O':$gmt = ($is_gmt) ? 0 : $this->getGMTDiff();if ($isphp5)$dates .= sprintf('%s%04d',($gmt<=0)?'+':'-',abs($gmt)/36);else$dates .= sprintf('%s%04d',($gmt<0)?'+':'-',abs($gmt)/36);break;case 'H':if ($hour < 10) $dates .= '0'.$hour;else $dates .= $hour;break;case 'h':if ($hour > 12) $hh = $hour - 12;else {if ($hour == 0) $hh = '12';else $hh = $hour;}if ($hh < 10) $dates .= '0'.$hh;else $dates .= $hh;break;case 'G':$dates .= $hour;break;case 'g':if ($hour > 12) $hh = $hour - 12;else {if ($hour == 0) $hh = '12';else $hh = $hour;}$dates .= $hh;break;// MINUTEScase 'i': if ($min < 10) $dates .= '0'.$min; else $dates .= $min; break;// SECONDScase 'U': $dates .= $d; break;case 's': if ($secs < 10) $dates .= '0'.$secs; else $dates .= $secs; break;// AM/PM// Note 00:00 to 11:59 is AM, while 12:00 to 23:59 is PMcase 'a':if ($hour>=12) $dates .= 'pm';else $dates .= 'am';break;case 'A':if ($hour>=12) $dates .= 'PM';else $dates .= 'AM';break;default:$dates .= $fmt[$i]; break;// ESCAPEcase "\\":$i++;if ($i < $max) $dates .= $fmt[$i];break;}}return $dates;}/*** Not a very fast algorithm - O(n) operation. Could be optimized to O(1).* @return integer|float a timestamp given a local time. Originally by jackbbs.*/function getTimeStamp($hr,$min,$sec,$mon=false,$day=false,$year=false,$is_gmt=false){if ($mon === false)return $is_gmt? @gmmktime($hr,$min,$sec): @mktime($hr,$min,$sec);// for windows, we don't check 1970 because with timezone differences,// 1 Jan 1970 could generate negative timestamp, which is illegalif (1971 <= $year && $year < 2038 || !defined('ADODB_NO_NEGATIVE_TS')&& (1901 < $year && $year < 2038)){return $is_gmt ? @gmmktime($hr,$min,$sec,$mon,$day,$year): @mktime($hr,$min,$sec,$mon,$day,$year);}$gmt_different = ($is_gmt) ? 0 : $this->getGMTDiff();/*# disabled because some people place large values in $sec.# however we need it for $mon because we use an array...$hr = intval($hr);$min = intval($min);$sec = intval($sec);*/$mon = (int)$mon;$day = (int)$day;$year = (int)$year;$year = $this->digitCheck($year);if ($mon > 12){$y = floor($mon / 12);$year += $y;$mon -= $y*12;}else if ($mon < 1){$y = ceil((1-$mon) / 12);$year -= $y;$mon += $y*12;}$_day_power = 86400;$_hour_power = 3600;$_min_power = 60;$_month_table_normal = & self::$_month_normal;$_month_table_leaf = & self::$_month_leaf;$_total_date = 0;if ($year >= 1970){for ($a = 1970 ; $a <= $year; $a++){$leaf = $this->isLeapYear($a);if ($leaf == true) {$loop_table = $_month_table_leaf;$_add_date = 366;} else {$loop_table = $_month_table_normal;$_add_date = 365;}if ($a < $year) {$_total_date += $_add_date;} else {for($b=1;$b<$mon;$b++) {$_total_date += $loop_table[$b];}}}$_total_date +=$day-1;$ret = $_total_date * $_day_power + $hr * $_hour_power + $min * $_min_power + $sec + $gmt_different;} else {for ($a = 1969 ; $a >= $year; $a--) {$leaf = $this->isLeapYear($a);if ($leaf == true) {$loop_table = $_month_table_leaf;$_add_date = 366;} else {$loop_table = $_month_table_normal;$_add_date = 365;}if ($a > $year) { $_total_date += $_add_date;} else {for($b=12;$b>$mon;$b--) {$_total_date += $loop_table[$b];}}}$_total_date += $loop_table[$mon] - $day;$_day_time = $hr * $_hour_power + $min * $_min_power + $sec;$_day_time = $_day_power - $_day_time;$ret = -( $_total_date * $_day_power + $_day_time - $gmt_different);if ($ret < -12220185600) $ret += 10*86400; // if earlier than 5 Oct 1582 - gregorian correctionelse if ($ret < -12219321600) $ret = -12219321600; // if in limbo, reset to 15 Oct 1582.}//print " dmy=$day/$mon/$year $hr:$min:$sec => " .$ret;return $ret;}}?>