[ PHPXref.com ] [ Generated: Sun Jul 20 20:47:44 2008 ] [ TUTOS 1.2 ]
[ Index ]     [ Variables ]     [ Functions ]     [ Classes ]     [ Constants ]     [ Statistics ]

title

Body

[close]

/php/ -> adodb-time.inc.php (source)

   1  <?php
   2  /**

   3  ADOdb Date Library, part of the ADOdb abstraction library

   4  Download: http://php.weblogs.com/adodb_date_time_library

   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 822 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  

 245  - 18 July  2005  0.21

 246  - In PHP 4.3.11, the 'r' format has changed. Leading 0 in day is added. Changed for compat.

 247  - Added support for negative months in adodb_mktime().

 248  

 249  - 24 Feb 2005 0.20

 250  Added limited strftime/gmstrftime support. x10 improvement in performance of adodb_date().

 251  

 252  - 21 Dec 2004 0.17

 253  In adodb_getdate(), the timestamp was accidentally converted to gmt when $is_gmt is false. 

 254  Also adodb_mktime(0,0,0) did not work properly. Both fixed thx Mauro.

 255  

 256  - 17 Nov 2004 0.16

 257  Removed intval typecast in adodb_mktime() for secs, allowing:

 258       adodb_mktime(0,0,0 + 2236672153,1,1,1934);

 259  Suggested by Ryan.

 260  

 261  - 18 July 2004 0.15

 262  All params in adodb_mktime were formerly compulsory. Now only the hour, min, secs is compulsory. 

 263  This brings it more in line with mktime (still not identical).

 264  

 265  - 23 June 2004 0.14

 266  

 267  Allow you to define your own daylights savings function, adodb_daylight_sv.

 268  If the function is defined (somewhere in an include), then you can correct for daylights savings.

 269  

 270  In this example, we apply daylights savings in June or July, adding one hour. This is extremely

 271  unrealistic as it does not take into account time-zone, geographic location, current year.

 272  

 273  function adodb_daylight_sv(&$arr, $is_gmt)

 274  {

 275      if ($is_gmt) return;

 276      $m = $arr['mon'];

 277      if ($m == 6 || $m == 7) $arr['hours'] += 1;

 278  }

 279  

 280  This is only called by adodb_date() and not by adodb_mktime(). 

 281  

 282  The format of $arr is

 283  Array ( 

 284     [seconds] => 0 

 285     [minutes] => 0 

 286     [hours] => 0 

 287     [mday] => 1      # day of month, eg 1st day of the month

 288     [mon] => 2       # month (eg. Feb)

 289     [year] => 2102 

 290     [yday] => 31     # days in current year

 291     [leap] =>        # true if leap year

 292     [ndays] => 28    # no of days in current month

 293     ) 

 294     

 295  

 296  - 28 Apr 2004 0.13

 297  Fixed adodb_date to properly support $is_gmt. Thx to Dimitar Angelov.

 298  

 299  - 20 Mar 2004 0.12

 300  Fixed month calculation error in adodb_date. 2102-June-01 appeared as 2102-May-32.

 301  

 302  - 26 Oct 2003 0.11

 303  Because of daylight savings problems (some systems apply daylight savings to 

 304  January!!!), changed adodb_get_gmt_diff() to ignore daylight savings.

 305  

 306  - 9 Aug 2003 0.10

 307  Fixed bug with dates after 2038. 

 308  See http://phplens.com/lens/lensforum/msgs.php?id=6980

 309  

 310  - 1 July 2003 0.09

 311  Added support for Q (Quarter).

 312  Added adodb_date2(), which accepts ISO date in 2nd param

 313  

 314  - 3 March 2003 0.08

 315  Added support for 'S' adodb_date() format char. Added constant ADODB_ALLOW_NEGATIVE_TS

 316  if you want PHP to handle negative timestamps between 1901 to 1969.

 317  

 318  - 27 Feb 2003 0.07

 319  All negative numbers handled by adodb now because of RH 7.3+ problems.

 320  See http://bugs.php.net/bug.php?id=20048&edit=2

 321  

 322  - 4 Feb 2003 0.06

 323  Fixed a typo, 1852 changed to 1582! This means that pre-1852 dates

 324  are now correctly handled.

 325  

 326  - 29 Jan 2003 0.05

 327  

 328  Leap year checking differs under Julian calendar (pre 1582). Also

 329  leap year code optimized by checking for most common case first.

 330  

 331  We also handle month overflow correctly in mktime (eg month set to 13).

 332  

 333  Day overflow for less than one month's days is supported.

 334  

 335  - 28 Jan 2003 0.04

 336  

 337  Gregorian correction handled. In PHP5, we might throw an error if 

 338  mktime uses invalid dates around 5-14 Oct 1582. Released with ADOdb 3.10.

 339  Added limbo 5-14 Oct 1582 check, when we set to 15 Oct 1582.

 340  

 341  - 27 Jan 2003 0.03

 342  

 343  Fixed some more month problems due to gmt issues. Added constant ADODB_DATE_VERSION.

 344  Fixed calculation of days since start of year for <1970. 

 345  

 346  - 27 Jan 2003 0.02

 347  

 348  Changed _adodb_getdate() to inline leap year checking for better performance.

 349  Fixed problem with time-zones west of GMT +0000.

 350  

 351  - 24 Jan 2003 0.01

 352  

 353  First implementation.

 354  */
 355  
 356  
 357  /* Initialization */

 358  
 359  /*

 360      Version Number

 361  */
 362  define('ADODB_DATE_VERSION',0.21);
 363  
 364  /*

 365      This code was originally for windows. But apparently this problem happens 

 366      also with Linux, RH 7.3 and later!

 367      

 368      glibc-2.2.5-34 and greater has been changed to return -1 for dates <

 369      1970.  This used to work.  The problem exists with RedHat 7.3 and 8.0

 370      echo (mktime(0, 0, 0, 1, 1, 1960));  // prints -1

 371      

 372      References:

 373       http://bugs.php.net/bug.php?id=20048&edit=2

 374       http://lists.debian.org/debian-glibc/2002/debian-glibc-200205/msg00010.html

 375  */
 376  
 377  if (!defined('ADODB_ALLOW_NEGATIVE_TS')) define('ADODB_NO_NEGATIVE_TS',1);
 378  
 379  function adodb_date_test_date($y1,$m,$d=13)
 380  {
 381      $t = adodb_mktime(0,0,0,$m,$d,$y1);
 382      $rez = adodb_date('Y-n-j H:i:s',$t);
 383      if ("$y1-$m-$d 00:00:00" != $rez) {
 384          print "<b>$y1 error, expected=$y1-$m-$d 00:00:00, adodb=$rez</b><br>";
 385          return false;
 386      }
 387      return true;
 388  }
 389  
 390  function adodb_date_test_strftime($fmt)
 391  {
 392      $s1 = strftime($fmt);
 393      $s2 = adodb_strftime($fmt);
 394      
 395      if ($s1 == $s2) return true;
 396      
 397      echo "error for $fmt,  strftime=$s1, $adodb=$s2<br>";
 398      return false;
 399  }
 400  
 401  /**

 402       Test Suite

 403  */
 404  function adodb_date_test()
 405  {
 406      
 407      error_reporting(E_ALL);
 408      print "<h4>Testing adodb_date and adodb_mktime. version=".ADODB_DATE_VERSION.' PHP='.PHP_VERSION."</h4>";
 409      @set_time_limit(0);
 410      $fail = false;
 411      
 412      // This flag disables calling of PHP native functions, so we can properly test the code

 413      if (!defined('ADODB_TEST_DATES')) define('ADODB_TEST_DATES',1);
 414      
 415      adodb_date_test_strftime('%Y %m %x %X');
 416      adodb_date_test_strftime("%A %d %B %Y");
 417      adodb_date_test_strftime("%H %M S");
 418      
 419      $t = adodb_mktime(0,0,0);
 420      if (!(adodb_date('Y-m-d') == date('Y-m-d'))) print 'Error in '.adodb_mktime(0,0,0).'<br>';
 421      
 422      $t = adodb_mktime(0,0,0,6,1,2102);
 423      if (!(adodb_date('Y-m-d',$t) == '2102-06-01')) print 'Error in '.adodb_date('Y-m-d',$t).'<br>';
 424      
 425      $t = adodb_mktime(0,0,0,2,1,2102);
 426      if (!(adodb_date('Y-m-d',$t) == '2102-02-01')) print 'Error in '.adodb_date('Y-m-d',$t).'<br>';
 427      
 428      
 429      print "<p>Testing gregorian <=> julian conversion<p>";
 430      $t = adodb_mktime(0,0,0,10,11,1492);
 431      //http://www.holidayorigins.com/html/columbus_day.html - Friday check

 432      if (!(adodb_date('D Y-m-d',$t) == 'Fri 1492-10-11')) print 'Error in Columbus landing<br>';
 433      
 434      $t = adodb_mktime(0,0,0,2,29,1500);
 435      if (!(adodb_date('Y-m-d',$t) == '1500-02-29')) print 'Error in julian leap years<br>';
 436      
 437      $t = adodb_mktime(0,0,0,2,29,1700);
 438      if (!(adodb_date('Y-m-d',$t) == '1700-03-01')) print 'Error in gregorian leap years<br>';
 439      
 440      print  adodb_mktime(0,0,0,10,4,1582).' ';
 441      print adodb_mktime(0,0,0,10,15,1582);
 442      $diff = (adodb_mktime(0,0,0,10,15,1582) - adodb_mktime(0,0,0,10,4,1582));
 443      if ($diff != 3600*24) print " <b>Error in gregorian correction = ".($diff/3600/24)." days </b><br>";
 444          
 445      print " 15 Oct 1582, Fri=".(adodb_dow(1582,10,15) == 5 ? 'Fri' : '<b>Error</b>')."<br>";
 446      print " 4 Oct 1582, Thu=".(adodb_dow(1582,10,4) == 4 ? 'Thu' : '<b>Error</b>')."<br>";
 447      
 448      print "<p>Testing overflow<p>";
 449      
 450      $t = adodb_mktime(0,0,0,3,33,1965);
 451      if (!(adodb_date('Y-m-d',$t) == '1965-04-02')) print 'Error in day overflow 1 <br>';
 452      $t = adodb_mktime(0,0,0,4,33,1971);
 453      if (!(adodb_date('Y-m-d',$t) == '1971-05-03')) print 'Error in day overflow 2 <br>';
 454      $t = adodb_mktime(0,0,0,1,60,1965);
 455      if (!(adodb_date('Y-m-d',$t) == '1965-03-01')) print 'Error in day overflow 3 '.adodb_date('Y-m-d',$t).' <br>';
 456      $t = adodb_mktime(0,0,0,12,32,1965);
 457      if (!(adodb_date('Y-m-d',$t) == '1966-01-01')) print 'Error in day overflow 4 '.adodb_date('Y-m-d',$t).' <br>';
 458      $t = adodb_mktime(0,0,0,12,63,1965);
 459      if (!(adodb_date('Y-m-d',$t) == '1966-02-01')) print 'Error in day overflow 5 '.adodb_date('Y-m-d',$t).' <br>';
 460      $t = adodb_mktime(0,0,0,13,3,1965);
 461      if (!(adodb_date('Y-m-d',$t) == '1966-01-03')) print 'Error in mth overflow 1 <br>';
 462      
 463      print "Testing 2-digit => 4-digit year conversion<p>";
 464      if (adodb_year_digit_check(00) != 2000) print "Err 2-digit 2000<br>";
 465      if (adodb_year_digit_check(10) != 2010) print "Err 2-digit 2010<br>";
 466      if (adodb_year_digit_check(20) != 2020) print "Err 2-digit 2020<br>";
 467      if (adodb_year_digit_check(30) != 2030) print "Err 2-digit 2030<br>";
 468      if (adodb_year_digit_check(40) != 1940) print "Err 2-digit 1940<br>";
 469      if (adodb_year_digit_check(50) != 1950) print "Err 2-digit 1950<br>";
 470      if (adodb_year_digit_check(90) != 1990) print "Err 2-digit 1990<br>";
 471      
 472      // Test string formating

 473      print "<p>Testing date formating</p>";
 474      $fmt = '\d\a\t\e T Y-m-d H:i:s a A d D F g G h H i j l L m M n O \R\F\C822 r s t U w y Y z Z 2003';
 475      $s1 = date($fmt,0);
 476      $s2 = adodb_date($fmt,0);
 477      if ($s1 != $s2) {
 478          print " date() 0 failed<br>$s1<br>$s2<br>";
 479      }
 480      flush();
 481      for ($i=100; --$i > 0; ) {
 482  
 483          $ts = 3600.0*((rand()%60000)+(rand()%60000))+(rand()%60000);
 484          $s1 = date($fmt,$ts);
 485          $s2 = adodb_date($fmt,$ts);
 486          //print "$s1 <br>$s2 <p>";

 487          $pos = strcmp($s1,$s2);
 488  
 489          if (($s1) != ($s2)) {
 490              for ($j=0,$k=strlen($s1); $j < $k; $j++) {
 491                  if ($s1[$j] != $s2[$j]) {
 492                      print substr($s1,$j).' ';
 493                      break;
 494                  }
 495              }
 496              print "<b>Error date(): $ts<br><pre> 
 497  &nbsp; \"$s1\" (date len=".strlen($s1).")
 498  &nbsp; \"$s2\" (adodb_date len=".strlen($s2).")</b></pre><br>";
 499              $fail = true;
 500          }
 501          
 502          $a1 = getdate($ts);
 503          $a2 = adodb_getdate($ts);
 504          $rez = array_diff($a1,$a2);
 505          if (sizeof($rez)>0) {
 506              print "<b>Error getdate() $ts</b><br>";
 507                  print_r($a1);
 508              print "<br>";
 509                  print_r($a2);
 510              print "<p>";
 511              $fail = true;
 512          }
 513      }
 514      
 515      // Test generation of dates outside 1901-2038

 516      print "<p>Testing random dates between 100 and 4000</p>";
 517      adodb_date_test_date(100,1);
 518      for ($i=100; --$i >= 0;) {
 519          $y1 = 100+rand(0,1970-100);
 520          $m = rand(1,12);
 521          adodb_date_test_date($y1,$m);
 522          
 523          $y1 = 3000-rand(0,3000-1970);
 524          adodb_date_test_date($y1,$m);
 525      }
 526      print '<p>';
 527      $start = 1960+rand(0,10);
 528      $yrs = 12;
 529      $i = 365.25*86400*($start-1970);
 530      $offset = 36000+rand(10000,60000);
 531      $max = 365*$yrs*86400;
 532      $lastyear = 0;
 533      
 534      // we generate a timestamp, convert it to a date, and convert it back to a timestamp

 535      // and check if the roundtrip broke the original timestamp value.

 536      print "Testing $start to ".($start+$yrs).", or $max seconds, offset=$offset: ";
 537      $cnt = 0;
 538      for ($max += $i; $i < $max; $i += $offset) {
 539          $ret = adodb_date('m,d,Y,H,i,s',$i);
 540          $arr = explode(',',$ret);
 541          if ($lastyear != $arr[2]) {
 542              $lastyear = $arr[2];
 543              print " $lastyear ";
 544              flush();
 545          }
 546          $newi = adodb_mktime($arr[3],$arr[4],$arr[5],$arr[0],$arr[1],$arr[2]);
 547          if ($i != $newi) {
 548              print "Error at $i, adodb_mktime returned $newi ($ret)";
 549              $fail = true;
 550              break;
 551          }
 552          $cnt += 1;
 553      }
 554      echo "Tested $cnt dates<br>";
 555      if (!$fail) print "<p>Passed !</p>";
 556      else print "<p><b>Failed</b> :-(</p>";
 557  }
 558  
 559  /**

 560      Returns day of week, 0 = Sunday,... 6=Saturday. 

 561      Algorithm from PEAR::Date_Calc

 562  */
 563  function adodb_dow($year, $month, $day)
 564  {
 565  /*

 566  Pope Gregory removed 10 days - October 5 to October 14 - from the year 1582 and 

 567  proclaimed that from that time onwards 3 days would be dropped from the calendar 

 568  every 400 years.

 569  

 570  Thursday, October 4, 1582 (Julian) was followed immediately by Friday, October 15, 1582 (Gregorian). 

 571  */
 572      if ($year <= 1582) {
 573          if ($year < 1582 || 
 574              ($year == 1582 && ($month < 10 || ($month == 10 && $day < 15)))) $greg_correction = 3;
 575           else
 576              $greg_correction = 0;
 577      } else
 578          $greg_correction = 0;
 579      
 580      if($month > 2)
 581          $month -= 2;
 582      else {
 583          $month += 10;
 584          $year--;
 585      }
 586      
 587      $day =  floor((13 * $month - 1) / 5) +
 588              $day + ($year % 100) +
 589              floor(($year % 100) / 4) +
 590              floor(($year / 100) / 4) - 2 *
 591              floor($year / 100) + 77 + $greg_correction;
 592      
 593      return $day - 7 * floor($day / 7);
 594  }
 595  
 596  
 597  /**

 598   Checks for leap year, returns true if it is. No 2-digit year check. Also 

 599   handles julian calendar correctly.

 600  */
 601  function _adodb_is_leap_year($year) 
 602  {
 603      if ($year % 4 != 0) return false;
 604      
 605      if ($year % 400 == 0) {
 606          return true;
 607      // if gregorian calendar (>1582), century not-divisible by 400 is not leap

 608      } else if ($year > 1582 && $year % 100 == 0 ) {
 609          return false;
 610      } 
 611      
 612      return true;
 613  }
 614  
 615  
 616  /**

 617   checks for leap year, returns true if it is. Has 2-digit year check

 618  */
 619  function adodb_is_leap_year($year) 
 620  {
 621      return  _adodb_is_leap_year(adodb_year_digit_check($year));
 622  }
 623  
 624  /**

 625      Fix 2-digit years. Works for any century.

 626       Assumes that if 2-digit is more than 30 years in future, then previous century.

 627  */
 628  function adodb_year_digit_check($y) 
 629  {
 630      if ($y < 100) {
 631      
 632          $yr = (integer) date("Y");
 633          $century = (integer) ($yr /100);
 634          
 635          if ($yr%100 > 50) {
 636              $c1 = $century + 1;
 637              $c0 = $century;
 638          } else {
 639              $c1 = $century;
 640              $c0 = $century - 1;
 641          }
 642          $c1 *= 100;
 643          // if 2-digit year is less than 30 years in future, set it to this century

 644          // otherwise if more than 30 years in future, then we set 2-digit year to the prev century.

 645          if (($y + $c1) < $yr+30) $y = $y + $c1;
 646          else $y = $y + $c0*100;
 647      }
 648      return $y;
 649  }
 650  
 651  /**

 652   get local time zone offset from GMT

 653  */
 654  function adodb_get_gmt_diff() 
 655  {
 656  static $TZ;
 657      if (isset($TZ)) return $TZ;
 658      
 659      $TZ = mktime(0,0,0,1,2,1970,0) - gmmktime(0,0,0,1,2,1970,0);
 660      return $TZ;
 661  }
 662  
 663  /**

 664      Returns an array with date info.

 665  */
 666  function adodb_getdate($d=false,$fast=false)
 667  {
 668      if ($d === false) return getdate();
 669      if (!defined('ADODB_TEST_DATES')) {
 670          if ((abs($d) <= 0x7FFFFFFF)) { // check if number in 32-bit signed range
 671              if (!defined('ADODB_NO_NEGATIVE_TS') || $d >= 0) // if windows, must be +ve integer
 672                  return @getdate($d);
 673          }
 674      }
 675      return _adodb_getdate($d);
 676  }
 677  
 678  /*

 679  // generate $YRS table for _adodb_getdate()

 680  function adodb_date_gentable($out=true)

 681  {

 682  

 683      for ($i=1970; $i >= 1600; $i-=10) {

 684          $s = adodb_gmmktime(0,0,0,1,1,$i);

 685          echo "$i => $s,<br>";    

 686      }

 687  }

 688  adodb_date_gentable();

 689  

 690  for ($i=1970; $i > 1500; $i--) {

 691  

 692  echo "<hr>$i ";

 693      adodb_date_test_date($i,1,1);

 694  }

 695  

 696  */
 697  
 698  /**

 699      Low-level function that returns the getdate() array. We have a special

 700      $fast flag, which if set to true, will return fewer array values,

 701      and is much faster as it does not calculate dow, etc.