source: sandbox/2.5.1-evolucao/phpgwapi/inc/adodb/adodb-time.inc.php @ 8222

Revision 8222, 42.3 KB checked in by angelo, 11 years ago (diff)

Ticket #3491 - Compatibilizar Expresso com novas versoes do PHP

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