Subversion Repositories svnkaklik

Rev

Details | Last modification | View Log

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