[ Index ]

PHP Cross Reference of moodle-2.8

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


Generated: Fri Nov 28 20:29:05 2014 Cross-referenced by PHPXref 0.7.1