[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

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

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


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1