3 ADOdb Date Library, part of the ADOdb abstraction library
\r
4 Download: http://php.weblogs.com/adodb_date_time_library
\r
6 PHP native date functions use integer timestamps for computations.
\r
7 Because of this, dates are restricted to the years 1901-2038 on Unix
\r
8 and 1970-2038 on Windows due to integer overflow for dates beyond
\r
9 those years. This library overcomes these limitations by replacing the
\r
10 native function's signed integers (normally 32-bits) with PHP floating
\r
11 point numbers (normally 64-bits).
\r
13 Dates from 100 A.D. to 3000 A.D. and later
\r
14 have been tested. The minimum is 100 A.D. as <100 will invoke the
\r
15 2 => 4 digit year conversion. The maximum is billions of years in the
\r
16 future, but this is a theoretical limit as the computation of that year
\r
17 would take too long with the current implementation of adodb_mktime().
\r
19 This library replaces native functions as follows:
\r
22 getdate() with adodb_getdate()
\r
23 date() with adodb_date()
\r
24 gmdate() with adodb_gmdate()
\r
25 mktime() with adodb_mktime()
\r
26 gmmktime() with adodb_gmmktime()
\r
29 The parameters are identical, except that adodb_date() accepts a subset
\r
30 of date()'s field formats. Mktime() will convert from local time to GMT,
\r
31 and date() will convert from GMT to local time, but daylight savings is
\r
32 not handled currently.
\r
34 This library is independant of the rest of ADOdb, and can be used
\r
39 For high speed, this library uses the native date functions where
\r
40 possible, and only switches to PHP code when the dates fall outside
\r
41 the 32-bit signed integer range.
\r
43 GREGORIAN CORRECTION
\r
45 Pope Gregory shortened October of A.D. 1582 by ten days. Thursday,
\r
46 October 4, 1582 (Julian) was followed immediately by Friday, October 15,
\r
49 Since 0.06, we handle this correctly, so:
\r
51 adodb_mktime(0,0,0,10,15,1582) - adodb_mktime(0,0,0,10,4,1582)
\r
52 == 24 * 3600 (1 day)
\r
54 =============================================================================
\r
58 (c) 2003 John Lim and released under BSD-style license except for code by jackbbs,
\r
59 which includes adodb_mktime, adodb_get_gmt_diff, adodb_is_leap_year
\r
60 and originally found at http://www.php.net/manual/en/function.mktime.php
\r
62 =============================================================================
\r
66 These should be posted to the ADOdb forums at
\r
68 http://phplens.com/lens/lensforum/topics.php?id=4
\r
70 =============================================================================
\r
72 FUNCTION DESCRIPTIONS
\r
75 FUNCTION adodb_getdate($date=false)
\r
77 Returns an array containing date information, as getdate(), but supports
\r
78 dates greater than 1901 to 2038.
\r
81 FUNCTION adodb_date($fmt, $timestamp = false)
\r
83 Convert a timestamp to a formatted local date. If $timestamp is not defined, the
\r
84 current timestamp is used. Unlike the function date(), it supports dates
\r
85 outside the 1901 to 2038 range.
\r
87 The format fields that adodb_date supports:
\r
92 d - day of the month, 2 digits with leading zeros; i.e. "01" to "31"
\r
93 D - day of the week, textual, 3 letters; e.g. "Fri"
\r
94 F - month, textual, long; e.g. "January"
\r
95 g - hour, 12-hour format without leading zeros; i.e. "1" to "12"
\r
96 G - hour, 24-hour format without leading zeros; i.e. "0" to "23"
\r
97 h - hour, 12-hour format; i.e. "01" to "12"
\r
98 H - hour, 24-hour format; i.e. "00" to "23"
\r
99 i - minutes; i.e. "00" to "59"
\r
100 j - day of the month without leading zeros; i.e. "1" to "31"
\r
101 l (lowercase 'L') - day of the week, textual, long; e.g. "Friday"
\r
102 L - boolean for whether it is a leap year; i.e. "0" or "1"
\r
103 m - month; i.e. "01" to "12"
\r
104 M - month, textual, 3 letters; e.g. "Jan"
\r
105 n - month without leading zeros; i.e. "1" to "12"
\r
106 O - Difference to Greenwich time in hours; e.g. "+0200"
\r
107 Q - Quarter, as in 1, 2, 3, 4
\r
108 r - RFC 822 formatted date; e.g. "Thu, 21 Dec 2000 16:01:07 +0200"
\r
109 s - seconds; i.e. "00" to "59"
\r
110 S - English ordinal suffix for the day of the month, 2 characters;
\r
111 i.e. "st", "nd", "rd" or "th"
\r
112 t - number of days in the given month; i.e. "28" to "31"
\r
113 T - Timezone setting of this machine; e.g. "EST" or "MDT"
\r
114 U - seconds since the Unix Epoch (January 1 1970 00:00:00 GMT)
\r
115 w - day of the week, numeric, i.e. "0" (Sunday) to "6" (Saturday)
\r
116 Y - year, 4 digits; e.g. "1999"
\r
117 y - year, 2 digits; e.g. "99"
\r
118 z - day of the year; i.e. "0" to "365"
\r
119 Z - timezone offset in seconds (i.e. "-43200" to "43200").
\r
120 The offset for timezones west of UTC is always negative,
\r
121 and for those east of UTC is always positive.
\r
126 B - Swatch Internet time
\r
127 I (capital i) - "1" if Daylight Savings Time, "0" otherwise.
\r
128 W - ISO-8601 week number of year, weeks starting on Monday
\r
132 FUNCTION adodb_date2($fmt, $isoDateString = false)
\r
133 Same as adodb_date, but 2nd parameter accepts iso date, eg.
\r
135 adodb_date2('d-M-Y H:i','2003-12-25 13:01:34');
\r
137 FUNCTION adodb_gmdate($fmt, $timestamp = false)
\r
139 Convert a timestamp to a formatted GMT date. If $timestamp is not defined, the
\r
140 current timestamp is used. Unlike the function date(), it supports dates
\r
141 outside the 1901 to 2038 range.
\r
144 FUNCTION adodb_mktime($hr, $min, $sec, $month, $day, $year)
\r
146 Converts a local date to a unix timestamp. Unlike the function mktime(), it supports
\r
147 dates outside the 1901 to 2038 range. Differs from mktime() in that all parameters
\r
148 are currently compulsory.
\r
150 FUNCTION adodb_gmmktime($hr, $min, $sec, $month, $day, $year)
\r
152 Converts a gmt date to a unix timestamp. Unlike the function gmmktime(), it supports
\r
153 dates outside the 1901 to 2038 range. Differs from gmmktime() in that all parameters
\r
154 are currently compulsory.
\r
156 =============================================================================
\r
160 Useful url for generating test timestamps:
\r
161 http://www.4webhelp.net/us/timestamp.php
\r
163 Possible future optimizations include
\r
165 a. Using an algorithm similar to Plauger's in "The Standard C Library"
\r
166 (page 428, xttotm.c _Ttotm() function). Plauger's algorithm will not
\r
167 work outside 32-bit signed range, so i decided not to implement it.
\r
169 b. Iterate over a block of years (say 12) when searching for the
\r
172 c. Implement daylight savings, which looks awfully complicated, see
\r
173 http://webexhibits.org/daylightsaving/
\r
178 Fixed month calculation error in adodb_date. 2102-June-01 appeared as 2102-May-32.
\r
181 Because of daylight savings problems (some systems apply daylight savings to
\r
182 January!!!), changed adodb_get_gmt_diff() to ignore daylight savings.
\r
185 Fixed bug with dates after 2038.
\r
186 See http://phplens.com/lens/lensforum/msgs.php?id=6980
\r
189 Added support for Q (Quarter).
\r
190 Added adodb_date2(), which accepts ISO date in 2nd param
\r
192 - 3 March 2003 0.08
\r
193 Added support for 'S' adodb_date() format char. Added constant ADODB_ALLOW_NEGATIVE_TS
\r
194 if you want PHP to handle negative timestamps between 1901 to 1969.
\r
197 All negative numbers handled by adodb now because of RH 7.3+ problems.
\r
198 See http://bugs.php.net/bug.php?id=20048&edit=2
\r
201 Fixed a typo, 1852 changed to 1582! This means that pre-1852 dates
\r
202 are now correctly handled.
\r
206 Leap year checking differs under Julian calendar (pre 1582). Also
\r
207 leap year code optimized by checking for most common case first.
\r
209 We also handle month overflow correctly in mktime (eg month set to 13).
\r
211 Day overflow for less than one month's days is supported.
\r
215 Gregorian correction handled. In PHP5, we might throw an error if
\r
216 mktime uses invalid dates around 5-14 Oct 1582. Released with ADOdb 3.10.
\r
217 Added limbo 5-14 Oct 1582 check, when we set to 15 Oct 1582.
\r
221 Fixed some more month problems due to gmt issues. Added constant ADODB_DATE_VERSION.
\r
222 Fixed calculation of days since start of year for <1970.
\r
226 Changed _adodb_getdate() to inline leap year checking for better performance.
\r
227 Fixed problem with time-zones west of GMT +0000.
\r
231 First implementation.
\r
235 /* Initialization */
\r
240 define('ADODB_DATE_VERSION',0.12);
\r
243 We check for Windows as only +ve ints are accepted as dates on Windows.
\r
245 Apparently this problem happens also with Linux, RH 7.3 and later!
\r
247 glibc-2.2.5-34 and greater has been changed to return -1 for dates <
\r
248 1970. This used to work. The problem exists with RedHat 7.3 and 8.0
\r
249 echo (mktime(0, 0, 0, 1, 1, 1960)); // prints -1
\r
252 http://bugs.php.net/bug.php?id=20048&edit=2
\r
253 http://lists.debian.org/debian-glibc/2002/debian-glibc-200205/msg00010.html
\r
256 if (!defined('ADODB_ALLOW_NEGATIVE_TS')) define('ADODB_NO_NEGATIVE_TS',1);
\r
258 function adodb_date_test_date($y1,$m)
\r
260 //print " $y1/$m ";
\r
261 $t = adodb_mktime(0,0,0,$m,13,$y1);
\r
262 if ("$y1-$m-13 00:00:00" != adodb_date('Y-n-d H:i:s',$t)) {
\r
263 print "<b>$y1 error</b><br>";
\r
271 function adodb_date_test()
\r
274 error_reporting(E_ALL);
\r
275 print "<h4>Testing adodb_date and adodb_mktime. version=".ADODB_DATE_VERSION. "</h4>";
\r
279 // This flag disables calling of PHP native functions, so we can properly test the code
\r
280 if (!defined('ADODB_TEST_DATES')) define('ADODB_TEST_DATES',1);
\r
282 $t = adodb_mktime(0,0,0,6,1,2102);
\r
283 if (!(adodb_date('Y-m-d',$t) == '2102-06-01')) print 'Error in '.adodb_date('Y-m-d',$t).'<br>';
\r
285 $t = adodb_mktime(0,0,0,2,1,2102);
\r
286 if (!(adodb_date('Y-m-d',$t) == '2102-02-01')) print 'Error in '.adodb_date('Y-m-d',$t).'<br>';
\r
289 print "<p>Testing gregorian <=> julian conversion<p>";
\r
290 $t = adodb_mktime(0,0,0,10,11,1492);
\r
291 //http://www.holidayorigins.com/html/columbus_day.html - Friday check
\r
292 if (!(adodb_date('D Y-m-d',$t) == 'Fri 1492-10-11')) print 'Error in Columbus landing<br>';
\r
294 $t = adodb_mktime(0,0,0,2,29,1500);
\r
295 if (!(adodb_date('Y-m-d',$t) == '1500-02-29')) print 'Error in julian leap years<br>';
\r
297 $t = adodb_mktime(0,0,0,2,29,1700);
\r
298 if (!(adodb_date('Y-m-d',$t) == '1700-03-01')) print 'Error in gregorian leap years<br>';
\r
300 print adodb_mktime(0,0,0,10,4,1582).' ';
\r
301 print adodb_mktime(0,0,0,10,15,1582);
\r
302 $diff = (adodb_mktime(0,0,0,10,15,1582) - adodb_mktime(0,0,0,10,4,1582));
\r
303 if ($diff != 3600*24) print " <b>Error in gregorian correction = ".($diff/3600/24)." days </b><br>";
\r
305 print " 15 Oct 1582, Fri=".(adodb_dow(1582,10,15) == 5 ? 'Fri' : '<b>Error</b>')."<br>";
\r
306 print " 4 Oct 1582, Thu=".(adodb_dow(1582,10,4) == 4 ? 'Thu' : '<b>Error</b>')."<br>";
\r
308 print "<p>Testing overflow<p>";
\r
310 $t = adodb_mktime(0,0,0,3,33,1965);
\r
311 if (!(adodb_date('Y-m-d',$t) == '1965-04-02')) print 'Error in day overflow 1 <br>';
\r
312 $t = adodb_mktime(0,0,0,4,33,1971);
\r
313 if (!(adodb_date('Y-m-d',$t) == '1971-05-03')) print 'Error in day overflow 2 <br>';
\r
314 $t = adodb_mktime(0,0,0,1,60,1965);
\r
315 if (!(adodb_date('Y-m-d',$t) == '1965-03-01')) print 'Error in day overflow 3 '.adodb_date('Y-m-d',$t).' <br>';
\r
316 $t = adodb_mktime(0,0,0,12,32,1965);
\r
317 if (!(adodb_date('Y-m-d',$t) == '1966-01-01')) print 'Error in day overflow 4 '.adodb_date('Y-m-d',$t).' <br>';
\r
318 $t = adodb_mktime(0,0,0,12,63,1965);
\r
319 if (!(adodb_date('Y-m-d',$t) == '1966-02-01')) print 'Error in day overflow 5 '.adodb_date('Y-m-d',$t).' <br>';
\r
320 $t = adodb_mktime(0,0,0,13,3,1965);
\r
321 if (!(adodb_date('Y-m-d',$t) == '1966-01-03')) print 'Error in mth overflow 1 <br>';
\r
323 print "Testing 2-digit => 4-digit year conversion<p>";
\r
324 if (adodb_year_digit_check(00) != 2000) print "Err 2-digit 2000<br>";
\r
325 if (adodb_year_digit_check(10) != 2010) print "Err 2-digit 2010<br>";
\r
326 if (adodb_year_digit_check(20) != 2020) print "Err 2-digit 2020<br>";
\r
327 if (adodb_year_digit_check(30) != 2030) print "Err 2-digit 2030<br>";
\r
328 if (adodb_year_digit_check(40) != 1940) print "Err 2-digit 1940<br>";
\r
329 if (adodb_year_digit_check(50) != 1950) print "Err 2-digit 1950<br>";
\r
330 if (adodb_year_digit_check(90) != 1990) print "Err 2-digit 1990<br>";
\r
332 // Test string formating
\r
333 print "<p>Testing date formating</p>";
\r
334 $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\C822 r s t U w y Y z Z 2003';
\r
335 $s1 = date($fmt,0);
\r
336 $s2 = adodb_date($fmt,0);
\r
338 print " date() 0 failed<br>$s1<br>$s2<br>";
\r
341 for ($i=100; --$i > 0; ) {
\r
343 $ts = 3600.0*((rand()%60000)+(rand()%60000))+(rand()%60000);
\r
344 $s1 = date($fmt,$ts);
\r
345 $s2 = adodb_date($fmt,$ts);
\r
346 //print "$s1 <br>$s2 <p>";
\r
347 $pos = strcmp($s1,$s2);
\r
349 if (($s1) != ($s2)) {
\r
350 for ($j=0,$k=strlen($s1); $j < $k; $j++) {
\r
351 if ($s1[$j] != $s2[$j]) {
\r
352 print substr($s1,$j).' ';
\r
356 print "<b>Error date(): $ts<br><pre>
\r
357 \"$s1\" (date len=".strlen($s1).")
\r
358 \"$s2\" (adodb_date len=".strlen($s2).")</b></pre><br>";
\r
362 $a1 = getdate($ts);
\r
363 $a2 = adodb_getdate($ts);
\r
364 $rez = array_diff($a1,$a2);
\r
365 if (sizeof($rez)>0) {
\r
366 print "<b>Error getdate() $ts</b><br>";
\r
375 // Test generation of dates outside 1901-2038
\r
376 print "<p>Testing random dates between 100 and 4000</p>";
\r
377 adodb_date_test_date(100,1);
\r
378 for ($i=100; --$i >= 0;) {
\r
379 $y1 = 100+rand(0,1970-100);
\r
381 adodb_date_test_date($y1,$m);
\r
383 $y1 = 3000-rand(0,3000-1970);
\r
384 adodb_date_test_date($y1,$m);
\r
387 $start = 1960+rand(0,10);
\r
389 $i = 365.25*86400*($start-1970);
\r
390 $offset = 36000+rand(10000,60000);
\r
391 $max = 365*$yrs*86400;
\r
394 // we generate a timestamp, convert it to a date, and convert it back to a timestamp
\r
395 // and check if the roundtrip broke the original timestamp value.
\r
396 print "Testing $start to ".($start+$yrs).", or $max seconds, offset=$offset: ";
\r
398 for ($max += $i; $i < $max; $i += $offset) {
\r
399 $ret = adodb_date('m,d,Y,H,i,s',$i);
\r
400 $arr = explode(',',$ret);
\r
401 if ($lastyear != $arr[2]) {
\r
402 $lastyear = $arr[2];
\r
403 print " $lastyear ";
\r
406 $newi = adodb_mktime($arr[3],$arr[4],$arr[5],$arr[0],$arr[1],$arr[2]);
\r
408 print "Error at $i, adodb_mktime returned $newi ($ret)";
\r
414 if (!$fail) print "<p>Passed !</p>";
\r
415 else print "<p><b>Failed</b> :-(</p>";
\r
419 Returns day of week, 0 = Sunday,... 6=Saturday.
\r
420 Algorithm from PEAR::Date_Calc
\r
422 function adodb_dow($year, $month, $day)
\r
425 Pope Gregory removed 10 days - October 5 to October 14 - from the year 1582 and
\r
426 proclaimed that from that time onwards 3 days would be dropped from the calendar
\r
429 Thursday, October 4, 1582 (Julian) was followed immediately by Friday, October 15, 1582 (Gregorian).
\r
431 if ($year <= 1582) {
\r
432 if ($year < 1582 ||
\r
433 ($year == 1582 && ($month < 10 || ($month == 10 && $day < 15)))) $greg_correction = 3;
\r
435 $greg_correction = 0;
\r
437 $greg_correction = 0;
\r
446 $day = ( floor((13 * $month - 1) / 5) +
\r
447 $day + ($year % 100) +
\r
448 floor(($year % 100) / 4) +
\r
449 floor(($year / 100) / 4) - 2 *
\r
450 floor($year / 100) + 77);
\r
452 return (($day - 7 * floor($day / 7))) + $greg_correction;
\r
457 Checks for leap year, returns true if it is. No 2-digit year check. Also
\r
458 handles julian calendar correctly.
\r
460 function _adodb_is_leap_year($year)
\r
462 if ($year % 4 != 0) return false;
\r
464 if ($year % 400 == 0) {
\r
466 // if gregorian calendar (>1582), century not-divisible by 400 is not leap
\r
467 } else if ($year > 1582 && $year % 100 == 0 ) {
\r
475 checks for leap year, returns true if it is. Has 2-digit year check
\r
477 function adodb_is_leap_year($year)
\r
479 return _adodb_is_leap_year(adodb_year_digit_check($year));
\r
483 Fix 2-digit years. Works for any century.
\r
484 Assumes that if 2-digit is more than 30 years in future, then previous century.
\r
486 function adodb_year_digit_check($y)
\r
490 $yr = (integer) date("Y");
\r
491 $century = (integer) ($yr /100);
\r
493 if ($yr%100 > 50) {
\r
494 $c1 = $century + 1;
\r
498 $c0 = $century - 1;
\r
501 // if 2-digit year is less than 30 years in future, set it to this century
\r
502 // otherwise if more than 30 years in future, then we set 2-digit year to the prev century.
\r
503 if (($y + $c1) < $yr+30) $y = $y + $c1;
\r
504 else $y = $y + $c0*100;
\r
510 get local time zone offset from GMT
\r
512 function adodb_get_gmt_diff()
\r
515 if (isset($TZ)) return $TZ;
\r
517 $TZ = mktime(0,0,0,1,2,1970,0) - gmmktime(0,0,0,1,2,1970,0);
\r
522 Returns an array with date info.
\r
524 function adodb_getdate($d=false,$fast=false)
\r
526 if ($d === false) return getdate();
\r
527 if (!defined('ADODB_TEST_DATES')) {
\r
528 if ((abs($d) <= 0x7FFFFFFF)) { // check if number in 32-bit signed range
\r
529 if (!defined('ADODB_NO_NEGATIVE_TS') || $d >= 0) // if windows, must be +ve integer
\r
530 return @getdate($d);
\r
533 return _adodb_getdate($d);
\r
537 Low-level function that returns the getdate() array. We have a special
\r
538 $fast flag, which if set to true, will return fewer array values,
\r
539 and is much faster as it does not calculate dow, etc.
\r
541 function _adodb_getdate($origd=false,$fast=false,$is_gmt=false)
\r
543 $d = $origd - ($is_gmt ? 0 : adodb_get_gmt_diff());
\r
545 $_day_power = 86400;
\r
546 $_hour_power = 3600;
\r
549 if ($d < -12219321600) $d -= 86400*10; // if 15 Oct 1582 or earlier, gregorian correction
\r
551 $_month_table_normal = array("",31,28,31,30,31,30,31,31,30,31,30,31);
\r
552 $_month_table_leaf = array("",31,29,31,30,31,30,31,31,30,31,30,31);
\r
556 // The valid range of a 32bit signed timestamp is typically from
\r
557 // Fri, 13 Dec 1901 20:45:54 GMT to Tue, 19 Jan 2038 03:14:07 GMT
\r
558 for ($a = 1970 ; --$a >= 0;) {
\r
561 if ($leaf = _adodb_is_leap_year($a)) {
\r
562 $d += $_day_power * 366;
\r
564 $d += $_day_power * 365;
\r
571 $secsInYear = 86400 * ($leaf ? 366 : 365) + $lastd;
\r
574 $mtab = ($leaf) ? $_month_table_leaf : $_month_table_normal;
\r
575 for ($a = 13 ; --$a > 0;) {
\r
577 $d += $mtab[$a] * $_day_power;
\r
580 $ndays = $mtab[$a];
\r
586 $day = $ndays + ceil(($d+1) / ($_day_power));
\r
588 $d += ($ndays - $day+1)* $_day_power;
\r
589 $hour = floor($d/$_hour_power);
\r
593 for ($a = 1970 ;; $a++) {
\r
596 if ($leaf = _adodb_is_leap_year($a)) {
\r
597 $d -= $_day_power * 366;
\r
599 $d -= $_day_power * 365;
\r
605 $secsInYear = $lastd;
\r
607 $mtab = ($leaf) ? $_month_table_leaf : $_month_table_normal;
\r
608 for ($a = 1 ; $a <= 12; $a++) {
\r
610 $d -= $mtab[$a] * $_day_power;
\r
613 $ndays = $mtab[$a];
\r
618 $day = ceil(($d+1) / $_day_power);
\r
619 $d = $d - ($day-1) * $_day_power;
\r
620 $hour = floor($d /$_hour_power);
\r
623 $d -= $hour * $_hour_power;
\r
624 $min = floor($d/$_min_power);
\r
625 $secs = $d - $min * $_min_power;
\r
628 'seconds' => $secs,
\r
634 'yday' => floor($secsInYear/$_day_power),
\r
641 $dow = adodb_dow($year,$month,$day);
\r
644 'seconds' => $secs,
\r
651 'yday' => floor($secsInYear/$_day_power),
\r
652 'weekday' => gmdate('l',$_day_power*(3+$dow)),
\r
653 'month' => gmdate('F',mktime(0,0,0,$month,2,1971)),
\r
658 function adodb_gmdate($fmt,$d=false)
\r
660 return adodb_date($fmt,$d,true);
\r
663 function adodb_date2($fmt, $d=false, $is_gmt=false)
\r
665 if ($d !== false) {
\r
667 "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})[ -]?(([0-9]{1,2}):?([0-9]{1,2}):?([0-9\.]{1,4}))?|",
\r
668 ($d), $rr)) return adodb_date($fmt,false,$is_gmt);
\r
670 if ($rr[1] <= 100 && $rr[2]<= 1) return adodb_date($fmt,false,$is_gmt);
\r
673 if (!isset($rr[5])) $d = adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1]);
\r
674 else $d = @adodb_mktime($rr[5],$rr[6],$rr[7],$rr[2],$rr[3],$rr[1]);
\r
677 return adodb_date($fmt,$d,$is_gmt);
\r
681 Return formatted date based on timestamp $d
\r
683 function adodb_date($fmt,$d=false,$is_gmt=false)
\r
685 if ($d === false) return date($fmt);
\r
686 if (!defined('ADODB_TEST_DATES')) {
\r
687 if ((abs($d) <= 0x7FFFFFFF)) { // check if number in 32-bit signed range
\r
688 if (!defined('ADODB_NO_NEGATIVE_TS') || $d >= 0) // if windows, must be +ve integer
\r
689 return @date($fmt,$d);
\r
692 $_day_power = 86400;
\r
694 $arr = _adodb_getdate($d,true,$is_gmt);
\r
695 $year = $arr['year'];
\r
696 $month = $arr['mon'];
\r
697 $day = $arr['mday'];
\r
698 $hour = $arr['hours'];
\r
699 $min = $arr['minutes'];
\r
700 $secs = $arr['seconds'];
\r
702 $max = strlen($fmt);
\r
706 at this point, we have the following integer vars to manipulate:
\r
707 $year, $month, $day, $hour, $min, $secs
\r
709 for ($i=0; $i < $max; $i++) {
\r
711 case 'T': $dates .= date('T');break;
\r
713 case 'L': $dates .= $arr['leap'] ? '1' : '0'; break;
\r
714 case 'r': // Thu, 21 Dec 2000 16:01:07 +0200
\r
716 $dates .= gmdate('D',$_day_power*(3+adodb_dow($year,$month,$day))).', '
\r
717 . ($day<10?' '.$day:$day) . ' '.date('M',mktime(0,0,0,$month,2,1971)).' '.$year.' ';
\r
719 if ($hour < 10) $dates .= '0'.$hour; else $dates .= $hour;
\r
721 if ($min < 10) $dates .= ':0'.$min; else $dates .= ':'.$min;
\r
723 if ($secs < 10) $dates .= ':0'.$secs; else $dates .= ':'.$secs;
\r
725 $gmt = adodb_get_gmt_diff();
\r
726 $dates .= sprintf(' %s%04d',($gmt<0)?'+':'-',abs($gmt)/36); break;
\r
728 case 'Y': $dates .= $year; break;
\r
729 case 'y': $dates .= substr($year,strlen($year)-2,2); break;
\r
731 case 'm': if ($month<10) $dates .= '0'.$month; else $dates .= $month; break;
\r
732 case 'Q': $dates .= ($month+3)>>2; break;
\r
733 case 'n': $dates .= $month; break;
\r
734 case 'M': $dates .= date('M',mktime(0,0,0,$month,2,1971)); break;
\r
735 case 'F': $dates .= date('F',mktime(0,0,0,$month,2,1971)); break;
\r
737 case 't': $dates .= $arr['ndays']; break;
\r
738 case 'z': $dates .= $arr['yday']; break;
\r
739 case 'w': $dates .= adodb_dow($year,$month,$day); break;
\r
740 case 'l': $dates .= gmdate('l',$_day_power*(3+adodb_dow($year,$month,$day))); break;
\r
741 case 'D': $dates .= gmdate('D',$_day_power*(3+adodb_dow($year,$month,$day))); break;
\r
742 case 'j': $dates .= $day; break;
\r
743 case 'd': if ($day<10) $dates .= '0'.$day; else $dates .= $day; break;
\r
746 if ($d10 == 1) $dates .= 'st';
\r
747 else if ($d10 == 2) $dates .= 'nd';
\r
748 else if ($d10 == 3) $dates .= 'rd';
\r
749 else $dates .= 'th';
\r
754 $dates .= ($is_gmt) ? 0 : -adodb_get_gmt_diff(); break;
\r
756 $gmt = ($is_gmt) ? 0 : adodb_get_gmt_diff();
\r
757 $dates .= sprintf('%s%04d',($gmt<0)?'+':'-',abs($gmt)/36); break;
\r
760 if ($hour < 10) $dates .= '0'.$hour;
\r
761 else $dates .= $hour;
\r
764 if ($hour > 12) $hh = $hour - 12;
\r
766 if ($hour == 0) $hh = '12';
\r
770 if ($hh < 10) $dates .= '0'.$hh;
\r
771 else $dates .= $hh;
\r
779 if ($hour > 12) $hh = $hour - 12;
\r
781 if ($hour == 0) $hh = '12';
\r
787 case 'i': if ($min < 10) $dates .= '0'.$min; else $dates .= $min; break;
\r
789 case 'U': $dates .= $d; break;
\r
790 case 's': if ($secs < 10) $dates .= '0'.$secs; else $dates .= $secs; break;
\r
792 // Note 00:00 to 11:59 is AM, while 12:00 to 23:59 is PM
\r
794 if ($hour>=12) $dates .= 'pm';
\r
795 else $dates .= 'am';
\r
798 if ($hour>=12) $dates .= 'PM';
\r
799 else $dates .= 'AM';
\r
802 $dates .= $fmt[$i]; break;
\r
806 if ($i < $max) $dates .= $fmt[$i];
\r
814 Returns a timestamp given a GMT/UTC time.
\r
815 Note that $is_dst is not implemented and is ignored.
\r
817 function adodb_gmmktime($hr,$min,$sec,$mon,$day,$year,$is_dst=false)
\r
819 return adodb_mktime($hr,$min,$sec,$mon,$day,$year,$is_dst,true);
\r
823 Return a timestamp given a local time. Originally by jackbbs.
\r
824 Note that $is_dst is not implemented and is ignored.
\r
826 function adodb_mktime($hr,$min,$sec,$mon,$day,$year,$is_dst=false,$is_gmt=false)
\r
828 if (!defined('ADODB_TEST_DATES')) {
\r
829 // for windows, we don't check 1970 because with timezone differences,
\r
830 // 1 Jan 1970 could generate negative timestamp, which is illegal
\r
831 if (!defined('ADODB_NO_NEGATIVE_TS') || ($year >= 1971))
\r
832 if (1901 < $year && $year < 2038)
\r
833 return @mktime($hr,$min,$sec,$mon,$day,$year);
\r
836 $gmt_different = ($is_gmt) ? 0 : adodb_get_gmt_diff();
\r
839 $min = intval($min);
\r
840 $sec = intval($sec);
\r
841 $mon = intval($mon);
\r
842 $day = intval($day);
\r
843 $year = intval($year);
\r
846 $year = adodb_year_digit_check($year);
\r
849 $y = floor($mon / 12);
\r
854 $_day_power = 86400;
\r
855 $_hour_power = 3600;
\r
858 $_month_table_normal = array("",31,28,31,30,31,30,31,31,30,31,30,31);
\r
859 $_month_table_leaf = array("",31,29,31,30,31,30,31,31,30,31,30,31);
\r
862 if ($year >= 1970) {
\r
863 for ($a = 1970 ; $a <= $year; $a++) {
\r
864 $leaf = _adodb_is_leap_year($a);
\r
865 if ($leaf == true) {
\r
866 $loop_table = $_month_table_leaf;
\r
869 $loop_table = $_month_table_normal;
\r
873 $_total_date += $_add_date;
\r
875 for($b=1;$b<$mon;$b++) {
\r
876 $_total_date += $loop_table[$b];
\r
880 $_total_date +=$day-1;
\r
881 $ret = $_total_date * $_day_power + $hr * $_hour_power + $min * $_min_power + $sec + $gmt_different;
\r
884 for ($a = 1969 ; $a >= $year; $a--) {
\r
885 $leaf = _adodb_is_leap_year($a);
\r
886 if ($leaf == true) {
\r
887 $loop_table = $_month_table_leaf;
\r
890 $loop_table = $_month_table_normal;
\r
893 if ($a > $year) { $_total_date += $_add_date;
\r
895 for($b=12;$b>$mon;$b--) {
\r
896 $_total_date += $loop_table[$b];
\r
900 $_total_date += $loop_table[$mon] - $day;
\r
902 $_day_time = $hr * $_hour_power + $min * $_min_power + $sec;
\r
903 $_day_time = $_day_power - $_day_time;
\r
904 $ret = -( $_total_date * $_day_power + $_day_time - $gmt_different);
\r
905 if ($ret < -12220185600) $ret += 10*86400; // if earlier than 5 Oct 1582 - gregorian correction
\r
906 else if ($ret < -12219321600) $ret = -12219321600; // if in limbo, reset to 15 Oct 1582.
\r
908 //print " dmy=$day/$mon/$year $hr:$min:$sec => " .$ret;
\r