[ Index ]

PHP Cross Reference of moodle-2.8

title

Body

[close]

/lib/zend/Zend/Date/ -> DateObject.php (source)

   1  <?php
   2  /**
   3   * Zend Framework
   4   *
   5   * LICENSE
   6   *
   7   * This source file is subject to the new BSD license that is bundled
   8   * with this package in the file LICENSE.txt.
   9   * It is also available through the world-wide-web at this URL:
  10   * http://framework.zend.com/license/new-bsd
  11   * If you did not receive a copy of the license and are unable to
  12   * obtain it through the world-wide-web, please send an email
  13   * to [email protected] so we can send you a copy immediately.
  14   *
  15   * @category   Zend
  16   * @package    Zend_Date
  17   * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
  18   * @version    $Id$
  19   * @license    http://framework.zend.com/license/new-bsd     New BSD License
  20   */
  21  
  22  /**
  23   * @category   Zend
  24   * @package    Zend_Date
  25   * @subpackage Zend_Date_DateObject
  26   * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
  27   * @license    http://framework.zend.com/license/new-bsd     New BSD License
  28   */
  29  abstract class Zend_Date_DateObject {
  30  
  31      /**
  32       * UNIX Timestamp
  33       */
  34      private   $_unixTimestamp;
  35      protected static $_cache         = null;
  36      protected static $_defaultOffset = 0;
  37  
  38      /**
  39       * active timezone
  40       */
  41      private   $_timezone    = 'UTC';
  42      private   $_offset      = 0;
  43      private   $_syncronised = 0;
  44  
  45      // turn off DST correction if UTC or GMT
  46      protected $_dst         = true;
  47  
  48      /**
  49       * Table of Monthdays
  50       */
  51      private static $_monthTable = array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
  52  
  53      /**
  54       * Table of Years
  55       */
  56      private static $_yearTable = array(
  57          1970 => 0,            1960 => -315619200,   1950 => -631152000,
  58          1940 => -946771200,   1930 => -1262304000,  1920 => -1577923200,
  59          1910 => -1893456000,  1900 => -2208988800,  1890 => -2524521600,
  60          1880 => -2840140800,  1870 => -3155673600,  1860 => -3471292800,
  61          1850 => -3786825600,  1840 => -4102444800,  1830 => -4417977600,
  62          1820 => -4733596800,  1810 => -5049129600,  1800 => -5364662400,
  63          1790 => -5680195200,  1780 => -5995814400,  1770 => -6311347200,
  64          1760 => -6626966400,  1750 => -6942499200,  1740 => -7258118400,
  65          1730 => -7573651200,  1720 => -7889270400,  1710 => -8204803200,
  66          1700 => -8520336000,  1690 => -8835868800,  1680 => -9151488000,
  67          1670 => -9467020800,  1660 => -9782640000,  1650 => -10098172800,
  68          1640 => -10413792000, 1630 => -10729324800, 1620 => -11044944000,
  69          1610 => -11360476800, 1600 => -11676096000);
  70  
  71      /**
  72       * Set this object to have a new UNIX timestamp.
  73       *
  74       * @param  string|integer  $timestamp  OPTIONAL timestamp; defaults to local time using time()
  75       * @return string|integer  old timestamp
  76       * @throws Zend_Date_Exception
  77       */
  78      protected function setUnixTimestamp($timestamp = null)
  79      {
  80          $old = $this->_unixTimestamp;
  81  
  82          if (is_numeric($timestamp)) {
  83              $this->_unixTimestamp = $timestamp;
  84          } else if ($timestamp === null) {
  85              $this->_unixTimestamp = time();
  86          } else {
  87              require_once 'Zend/Date/Exception.php';
  88              throw new Zend_Date_Exception('\'' . $timestamp . '\' is not a valid UNIX timestamp', 0, null, $timestamp);
  89          }
  90  
  91          return $old;
  92      }
  93  
  94      /**
  95       * Returns this object's UNIX timestamp
  96       * A timestamp greater then the integer range will be returned as string
  97       * This function does not return the timestamp as object. Use copy() instead.
  98       *
  99       * @return  integer|string  timestamp
 100       */
 101      protected function getUnixTimestamp()
 102      {
 103          if ($this->_unixTimestamp === intval($this->_unixTimestamp)) {
 104              return (int) $this->_unixTimestamp;
 105          } else {
 106              return (string) $this->_unixTimestamp;
 107          }
 108      }
 109  
 110      /**
 111       * Internal function.
 112       * Returns time().  This method exists to allow unit tests to work-around methods that might otherwise
 113       * be hard-coded to use time().  For example, this makes it possible to test isYesterday() in Date.php.
 114       *
 115       * @param   integer  $sync      OPTIONAL time syncronisation value
 116       * @return  integer  timestamp
 117       */
 118      protected function _getTime($sync = null)
 119      {
 120          if ($sync !== null) {
 121              $this->_syncronised = round($sync);
 122          }
 123          return (time() + $this->_syncronised);
 124      }
 125  
 126      /**
 127       * Internal mktime function used by Zend_Date.
 128       * The timestamp returned by mktime() can exceed the precision of traditional UNIX timestamps,
 129       * by allowing PHP to auto-convert to using a float value.
 130       *
 131       * Returns a timestamp relative to 1970/01/01 00:00:00 GMT/UTC.
 132       * DST (Summer/Winter) is depriciated since php 5.1.0.
 133       * Year has to be 4 digits otherwise it would be recognised as
 134       * year 70 AD instead of 1970 AD as expected !!
 135       *
 136       * @param  integer  $hour
 137       * @param  integer  $minute
 138       * @param  integer  $second
 139       * @param  integer  $month
 140       * @param  integer  $day
 141       * @param  integer  $year
 142       * @param  boolean  $gmt     OPTIONAL true = other arguments are for UTC time, false = arguments are for local time/date
 143       * @return  integer|float  timestamp (number of seconds elapsed relative to 1970/01/01 00:00:00 GMT/UTC)
 144       */
 145      protected function mktime($hour, $minute, $second, $month, $day, $year, $gmt = false)
 146      {
 147          // complete date but in 32bit timestamp - use PHP internal
 148          if ((1901 < $year) and ($year < 2038)) {
 149  
 150              $oldzone = @date_default_timezone_get();
 151              // Timezone also includes DST settings, therefor substracting the GMT offset is not enough
 152              // We have to set the correct timezone to get the right value
 153              if (($this->_timezone != $oldzone) and ($gmt === false)) {
 154                  date_default_timezone_set($this->_timezone);
 155              }
 156              $result = ($gmt) ? @gmmktime($hour, $minute, $second, $month, $day, $year)
 157                               :   @mktime($hour, $minute, $second, $month, $day, $year);
 158              date_default_timezone_set($oldzone);
 159  
 160              return $result;
 161          }
 162  
 163          if ($gmt !== true) {
 164              $second += $this->_offset;
 165          }
 166  
 167          if (isset(self::$_cache)) {
 168              $id = strtr('Zend_DateObject_mkTime_' . $this->_offset . '_' . $year.$month.$day.'_'.$hour.$minute.$second . '_'.(int)$gmt, '-','_');
 169              if ($result = self::$_cache->load($id)) {
 170                  return unserialize($result);
 171              }
 172          }
 173  
 174          // date to integer
 175          $day   = intval($day);
 176          $month = intval($month);
 177          $year  = intval($year);
 178  
 179          // correct months > 12 and months < 1
 180          if ($month > 12) {
 181              $overlap = floor($month / 12);
 182              $year   += $overlap;
 183              $month  -= $overlap * 12;
 184          } else {
 185              $overlap = ceil((1 - $month) / 12);
 186              $year   -= $overlap;
 187              $month  += $overlap * 12;
 188          }
 189  
 190          $date = 0;
 191          if ($year >= 1970) {
 192  
 193              // Date is after UNIX epoch
 194              // go through leapyears
 195              // add months from latest given year
 196              for ($count = 1970; $count <= $year; $count++) {
 197  
 198                  $leapyear = self::isYearLeapYear($count);
 199                  if ($count < $year) {
 200  
 201                      $date += 365;
 202                      if ($leapyear === true) {
 203                          $date++;
 204                      }
 205  
 206                  } else {
 207  
 208                      for ($mcount = 0; $mcount < ($month - 1); $mcount++) {
 209                          $date += self::$_monthTable[$mcount];
 210                          if (($leapyear === true) and ($mcount == 1)) {
 211                              $date++;
 212                          }
 213  
 214                      }
 215                  }
 216              }
 217  
 218              $date += $day - 1;
 219              $date = (($date * 86400) + ($hour * 3600) + ($minute * 60) + $second);
 220          } else {
 221  
 222              // Date is before UNIX epoch
 223              // go through leapyears
 224              // add months from latest given year
 225              for ($count = 1969; $count >= $year; $count--) {
 226  
 227                  $leapyear = self::isYearLeapYear($count);
 228                  if ($count > $year)
 229                  {
 230                      $date += 365;
 231                      if ($leapyear === true)
 232                          $date++;
 233                  } else {
 234  
 235                      for ($mcount = 11; $mcount > ($month - 1); $mcount--) {
 236                          $date += self::$_monthTable[$mcount];
 237                          if (($leapyear === true) and ($mcount == 2)) {
 238                              $date++;
 239                          }
 240  
 241                      }
 242                  }
 243              }
 244  
 245              $date += (self::$_monthTable[$month - 1] - $day);
 246              $date = -(($date * 86400) + (86400 - (($hour * 3600) + ($minute * 60) + $second)));
 247  
 248              // gregorian correction for 5.Oct.1582
 249              if ($date < -12220185600) {
 250                  $date += 864000;
 251              } else if ($date < -12219321600) {
 252                  $date  = -12219321600;
 253              }
 254          }
 255  
 256          if (isset(self::$_cache)) {
 257              self::$_cache->save( serialize($date), $id);
 258          }
 259  
 260          return $date;
 261      }
 262  
 263      /**
 264       * Returns true, if given $year is a leap year.
 265       *
 266       * @param  integer  $year
 267       * @return boolean  true, if year is leap year
 268       */
 269      protected static function isYearLeapYear($year)
 270      {
 271          // all leapyears can be divided through 4
 272          if (($year % 4) != 0) {
 273              return false;
 274          }
 275  
 276          // all leapyears can be divided through 400
 277          if ($year % 400 == 0) {
 278              return true;
 279          } else if (($year > 1582) and ($year % 100 == 0)) {
 280              return false;
 281          }
 282  
 283          return true;
 284      }
 285  
 286      /**
 287       * Internal mktime function used by Zend_Date for handling 64bit timestamps.
 288       *
 289       * Returns a formatted date for a given timestamp.
 290       *
 291       * @param  string   $format     format for output
 292       * @param  mixed    $timestamp
 293       * @param  boolean  $gmt        OPTIONAL true = other arguments are for UTC time, false = arguments are for local time/date
 294       * @return string
 295       */
 296      protected function date($format, $timestamp = null, $gmt = false)
 297      {
 298          $oldzone = @date_default_timezone_get();
 299          if ($this->_timezone != $oldzone) {
 300              date_default_timezone_set($this->_timezone);
 301          }
 302  
 303          if ($timestamp === null) {
 304              $result = ($gmt) ? @gmdate($format) : @date($format);
 305              date_default_timezone_set($oldzone);
 306              return $result;
 307          }
 308  
 309          if (abs($timestamp) <= 0x7FFFFFFF) {
 310              $result = ($gmt) ? @gmdate($format, $timestamp) : @date($format, $timestamp);
 311              date_default_timezone_set($oldzone);
 312              return $result;
 313          }
 314  
 315          $jump      = false;
 316          $origstamp = $timestamp;
 317          if (isset(self::$_cache)) {
 318              $idstamp = strtr('Zend_DateObject_date_' . $this->_offset . '_'. $timestamp . '_'.(int)$gmt, '-','_');
 319              if ($result2 = self::$_cache->load($idstamp)) {
 320                  $timestamp = unserialize($result2);
 321                  $jump = true;
 322              }
 323          }
 324  
 325          // check on false or null alone fails
 326          if (empty($gmt) and empty($jump)) {
 327              $tempstamp = $timestamp;
 328              if ($tempstamp > 0) {
 329                  while (abs($tempstamp) > 0x7FFFFFFF) {
 330                      $tempstamp -= (86400 * 23376);
 331                  }
 332  
 333                  $dst = date("I", $tempstamp);
 334                  if ($dst === 1) {
 335                      $timestamp += 3600;
 336                  }
 337  
 338                  $temp       = date('Z', $tempstamp);
 339                  $timestamp += $temp;
 340              }
 341  
 342              if (isset(self::$_cache)) {
 343                  self::$_cache->save( serialize($timestamp), $idstamp);
 344              }
 345          }
 346  
 347          if (($timestamp < 0) and ($gmt !== true)) {
 348              $timestamp -= $this->_offset;
 349          }
 350  
 351          date_default_timezone_set($oldzone);
 352          $date   = $this->getDateParts($timestamp, true);
 353          $length = strlen($format);
 354          $output = '';
 355  
 356          for ($i = 0; $i < $length; $i++) {
 357              switch($format[$i]) {
 358                  // day formats
 359                  case 'd':  // day of month, 2 digits, with leading zero, 01 - 31
 360                      $output .= (($date['mday'] < 10) ? '0' . $date['mday'] : $date['mday']);
 361                      break;
 362  
 363                  case 'D':  // day of week, 3 letters, Mon - Sun
 364                      $output .= date('D', 86400 * (3 + self::dayOfWeek($date['year'], $date['mon'], $date['mday'])));
 365                      break;
 366  
 367                  case 'j':  // day of month, without leading zero, 1 - 31
 368                      $output .= $date['mday'];
 369                      break;
 370  
 371                  case 'l':  // day of week, full string name, Sunday - Saturday
 372                      $output .= date('l', 86400 * (3 + self::dayOfWeek($date['year'], $date['mon'], $date['mday'])));
 373                      break;
 374  
 375                  case 'N':  // ISO 8601 numeric day of week, 1 - 7
 376                      $day = self::dayOfWeek($date['year'], $date['mon'], $date['mday']);
 377                      if ($day == 0) {
 378                          $day = 7;
 379                      }
 380                      $output .= $day;
 381                      break;
 382  
 383                  case 'S':  // english suffix for day of month, st nd rd th
 384                      if (($date['mday'] % 10) == 1) {
 385                          $output .= 'st';
 386                      } else if ((($date['mday'] % 10) == 2) and ($date['mday'] != 12)) {
 387                          $output .= 'nd';
 388                      } else if (($date['mday'] % 10) == 3) {
 389                          $output .= 'rd';
 390                      } else {
 391                          $output .= 'th';
 392                      }
 393                      break;
 394  
 395                  case 'w':  // numeric day of week, 0 - 6
 396                      $output .= self::dayOfWeek($date['year'], $date['mon'], $date['mday']);
 397                      break;
 398  
 399                  case 'z':  // day of year, 0 - 365
 400                      $output .= $date['yday'];
 401                      break;
 402  
 403  
 404                  // week formats
 405                  case 'W':  // ISO 8601, week number of year
 406                      $output .= $this->weekNumber($date['year'], $date['mon'], $date['mday']);
 407                      break;
 408  
 409  
 410                  // month formats
 411                  case 'F':  // string month name, january - december
 412                      $output .= date('F', mktime(0, 0, 0, $date['mon'], 2, 1971));
 413                      break;
 414  
 415                  case 'm':  // number of month, with leading zeros, 01 - 12
 416                      $output .= (($date['mon'] < 10) ? '0' . $date['mon'] : $date['mon']);
 417                      break;
 418  
 419                  case 'M':  // 3 letter month name, Jan - Dec
 420                      $output .= date('M',mktime(0, 0, 0, $date['mon'], 2, 1971));
 421                      break;
 422  
 423                  case 'n':  // number of month, without leading zeros, 1 - 12
 424                      $output .= $date['mon'];
 425                      break;
 426  
 427                  case 't':  // number of day in month
 428                      $output .= self::$_monthTable[$date['mon'] - 1];
 429                      break;
 430  
 431  
 432                  // year formats
 433                  case 'L':  // is leap year ?
 434                      $output .= (self::isYearLeapYear($date['year'])) ? '1' : '0';
 435                      break;
 436  
 437                  case 'o':  // ISO 8601 year number
 438                      $week = $this->weekNumber($date['year'], $date['mon'], $date['mday']);
 439                      if (($week > 50) and ($date['mon'] == 1)) {
 440                          $output .= ($date['year'] - 1);
 441                      } else {
 442                          $output .= $date['year'];
 443                      }
 444                      break;
 445  
 446                  case 'Y':  // year number, 4 digits
 447                      $output .= $date['year'];
 448                      break;
 449  
 450                  case 'y':  // year number, 2 digits
 451                      $output .= substr($date['year'], strlen($date['year']) - 2, 2);
 452                      break;
 453  
 454  
 455                  // time formats
 456                  case 'a':  // lower case am/pm
 457                      $output .= (($date['hours'] >= 12) ? 'pm' : 'am');
 458                      break;
 459  
 460                  case 'A':  // upper case am/pm
 461                      $output .= (($date['hours'] >= 12) ? 'PM' : 'AM');
 462                      break;
 463  
 464                  case 'B':  // swatch internet time
 465                      $dayseconds = ($date['hours'] * 3600) + ($date['minutes'] * 60) + $date['seconds'];
 466                      if ($gmt === true) {
 467                          $dayseconds += 3600;
 468                      }
 469                      $output .= (int) (($dayseconds % 86400) / 86.4);
 470                      break;
 471  
 472                  case 'g':  // hours without leading zeros, 12h format
 473                      if ($date['hours'] > 12) {
 474                          $hour = $date['hours'] - 12;
 475                      } else {
 476                          if ($date['hours'] == 0) {
 477                              $hour = '12';
 478                          } else {
 479                              $hour = $date['hours'];
 480                          }
 481                      }
 482                      $output .= $hour;
 483                      break;
 484  
 485                  case 'G':  // hours without leading zeros, 24h format
 486                      $output .= $date['hours'];
 487                      break;
 488  
 489                  case 'h':  // hours with leading zeros, 12h format
 490                      if ($date['hours'] > 12) {
 491                          $hour = $date['hours'] - 12;
 492                      } else {
 493                          if ($date['hours'] == 0) {
 494                              $hour = '12';
 495                          } else {
 496                              $hour = $date['hours'];
 497                          }
 498                      }
 499                      $output .= (($hour < 10) ? '0'.$hour : $hour);
 500                      break;
 501  
 502                  case 'H':  // hours with leading zeros, 24h format
 503                      $output .= (($date['hours'] < 10) ? '0' . $date['hours'] : $date['hours']);
 504                      break;
 505  
 506                  case 'i':  // minutes with leading zeros
 507                      $output .= (($date['minutes'] < 10) ? '0' . $date['minutes'] : $date['minutes']);
 508                      break;
 509  
 510                  case 's':  // seconds with leading zeros
 511                      $output .= (($date['seconds'] < 10) ? '0' . $date['seconds'] : $date['seconds']);
 512                      break;
 513  
 514  
 515                  // timezone formats
 516                  case 'e':  // timezone identifier
 517                      if ($gmt === true) {
 518                          $output .= gmdate('e', mktime($date['hours'], $date['minutes'], $date['seconds'],
 519                                                        $date['mon'], $date['mday'], 2000));
 520                      } else {
 521                          $output .=   date('e', mktime($date['hours'], $date['minutes'], $date['seconds'],
 522                                                        $date['mon'], $date['mday'], 2000));
 523                      }
 524                      break;
 525  
 526                  case 'I':  // daylight saving time or not
 527                      if ($gmt === true) {
 528                          $output .= gmdate('I', mktime($date['hours'], $date['minutes'], $date['seconds'],
 529                                                        $date['mon'], $date['mday'], 2000));
 530                      } else {
 531                          $output .=   date('I', mktime($date['hours'], $date['minutes'], $date['seconds'],
 532                                                        $date['mon'], $date['mday'], 2000));
 533                      }
 534                      break;
 535  
 536                  case 'O':  // difference to GMT in hours
 537                      $gmtstr = ($gmt === true) ? 0 : $this->getGmtOffset();
 538                      $output .= sprintf('%s%04d', ($gmtstr <= 0) ? '+' : '-', abs($gmtstr) / 36);
 539                      break;
 540  
 541                  case 'P':  // difference to GMT with colon
 542                      $gmtstr = ($gmt === true) ? 0 : $this->getGmtOffset();
 543                      $gmtstr = sprintf('%s%04d', ($gmtstr <= 0) ? '+' : '-', abs($gmtstr) / 36);
 544                      $output = $output . substr($gmtstr, 0, 3) . ':' . substr($gmtstr, 3);
 545                      break;
 546  
 547                  case 'T':  // timezone settings
 548                      if ($gmt === true) {
 549                          $output .= gmdate('T', mktime($date['hours'], $date['minutes'], $date['seconds'],
 550                                                        $date['mon'], $date['mday'], 2000));
 551                      } else {
 552                          $output .=   date('T', mktime($date['hours'], $date['minutes'], $date['seconds'],
 553                                                        $date['mon'], $date['mday'], 2000));
 554                      }
 555                      break;
 556  
 557                  case 'Z':  // timezone offset in seconds
 558                      $output .= ($gmt === true) ? 0 : -$this->getGmtOffset();
 559                      break;
 560  
 561  
 562                  // complete time formats
 563                  case 'c':  // ISO 8601 date format
 564                      $difference = $this->getGmtOffset();
 565                      $difference = sprintf('%s%04d', ($difference <= 0) ? '+' : '-', abs($difference) / 36);
 566                      $difference = substr($difference, 0, 3) . ':' . substr($difference, 3);
 567                      $output .= $date['year'] . '-'
 568                               . (($date['mon']     < 10) ? '0' . $date['mon']     : $date['mon'])     . '-'
 569                               . (($date['mday']    < 10) ? '0' . $date['mday']    : $date['mday'])    . 'T'
 570                               . (($date['hours']   < 10) ? '0' . $date['hours']   : $date['hours'])   . ':'
 571                               . (($date['minutes'] < 10) ? '0' . $date['minutes'] : $date['minutes']) . ':'
 572                               . (($date['seconds'] < 10) ? '0' . $date['seconds'] : $date['seconds'])
 573                               . $difference;
 574                      break;
 575  
 576                  case 'r':  // RFC 2822 date format
 577                      $difference = $this->getGmtOffset();
 578                      $difference = sprintf('%s%04d', ($difference <= 0) ? '+' : '-', abs($difference) / 36);
 579                      $output .= gmdate('D', 86400 * (3 + self::dayOfWeek($date['year'], $date['mon'], $date['mday']))) . ', '
 580                               . (($date['mday']    < 10) ? '0' . $date['mday']    : $date['mday'])    . ' '
 581                               . date('M', mktime(0, 0, 0, $date['mon'], 2, 1971)) . ' '
 582                               . $date['year'] . ' '
 583                               . (($date['hours']   < 10) ? '0' . $date['hours']   : $date['hours'])   . ':'
 584                               . (($date['minutes'] < 10) ? '0' . $date['minutes'] : $date['minutes']) . ':'
 585                               . (($date['seconds'] < 10) ? '0' . $date['seconds'] : $date['seconds']) . ' '
 586                               . $difference;
 587                      break;
 588  
 589                  case 'U':  // Unix timestamp
 590                      $output .= $origstamp;
 591                      break;
 592  
 593  
 594                  // special formats
 595                  case "\\":  // next letter to print with no format
 596                      $i++;
 597                      if ($i < $length) {
 598                          $output .= $format[$i];
 599                      }
 600                      break;
 601  
 602                  default:  // letter is no format so add it direct
 603                      $output .= $format[$i];
 604                      break;
 605              }
 606          }
 607  
 608          return (string) $output;
 609      }
 610  
 611      /**
 612       * Returns the day of week for a Gregorian calendar date.
 613       * 0 = sunday, 6 = saturday
 614       *
 615       * @param  integer  $year
 616       * @param  integer  $month
 617       * @param  integer  $day
 618       * @return integer  dayOfWeek
 619       */
 620      protected static function dayOfWeek($year, $month, $day)
 621      {
 622          if ((1901 < $year) and ($year < 2038)) {
 623              return (int) date('w', mktime(0, 0, 0, $month, $day, $year));
 624          }
 625  
 626          // gregorian correction
 627          $correction = 0;
 628          if (($year < 1582) or (($year == 1582) and (($month < 10) or (($month == 10) && ($day < 15))))) {
 629              $correction = 3;
 630          }
 631  
 632          if ($month > 2) {
 633              $month -= 2;
 634          } else {
 635              $month += 10;
 636              $year--;
 637          }
 638  
 639          $day  = floor((13 * $month - 1) / 5) + $day + ($year % 100) + floor(($year % 100) / 4);
 640          $day += floor(($year / 100) / 4) - 2 * floor($year / 100) + 77 + $correction;
 641  
 642          return (int) ($day - 7 * floor($day / 7));
 643      }
 644  
 645      /**
 646       * Internal getDateParts function for handling 64bit timestamps, similar to:
 647       * http://www.php.net/getdate
 648       *
 649       * Returns an array of date parts for $timestamp, relative to 1970/01/01 00:00:00 GMT/UTC.
 650       *
 651       * $fast specifies ALL date parts should be returned (slower)
 652       * Default is false, and excludes $dayofweek, weekday, month and timestamp from parts returned.
 653       *
 654       * @param   mixed    $timestamp
 655       * @param   boolean  $fast   OPTIONAL defaults to fast (false), resulting in fewer date parts
 656       * @return  array
 657       */
 658      protected function getDateParts($timestamp = null, $fast = null)
 659      {
 660  
 661          // actual timestamp
 662          if (!is_numeric($timestamp)) {
 663              return getdate();
 664          }
 665  
 666          // 32bit timestamp
 667          if (abs($timestamp) <= 0x7FFFFFFF) {
 668              return @getdate((int) $timestamp);
 669          }
 670  
 671          if (isset(self::$_cache)) {
 672              $id = strtr('Zend_DateObject_getDateParts_' . $timestamp.'_'.(int)$fast, '-','_');
 673              if ($result = self::$_cache->load($id)) {
 674                  return unserialize($result);
 675              }
 676          }
 677  
 678          $otimestamp = $timestamp;
 679          $numday = 0;
 680          $month = 0;
 681          // gregorian correction
 682          if ($timestamp < -12219321600) {
 683              $timestamp -= 864000;
 684          }
 685  
 686          // timestamp lower 0
 687          if ($timestamp < 0) {
 688              $sec = 0;
 689              $act = 1970;
 690  
 691              // iterate through 10 years table, increasing speed
 692              foreach(self::$_yearTable as $year => $seconds) {
 693                  if ($timestamp >= $seconds) {
 694                      $i = $act;
 695                      break;
 696                  }
 697                  $sec = $seconds;
 698                  $act = $year;
 699              }
 700  
 701              $timestamp -= $sec;
 702              if (!isset($i)) {
 703                  $i = $act;
 704              }
 705  
 706              // iterate the max last 10 years
 707              do {
 708                  --$i;
 709                  $day = $timestamp;
 710  
 711                  $timestamp += 31536000;
 712                  $leapyear = self::isYearLeapYear($i);
 713                  if ($leapyear === true) {
 714                      $timestamp += 86400;
 715                  }
 716  
 717                  if ($timestamp >= 0) {
 718                      $year = $i;
 719                      break;
 720                  }
 721              } while ($timestamp < 0);
 722  
 723              $secondsPerYear = 86400 * ($leapyear ? 366 : 365) + $day;
 724  
 725              $timestamp = $day;
 726              // iterate through months
 727              for ($i = 12; --$i >= 0;) {
 728                  $day = $timestamp;
 729  
 730                  $timestamp += self::$_monthTable[$i] * 86400;
 731                  if (($leapyear === true) and ($i == 1)) {
 732                      $timestamp += 86400;
 733                  }
 734  
 735                  if ($timestamp >= 0) {
 736                      $month  = $i;
 737                      $numday = self::$_monthTable[$i];
 738                      if (($leapyear === true) and ($i == 1)) {
 739                          ++$numday;
 740                      }
 741                      break;
 742                  }
 743              }
 744  
 745              $timestamp  = $day;
 746              $numberdays = $numday + ceil(($timestamp + 1) / 86400);
 747  
 748              $timestamp += ($numday - $numberdays + 1) * 86400;
 749              $hours      = floor($timestamp / 3600);
 750          } else {
 751  
 752              // iterate through years
 753              for ($i = 1970;;$i++) {
 754                  $day = $timestamp;
 755  
 756                  $timestamp -= 31536000;
 757                  $leapyear = self::isYearLeapYear($i);
 758                  if ($leapyear === true) {
 759                      $timestamp -= 86400;
 760                  }
 761  
 762                  if ($timestamp < 0) {
 763                      $year = $i;
 764                      break;
 765                  }
 766              }
 767  
 768              $secondsPerYear = $day;
 769  
 770              $timestamp = $day;
 771              // iterate through months
 772              for ($i = 0; $i <= 11; $i++) {
 773                  $day = $timestamp;
 774                  $timestamp -= self::$_monthTable[$i] * 86400;
 775  
 776                  if (($leapyear === true) and ($i == 1)) {
 777                      $timestamp -= 86400;
 778                  }
 779  
 780                  if ($timestamp < 0) {
 781                      $month  = $i;
 782                      $numday = self::$_monthTable[$i];
 783                      if (($leapyear === true) and ($i == 1)) {
 784                          ++$numday;
 785                      }
 786                      break;
 787                  }
 788              }
 789  
 790              $timestamp  = $day;
 791              $numberdays = ceil(($timestamp + 1) / 86400);
 792              $timestamp  = $timestamp - ($numberdays - 1) * 86400;
 793              $hours = floor($timestamp / 3600);
 794          }
 795  
 796          $timestamp -= $hours * 3600;
 797  
 798          $month  += 1;
 799          $minutes = floor($timestamp / 60);
 800          $seconds = $timestamp - $minutes * 60;
 801  
 802          if ($fast === true) {
 803              $array = array(
 804                  'seconds' => $seconds,
 805                  'minutes' => $minutes,
 806                  'hours'   => $hours,
 807                  'mday'    => $numberdays,
 808                  'mon'     => $month,
 809                  'year'    => $year,
 810                  'yday'    => floor($secondsPerYear / 86400),
 811              );
 812          } else {
 813  
 814              $dayofweek = self::dayOfWeek($year, $month, $numberdays);
 815              $array = array(
 816                      'seconds' => $seconds,
 817                      'minutes' => $minutes,
 818                      'hours'   => $hours,
 819                      'mday'    => $numberdays,
 820                      'wday'    => $dayofweek,
 821                      'mon'     => $month,
 822                      'year'    => $year,
 823                      'yday'    => floor($secondsPerYear / 86400),
 824                      'weekday' => gmdate('l', 86400 * (3 + $dayofweek)),
 825                      'month'   => gmdate('F', mktime(0, 0, 0, $month, 1, 1971)),
 826                      0         => $otimestamp
 827              );
 828          }
 829  
 830          if (isset(self::$_cache)) {
 831              self::$_cache->save( serialize($array), $id);
 832          }
 833  
 834          return $array;
 835      }
 836  
 837      /**
 838       * Internal getWeekNumber function for handling 64bit timestamps
 839       *
 840       * Returns the ISO 8601 week number of a given date
 841       *
 842       * @param  integer  $year
 843       * @param  integer  $month
 844       * @param  integer  $day
 845       * @return integer
 846       */
 847      protected function weekNumber($year, $month, $day)
 848      {
 849          if ((1901 < $year) and ($year < 2038)) {
 850              return (int) date('W', mktime(0, 0, 0, $month, $day, $year));
 851          }
 852  
 853          $dayofweek = self::dayOfWeek($year, $month, $day);
 854          $firstday  = self::dayOfWeek($year, 1, 1);
 855          if (($month == 1) and (($firstday < 1) or ($firstday > 4)) and ($day < 4)) {
 856              $firstday  = self::dayOfWeek($year - 1, 1, 1);
 857              $month     = 12;
 858              $day       = 31;
 859  
 860          } else if (($month == 12) and ((self::dayOfWeek($year + 1, 1, 1) < 5) and
 861                     (self::dayOfWeek($year + 1, 1, 1) > 0))) {
 862              return 1;
 863          }
 864  
 865          return intval (((self::dayOfWeek($year, 1, 1) < 5) and (self::dayOfWeek($year, 1, 1) > 0)) +
 866                 4 * ($month - 1) + (2 * ($month - 1) + ($day - 1) + $firstday - $dayofweek + 6) * 36 / 256);
 867      }
 868  
 869      /**
 870       * Internal _range function
 871       * Sets the value $a to be in the range of [0, $b]
 872       *
 873       * @param float $a - value to correct
 874       * @param float $b - maximum range to set
 875       */
 876      private function _range($a, $b) {
 877          while ($a < 0) {
 878              $a += $b;
 879          }
 880          while ($a >= $b) {
 881              $a -= $b;
 882          }
 883          return $a;
 884      }
 885  
 886      /**
 887       * Calculates the sunrise or sunset based on a location
 888       *
 889       * @param  array  $location  Location for calculation MUST include 'latitude', 'longitude', 'horizon'
 890       * @param  bool   $horizon   true: sunrise; false: sunset
 891       * @return mixed  - false: midnight sun, integer:
 892       */
 893      protected function calcSun($location, $horizon, $rise = false)
 894      {
 895          // timestamp within 32bit
 896          if (abs($this->_unixTimestamp) <= 0x7FFFFFFF) {
 897              if ($rise === false) {
 898                  return date_sunset($this->_unixTimestamp, SUNFUNCS_RET_TIMESTAMP, $location['latitude'],
 899                                     $location['longitude'], 90 + $horizon, $this->getGmtOffset() / 3600);
 900              }
 901              return date_sunrise($this->_unixTimestamp, SUNFUNCS_RET_TIMESTAMP, $location['latitude'],
 902                                  $location['longitude'], 90 + $horizon, $this->getGmtOffset() / 3600);
 903          }
 904  
 905          // self calculation - timestamp bigger than 32bit
 906          // fix circle values
 907          $quarterCircle      = 0.5 * M_PI;
 908          $halfCircle         =       M_PI;
 909          $threeQuarterCircle = 1.5 * M_PI;
 910          $fullCircle         = 2   * M_PI;
 911  
 912          // radiant conversion for coordinates
 913          $radLatitude  = $location['latitude']   * $halfCircle / 180;
 914          $radLongitude = $location['longitude']  * $halfCircle / 180;
 915  
 916          // get solar coordinates
 917          $tmpRise       = $rise ? $quarterCircle : $threeQuarterCircle;
 918          $radDay        = $this->date('z',$this->_unixTimestamp) + ($tmpRise - $radLongitude) / $fullCircle;
 919  
 920          // solar anomoly and longitude
 921          $solAnomoly    = $radDay * 0.017202 - 0.0574039;
 922          $solLongitude  = $solAnomoly + 0.0334405 * sin($solAnomoly);
 923          $solLongitude += 4.93289 + 3.49066E-4 * sin(2 * $solAnomoly);
 924  
 925          // get quadrant
 926          $solLongitude = $this->_range($solLongitude, $fullCircle);
 927  
 928          if (($solLongitude / $quarterCircle) - intval($solLongitude / $quarterCircle) == 0) {
 929              $solLongitude += 4.84814E-6;
 930          }
 931  
 932          // solar ascension
 933          $solAscension = sin($solLongitude) / cos($solLongitude);
 934          $solAscension = atan2(0.91746 * $solAscension, 1);
 935  
 936          // adjust quadrant
 937          if ($solLongitude > $threeQuarterCircle) {
 938              $solAscension += $fullCircle;
 939          } else if ($solLongitude > $quarterCircle) {
 940              $solAscension += $halfCircle;
 941          }
 942  
 943          // solar declination
 944          $solDeclination  = 0.39782 * sin($solLongitude);
 945          $solDeclination /=  sqrt(-$solDeclination * $solDeclination + 1);
 946          $solDeclination  = atan2($solDeclination, 1);
 947  
 948          $solHorizon = $horizon - sin($solDeclination) * sin($radLatitude);
 949          $solHorizon /= cos($solDeclination) * cos($radLatitude);
 950  
 951          // midnight sun, always night
 952          if (abs($solHorizon) > 1) {
 953              return false;
 954          }
 955  
 956          $solHorizon /= sqrt(-$solHorizon * $solHorizon + 1);
 957          $solHorizon  = $quarterCircle - atan2($solHorizon, 1);
 958  
 959          if ($rise) {
 960              $solHorizon = $fullCircle - $solHorizon;
 961          }
 962  
 963          // time calculation
 964          $localTime     = $solHorizon + $solAscension - 0.0172028 * $radDay - 1.73364;
 965          $universalTime = $localTime - $radLongitude;
 966  
 967          // determinate quadrant
 968          $universalTime = $this->_range($universalTime, $fullCircle);
 969  
 970          // radiant to hours
 971          $universalTime *= 24 / $fullCircle;
 972  
 973          // convert to time
 974          $hour = intval($universalTime);
 975          $universalTime    = ($universalTime - $hour) * 60;
 976          $min  = intval($universalTime);
 977          $universalTime    = ($universalTime - $min) * 60;
 978          $sec  = intval($universalTime);
 979  
 980          return $this->mktime($hour, $min, $sec, $this->date('m', $this->_unixTimestamp),
 981                               $this->date('j', $this->_unixTimestamp), $this->date('Y', $this->_unixTimestamp),
 982                               -1, true);
 983      }
 984  
 985      /**
 986       * Sets a new timezone for calculation of $this object's gmt offset.
 987       * For a list of supported timezones look here: http://php.net/timezones
 988       * If no timezone can be detected or the given timezone is wrong UTC will be set.
 989       *
 990       * @param  string  $zone      OPTIONAL timezone for date calculation; defaults to date_default_timezone_get()
 991       * @return Zend_Date_DateObject Provides fluent interface
 992       * @throws Zend_Date_Exception
 993       */
 994      public function setTimezone($zone = null)
 995      {
 996          $oldzone = @date_default_timezone_get();
 997          if ($zone === null) {
 998              $zone = $oldzone;
 999          }
1000  
1001          // throw an error on false input, but only if the new date extension is available
1002          if (function_exists('timezone_open')) {
1003              if (!@timezone_open($zone)) {
1004                  require_once 'Zend/Date/Exception.php';
1005                  throw new Zend_Date_Exception("timezone ($zone) is not a known timezone", 0, null, $zone);
1006              }
1007          }
1008          // this can generate an error if the date extension is not available and a false timezone is given
1009          $result = @date_default_timezone_set($zone);
1010          if ($result === true) {
1011              $this->_offset   = mktime(0, 0, 0, 1, 2, 1970) - gmmktime(0, 0, 0, 1, 2, 1970);
1012              $this->_timezone = $zone;
1013          }
1014          date_default_timezone_set($oldzone);
1015  
1016          if (($zone == 'UTC') or ($zone == 'GMT')) {
1017              $this->_dst = false;
1018          } else {
1019              $this->_dst = true;
1020          }
1021  
1022          return $this;
1023      }
1024  
1025      /**
1026       * Return the timezone of $this object.
1027       * The timezone is initially set when the object is instantiated.
1028       *
1029       * @return  string  actual set timezone string
1030       */
1031      public function getTimezone()
1032      {
1033          return $this->_timezone;
1034      }
1035  
1036      /**
1037       * Return the offset to GMT of $this object's timezone.
1038       * The offset to GMT is initially set when the object is instantiated using the currently,
1039       * in effect, default timezone for PHP functions.
1040       *
1041       * @return  integer  seconds difference between GMT timezone and timezone when object was instantiated
1042       */
1043      public function getGmtOffset()
1044      {
1045          $date   = $this->getDateParts($this->getUnixTimestamp(), true);
1046          $zone   = @date_default_timezone_get();
1047          $result = @date_default_timezone_set($this->_timezone);
1048          if ($result === true) {
1049              $offset = $this->mktime($date['hours'], $date['minutes'], $date['seconds'],
1050                                      $date['mon'], $date['mday'], $date['year'], false)
1051                      - $this->mktime($date['hours'], $date['minutes'], $date['seconds'],
1052                                      $date['mon'], $date['mday'], $date['year'], true);
1053          }
1054          date_default_timezone_set($zone);
1055  
1056          return $offset;
1057      }
1058  }


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