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