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