1<?php 2/** 3ADOdb Date Library, part of the ADOdb abstraction library 4Download: http://phplens.com/phpeverywhere/ 5 6PHP native date functions use integer timestamps for computations. 7Because of this, dates are restricted to the years 1901-2038 on Unix 8and 1970-2038 on Windows due to integer overflow for dates beyond 9those years. This library overcomes these limitations by replacing the 10native function's signed integers (normally 32-bits) with PHP floating 11point numbers (normally 64-bits). 12 13Dates from 100 A.D. to 3000 A.D. and later 14have been tested. The minimum is 100 A.D. as <100 will invoke the 152 => 4 digit year conversion. The maximum is billions of years in the 16future, but this is a theoretical limit as the computation of that year 17would take too long with the current implementation of adodb_mktime(). 18 19This library replaces native functions as follows: 20 21<pre> 22 getdate() with adodb_getdate() 23 date() with adodb_date() 24 gmdate() with adodb_gmdate() 25 mktime() with adodb_mktime() 26 gmmktime() with adodb_gmmktime() 27 strftime() with adodb_strftime() 28 strftime() with adodb_gmstrftime() 29</pre> 30 31The parameters are identical, except that adodb_date() accepts a subset 32of date()'s field formats. Mktime() will convert from local time to GMT, 33and date() will convert from GMT to local time, but daylight savings is 34not handled currently. 35 36This library is independant of the rest of ADOdb, and can be used 37as standalone code. 38 39PERFORMANCE 40 41For high speed, this library uses the native date functions where 42possible, and only switches to PHP code when the dates fall outside 43the 32-bit signed integer range. 44 45GREGORIAN CORRECTION 46 47Pope Gregory shortened October of A.D. 1582 by ten days. Thursday, 48October 4, 1582 (Julian) was followed immediately by Friday, October 15, 491582 (Gregorian). 50 51Since 0.06, we handle this correctly, so: 52 53adodb_mktime(0,0,0,10,15,1582) - adodb_mktime(0,0,0,10,4,1582) 54 == 24 * 3600 (1 day) 55 56============================================================================= 57 58COPYRIGHT 59 60(c) 2003-2005 John Lim and released under BSD-style license except for code by 61jackbbs, which includes adodb_mktime, adodb_get_gmt_diff, adodb_is_leap_year 62and originally found at http://www.php.net/manual/en/function.mktime.php 63 64============================================================================= 65 66BUG REPORTS 67 68These should be posted to the ADOdb forums at 69 70 http://phplens.com/lens/lensforum/topics.php?id=4 71 72============================================================================= 73 74FUNCTION DESCRIPTIONS 75 76 77** FUNCTION adodb_getdate($date=false) 78 79Returns an array containing date information, as getdate(), but supports 80dates greater than 1901 to 2038. The local date/time format is derived from a 81heuristic the first time adodb_getdate is called. 82 83 84** FUNCTION adodb_date($fmt, $timestamp = false) 85 86Convert a timestamp to a formatted local date. If $timestamp is not defined, the 87current timestamp is used. Unlike the function date(), it supports dates 88outside the 1901 to 2038 range. 89 90The format fields that adodb_date supports: 91 92<pre> 93 a - "am" or "pm" 94 A - "AM" or "PM" 95 d - day of the month, 2 digits with leading zeros; i.e. "01" to "31" 96 D - day of the week, textual, 3 letters; e.g. "Fri" 97 F - month, textual, long; e.g. "January" 98 g - hour, 12-hour format without leading zeros; i.e. "1" to "12" 99 G - hour, 24-hour format without leading zeros; i.e. "0" to "23" 100 h - hour, 12-hour format; i.e. "01" to "12" 101 H - hour, 24-hour format; i.e. "00" to "23" 102 i - minutes; i.e. "00" to "59" 103 j - day of the month without leading zeros; i.e. "1" to "31" 104 l (lowercase 'L') - day of the week, textual, long; e.g. "Friday" 105 L - boolean for whether it is a leap year; i.e. "0" or "1" 106 m - month; i.e. "01" to "12" 107 M - month, textual, 3 letters; e.g. "Jan" 108 n - month without leading zeros; i.e. "1" to "12" 109 O - Difference to Greenwich time in hours; e.g. "+0200" 110 Q - Quarter, as in 1, 2, 3, 4 111 r - RFC 2822 formatted date; e.g. "Thu, 21 Dec 2000 16:01:07 +0200" 112 s - seconds; i.e. "00" to "59" 113 S - English ordinal suffix for the day of the month, 2 characters; 114 i.e. "st", "nd", "rd" or "th" 115 t - number of days in the given month; i.e. "28" to "31" 116 T - Timezone setting of this machine; e.g. "EST" or "MDT" 117 U - seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) 118 w - day of the week, numeric, i.e. "0" (Sunday) to "6" (Saturday) 119 Y - year, 4 digits; e.g. "1999" 120 y - year, 2 digits; e.g. "99" 121 z - day of the year; i.e. "0" to "365" 122 Z - timezone offset in seconds (i.e. "-43200" to "43200"). 123 The offset for timezones west of UTC is always negative, 124 and for those east of UTC is always positive. 125</pre> 126 127Unsupported: 128<pre> 129 B - Swatch Internet time 130 I (capital i) - "1" if Daylight Savings Time, "0" otherwise. 131 W - ISO-8601 week number of year, weeks starting on Monday 132 133</pre> 134 135 136** FUNCTION adodb_date2($fmt, $isoDateString = false) 137Same as adodb_date, but 2nd parameter accepts iso date, eg. 138 139 adodb_date2('d-M-Y H:i','2003-12-25 13:01:34'); 140 141 142** FUNCTION adodb_gmdate($fmt, $timestamp = false) 143 144Convert a timestamp to a formatted GMT date. If $timestamp is not defined, the 145current timestamp is used. Unlike the function date(), it supports dates 146outside the 1901 to 2038 range. 147 148 149** FUNCTION adodb_mktime($hr, $min, $sec[, $month, $day, $year]) 150 151Converts a local date to a unix timestamp. Unlike the function mktime(), it supports 152dates outside the 1901 to 2038 range. All parameters are optional. 153 154 155** FUNCTION adodb_gmmktime($hr, $min, $sec [, $month, $day, $year]) 156 157Converts a gmt date to a unix timestamp. Unlike the function gmmktime(), it supports 158dates outside the 1901 to 2038 range. Differs from gmmktime() in that all parameters 159are currently compulsory. 160 161** FUNCTION adodb_gmstrftime($fmt, $timestamp = false) 162Convert a timestamp to a formatted GMT date. 163 164** FUNCTION adodb_strftime($fmt, $timestamp = false) 165 166Convert a timestamp to a formatted local date. Internally converts $fmt into 167adodb_date format, then echo result. 168 169For best results, you can define the local date format yourself. Define a global 170variable $ADODB_DATE_LOCALE which is an array, 1st element is date format using 171adodb_date syntax, and 2nd element is the time format, also in adodb_date syntax. 172 173 eg. $ADODB_DATE_LOCALE = array('d/m/Y','H:i:s'); 174 175 Supported format codes: 176 177<pre> 178 %a - abbreviated weekday name according to the current locale 179 %A - full weekday name according to the current locale 180 %b - abbreviated month name according to the current locale 181 %B - full month name according to the current locale 182 %c - preferred date and time representation for the current locale 183 %d - day of the month as a decimal number (range 01 to 31) 184 %D - same as %m/%d/%y 185 %e - day of the month as a decimal number, a single digit is preceded by a space (range ' 1' to '31') 186 %h - same as %b 187 %H - hour as a decimal number using a 24-hour clock (range 00 to 23) 188 %I - hour as a decimal number using a 12-hour clock (range 01 to 12) 189 %m - month as a decimal number (range 01 to 12) 190 %M - minute as a decimal number 191 %n - newline character 192 %p - either `am' or `pm' according to the given time value, or the corresponding strings for the current locale 193 %r - time in a.m. and p.m. notation 194 %R - time in 24 hour notation 195 %S - second as a decimal number 196 %t - tab character 197 %T - current time, equal to %H:%M:%S 198 %x - preferred date representation for the current locale without the time 199 %X - preferred time representation for the current locale without the date 200 %y - year as a decimal number without a century (range 00 to 99) 201 %Y - year as a decimal number including the century 202 %Z - time zone or name or abbreviation 203 %% - a literal `%' character 204</pre> 205 206 Unsupported codes: 207<pre> 208 %C - century number (the year divided by 100 and truncated to an integer, range 00 to 99) 209 %g - like %G, but without the century. 210 %G - The 4-digit year corresponding to the ISO week number (see %V). 211 This has the same format and value as %Y, except that if the ISO week number belongs 212 to the previous or next year, that year is used instead. 213 %j - day of the year as a decimal number (range 001 to 366) 214 %u - weekday as a decimal number [1,7], with 1 representing Monday 215 %U - week number of the current year as a decimal number, starting 216 with the first Sunday as the first day of the first week 217 %V - The ISO 8601:1988 week number of the current year as a decimal number, 218 range 01 to 53, where week 1 is the first week that has at least 4 days in the 219 current year, and with Monday as the first day of the week. (Use %G or %g for 220 the year component that corresponds to the week number for the specified timestamp.) 221 %w - day of the week as a decimal, Sunday being 0 222 %W - week number of the current year as a decimal number, starting with the 223 first Monday as the first day of the first week 224</pre> 225 226============================================================================= 227 228NOTES 229 230Useful url for generating test timestamps: 231 http://www.4webhelp.net/us/timestamp.php 232 233Possible future optimizations include 234 235a. Using an algorithm similar to Plauger's in "The Standard C Library" 236(page 428, xttotm.c _Ttotm() function). Plauger's algorithm will not 237work outside 32-bit signed range, so i decided not to implement it. 238 239b. Implement daylight savings, which looks awfully complicated, see 240 http://webexhibits.org/daylightsaving/ 241 242 243CHANGELOG 244 245- 11 Feb 2008 0.33 246* Bug in 0.32 fix for hour handling. Fixed. 247 248- 1 Feb 2008 0.32 249* Now adodb_mktime(0,0,0,12+$m,20,2040) works properly. 250 251- 10 Jan 2008 0.31 252* Now adodb_mktime(0,0,0,24,1,2037) works correctly. 253 254- 15 July 2007 0.30 255Added PHP 5.2.0 compatability fixes. 256 * gmtime behaviour for 1970 has changed. We use the actual date if it is between 1970 to 2038 to get the 257 * timezone, otherwise we use the current year as the baseline to retrieve the timezone. 258 * Also the timezone's in php 5.2.* support historical data better, eg. if timezone today was +8, but 259 in 1970 it was +7:30, then php 5.2 return +7:30, while this library will use +8. 260 * 261 262- 19 March 2006 0.24 263Changed strftime() locale detection, because some locales prepend the day of week to the date when %c is used. 264 265- 10 Feb 2006 0.23 266PHP5 compat: when we detect PHP5, the RFC2822 format for gmt 0000hrs is changed from -0000 to +0000. 267 In PHP4, we will still use -0000 for 100% compat with PHP4. 268 269- 08 Sept 2005 0.22 270In adodb_date2(), $is_gmt not supported properly. Fixed. 271 272- 18 July 2005 0.21 273In PHP 4.3.11, the 'r' format has changed. Leading 0 in day is added. Changed for compat. 274Added support for negative months in adodb_mktime(). 275 276- 24 Feb 2005 0.20 277Added limited strftime/gmstrftime support. x10 improvement in performance of adodb_date(). 278 279- 21 Dec 2004 0.17 280In adodb_getdate(), the timestamp was accidentally converted to gmt when $is_gmt is false. 281Also adodb_mktime(0,0,0) did not work properly. Both fixed thx Mauro. 282 283- 17 Nov 2004 0.16 284Removed intval typecast in adodb_mktime() for secs, allowing: 285 adodb_mktime(0,0,0 + 2236672153,1,1,1934); 286Suggested by Ryan. 287 288- 18 July 2004 0.15 289All params in adodb_mktime were formerly compulsory. Now only the hour, min, secs is compulsory. 290This brings it more in line with mktime (still not identical). 291 292- 23 June 2004 0.14 293 294Allow you to define your own daylights savings function, adodb_daylight_sv. 295If the function is defined (somewhere in an include), then you can correct for daylights savings. 296 297In this example, we apply daylights savings in June or July, adding one hour. This is extremely 298unrealistic as it does not take into account time-zone, geographic location, current year. 299 300function adodb_daylight_sv(&$arr, $is_gmt) 301{ 302 if ($is_gmt) return; 303 $m = $arr['mon']; 304 if ($m == 6 || $m == 7) $arr['hours'] += 1; 305} 306 307This is only called by adodb_date() and not by adodb_mktime(). 308 309The format of $arr is 310Array ( 311 [seconds] => 0 312 [minutes] => 0 313 [hours] => 0 314 [mday] => 1 # day of month, eg 1st day of the month 315 [mon] => 2 # month (eg. Feb) 316 [year] => 2102 317 [yday] => 31 # days in current year 318 [leap] => # true if leap year 319 [ndays] => 28 # no of days in current month 320 ) 321 322 323- 28 Apr 2004 0.13 324Fixed adodb_date to properly support $is_gmt. Thx to Dimitar Angelov. 325 326- 20 Mar 2004 0.12 327Fixed month calculation error in adodb_date. 2102-June-01 appeared as 2102-May-32. 328 329- 26 Oct 2003 0.11 330Because of daylight savings problems (some systems apply daylight savings to 331January!!!), changed adodb_get_gmt_diff() to ignore daylight savings. 332 333- 9 Aug 2003 0.10 334Fixed bug with dates after 2038. 335See http://phplens.com/lens/lensforum/msgs.php?id=6980 336 337- 1 July 2003 0.09 338Added support for Q (Quarter). 339Added adodb_date2(), which accepts ISO date in 2nd param 340 341- 3 March 2003 0.08 342Added support for 'S' adodb_date() format char. Added constant ADODB_ALLOW_NEGATIVE_TS 343if you want PHP to handle negative timestamps between 1901 to 1969. 344 345- 27 Feb 2003 0.07 346All negative numbers handled by adodb now because of RH 7.3+ problems. 347See http://bugs.php.net/bug.php?id=20048&edit=2 348 349- 4 Feb 2003 0.06 350Fixed a typo, 1852 changed to 1582! This means that pre-1852 dates 351are now correctly handled. 352 353- 29 Jan 2003 0.05 354 355Leap year checking differs under Julian calendar (pre 1582). Also 356leap year code optimized by checking for most common case first. 357 358We also handle month overflow correctly in mktime (eg month set to 13). 359 360Day overflow for less than one month's days is supported. 361 362- 28 Jan 2003 0.04 363 364Gregorian correction handled. In PHP5, we might throw an error if 365mktime uses invalid dates around 5-14 Oct 1582. Released with ADOdb 3.10. 366Added limbo 5-14 Oct 1582 check, when we set to 15 Oct 1582. 367 368- 27 Jan 2003 0.03 369 370Fixed some more month problems due to gmt issues. Added constant ADODB_DATE_VERSION. 371Fixed calculation of days since start of year for <1970. 372 373- 27 Jan 2003 0.02 374 375Changed _adodb_getdate() to inline leap year checking for better performance. 376Fixed problem with time-zones west of GMT +0000. 377 378- 24 Jan 2003 0.01 379 380First implementation. 381*/ 382 383 384/* Initialization */ 385 386/* 387 Version Number 388*/ 389define('ADODB_DATE_VERSION',0.33); 390 391$ADODB_DATETIME_CLASS = (PHP_VERSION >= 5.2); 392 393/* 394 This code was originally for windows. But apparently this problem happens 395 also with Linux, RH 7.3 and later! 396 397 glibc-2.2.5-34 and greater has been changed to return -1 for dates < 398 1970. This used to work. The problem exists with RedHat 7.3 and 8.0 399 echo (mktime(0, 0, 0, 1, 1, 1960)); // prints -1 400 401 References: 402 http://bugs.php.net/bug.php?id=20048&edit=2 403 http://lists.debian.org/debian-glibc/2002/debian-glibc-200205/msg00010.html 404*/ 405 406if (!defined('ADODB_ALLOW_NEGATIVE_TS')) define('ADODB_NO_NEGATIVE_TS',1); 407 408function adodb_date_test_date($y1,$m,$d=13) 409{ 410 $h = round(rand()% 24); 411 $t = adodb_mktime($h,0,0,$m,$d,$y1); 412 $rez = adodb_date('Y-n-j H:i:s',$t); 413 if ($h == 0) $h = '00'; 414 else if ($h < 10) $h = '0'.$h; 415 if ("$y1-$m-$d $h:00:00" != $rez) { 416 print "<b>$y1 error, expected=$y1-$m-$d $h:00:00, adodb=$rez</b><br>"; 417 return false; 418 } 419 return true; 420} 421 422function adodb_date_test_strftime($fmt) 423{ 424 $s1 = strftime($fmt); 425 $s2 = adodb_strftime($fmt); 426 427 if ($s1 == $s2) return true; 428 429 echo "error for $fmt, strftime=$s1, adodb=$s2<br>"; 430 return false; 431} 432 433/** 434 Test Suite 435*/ 436function adodb_date_test() 437{ 438 439 for ($m=-24; $m<=24; $m++) 440 echo "$m :",adodb_date('d-m-Y',adodb_mktime(0,0,0,1+$m,20,2040)),"<br>"; 441 442 error_reporting(E_ALL); 443 print "<h4>Testing adodb_date and adodb_mktime. version=".ADODB_DATE_VERSION.' PHP='.PHP_VERSION."</h4>"; 444 @set_time_limit(0); 445 $fail = false; 446 447 // This flag disables calling of PHP native functions, so we can properly test the code 448 if (!defined('ADODB_TEST_DATES')) define('ADODB_TEST_DATES',1); 449 450 $t = time(); 451 452 453 $fmt = 'Y-m-d H:i:s'; 454 echo '<pre>'; 455 echo 'adodb: ',adodb_date($fmt,$t),'<br>'; 456 echo 'php : ',date($fmt,$t),'<br>'; 457 echo '</pre>'; 458 459 adodb_date_test_strftime('%Y %m %x %X'); 460 adodb_date_test_strftime("%A %d %B %Y"); 461 adodb_date_test_strftime("%H %M S"); 462 463 $t = adodb_mktime(0,0,0); 464 if (!(adodb_date('Y-m-d') == date('Y-m-d'))) print 'Error in '.adodb_mktime(0,0,0).'<br>'; 465 466 $t = adodb_mktime(0,0,0,6,1,2102); 467 if (!(adodb_date('Y-m-d',$t) == '2102-06-01')) print 'Error in '.adodb_date('Y-m-d',$t).'<br>'; 468 469 $t = adodb_mktime(0,0,0,2,1,2102); 470 if (!(adodb_date('Y-m-d',$t) == '2102-02-01')) print 'Error in '.adodb_date('Y-m-d',$t).'<br>'; 471 472 473 print "<p>Testing gregorian <=> julian conversion<p>"; 474 $t = adodb_mktime(0,0,0,10,11,1492); 475 //http://www.holidayorigins.com/html/columbus_day.html - Friday check 476 if (!(adodb_date('D Y-m-d',$t) == 'Fri 1492-10-11')) print 'Error in Columbus landing<br>'; 477 478 $t = adodb_mktime(0,0,0,2,29,1500); 479 if (!(adodb_date('Y-m-d',$t) == '1500-02-29')) print 'Error in julian leap years<br>'; 480 481 $t = adodb_mktime(0,0,0,2,29,1700); 482 if (!(adodb_date('Y-m-d',$t) == '1700-03-01')) print 'Error in gregorian leap years<br>'; 483 484 print adodb_mktime(0,0,0,10,4,1582).' '; 485 print adodb_mktime(0,0,0,10,15,1582); 486 $diff = (adodb_mktime(0,0,0,10,15,1582) - adodb_mktime(0,0,0,10,4,1582)); 487 if ($diff != 3600*24) print " <b>Error in gregorian correction = ".($diff/3600/24)." days </b><br>"; 488 489 print " 15 Oct 1582, Fri=".(adodb_dow(1582,10,15) == 5 ? 'Fri' : '<b>Error</b>')."<br>"; 490 print " 4 Oct 1582, Thu=".(adodb_dow(1582,10,4) == 4 ? 'Thu' : '<b>Error</b>')."<br>"; 491 492 print "<p>Testing overflow<p>"; 493 494 $t = adodb_mktime(0,0,0,3,33,1965); 495 if (!(adodb_date('Y-m-d',$t) == '1965-04-02')) print 'Error in day overflow 1 <br>'; 496 $t = adodb_mktime(0,0,0,4,33,1971); 497 if (!(adodb_date('Y-m-d',$t) == '1971-05-03')) print 'Error in day overflow 2 <br>'; 498 $t = adodb_mktime(0,0,0,1,60,1965); 499 if (!(adodb_date('Y-m-d',$t) == '1965-03-01')) print 'Error in day overflow 3 '.adodb_date('Y-m-d',$t).' <br>'; 500 $t = adodb_mktime(0,0,0,12,32,1965); 501 if (!(adodb_date('Y-m-d',$t) == '1966-01-01')) print 'Error in day overflow 4 '.adodb_date('Y-m-d',$t).' <br>'; 502 $t = adodb_mktime(0,0,0,12,63,1965); 503 if (!(adodb_date('Y-m-d',$t) == '1966-02-01')) print 'Error in day overflow 5 '.adodb_date('Y-m-d',$t).' <br>'; 504 $t = adodb_mktime(0,0,0,13,3,1965); 505 if (!(adodb_date('Y-m-d',$t) == '1966-01-03')) print 'Error in mth overflow 1 <br>'; 506 507 print "Testing 2-digit => 4-digit year conversion<p>"; 508 if (adodb_year_digit_check(00) != 2000) print "Err 2-digit 2000<br>"; 509 if (adodb_year_digit_check(10) != 2010) print "Err 2-digit 2010<br>"; 510 if (adodb_year_digit_check(20) != 2020) print "Err 2-digit 2020<br>"; 511 if (adodb_year_digit_check(30) != 2030) print "Err 2-digit 2030<br>"; 512 if (adodb_year_digit_check(40) != 1940) print "Err 2-digit 1940<br>"; 513 if (adodb_year_digit_check(50) != 1950) print "Err 2-digit 1950<br>"; 514 if (adodb_year_digit_check(90) != 1990) print "Err 2-digit 1990<br>"; 515 516 // Test string formating 517 print "<p>Testing date formating</p>"; 518 519 $fmt = '\d\a\t\e T Y-m-d H:i:s a A d D F g G h H i j l L m M n O \R\F\C2822 r s t U w y Y z Z 2003'; 520 $s1 = date($fmt,0); 521 $s2 = adodb_date($fmt,0); 522 if ($s1 != $s2) { 523 print " date() 0 failed<br>$s1<br>$s2<br>"; 524 } 525 flush(); 526 for ($i=100; --$i > 0; ) { 527 528 $ts = 3600.0*((rand()%60000)+(rand()%60000))+(rand()%60000); 529 $s1 = date($fmt,$ts); 530 $s2 = adodb_date($fmt,$ts); 531 //print "$s1 <br>$s2 <p>"; 532 $pos = strcmp($s1,$s2); 533 534 if (($s1) != ($s2)) { 535 for ($j=0,$k=strlen($s1); $j < $k; $j++) { 536 if ($s1[$j] != $s2[$j]) { 537 print substr($s1,$j).' '; 538 break; 539 } 540 } 541 print "<b>Error date(): $ts<br><pre> 542 \"$s1\" (date len=".strlen($s1).") 543 \"$s2\" (adodb_date len=".strlen($s2).")</b></pre><br>"; 544 $fail = true; 545 } 546 547 $a1 = getdate($ts); 548 $a2 = adodb_getdate($ts); 549 $rez = array_diff($a1,$a2); 550 if (sizeof($rez)>0) { 551 print "<b>Error getdate() $ts</b><br>"; 552 print_r($a1); 553 print "<br>"; 554 print_r($a2); 555 print "<p>"; 556 $fail = true; 557 } 558 } 559 560 // Test generation of dates outside 1901-2038 561 print "<p>Testing random dates between 100 and 4000</p>"; 562 adodb_date_test_date(100,1); 563 for ($i=100; --$i >= 0;) { 564 $y1 = 100+rand(0,1970-100); 565 $m = rand(1,12); 566 adodb_date_test_date($y1,$m); 567 568 $y1 = 3000-rand(0,3000-1970); 569 adodb_date_test_date($y1,$m); 570 } 571 print '<p>'; 572 $start = 1960+rand(0,10); 573 $yrs = 12; 574 $i = 365.25*86400*($start-1970); 575 $offset = 36000+rand(10000,60000); 576 $max = 365*$yrs*86400; 577 $lastyear = 0; 578 579 // we generate a timestamp, convert it to a date, and convert it back to a timestamp 580 // and check if the roundtrip broke the original timestamp value. 581 print "Testing $start to ".($start+$yrs).", or $max seconds, offset=$offset: "; 582 $cnt = 0; 583 for ($max += $i; $i < $max; $i += $offset) { 584 $ret = adodb_date('m,d,Y,H,i,s',$i); 585 $arr = explode(',',$ret); 586 if ($lastyear != $arr[2]) { 587 $lastyear = $arr[2]; 588 print " $lastyear "; 589 flush(); 590 } 591 $newi = adodb_mktime($arr[3],$arr[4],$arr[5],$arr[0],$arr[1],$arr[2]); 592 if ($i != $newi) { 593 print "Error at $i, adodb_mktime returned $newi ($ret)"; 594 $fail = true; 595 break; 596 } 597 $cnt += 1; 598 } 599 echo "Tested $cnt dates<br>"; 600 if (!$fail) print "<p>Passed !</p>"; 601 else print "<p><b>Failed</b> :-(</p>"; 602} 603 604/** 605 Returns day of week, 0 = Sunday,... 6=Saturday. 606 Algorithm from PEAR::Date_Calc 607*/ 608function adodb_dow($year, $month, $day) 609{ 610/* 611Pope Gregory removed 10 days - October 5 to October 14 - from the year 1582 and 612proclaimed that from that time onwards 3 days would be dropped from the calendar 613every 400 years. 614 615Thursday, October 4, 1582 (Julian) was followed immediately by Friday, October 15, 1582 (Gregorian). 616*/ 617 if ($year <= 1582) { 618 if ($year < 1582 || 619 ($year == 1582 && ($month < 10 || ($month == 10 && $day < 15)))) $greg_correction = 3; 620 else 621 $greg_correction = 0; 622 } else 623 $greg_correction = 0; 624 625 if($month > 2) 626 $month -= 2; 627 else { 628 $month += 10; 629 $year--; 630 } 631 632 $day = floor((13 * $month - 1) / 5) + 633 $day + ($year % 100) + 634 floor(($year % 100) / 4) + 635 floor(($year / 100) / 4) - 2 * 636 floor($year / 100) + 77 + $greg_correction; 637 638 return $day - 7 * floor($day / 7); 639} 640 641 642/** 643 Checks for leap year, returns true if it is. No 2-digit year check. Also 644 handles julian calendar correctly. 645*/ 646function _adodb_is_leap_year($year) 647{ 648 if ($year % 4 != 0) return false; 649 650 if ($year % 400 == 0) { 651 return true; 652 // if gregorian calendar (>1582), century not-divisible by 400 is not leap 653 } else if ($year > 1582 && $year % 100 == 0 ) { 654 return false; 655 } 656 657 return true; 658} 659 660 661/** 662 checks for leap year, returns true if it is. Has 2-digit year check 663*/ 664function adodb_is_leap_year($year) 665{ 666 return _adodb_is_leap_year(adodb_year_digit_check($year)); 667} 668 669/** 670 Fix 2-digit years. Works for any century. 671 Assumes that if 2-digit is more than 30 years in future, then previous century. 672*/ 673function adodb_year_digit_check($y) 674{ 675 if ($y < 100) { 676 677 $yr = (integer) date("Y"); 678 $century = (integer) ($yr /100); 679 680 if ($yr%100 > 50) { 681 $c1 = $century + 1; 682 $c0 = $century; 683 } else { 684 $c1 = $century; 685 $c0 = $century - 1; 686 } 687 $c1 *= 100; 688 // if 2-digit year is less than 30 years in future, set it to this century 689 // otherwise if more than 30 years in future, then we set 2-digit year to the prev century. 690 if (($y + $c1) < $yr+30) $y = $y + $c1; 691 else $y = $y + $c0*100; 692 } 693 return $y; 694} 695 696function adodb_get_gmt_diff_ts($ts) 697{ 698 if (0 <= $ts && $ts <= 0x7FFFFFFF) { // check if number in 32-bit signed range) { 699 $arr = getdate($ts); 700 $y = $arr['year']; 701 $m = $arr['mon']; 702 $d = $arr['mday']; 703 return adodb_get_gmt_diff($y,$m,$d); 704 } else { 705 return adodb_get_gmt_diff(false,false,false); 706 } 707 708} 709 710/** 711 get local time zone offset from GMT. Does not handle historical timezones before 1970. 712*/ 713function adodb_get_gmt_diff($y,$m,$d) 714{ 715static $TZ,$tzo; 716global $ADODB_DATETIME_CLASS; 717 718 if (!defined('ADODB_TEST_DATES')) $y = false; 719 else if ($y < 1970 || $y >= 2038) $y = false; 720 721 if ($ADODB_DATETIME_CLASS && $y !== false) { 722 $dt = new DateTime(); 723 $dt->setISODate($y,$m,$d); 724 if (empty($tzo)) { 725 $tzo = new DateTimeZone(date_default_timezone_get()); 726 # $tzt = timezone_transitions_get( $tzo ); 727 } 728 return -$tzo->getOffset($dt); 729 } else { 730 if (isset($TZ)) return $TZ; 731 $y = date('Y'); 732 $TZ = mktime(0,0,0,12,2,$y,0) - gmmktime(0,0,0,12,2,$y,0); 733 } 734 735 return $TZ; 736} 737 738/** 739 Returns an array with date info. 740*/ 741function adodb_getdate($d=false,$fast=false) 742{ 743 if ($d === false) return getdate(); 744 if (!defined('ADODB_TEST_DATES')) { 745 if ((abs($d) <= 0x7FFFFFFF)) { // check if number in 32-bit signed range 746 if (!defined('ADODB_NO_NEGATIVE_TS') || $d >= 0) // if windows, must be +ve integer 747 return @getdate($d); 748 } 749 } 750 return _adodb_getdate($d); 751} 752 753/* 754// generate $YRS table for _adodb_getdate() 755function adodb_date_gentable($out=true) 756{ 757 758 for ($i=1970; $i >= 1600; $i-=10) { 759 $s = adodb_gmmktime(0,0,0,1,1,$i); 760 echo "$i => $s,<br>"; 761 } 762} 763adodb_date_gentable(); 764 765for ($i=1970; $i > 1500; $i--) { 766 767echo "<hr />$i "; 768 adodb_date_test_date($i,1,1); 769} 770 771*/ 772 773 774$_month_table_normal = array("",31,28,31,30,31,30,31,31,30,31,30,31); 775$_month_table_leaf = array("",31,29,31,30,31,30,31,31,30,31,30,31); 776 777function adodb_validdate($y,$m,$d) 778{ 779global $_month_table_normal,$_month_table_leaf; 780 781 if (_adodb_is_leap_year($y)) $marr = $_month_table_leaf; 782 else $marr = $_month_table_normal; 783 784 if ($m > 12 || $m < 1) return false; 785 786 if ($d > 31 || $d < 1) return false; 787 788 if ($marr[$m] < $d) return false; 789 790 if ($y < 1000 && $y > 3000) return false; 791 792 return true; 793} 794 795/** 796 Low-level function that returns the getdate() array. We have a special 797 $fast flag, which if set to true, will return fewer array values, 798 and is much faster as it does not calculate dow, etc. 799*/ 800function _adodb_getdate($origd=false,$fast=false,$is_gmt=false) 801{ 802static $YRS; 803global $_month_table_normal,$_month_table_leaf; 804 805 $d = $origd - ($is_gmt ? 0 : adodb_get_gmt_diff_ts($origd)); 806 $_day_power = 86400; 807 $_hour_power = 3600; 808 $_min_power = 60; 809 810 if ($d < -12219321600) $d -= 86400*10; // if 15 Oct 1582 or earlier, gregorian correction 811 812 $_month_table_normal = array("",31,28,31,30,31,30,31,31,30,31,30,31); 813 $_month_table_leaf = array("",31,29,31,30,31,30,31,31,30,31,30,31); 814 815 $d366 = $_day_power * 366; 816 $d365 = $_day_power * 365; 817 818 if ($d < 0) { 819 820 if (empty($YRS)) $YRS = array( 821 1970 => 0, 822 1960 => -315619200, 823 1950 => -631152000, 824 1940 => -946771200, 825 1930 => -1262304000, 826 1920 => -1577923200, 827 1910 => -1893456000, 828 1900 => -2208988800, 829 1890 => -2524521600, 830 1880 => -2840140800, 831 1870 => -3155673600, 832 1860 => -3471292800, 833 1850 => -3786825600, 834 1840 => -4102444800, 835 1830 => -4417977600, 836 1820 => -4733596800, 837 1810 => -5049129600, 838 1800 => -5364662400, 839 1790 => -5680195200, 840 1780 => -5995814400, 841 1770 => -6311347200, 842 1760 => -6626966400, 843 1750 => -6942499200, 844 1740 => -7258118400, 845 1730 => -7573651200, 846 1720 => -7889270400, 847 1710 => -8204803200, 848 1700 => -8520336000, 849 1690 => -8835868800, 850 1680 => -9151488000, 851 1670 => -9467020800, 852 1660 => -9782640000, 853 1650 => -10098172800, 854 1640 => -10413792000, 855 1630 => -10729324800, 856 1620 => -11044944000, 857 1610 => -11360476800, 858 1600 => -11676096000); 859 860 if ($is_gmt) $origd = $d; 861 // The valid range of a 32bit signed timestamp is typically from 862 // Fri, 13 Dec 1901 20:45:54 GMT to Tue, 19 Jan 2038 03:14:07 GMT 863 // 864 865 # old algorithm iterates through all years. new algorithm does it in 866 # 10 year blocks 867 868 /* 869 # old algo 870 for ($a = 1970 ; --$a >= 0;) { 871 $lastd = $d; 872 873 if ($leaf = _adodb_is_leap_year($a)) $d += $d366; 874 else $d += $d365; 875 876 if ($d >= 0) { 877 $year = $a; 878 break; 879 } 880 } 881 */ 882 883 $lastsecs = 0; 884 $lastyear = 1970; 885 foreach($YRS as $year => $secs) { 886 if ($d >= $secs) { 887 $a = $lastyear; 888 break; 889 } 890 $lastsecs = $secs; 891 $lastyear = $year; 892 } 893 894 $d -= $lastsecs; 895 if (!isset($a)) $a = $lastyear; 896 897 //echo ' yr=',$a,' ', $d,'.'; 898 899 for (; --$a >= 0;) { 900 $lastd = $d; 901 902 if ($leaf = _adodb_is_leap_year($a)) $d += $d366; 903 else $d += $d365; 904 905 if ($d >= 0) { 906 $year = $a; 907 break; 908 } 909 } 910 /**/ 911 912 $secsInYear = 86400 * ($leaf ? 366 : 365) + $lastd; 913 914 $d = $lastd; 915 $mtab = ($leaf) ? $_month_table_leaf : $_month_table_normal; 916 for ($a = 13 ; --$a > 0;) { 917 $lastd = $d; 918 $d += $mtab[$a] * $_day_power; 919 if ($d >= 0) { 920 $month = $a; 921 $ndays = $mtab[$a]; 922 break; 923 } 924 } 925 926 $d = $lastd; 927 $day = $ndays + ceil(($d+1) / ($_day_power)); 928 929 $d += ($ndays - $day+1)* $_day_power; 930 $hour = floor($d/$_hour_power); 931 932 } else { 933 for ($a = 1970 ;; $a++) { 934 $lastd = $d; 935 936 if ($leaf = _adodb_is_leap_year($a)) $d -= $d366; 937 else $d -= $d365; 938 if ($d < 0) { 939 $year = $a; 940 break; 941 } 942 } 943 $secsInYear = $lastd; 944 $d = $lastd; 945 $mtab = ($leaf) ? $_month_table_leaf : $_month_table_normal; 946 for ($a = 1 ; $a <= 12; $a++) { 947 $lastd = $d; 948 $d -= $mtab[$a] * $_day_power; 949 if ($d < 0) { 950 $month = $a; 951 $ndays = $mtab[$a]; 952 break; 953 } 954 } 955 $d = $lastd; 956 $day = ceil(($d+1) / $_day_power); 957 $d = $d - ($day-1) * $_day_power; 958 $hour = floor($d /$_hour_power); 959 } 960 961 $d -= $hour * $_hour_power; 962 $min = floor($d/$_min_power); 963 $secs = $d - $min * $_min_power; 964 if ($fast) { 965 return array( 966 'seconds' => $secs, 967 'minutes' => $min, 968 'hours' => $hour, 969 'mday' => $day, 970 'mon' => $month, 971 'year' => $year, 972 'yday' => floor($secsInYear/$_day_power), 973 'leap' => $leaf, 974 'ndays' => $ndays 975 ); 976 } 977 978 979 $dow = adodb_dow($year,$month,$day); 980 981 return array( 982 'seconds' => $secs, 983 'minutes' => $min, 984 'hours' => $hour, 985 'mday' => $day, 986 'wday' => $dow, 987 'mon' => $month, 988 'year' => $year, 989 'yday' => floor($secsInYear/$_day_power), 990 'weekday' => gmdate('l',$_day_power*(3+$dow)), 991 'month' => gmdate('F',mktime(0,0,0,$month,2,1971)), 992 0 => $origd 993 ); 994} 995/* 996 if ($isphp5) 997 $dates .= sprintf('%s%04d',($gmt<=0)?'+':'-',abs($gmt)/36); 998 else 999 $dates .= sprintf('%s%04d',($gmt<0)?'+':'-',abs($gmt)/36); 1000 break;*/ 1001function adodb_tz_offset($gmt,$isphp5) 1002{ 1003 $zhrs = abs($gmt)/3600; 1004 $hrs = floor($zhrs); 1005 if ($isphp5) 1006 return sprintf('%s%02d%02d',($gmt<=0)?'+':'-',floor($zhrs),($zhrs-$hrs)*60); 1007 else 1008 return sprintf('%s%02d%02d',($gmt<0)?'+':'-',floor($zhrs),($zhrs-$hrs)*60); 1009} 1010 1011 1012function adodb_gmdate($fmt,$d=false) 1013{ 1014 return adodb_date($fmt,$d,true); 1015} 1016 1017// accepts unix timestamp and iso date format in $d 1018function adodb_date2($fmt, $d=false, $is_gmt=false) 1019{ 1020 if ($d !== false) { 1021 if (!preg_match( 1022 "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})[ -]?(([0-9]{1,2}):?([0-9]{1,2}):?([0-9\.]{1,4}))?|", 1023 ($d), $rr)) return adodb_date($fmt,false,$is_gmt); 1024 1025 if ($rr[1] <= 100 && $rr[2]<= 1) return adodb_date($fmt,false,$is_gmt); 1026 1027 // h-m-s-MM-DD-YY 1028 if (!isset($rr[5])) $d = adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1],false,$is_gmt); 1029 else $d = @adodb_mktime($rr[5],$rr[6],$rr[7],$rr[2],$rr[3],$rr[1],false,$is_gmt); 1030 } 1031 1032 return adodb_date($fmt,$d,$is_gmt); 1033} 1034 1035 1036/** 1037 Return formatted date based on timestamp $d 1038*/ 1039function adodb_date($fmt,$d=false,$is_gmt=false) 1040{ 1041static $daylight; 1042global $ADODB_DATETIME_CLASS; 1043 1044 if ($d === false) return ($is_gmt)? @gmdate($fmt): @date($fmt); 1045 if (!defined('ADODB_TEST_DATES')) { 1046 if ((abs($d) <= 0x7FFFFFFF)) { // check if number in 32-bit signed range 1047 if (!defined('ADODB_NO_NEGATIVE_TS') || $d >= 0) // if windows, must be +ve integer 1048 return ($is_gmt)? @gmdate($fmt,$d): @date($fmt,$d); 1049 1050 } 1051 } 1052 $_day_power = 86400; 1053 1054 $arr = _adodb_getdate($d,true,$is_gmt); 1055 1056 if (!isset($daylight)) $daylight = function_exists('adodb_daylight_sv'); 1057 if ($daylight) adodb_daylight_sv($arr, $is_gmt); 1058 1059 $year = $arr['year']; 1060 $month = $arr['mon']; 1061 $day = $arr['mday']; 1062 $hour = $arr['hours']; 1063 $min = $arr['minutes']; 1064 $secs = $arr['seconds']; 1065 1066 $max = strlen($fmt); 1067 $dates = ''; 1068 1069 $isphp5 = PHP_VERSION >= 5; 1070 1071 /* 1072 at this point, we have the following integer vars to manipulate: 1073 $year, $month, $day, $hour, $min, $secs 1074 */ 1075 for ($i=0; $i < $max; $i++) { 1076 switch($fmt[$i]) { 1077 case 'T': 1078 if ($ADODB_DATETIME_CLASS) { 1079 $dt = new DateTime(); 1080 $dt->SetDate($year,$month,$day); 1081 $dates .= $dt->Format('T'); 1082 } else 1083 $dates .= date('T'); 1084 break; 1085 // YEAR 1086 case 'L': $dates .= $arr['leap'] ? '1' : '0'; break; 1087 case 'r': // Thu, 21 Dec 2000 16:01:07 +0200 1088 1089 // 4.3.11 uses '04 Jun 2004' 1090 // 4.3.8 uses ' 4 Jun 2004' 1091 $dates .= gmdate('D',$_day_power*(3+adodb_dow($year,$month,$day))).', ' 1092 . ($day<10?'0'.$day:$day) . ' '.date('M',mktime(0,0,0,$month,2,1971)).' '.$year.' '; 1093 1094 if ($hour < 10) $dates .= '0'.$hour; else $dates .= $hour; 1095 1096 if ($min < 10) $dates .= ':0'.$min; else $dates .= ':'.$min; 1097 1098 if ($secs < 10) $dates .= ':0'.$secs; else $dates .= ':'.$secs; 1099 1100 $gmt = adodb_get_gmt_diff($year,$month,$day); 1101 1102 $dates .= ' '.adodb_tz_offset($gmt,$isphp5); 1103 break; 1104 1105 case 'Y': $dates .= $year; break; 1106 case 'y': $dates .= substr($year,strlen($year)-2,2); break; 1107 // MONTH 1108 case 'm': if ($month<10) $dates .= '0'.$month; else $dates .= $month; break; 1109 case 'Q': $dates .= ($month+3)>>2; break; 1110 case 'n': $dates .= $month; break; 1111 case 'M': $dates .= date('M',mktime(0,0,0,$month,2,1971)); break; 1112 case 'F': $dates .= date('F',mktime(0,0,0,$month,2,1971)); break; 1113 // DAY 1114 case 't': $dates .= $arr['ndays']; break; 1115 case 'z': $dates .= $arr['yday']; break; 1116 case 'w': $dates .= adodb_dow($year,$month,$day); break; 1117 case 'l': $dates .= gmdate('l',$_day_power*(3+adodb_dow($year,$month,$day))); break; 1118 case 'D': $dates .= gmdate('D',$_day_power*(3+adodb_dow($year,$month,$day))); break; 1119 case 'j': $dates .= $day; break; 1120 case 'd': if ($day<10) $dates .= '0'.$day; else $dates .= $day; break; 1121 case 'S': 1122 $d10 = $day % 10; 1123 if ($d10 == 1) $dates .= 'st'; 1124 else if ($d10 == 2 && $day != 12) $dates .= 'nd'; 1125 else if ($d10 == 3) $dates .= 'rd'; 1126 else $dates .= 'th'; 1127 break; 1128 1129 // HOUR 1130 case 'Z': 1131 $dates .= ($is_gmt) ? 0 : -adodb_get_gmt_diff($year,$month,$day); break; 1132 case 'O': 1133 $gmt = ($is_gmt) ? 0 : adodb_get_gmt_diff($year,$month,$day); 1134 1135 $dates .= adodb_tz_offset($gmt,$isphp5); 1136 break; 1137 1138 case 'H': 1139 if ($hour < 10) $dates .= '0'.$hour; 1140 else $dates .= $hour; 1141 break; 1142 case 'h': 1143 if ($hour > 12) $hh = $hour - 12; 1144 else { 1145 if ($hour == 0) $hh = '12'; 1146 else $hh = $hour; 1147 } 1148 1149 if ($hh < 10) $dates .= '0'.$hh; 1150 else $dates .= $hh; 1151 break; 1152 1153 case 'G': 1154 $dates .= $hour; 1155 break; 1156 1157 case 'g': 1158 if ($hour > 12) $hh = $hour - 12; 1159 else { 1160 if ($hour == 0) $hh = '12'; 1161 else $hh = $hour; 1162 } 1163 $dates .= $hh; 1164 break; 1165 // MINUTES 1166 case 'i': if ($min < 10) $dates .= '0'.$min; else $dates .= $min; break; 1167 // SECONDS 1168 case 'U': $dates .= $d; break; 1169 case 's': if ($secs < 10) $dates .= '0'.$secs; else $dates .= $secs; break; 1170 // AM/PM 1171 // Note 00:00 to 11:59 is AM, while 12:00 to 23:59 is PM 1172 case 'a': 1173 if ($hour>=12) $dates .= 'pm'; 1174 else $dates .= 'am'; 1175 break; 1176 case 'A': 1177 if ($hour>=12) $dates .= 'PM'; 1178 else $dates .= 'AM'; 1179 break; 1180 default: 1181 $dates .= $fmt[$i]; break; 1182 // ESCAPE 1183 case "\\": 1184 $i++; 1185 if ($i < $max) $dates .= $fmt[$i]; 1186 break; 1187 } 1188 } 1189 return $dates; 1190} 1191 1192/** 1193 Returns a timestamp given a GMT/UTC time. 1194 Note that $is_dst is not implemented and is ignored. 1195*/ 1196function adodb_gmmktime($hr,$min,$sec,$mon=false,$day=false,$year=false,$is_dst=false) 1197{ 1198 return adodb_mktime($hr,$min,$sec,$mon,$day,$year,$is_dst,true); 1199} 1200 1201/** 1202 Return a timestamp given a local time. Originally by jackbbs. 1203 Note that $is_dst is not implemented and is ignored. 1204 1205 Not a very fast algorithm - O(n) operation. Could be optimized to O(1). 1206*/ 1207function adodb_mktime($hr,$min,$sec,$mon=false,$day=false,$year=false,$is_dst=false,$is_gmt=false) 1208{ 1209 if (!defined('ADODB_TEST_DATES')) { 1210 1211 if ($mon === false) { 1212 return $is_gmt? @gmmktime($hr,$min,$sec): @mktime($hr,$min,$sec); 1213 } 1214 1215 // for windows, we don't check 1970 because with timezone differences, 1216 // 1 Jan 1970 could generate negative timestamp, which is illegal 1217 $usephpfns = (1971 < $year && $year < 2038 1218 || !defined('ADODB_NO_NEGATIVE_TS') && (1901 < $year && $year < 2038) 1219 ); 1220 1221 1222 if ($usephpfns && ($year + $mon/12+$day/365.25+$hr/(24*365.25) >= 2038)) $usephpfns = false; 1223 1224 if ($usephpfns) { 1225 return $is_gmt ? 1226 @gmmktime($hr,$min,$sec,$mon,$day,$year): 1227 @mktime($hr,$min,$sec,$mon,$day,$year); 1228 } 1229 } 1230 1231 $gmt_different = ($is_gmt) ? 0 : adodb_get_gmt_diff($year,$mon,$day); 1232 1233 /* 1234 # disabled because some people place large values in $sec. 1235 # however we need it for $mon because we use an array... 1236 $hr = intval($hr); 1237 $min = intval($min); 1238 $sec = intval($sec); 1239 */ 1240 $mon = intval($mon); 1241 $day = intval($day); 1242 $year = intval($year); 1243 1244 1245 $year = adodb_year_digit_check($year); 1246 1247 if ($mon > 12) { 1248 $y = floor(($mon-1)/ 12); 1249 $year += $y; 1250 $mon -= $y*12; 1251 } else if ($mon < 1) { 1252 $y = ceil((1-$mon) / 12); 1253 $year -= $y; 1254 $mon += $y*12; 1255 } 1256 1257 $_day_power = 86400; 1258 $_hour_power = 3600; 1259 $_min_power = 60; 1260 1261 $_month_table_normal = array("",31,28,31,30,31,30,31,31,30,31,30,31); 1262 $_month_table_leaf = array("",31,29,31,30,31,30,31,31,30,31,30,31); 1263 1264 $_total_date = 0; 1265 if ($year >= 1970) { 1266 for ($a = 1970 ; $a <= $year; $a++) { 1267 $leaf = _adodb_is_leap_year($a); 1268 if ($leaf == true) { 1269 $loop_table = $_month_table_leaf; 1270 $_add_date = 366; 1271 } else { 1272 $loop_table = $_month_table_normal; 1273 $_add_date = 365; 1274 } 1275 if ($a < $year) { 1276 $_total_date += $_add_date; 1277 } else { 1278 for($b=1;$b<$mon;$b++) { 1279 $_total_date += $loop_table[$b]; 1280 } 1281 } 1282 } 1283 $_total_date +=$day-1; 1284 $ret = $_total_date * $_day_power + $hr * $_hour_power + $min * $_min_power + $sec + $gmt_different; 1285 1286 } else { 1287 for ($a = 1969 ; $a >= $year; $a--) { 1288 $leaf = _adodb_is_leap_year($a); 1289 if ($leaf == true) { 1290 $loop_table = $_month_table_leaf; 1291 $_add_date = 366; 1292 } else { 1293 $loop_table = $_month_table_normal; 1294 $_add_date = 365; 1295 } 1296 if ($a > $year) { $_total_date += $_add_date; 1297 } else { 1298 for($b=12;$b>$mon;$b--) { 1299 $_total_date += $loop_table[$b]; 1300 } 1301 } 1302 } 1303 $_total_date += $loop_table[$mon] - $day; 1304 1305 $_day_time = $hr * $_hour_power + $min * $_min_power + $sec; 1306 $_day_time = $_day_power - $_day_time; 1307 $ret = -( $_total_date * $_day_power + $_day_time - $gmt_different); 1308 if ($ret < -12220185600) $ret += 10*86400; // if earlier than 5 Oct 1582 - gregorian correction 1309 else if ($ret < -12219321600) $ret = -12219321600; // if in limbo, reset to 15 Oct 1582. 1310 } 1311 //print " dmy=$day/$mon/$year $hr:$min:$sec => " .$ret; 1312 return $ret; 1313} 1314 1315function adodb_gmstrftime($fmt, $ts=false) 1316{ 1317 return adodb_strftime($fmt,$ts,true); 1318} 1319 1320// hack - convert to adodb_date 1321function adodb_strftime($fmt, $ts=false,$is_gmt=false) 1322{ 1323global $ADODB_DATE_LOCALE; 1324 1325 if (!defined('ADODB_TEST_DATES')) { 1326 if ((abs($ts) <= 0x7FFFFFFF)) { // check if number in 32-bit signed range 1327 if (!defined('ADODB_NO_NEGATIVE_TS') || $ts >= 0) // if windows, must be +ve integer 1328 return ($is_gmt)? @gmstrftime($fmt,$ts): @strftime($fmt,$ts); 1329 1330 } 1331 } 1332 1333 if (empty($ADODB_DATE_LOCALE)) { 1334 /* 1335 $tstr = strtoupper(gmstrftime('%c',31366800)); // 30 Dec 1970, 1 am 1336 $sep = substr($tstr,2,1); 1337 $hasAM = strrpos($tstr,'M') !== false; 1338 */ 1339 # see http://phplens.com/lens/lensforum/msgs.php?id=14865 for reasoning, and changelog for version 0.24 1340 $dstr = gmstrftime('%x',31366800); // 30 Dec 1970, 1 am 1341 $sep = substr($dstr,2,1); 1342 $tstr = strtoupper(gmstrftime('%X',31366800)); // 30 Dec 1970, 1 am 1343 $hasAM = strrpos($tstr,'M') !== false; 1344 1345 $ADODB_DATE_LOCALE = array(); 1346 $ADODB_DATE_LOCALE[] = strncmp($tstr,'30',2) == 0 ? 'd'.$sep.'m'.$sep.'y' : 'm'.$sep.'d'.$sep.'y'; 1347 $ADODB_DATE_LOCALE[] = ($hasAM) ? 'h:i:s a' : 'H:i:s'; 1348 1349 } 1350 $inpct = false; 1351 $fmtdate = ''; 1352 for ($i=0,$max = strlen($fmt); $i < $max; $i++) { 1353 $ch = $fmt[$i]; 1354 if ($ch == '%') { 1355 if ($inpct) { 1356 $fmtdate .= '%'; 1357 $inpct = false; 1358 } else 1359 $inpct = true; 1360 } else if ($inpct) { 1361 1362 $inpct = false; 1363 switch($ch) { 1364 case '0': 1365 case '1': 1366 case '2': 1367 case '3': 1368 case '4': 1369 case '5': 1370 case '6': 1371 case '7': 1372 case '8': 1373 case '9': 1374 case 'E': 1375 case 'O': 1376 /* ignore format modifiers */ 1377 $inpct = true; 1378 break; 1379 1380 case 'a': $fmtdate .= 'D'; break; 1381 case 'A': $fmtdate .= 'l'; break; 1382 case 'h': 1383 case 'b': $fmtdate .= 'M'; break; 1384 case 'B': $fmtdate .= 'F'; break; 1385 case 'c': $fmtdate .= $ADODB_DATE_LOCALE[0].$ADODB_DATE_LOCALE[1]; break; 1386 case 'C': $fmtdate .= '\C?'; break; // century 1387 case 'd': $fmtdate .= 'd'; break; 1388 case 'D': $fmtdate .= 'm/d/y'; break; 1389 case 'e': $fmtdate .= 'j'; break; 1390 case 'g': $fmtdate .= '\g?'; break; //? 1391 case 'G': $fmtdate .= '\G?'; break; //? 1392 case 'H': $fmtdate .= 'H'; break; 1393 case 'I': $fmtdate .= 'h'; break; 1394 case 'j': $fmtdate .= '?z'; $parsej = true; break; // wrong as j=1-based, z=0-basd 1395 case 'm': $fmtdate .= 'm'; break; 1396 case 'M': $fmtdate .= 'i'; break; 1397 case 'n': $fmtdate .= "\n"; break; 1398 case 'p': $fmtdate .= 'a'; break; 1399 case 'r': $fmtdate .= 'h:i:s a'; break; 1400 case 'R': $fmtdate .= 'H:i:s'; break; 1401 case 'S': $fmtdate .= 's'; break; 1402 case 't': $fmtdate .= "\t"; break; 1403 case 'T': $fmtdate .= 'H:i:s'; break; 1404 case 'u': $fmtdate .= '?u'; $parseu = true; break; // wrong strftime=1-based, date=0-based 1405 case 'U': $fmtdate .= '?U'; $parseU = true; break;// wrong strftime=1-based, date=0-based 1406 case 'x': $fmtdate .= $ADODB_DATE_LOCALE[0]; break; 1407 case 'X': $fmtdate .= $ADODB_DATE_LOCALE[1]; break; 1408 case 'w': $fmtdate .= '?w'; $parseu = true; break; // wrong strftime=1-based, date=0-based 1409 case 'W': $fmtdate .= '?W'; $parseU = true; break;// wrong strftime=1-based, date=0-based 1410 case 'y': $fmtdate .= 'y'; break; 1411 case 'Y': $fmtdate .= 'Y'; break; 1412 case 'Z': $fmtdate .= 'T'; break; 1413 } 1414 } else if (('A' <= ($ch) && ($ch) <= 'Z' ) || ('a' <= ($ch) && ($ch) <= 'z' )) 1415 $fmtdate .= "\\".$ch; 1416 else 1417 $fmtdate .= $ch; 1418 } 1419 //echo "fmt=",$fmtdate,"<br>"; 1420 if ($ts === false) $ts = time(); 1421 $ret = adodb_date($fmtdate, $ts, $is_gmt); 1422 return $ret; 1423} 1424 1425?>