open/home/c1802190/public_html/library/Zend/Date.php
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 license@zend.com so we can send you a copy immediately.
14 *
15 * @category Zend
16 * @package Zend_Date
17 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
18 * @license http://framework.zend.com/license/new-bsd New BSD License
19 * @version $Id$
20 */
21
22 /**
23 * Include needed Date classes
24 */
25 require_once 'Zend/Date/DateObject.php';
26 require_once 'Zend/Locale.php';
27 require_once 'Zend/Locale/Format.php';
28 require_once 'Zend/Locale/Math.php';
29
30 /**
31 * @category Zend
32 * @package Zend_Date
33 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
34 * @license http://framework.zend.com/license/new-bsd New BSD License
35 */
36 class Zend_Date extends Zend_Date_DateObject
37 {
38 private $_locale = null;
39
40 // Fractional second variables
41 private $_fractional = 0;
42 private $_precision = 3;
43
44 private static $_options = [
45 'format_type' => 'iso', // format for date strings 'iso' or 'php'
46 'fix_dst' => true, // fix dst on summer/winter time change
47 'extend_month' => false, // false - addMonth like SQL, true like excel
48 'cache' => null, // cache to set
49 'timesync' => null // timesync server to set
50 ];
51
52 // Class wide Date Constants
53 public const DAY = 'dd';
54 public const DAY_SHORT = 'd';
55 public const DAY_SUFFIX = 'SS';
56 public const DAY_OF_YEAR = 'D';
57 public const WEEKDAY = 'EEEE';
58 public const WEEKDAY_SHORT = 'EEE';
59 public const WEEKDAY_NARROW = 'E';
60 public const WEEKDAY_NAME = 'EE';
61 public const WEEKDAY_8601 = 'eee';
62 public const WEEKDAY_DIGIT = 'e';
63 public const WEEK = 'ww';
64 public const MONTH = 'MM';
65 public const MONTH_SHORT = 'M';
66 public const MONTH_DAYS = 'ddd';
67 public const MONTH_NAME = 'MMMM';
68 public const MONTH_NAME_SHORT = 'MMM';
69 public const MONTH_NAME_NARROW = 'MMMMM';
70 public const YEAR = 'y';
71 public const YEAR_SHORT = 'yy';
72 public const YEAR_8601 = 'Y';
73 public const YEAR_SHORT_8601 = 'YY';
74 public const LEAPYEAR = 'l';
75 public const MERIDIEM = 'a';
76 public const SWATCH = 'B';
77 public const HOUR = 'HH';
78 public const HOUR_SHORT = 'H';
79 public const HOUR_AM = 'hh';
80 public const HOUR_SHORT_AM = 'h';
81 public const MINUTE = 'mm';
82 public const MINUTE_SHORT = 'm';
83 public const SECOND = 'ss';
84 public const SECOND_SHORT = 's';
85 public const MILLISECOND = 'S';
86 public const TIMEZONE_NAME = 'zzzz';
87 public const DAYLIGHT = 'I';
88 public const GMT_DIFF = 'Z';
89 public const GMT_DIFF_SEP = 'ZZZZ';
90 public const TIMEZONE = 'z';
91 public const TIMEZONE_SECS = 'X';
92 public const ISO_8601 = 'c';
93 public const RFC_2822 = 'r';
94 public const TIMESTAMP = 'U';
95 public const ERA = 'G';
96 public const ERA_NAME = 'GGGG';
97 public const ERA_NARROW = 'GGGGG';
98 public const DATES = 'F';
99 public const DATE_FULL = 'FFFFF';
100 public const DATE_LONG = 'FFFF';
101 public const DATE_MEDIUM = 'FFF';
102 public const DATE_SHORT = 'FF';
103 public const TIMES = 'WW';
104 public const TIME_FULL = 'TTTTT';
105 public const TIME_LONG = 'TTTT';
106 public const TIME_MEDIUM = 'TTT';
107 public const TIME_SHORT = 'TT';
108 public const DATETIME = 'K';
109 public const DATETIME_FULL = 'KKKKK';
110 public const DATETIME_LONG = 'KKKK';
111 public const DATETIME_MEDIUM = 'KKK';
112 public const DATETIME_SHORT = 'KK';
113 public const ATOM = 'OOO';
114 public const COOKIE = 'CCC';
115 public const RFC_822 = 'R';
116 public const RFC_850 = 'RR';
117 public const RFC_1036 = 'RRR';
118 public const RFC_1123 = 'RRRR';
119 public const RFC_3339 = 'RRRRR';
120 public const RSS = 'SSS';
121 public const W3C = 'WWW';
122
123 /**
124 * Generates the standard date object, could be a unix timestamp, localized date,
125 * string, integer, array and so on. Also parts of dates or time are supported
126 * Always set the default timezone: http://php.net/date_default_timezone_set
127 * For example, in your bootstrap: date_default_timezone_set('America/Los_Angeles');
128 * For detailed instructions please look in the docu.
129 *
130 * @param string|integer|Zend_Date|array $date OPTIONAL Date value or value of date part to set
131 * ,depending on $part. If null the actual time is set
132 * @param string $part OPTIONAL Defines the input format of $date
133 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
134 * @return void
135 * @throws Zend_Date_Exception
136 */
137 public function __construct($date = null, $part = null, $locale = null)
138 {
139 if (is_object($date) && !($date instanceof Zend_TimeSync_Protocol) &&
140 !($date instanceof Zend_Date)) {
141 if ($locale instanceof Zend_Locale) {
142 $locale = $date;
143 $date = null;
144 $part = null;
145 } else {
146 $date = (string) $date;
147 }
148 }
149
150 if (($date !== null) && !is_array($date) && !($date instanceof Zend_TimeSync_Protocol) &&
151 !($date instanceof Zend_Date) && !defined($date) && Zend_Locale::isLocale($date, true, false)) {
152 $locale = $date;
153 $date = null;
154 $part = null;
155 } else if (($part !== null) && !defined($part) && Zend_Locale::isLocale($part, true, false)) {
156 $locale = $part;
157 $part = null;
158 }
159
160 $this->setLocale($locale);
161 if (is_string($date) && ($part === null) && (strlen($date) <= 5)) {
162 $part = $date;
163 $date = null;
164 }
165
166 if ($date === null) {
167 if ($part === null) {
168 $date = time();
169 } else if ($part !== self::TIMESTAMP) {
170 $date = self::now($locale);
171 $date = $date->get($part);
172 }
173 }
174
175 if ($date instanceof Zend_TimeSync_Protocol) {
176 $date = $date->getInfo();
177 $date = $this->_getTime($date['offset']);
178 $part = null;
179 } else if (parent::$_defaultOffset != 0) {
180 $date = $this->_getTime(parent::$_defaultOffset);
181 }
182
183 // set the timezone and offset for $this
184 $zone = @date_default_timezone_get();
185 $this->setTimezone($zone);
186
187 // try to get timezone from date-string
188 if (!is_int($date)) {
189 $zone = $this->getTimezoneFromString($date);
190 $this->setTimezone($zone);
191 }
192
193 // set datepart
194 if (($part !== null && $part !== self::TIMESTAMP) || (!is_numeric($date))) {
195 // switch off dst handling for value setting
196 $this->setUnixTimestamp($this->getGmtOffset());
197 $this->set($date, $part, $this->_locale);
198
199 // DST fix
200 if (is_array($date) === true) {
201 if (!isset($date['hour'])) {
202 $date['hour'] = 0;
203 }
204
205 $hour = $this->toString('H', 'iso', true);
206 $hour = $date['hour'] - $hour;
207 switch ($hour) {
208 case 1 :
209 case -23 :
210 $this->addTimestamp(3600);
211 break;
212 case -1 :
213 case 23 :
214 $this->subTimestamp(3600);
215 break;
216 case 2 :
217 case -22 :
218 $this->addTimestamp(7200);
219 break;
220 case -2 :
221 case 22 :
222 $this->subTimestamp(7200);
223 break;
224 }
225 }
226 } else {
227 $this->setUnixTimestamp($date);
228 }
229 }
230
231 /**
232 * Sets class wide options, if no option was given, the actual set options will be returned
233 *
234 * @param array $options Options to set
235 * @throws Zend_Date_Exception
236 * @return array|void if no option was given
237 */
238 public static function setOptions(array $options = [])
239 {
240 if (empty($options)) {
241 return self::$_options;
242 }
243
244 foreach ($options as $name => $value) {
245 $name = strtolower($name);
246
247 if (array_key_exists($name, self::$_options)) {
248 switch($name) {
249 case 'format_type' :
250 if ((strtolower($value) != 'php') && (strtolower($value) != 'iso')) {
251 require_once 'Zend/Date/Exception.php';
252 throw new Zend_Date_Exception("Unknown format type ($value) for dates, only 'iso' and 'php' supported", 0, null, $value);
253 }
254 break;
255 case 'fix_dst' :
256 if (!is_bool($value)) {
257 require_once 'Zend/Date/Exception.php';
258 throw new Zend_Date_Exception("'fix_dst' has to be boolean", 0, null, $value);
259 }
260 break;
261 case 'extend_month' :
262 if (!is_bool($value)) {
263 require_once 'Zend/Date/Exception.php';
264 throw new Zend_Date_Exception("'extend_month' has to be boolean", 0, null, $value);
265 }
266 break;
267 case 'cache' :
268 if ($value === null) {
269 parent::$_cache = null;
270 } else {
271 if (!$value instanceof Zend_Cache_Core) {
272 require_once 'Zend/Date/Exception.php';
273 throw new Zend_Date_Exception("Instance of Zend_Cache expected");
274 }
275
276 parent::$_cache = $value;
277 parent::$_cacheTags = Zend_Date_DateObject::_getTagSupportForCache();
278 Zend_Locale_Data::setCache($value);
279 }
280 break;
281 case 'timesync' :
282 if ($value === null) {
283 parent::$_defaultOffset = 0;
284 } else {
285 if (!$value instanceof Zend_TimeSync_Protocol) {
286 require_once 'Zend/Date/Exception.php';
287 throw new Zend_Date_Exception("Instance of Zend_TimeSync expected");
288 }
289
290 $date = $value->getInfo();
291 parent::$_defaultOffset = $date['offset'];
292 }
293 break;
294 }
295 self::$_options[$name] = $value;
296 }
297 else {
298 require_once 'Zend/Date/Exception.php';
299 throw new Zend_Date_Exception("Unknown option: $name = $value");
300 }
301 }
302 }
303
304 /**
305 * Returns this object's internal UNIX timestamp (equivalent to Zend_Date::TIMESTAMP).
306 * If the timestamp is too large for integers, then the return value will be a string.
307 * This function does not return the timestamp as an object.
308 * Use clone() or copyPart() instead.
309 *
310 * @return integer|string UNIX timestamp
311 */
312 public function getTimestamp()
313 {
314 return $this->getUnixTimestamp();
315 }
316
317 /**
318 * Returns the calculated timestamp
319 * HINT: timestamps are always GMT
320 *
321 * @param string $calc Type of calculation to make
322 * @param string|integer|array|Zend_Date $stamp Timestamp to calculate, when null the actual timestamp is calculated
323 * @return Zend_Date|integer
324 * @throws Zend_Date_Exception
325 */
326 private function _timestamp($calc, $stamp)
327 {
328 if ($stamp instanceof Zend_Date) {
329 // extract timestamp from object
330 $stamp = $stamp->getTimestamp();
331 }
332
333 if (is_array($stamp)) {
334 if (isset($stamp['timestamp']) === true) {
335 $stamp = $stamp['timestamp'];
336 } else {
337 require_once 'Zend/Date/Exception.php';
338 throw new Zend_Date_Exception('no timestamp given in array');
339 }
340 }
341
342 if ($calc === 'set') {
343 $return = $this->setUnixTimestamp($stamp);
344 } else {
345 $return = $this->_calcdetail($calc, $stamp, self::TIMESTAMP, null);
346 }
347 if ($calc != 'cmp') {
348 return $this;
349 }
350 return $return;
351 }
352
353 /**
354 * Sets a new timestamp
355 *
356 * @param integer|string|array|Zend_Date $timestamp Timestamp to set
357 * @return $this
358 * @throws Zend_Date_Exception
359 */
360 public function setTimestamp($timestamp)
361 {
362 return $this->_timestamp('set', $timestamp);
363 }
364
365 /**
366 * Adds a timestamp
367 *
368 * @param integer|string|array|Zend_Date $timestamp Timestamp to add
369 * @return $this
370 * @throws Zend_Date_Exception
371 */
372 public function addTimestamp($timestamp)
373 {
374 return $this->_timestamp('add', $timestamp);
375 }
376
377 /**
378 * Subtracts a timestamp
379 *
380 * @param integer|string|array|Zend_Date $timestamp Timestamp to sub
381 * @return $this
382 * @throws Zend_Date_Exception
383 */
384 public function subTimestamp($timestamp)
385 {
386 return $this->_timestamp('sub', $timestamp);
387 }
388
389 /**
390 * Compares two timestamps, returning the difference as integer
391 *
392 * @param integer|string|array|Zend_Date $timestamp Timestamp to compare
393 * @return integer 0 = equal, 1 = later, -1 = earlier
394 * @throws Zend_Date_Exception
395 */
396 public function compareTimestamp($timestamp)
397 {
398 return $this->_timestamp('cmp', $timestamp);
399 }
400
401 /**
402 * Returns a string representation of the object
403 * Supported format tokens are:
404 * G - era, y - year, Y - ISO year, M - month, w - week of year, D - day of year, d - day of month
405 * E - day of week, e - number of weekday (1-7), h - hour 1-12, H - hour 0-23, m - minute, s - second
406 * A - milliseconds of day, z - timezone, Z - timezone offset, S - fractional second, a - period of day
407 *
408 * Additionally format tokens but non ISO conform are:
409 * SS - day suffix, eee - php number of weekday(0-6), ddd - number of days per month
410 * l - Leap year, B - swatch internet time, I - daylight saving time, X - timezone offset in seconds
411 * r - RFC2822 format, U - unix timestamp
412 *
413 * Not supported ISO tokens are
414 * u - extended year, Q - quarter, q - quarter, L - stand alone month, W - week of month
415 * F - day of week of month, g - modified julian, c - stand alone weekday, k - hour 0-11, K - hour 1-24
416 * v - wall zone
417 *
418 * @param string $format OPTIONAL Rule for formatting output. If null the default date format is used
419 * @param string $type OPTIONAL Type for the format string which overrides the standard setting
420 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
421 * @return string
422 */
423 public function toString($format = null, $type = null, $locale = null)
424 {
425 if (is_object($format)) {
426 if ($format instanceof Zend_Locale) {
427 $locale = $format;
428 $format = null;
429 } else {
430 $format = (string) $format;
431 }
432 }
433
434 if (is_object($type)) {
435 if ($type instanceof Zend_Locale) {
436 $locale = $type;
437 $type = null;
438 } else {
439 $type = (string) $type;
440 }
441 }
442
443 if (($format !== null) && !defined($format)
444 && ($format != 'ee') && ($format != 'ss') && ($format != 'GG') && ($format != 'MM') && ($format != 'EE') && ($format != 'TT')
445 && Zend_Locale::isLocale($format, null, false)) {
446 $locale = $format;
447 $format = null;
448 }
449
450 if (($type !== null) && ($type != 'php') && ($type != 'iso') &&
451 Zend_Locale::isLocale($type, null, false)) {
452 $locale = $type;
453 $type = null;
454 }
455
456 if ($locale === null) {
457 $locale = $this->getLocale();
458 }
459
460 if ($format === null) {
461 $format = Zend_Locale_Format::getDateFormat($locale) . ' ' . Zend_Locale_Format::getTimeFormat($locale);
462 } else if (((self::$_options['format_type'] == 'php') && ($type === null)) || ($type == 'php')) {
463 $format = Zend_Locale_Format::convertPhpToIsoFormat($format);
464 }
465
466 return $this->date($this->_toToken($format, $locale), $this->getUnixTimestamp(), false);
467 }
468
469 /**
470 * Returns a string representation of the date which is equal with the timestamp
471 *
472 * @return string
473 */
474 public function __toString()
475 {
476 return $this->toString(null, $this->_locale);
477 }
478
479 /**
480 * Returns a integer representation of the object
481 * But returns false when the given part is no value f.e. Month-Name
482 *
483 * @param string|integer|Zend_Date $part OPTIONAL Defines the date or datepart to return as integer
484 * @return integer|false
485 */
486 public function toValue($part = null)
487 {
488 $result = $this->get($part);
489 if (is_numeric($result)) {
490 return (int)$result;
491 } else {
492 return false;
493 }
494 }
495
496 /**
497 * Returns an array representation of the object
498 *
499 * @return array
500 */
501 public function toArray()
502 {
503 return ['day' => $this->toString(self::DAY_SHORT, 'iso'),
504 'month' => $this->toString(self::MONTH_SHORT, 'iso'),
505 'year' => $this->toString(self::YEAR, 'iso'),
506 'hour' => $this->toString(self::HOUR_SHORT, 'iso'),
507 'minute' => $this->toString(self::MINUTE_SHORT, 'iso'),
508 'second' => $this->toString(self::SECOND_SHORT, 'iso'),
509 'timezone' => $this->toString(self::TIMEZONE, 'iso'),
510 'timestamp' => $this->toString(self::TIMESTAMP, 'iso'),
511 'weekday' => $this->toString(self::WEEKDAY_8601, 'iso'),
512 'dayofyear' => $this->toString(self::DAY_OF_YEAR, 'iso'),
513 'week' => $this->toString(self::WEEK, 'iso'),
514 'gmtsecs' => $this->toString(self::TIMEZONE_SECS, 'iso')];
515 }
516
517 /**
518 * Returns a representation of a date or datepart
519 * This could be for example a localized monthname, the time without date,
520 * the era or only the fractional seconds. There are about 50 different supported date parts.
521 * For a complete list of supported datepart values look into the docu
522 *
523 * @param string $part OPTIONAL Part of the date to return, if null the timestamp is returned
524 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
525 * @return string date or datepart
526 */
527 public function get($part = null, $locale = null)
528 {
529 if ($locale === null) {
530 $locale = $this->getLocale();
531 }
532
533 if (($part !== null) && !defined($part)
534 && ($part != 'ee') && ($part != 'ss') && ($part != 'GG') && ($part != 'MM') && ($part != 'EE') && ($part != 'TT')
535 && Zend_Locale::isLocale($part, null, false)) {
536 $locale = $part;
537 $part = null;
538 }
539
540 if ($part === null) {
541 $part = self::TIMESTAMP;
542 } else if (self::$_options['format_type'] == 'php') {
543 $part = Zend_Locale_Format::convertPhpToIsoFormat($part);
544 }
545
546 return $this->date($this->_toToken($part, $locale), $this->getUnixTimestamp(), false);
547 }
548
549 /**
550 * Internal method to apply tokens
551 *
552 * @param string $part
553 * @param string $locale
554 * @return string
555 */
556 private function _toToken($part, $locale) {
557 // get format tokens
558 $comment = false;
559 $format = '';
560 $orig = '';
561 for ($i = 0; isset($part[$i]); ++$i) {
562 if ($part[$i] == "'") {
563 $comment = $comment ? false : true;
564 if (isset($part[$i+1]) && ($part[$i+1] == "'")) {
565 $comment = $comment ? false : true;
566 $format .= "\\'";
567 ++$i;
568 }
569
570 $orig = '';
571 continue;
572 }
573
574 if ($comment) {
575 $format .= '\\' . $part[$i];
576 $orig = '';
577 } else {
578 $orig .= $part[$i];
579 if (!isset($part[$i+1]) || (isset($orig[0]) && ($orig[0] != $part[$i+1]))) {
580 $format .= $this->_parseIsoToDate($orig, $locale);
581 $orig = '';
582 }
583 }
584 }
585
586 return $format;
587 }
588
589 /**
590 * Internal parsing method
591 *
592 * @param string $token
593 * @param string $locale
594 * @return string
595 */
596 private function _parseIsoToDate($token, $locale) {
597 switch($token) {
598 case self::DAY :
599 return 'd';
600
601 case self::WEEKDAY_SHORT :
602 $weekday = strtolower($this->date('D', $this->getUnixTimestamp(), false));
603 $day = Zend_Locale_Data::getContent($locale, 'day', ['gregorian', 'format', 'wide', $weekday]);
604 return $this->_toComment(iconv_substr($day, 0, 3, 'UTF-8'));
605
606 case self::DAY_SHORT :
607 return 'j';
608
609 case self::WEEKDAY :
610 $weekday = strtolower($this->date('D', $this->getUnixTimestamp(), false));
611 return $this->_toComment(Zend_Locale_Data::getContent($locale, 'day', ['gregorian', 'format', 'wide', $weekday]));
612
613 case self::WEEKDAY_8601 :
614 return 'N';
615
616 case 'ee' :
617 return $this->_toComment(str_pad($this->date('N', $this->getUnixTimestamp(), false), 2, '0', STR_PAD_LEFT));
618
619 case self::DAY_SUFFIX :
620 return 'S';
621
622 case self::WEEKDAY_DIGIT :
623 return 'w';
624
625 case self::DAY_OF_YEAR :
626 return 'z';
627
628 case 'DDD' :
629 return $this->_toComment(str_pad($this->date('z', $this->getUnixTimestamp(), false), 3, '0', STR_PAD_LEFT));
630
631 case 'DD' :
632 return $this->_toComment(str_pad($this->date('z', $this->getUnixTimestamp(), false), 2, '0', STR_PAD_LEFT));
633
634 case self::WEEKDAY_NARROW :
635 case 'EEEEE' :
636 $weekday = strtolower($this->date('D', $this->getUnixTimestamp(), false));
637 $day = Zend_Locale_Data::getContent($locale, 'day', ['gregorian', 'format', 'abbreviated', $weekday]);
638 return $this->_toComment(iconv_substr($day, 0, 1, 'UTF-8'));
639
640 case self::WEEKDAY_NAME :
641 $weekday = strtolower($this->date('D', $this->getUnixTimestamp(), false));
642 return $this->_toComment(Zend_Locale_Data::getContent($locale, 'day', ['gregorian', 'format', 'abbreviated', $weekday]));
643
644 case 'w' :
645 $week = $this->date('W', $this->getUnixTimestamp(), false);
646 return $this->_toComment(($week[0] == '0') ? $week[1] : $week);
647
648 case self::WEEK :
649 return 'W';
650
651 case self::MONTH_NAME :
652 $month = $this->date('n', $this->getUnixTimestamp(), false);
653 return $this->_toComment(Zend_Locale_Data::getContent($locale, 'month', ['gregorian', 'format', 'wide', $month]));
654
655 case self::MONTH :
656 return 'm';
657
658 case self::MONTH_NAME_SHORT :
659 $month = $this->date('n', $this->getUnixTimestamp(), false);
660 return $this->_toComment(Zend_Locale_Data::getContent($locale, 'month', ['gregorian', 'format', 'abbreviated', $month]));
661
662 case self::MONTH_SHORT :
663 return 'n';
664
665 case self::MONTH_DAYS :
666 return 't';
667
668 case self::MONTH_NAME_NARROW :
669 $month = $this->date('n', $this->getUnixTimestamp(), false);
670 $mon = Zend_Locale_Data::getContent($locale, 'month', ['gregorian', 'format', 'abbreviated', $month]);
671 return $this->_toComment(iconv_substr($mon, 0, 1, 'UTF-8'));
672
673 case self::LEAPYEAR :
674 return 'L';
675
676 case self::YEAR_8601 :
677 return 'o';
678
679 case self::YEAR :
680 return 'Y';
681
682 case self::YEAR_SHORT :
683 return 'y';
684
685 case self::YEAR_SHORT_8601 :
686 return $this->_toComment(substr($this->date('o', $this->getUnixTimestamp(), false), -2, 2));
687
688 case self::MERIDIEM :
689 $am = $this->date('a', $this->getUnixTimestamp(), false);
690 if ($am == 'am') {
691 return $this->_toComment(Zend_Locale_Data::getContent($locale, 'am'));
692 }
693
694 return $this->_toComment(Zend_Locale_Data::getContent($locale, 'pm'));
695
696 case self::SWATCH :
697 return 'B';
698
699 case self::HOUR_SHORT_AM :
700 return 'g';
701
702 case self::HOUR_SHORT :
703 return 'G';
704
705 case self::HOUR_AM :
706 return 'h';
707
708 case self::HOUR :
709 return 'H';
710
711 case self::MINUTE :
712 return $this->_toComment(str_pad($this->date('i', $this->getUnixTimestamp(), false), 2, '0', STR_PAD_LEFT));
713
714 case self::SECOND :
715 return $this->_toComment(str_pad($this->date('s', $this->getUnixTimestamp(), false), 2, '0', STR_PAD_LEFT));
716
717 case self::MINUTE_SHORT :
718 return 'i';
719
720 case self::SECOND_SHORT :
721 return 's';
722
723 case self::MILLISECOND :
724 return $this->_toComment($this->getMilliSecond());
725
726 case self::TIMEZONE_NAME :
727 case 'vvvv' :
728 return 'e';
729
730 case self::DAYLIGHT :
731 return 'I';
732
733 case self::GMT_DIFF :
734 case 'ZZ' :
735 case 'ZZZ' :
736 return 'O';
737
738 case self::GMT_DIFF_SEP :
739 return 'P';
740
741 case self::TIMEZONE :
742 case 'v' :
743 case 'zz' :
744 case 'zzz' :
745 return 'T';
746
747 case self::TIMEZONE_SECS :
748 return 'Z';
749
750 case self::ISO_8601 :
751 return 'c';
752
753 case self::RFC_2822 :
754 return 'r';
755
756 case self::TIMESTAMP :
757 return 'U';
758
759 case self::ERA :
760 case 'GG' :
761 case 'GGG' :
762 $year = $this->date('Y', $this->getUnixTimestamp(), false);
763 if ($year < 0) {
764 return $this->_toComment(Zend_Locale_Data::getContent($locale, 'era', ['gregorian', 'Abbr', '0']));
765 }
766
767 return $this->_toComment(Zend_Locale_Data::getContent($locale, 'era', ['gregorian', 'Abbr', '1']));
768
769 case self::ERA_NARROW :
770 $year = $this->date('Y', $this->getUnixTimestamp(), false);
771 if ($year < 0) {
772 return $this->_toComment(iconv_substr(Zend_Locale_Data::getContent($locale, 'era', ['gregorian', 'Abbr', '0']), 0, 1, 'UTF-8')) . '.';
773 }
774
775 return $this->_toComment(iconv_substr(Zend_Locale_Data::getContent($locale, 'era', ['gregorian', 'Abbr', '1']), 0, 1, 'UTF-8')) . '.';
776
777 case self::ERA_NAME :
778 $year = $this->date('Y', $this->getUnixTimestamp(), false);
779 if ($year < 0) {
780 return $this->_toComment(Zend_Locale_Data::getContent($locale, 'era', ['gregorian', 'Names', '0']));
781 }
782
783 return $this->_toComment(Zend_Locale_Data::getContent($locale, 'era', ['gregorian', 'Names', '1']));
784
785 case self::DATES :
786 return $this->_toToken(Zend_Locale_Format::getDateFormat($locale), $locale);
787
788 case self::DATE_FULL :
789 return $this->_toToken(Zend_Locale_Data::getContent($locale, 'date', ['gregorian', 'full']), $locale);
790
791 case self::DATE_LONG :
792 return $this->_toToken(Zend_Locale_Data::getContent($locale, 'date', ['gregorian', 'long']), $locale);
793
794 case self::DATE_MEDIUM :
795 return $this->_toToken(Zend_Locale_Data::getContent($locale, 'date', ['gregorian', 'medium']), $locale);
796
797 case self::DATE_SHORT :
798 return $this->_toToken(Zend_Locale_Data::getContent($locale, 'date', ['gregorian', 'short']), $locale);
799
800 case self::TIMES :
801 return $this->_toToken(Zend_Locale_Format::getTimeFormat($locale), $locale);
802
803 case self::TIME_FULL :
804 return $this->_toToken(Zend_Locale_Data::getContent($locale, 'time', 'full'), $locale);
805
806 case self::TIME_LONG :
807 return $this->_toToken(Zend_Locale_Data::getContent($locale, 'time', 'long'), $locale);
808
809 case self::TIME_MEDIUM :
810 return $this->_toToken(Zend_Locale_Data::getContent($locale, 'time', 'medium'), $locale);
811
812 case self::TIME_SHORT :
813 return $this->_toToken(Zend_Locale_Data::getContent($locale, 'time', 'short'), $locale);
814
815 case self::DATETIME :
816 return $this->_toToken(Zend_Locale_Format::getDateTimeFormat($locale), $locale);
817
818 case self::DATETIME_FULL :
819 return $this->_toToken(Zend_Locale_Data::getContent($locale, 'datetime', ['gregorian', 'full']), $locale);
820
821 case self::DATETIME_LONG :
822 return $this->_toToken(Zend_Locale_Data::getContent($locale, 'datetime', ['gregorian', 'long']), $locale);
823
824 case self::DATETIME_MEDIUM :
825 return $this->_toToken(Zend_Locale_Data::getContent($locale, 'datetime', ['gregorian', 'medium']), $locale);
826
827 case self::DATETIME_SHORT :
828 return $this->_toToken(Zend_Locale_Data::getContent($locale, 'datetime', ['gregorian', 'short']), $locale);
829
830 case self::ATOM :
831 return 'Y\-m\-d\TH\:i\:sP';
832
833 case self::COOKIE :
834 return 'l\, d\-M\-y H\:i\:s e';
835
836 case self::RFC_822 :
837 return 'D\, d M y H\:i\:s O';
838
839 case self::RFC_850 :
840 return 'l\, d\-M\-y H\:i\:s e';
841
842 case self::RFC_1036 :
843 return 'D\, d M y H\:i\:s O';
844
845 case self::RFC_1123 :
846 return 'D\, d M Y H\:i\:s O';
847
848 case self::RFC_3339 :
849 return 'Y\-m\-d\TH\:i\:sP';
850
851 case self::RSS :
852 return 'D\, d M Y H\:i\:s O';
853
854 case self::W3C :
855 return 'Y\-m\-d\TH\:i\:sP';
856 }
857
858 if ($token == '') {
859 return '';
860 }
861
862 switch ($token[0]) {
863 case 'y' :
864 if ((strlen($token) === 4) && (abs($this->getUnixTimestamp()) <= 0x7FFFFFFF)) {
865 return 'Y';
866 }
867
868 $length = iconv_strlen($token, 'UTF-8');
869 return $this->_toComment(str_pad($this->date('Y', $this->getUnixTimestamp(), false), $length, '0', STR_PAD_LEFT));
870
871 case 'Y' :
872 if ((strlen($token) === 4) && (abs($this->getUnixTimestamp()) <= 0x7FFFFFFF)) {
873 return 'o';
874 }
875
876 $length = iconv_strlen($token, 'UTF-8');
877 return $this->_toComment(str_pad($this->date('o', $this->getUnixTimestamp(), false), $length, '0', STR_PAD_LEFT));
878
879 case 'A' :
880 $length = iconv_strlen($token, 'UTF-8');
881 $result = substr($this->getMilliSecond(), 0, 3);
882 $result += $this->date('s', $this->getUnixTimestamp(), false) * 1000;
883 $result += $this->date('i', $this->getUnixTimestamp(), false) * 60000;
884 $result += $this->date('H', $this->getUnixTimestamp(), false) * 3600000;
885
886 return $this->_toComment(str_pad($result, $length, '0', STR_PAD_LEFT));
887 }
888
889 return $this->_toComment($token);
890 }
891
892 /**
893 * Private function to make a comment of a token
894 *
895 * @param string $token
896 * @return string
897 */
898 private function _toComment($token)
899 {
900 $token = str_split($token);
901 $result = '';
902 foreach ($token as $tok) {
903 $result .= '\\' . $tok;
904 }
905
906 return $result;
907 }
908
909 /**
910 * Return digit from standard names (english)
911 * Faster implementation than locale aware searching
912 *
913 * @param string $name
914 * @return integer Number of this month
915 * @throws Zend_Date_Exception
916 */
917 private function _getDigitFromName($name)
918 {
919 switch($name) {
920 case "Jan":
921 return 1;
922
923 case "Feb":
924 return 2;
925
926 case "Mar":
927 return 3;
928
929 case "Apr":
930 return 4;
931
932 case "May":
933 return 5;
934
935 case "Jun":
936 return 6;
937
938 case "Jul":
939 return 7;
940
941 case "Aug":
942 return 8;
943
944 case "Sep":
945 return 9;
946
947 case "Oct":
948 return 10;
949
950 case "Nov":
951 return 11;
952
953 case "Dec":
954 return 12;
955
956 default:
957 require_once 'Zend/Date/Exception.php';
958 throw new Zend_Date_Exception('Month ($name) is not a known month');
959 }
960 }
961
962 /**
963 * Counts the exact year number
964 * < 70 - 2000 added, >70 < 100 - 1900, others just returned
965 *
966 * @param integer $value year number
967 * @return integer Number of year
968 */
969 public static function getFullYear($value)
970 {
971 if ($value >= 0) {
972 if ($value < 70) {
973 $value += 2000;
974 } else if ($value < 100) {
975 $value += 1900;
976 }
977 }
978 return $value;
979 }
980
981 /**
982 * Sets the given date as new date or a given datepart as new datepart returning the new datepart
983 * This could be for example a localized dayname, the date without time,
984 * the month or only the seconds. There are about 50 different supported date parts.
985 * For a complete list of supported datepart values look into the docu
986 *
987 * @param string|integer|array|Zend_Date $date Date or datepart to set
988 * @param string $part OPTIONAL Part of the date to set, if null the timestamp is set
989 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
990 * @return $this
991 * @throws Zend_Date_Exception
992 */
993 public function set($date, $part = null, $locale = null)
994 {
995 if (self::$_options['format_type'] == 'php') {
996 $part = Zend_Locale_Format::convertPhpToIsoFormat($part);
997 }
998
999 $zone = $this->getTimezoneFromString($date);
1000 $this->setTimezone($zone);
1001
1002 $this->_calculate('set', $date, $part, $locale);
1003 return $this;
1004 }
1005
1006 /**
1007 * Adds a date or datepart to the existing date, by extracting $part from $date,
1008 * and modifying this object by adding that part. The $part is then extracted from
1009 * this object and returned as an integer or numeric string (for large values, or $part's
1010 * corresponding to pre-defined formatted date strings).
1011 * This could be for example a ISO 8601 date, the hour the monthname or only the minute.
1012 * There are about 50 different supported date parts.
1013 * For a complete list of supported datepart values look into the docu.
1014 *
1015 * @param string|integer|array|Zend_Date $date Date or datepart to add
1016 * @param string $part OPTIONAL Part of the date to add, if null the timestamp is added
1017 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
1018 * @return $this
1019 * @throws Zend_Date_Exception
1020 */
1021 public function add($date, $part = self::TIMESTAMP, $locale = null)
1022 {
1023 if (self::$_options['format_type'] == 'php') {
1024 $part = Zend_Locale_Format::convertPhpToIsoFormat($part);
1025 }
1026
1027 $this->_calculate('add', $date, $part, $locale);
1028 return $this;
1029 }
1030
1031 /**
1032 * Subtracts a date from another date.
1033 * This could be for example a RFC2822 date, the time,
1034 * the year or only the timestamp. There are about 50 different supported date parts.
1035 * For a complete list of supported datepart values look into the docu
1036 * Be aware: Adding -2 Months is not equal to Subtracting 2 Months !!!
1037 *
1038 * @param string|integer|array|Zend_Date $date Date or datepart to subtract
1039 * @param string $part OPTIONAL Part of the date to sub, if null the timestamp is subtracted
1040 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
1041 * @return $this
1042 * @throws Zend_Date_Exception
1043 */
1044 public function sub($date, $part = self::TIMESTAMP, $locale = null)
1045 {
1046 if (self::$_options['format_type'] == 'php') {
1047 $part = Zend_Locale_Format::convertPhpToIsoFormat($part);
1048 }
1049
1050 $this->_calculate('sub', $date, $part, $locale);
1051 return $this;
1052 }
1053
1054 /**
1055 * Compares a date or datepart with the existing one.
1056 * Returns -1 if earlier, 0 if equal and 1 if later.
1057 *
1058 * @param string|integer|array|Zend_Date $date Date or datepart to compare with the date object
1059 * @param string $part OPTIONAL Part of the date to compare, if null the timestamp is subtracted
1060 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
1061 * @return integer 0 = equal, 1 = later, -1 = earlier
1062 * @throws Zend_Date_Exception
1063 */
1064 public function compare($date, $part = self::TIMESTAMP, $locale = null)
1065 {
1066 if (self::$_options['format_type'] == 'php') {
1067 $part = Zend_Locale_Format::convertPhpToIsoFormat($part);
1068 }
1069
1070 $compare = $this->_calculate('cmp', $date, $part, $locale);
1071
1072 if ($compare > 0) {
1073 return 1;
1074 } else if ($compare < 0) {
1075 return -1;
1076 }
1077 return 0;
1078 }
1079
1080 /**
1081 * Returns a new instance of Zend_Date with the selected part copied.
1082 * To make an exact copy, use PHP's clone keyword.
1083 * For a complete list of supported date part values look into the docu.
1084 * If a date part is copied, all other date parts are set to standard values.
1085 * For example: If only YEAR is copied, the returned date object is equal to
1086 * 01-01-YEAR 00:00:00 (01-01-1970 00:00:00 is equal to timestamp 0)
1087 * If only HOUR is copied, the returned date object is equal to
1088 * 01-01-1970 HOUR:00:00 (so $this contains a timestamp equal to a timestamp of 0 plus HOUR).
1089 *
1090 * @param string $part Part of the date to compare, if null the timestamp is subtracted
1091 * @param string|Zend_Locale $locale OPTIONAL New object's locale. No adjustments to timezone are made.
1092 * @return Zend_Date New clone with requested part
1093 */
1094 public function copyPart($part, $locale = null)
1095 {
1096 $clone = clone $this; // copy all instance variables
1097 $clone->setUnixTimestamp(0); // except the timestamp
1098 if ($locale != null) {
1099 $clone->setLocale($locale); // set an other locale if selected
1100 }
1101 $clone->set($this, $part);
1102 return $clone;
1103 }
1104
1105 /**
1106 * Internal function, returns the offset of a given timezone
1107 *
1108 * @param string $zone
1109 * @return integer
1110 */
1111 public function getTimezoneFromString($zone)
1112 {
1113 if (is_array($zone)) {
1114 return $this->getTimezone();
1115 }
1116
1117 if ($zone instanceof Zend_Date) {
1118 return $zone->getTimezone();
1119 }
1120
1121 $match = [];
1122 preg_match('/\dZ$/', (string) $zone, $match);
1123 if (!empty($match)) {
1124 return "Etc/UTC";
1125 }
1126
1127 preg_match('/([+-]\d{2}):{0,1}\d{2}/', (string) $zone, $match);
1128 if (!empty($match) && ($match[count($match) - 1] <= 14) && ($match[count($match) - 1] >= -12)) {
1129 $zone = "Etc/GMT";
1130 $zone .= ($match[count($match) - 1] < 0) ? "+" : "-";
1131 $zone .= (int) abs($match[count($match) - 1]);
1132 return $zone;
1133 }
1134
1135 preg_match('/([[:alpha:]\/_-]{3,30})(?!.*([[:alpha:]\/_-]{3,30}))/', (string) $zone, $match);
1136 try {
1137 if (!empty($match) && (!is_int($match[count($match) - 1]))) {
1138 $oldzone = $this->getTimezone();
1139 $this->setTimezone($match[count($match) - 1]);
1140 $result = $this->getTimezone();
1141 $this->setTimezone($oldzone);
1142 if ($result !== $oldzone) {
1143 return $match[count($match) - 1];
1144 }
1145 }
1146 } catch (Exception $e) {
1147 // fall through
1148 }
1149
1150 return $this->getTimezone();
1151 }
1152
1153 /**
1154 * Calculates the date or object
1155 *
1156 * @param string $calc Calculation to make
1157 * @param string|integer $date Date for calculation
1158 * @param string|integer $comp Second date for calculation
1159 * @param boolean|integer $dst Use dst correction if option is set
1160 * @return integer|string|Zend_Date new timestamp or Zend_Date depending on calculation
1161 */
1162 private function _assign($calc, $date, $comp = 0, $dst = false)
1163 {
1164 switch ($calc) {
1165 case 'set' :
1166 if (!empty($comp)) {
1167 $this->setUnixTimestamp(call_user_func(Zend_Locale_Math::$sub, $this->getUnixTimestamp(), $comp));
1168 }
1169 $this->setUnixTimestamp(call_user_func(Zend_Locale_Math::$add, $this->getUnixTimestamp(), $date));
1170 $value = $this->getUnixTimestamp();
1171 break;
1172 case 'add' :
1173 $this->setUnixTimestamp(call_user_func(Zend_Locale_Math::$add, $this->getUnixTimestamp(), $date));
1174 $value = $this->getUnixTimestamp();
1175 break;
1176 case 'sub' :
1177 $this->setUnixTimestamp(call_user_func(Zend_Locale_Math::$sub, $this->getUnixTimestamp(), $date));
1178 $value = $this->getUnixTimestamp();
1179 break;
1180 default :
1181 // cmp - compare
1182 return call_user_func(Zend_Locale_Math::$comp, $comp, $date);
1183 }
1184
1185 // dst-correction if 'fix_dst' = true and dst !== false but only for non UTC and non GMT
1186 if ((self::$_options['fix_dst'] === true) && ($dst !== false) && ($this->_dst === true)) {
1187 $hour = $this->toString(self::HOUR, 'iso');
1188 if ($hour != $dst) {
1189 if (($dst == ($hour + 1)) || ($dst == ($hour - 23))) {
1190 $value += 3600;
1191 } else if (($dst == ($hour - 1)) || ($dst == ($hour + 23))) {
1192 $value -= 3600;
1193 }
1194 $this->setUnixTimestamp($value);
1195 }
1196 }
1197 return $this->getUnixTimestamp();
1198 }
1199
1200
1201 /**
1202 * Calculates the date or object
1203 *
1204 * @param string $calc Calculation to make, one of: 'add'|'sub'|'cmp'|'copy'|'set'
1205 * @param string|integer|array|Zend_Date $date Date or datepart to calculate with
1206 * @param string $part Part of the date to calculate, if null the timestamp is used
1207 * @param string|Zend_Locale $locale Locale for parsing input
1208 * @return integer|string|Zend_Date new timestamp
1209 * @throws Zend_Date_Exception
1210 */
1211 private function _calculate($calc, $date, $part, $locale)
1212 {
1213 if ($date === null) {
1214 require_once 'Zend/Date/Exception.php';
1215 throw new Zend_Date_Exception('parameter $date must be set, null is not allowed');
1216 }
1217
1218 if (($part !== null) && (strlen($part) !== 2) && (Zend_Locale::isLocale($part, null, false))) {
1219 $locale = $part;
1220 $part = null;
1221 }
1222
1223 if ($locale === null) {
1224 $locale = $this->getLocale();
1225 }
1226
1227 $locale = (string) $locale;
1228
1229 // Create date parts
1230 $year = $this->toString(self::YEAR, 'iso');
1231 $month = $this->toString(self::MONTH_SHORT, 'iso');
1232 $day = $this->toString(self::DAY_SHORT, 'iso');
1233 $hour = $this->toString(self::HOUR_SHORT, 'iso');
1234 $minute = $this->toString(self::MINUTE_SHORT, 'iso');
1235 $second = $this->toString(self::SECOND_SHORT, 'iso');
1236 // If object extract value
1237 if ($date instanceof Zend_Date) {
1238 $date = $date->toString($part, 'iso', $locale);
1239 }
1240
1241 if (is_array($date) === true) {
1242 if (empty($part) === false) {
1243 switch($part) {
1244 // Fall through
1245 case self::DAY:
1246 case self::DAY_SHORT:
1247 if (isset($date['day']) === true) {
1248 $date = $date['day'];
1249 }
1250 break;
1251 // Fall through
1252 case self::WEEKDAY_SHORT:
1253 case self::WEEKDAY:
1254 case self::WEEKDAY_8601:
1255 case self::WEEKDAY_DIGIT:
1256 case self::WEEKDAY_NARROW:
1257 case self::WEEKDAY_NAME:
1258 if (isset($date['weekday']) === true) {
1259 $date = $date['weekday'];
1260 $part = self::WEEKDAY_DIGIT;
1261 }
1262 break;
1263 case self::DAY_OF_YEAR:
1264 if (isset($date['day_of_year']) === true) {
1265 $date = $date['day_of_year'];
1266 }
1267 break;
1268 // Fall through
1269 case self::MONTH:
1270 case self::MONTH_SHORT:
1271 case self::MONTH_NAME:
1272 case self::MONTH_NAME_SHORT:
1273 case self::MONTH_NAME_NARROW:
1274 if (isset($date['month']) === true) {
1275 $date = $date['month'];
1276 }
1277 break;
1278 // Fall through
1279 case self::YEAR:
1280 case self::YEAR_SHORT:
1281 case self::YEAR_8601:
1282 case self::YEAR_SHORT_8601:
1283 if (isset($date['year']) === true) {
1284 $date = $date['year'];
1285 }
1286 break;
1287 // Fall through
1288 case self::HOUR:
1289 case self::HOUR_AM:
1290 case self::HOUR_SHORT:
1291 case self::HOUR_SHORT_AM:
1292 if (isset($date['hour']) === true) {
1293 $date = $date['hour'];
1294 }
1295 break;
1296 // Fall through
1297 case self::MINUTE:
1298 case self::MINUTE_SHORT:
1299 if (isset($date['minute']) === true) {
1300 $date = $date['minute'];
1301 }
1302 break;
1303 // Fall through
1304 case self::SECOND:
1305 case self::SECOND_SHORT:
1306 if (isset($date['second']) === true) {
1307 $date = $date['second'];
1308 }
1309 break;
1310 // Fall through
1311 case self::TIMEZONE:
1312 case self::TIMEZONE_NAME:
1313 if (isset($date['timezone']) === true) {
1314 $date = $date['timezone'];
1315 }
1316 break;
1317 case self::TIMESTAMP:
1318 if (isset($date['timestamp']) === true) {
1319 $date = $date['timestamp'];
1320 }
1321 break;
1322 case self::WEEK:
1323 if (isset($date['week']) === true) {
1324 $date = $date['week'];
1325 }
1326 break;
1327 case self::TIMEZONE_SECS:
1328 if (isset($date['gmtsecs']) === true) {
1329 $date = $date['gmtsecs'];
1330 }
1331 break;
1332 default:
1333 require_once 'Zend/Date/Exception.php';
1334 throw new Zend_Date_Exception("datepart for part ($part) not found in array");
1335 }
1336 } else {
1337 $hours = 0;
1338 if (isset($date['hour']) === true) {
1339 $hours = $date['hour'];
1340 }
1341 $minutes = 0;
1342 if (isset($date['minute']) === true) {
1343 $minutes = $date['minute'];
1344 }
1345 $seconds = 0;
1346 if (isset($date['second']) === true) {
1347 $seconds = $date['second'];
1348 }
1349 $months = 0;
1350 if (isset($date['month']) === true) {
1351 $months = $date['month'];
1352 }
1353 $days = 0;
1354 if (isset($date['day']) === true) {
1355 $days = $date['day'];
1356 }
1357 $years = 0;
1358 if (isset($date['year']) === true) {
1359 $years = $date['year'];
1360 }
1361 return $this->_assign($calc, $this->mktime($hours, $minutes, $seconds, $months, $days, $years, true),
1362 $this->mktime($hour, $minute, $second, $month, $day, $year, true), $hour);
1363 }
1364 }
1365
1366 // $date as object, part of foreign date as own date
1367 switch($part) {
1368
1369 // day formats
1370 case self::DAY:
1371 if (is_numeric($date)) {
1372 return $this->_assign($calc, $this->mktime(0, 0, 0, 1, 1 + (int)$date, 1970, true),
1373 $this->mktime(0, 0, 0, 1, 1 + (int)$day, 1970, true), $hour);
1374 }
1375
1376 require_once 'Zend/Date/Exception.php';
1377 throw new Zend_Date_Exception("invalid date ($date) operand, day expected", 0, null, $date);
1378
1379 case self::WEEKDAY_SHORT:
1380 $daylist = Zend_Locale_Data::getList($locale, 'day');
1381 $weekday = (int) $this->toString(self::WEEKDAY_DIGIT, 'iso', $locale);
1382 $cnt = 0;
1383
1384 foreach ($daylist as $key => $value) {
1385 if (strtoupper(iconv_substr($value, 0, 3, 'UTF-8')) == strtoupper($date)) {
1386 $found = $cnt;
1387 break;
1388 }
1389 ++$cnt;
1390 }
1391
1392 // Weekday found
1393 if ($cnt < 7) {
1394 return $this->_assign($calc, $this->mktime(0, 0, 0, 1, 1 + $found, 1970, true),
1395 $this->mktime(0, 0, 0, 1, 1 + $weekday, 1970, true), $hour);
1396 }
1397
1398 // Weekday not found
1399 require_once 'Zend/Date/Exception.php';
1400 throw new Zend_Date_Exception("invalid date ($date) operand, weekday expected", 0, null, $date);
1401
1402 case self::DAY_SHORT:
1403 if (is_numeric($date)) {
1404 return $this->_assign($calc, $this->mktime(0, 0, 0, 1, 1 + (int) $date, 1970, true),
1405 $this->mktime(0, 0, 0, 1, 1 + (int) $day, 1970, true), $hour);
1406 }
1407
1408 require_once 'Zend/Date/Exception.php';
1409 throw new Zend_Date_Exception("invalid date ($date) operand, day expected", 0, null, $date);
1410
1411 case self::WEEKDAY:
1412 $daylist = Zend_Locale_Data::getList($locale, 'day');
1413 $weekday = (int) $this->toString(self::WEEKDAY_DIGIT, 'iso', $locale);
1414 $cnt = 0;
1415
1416 foreach ($daylist as $key => $value) {
1417 if (strtoupper($value) == strtoupper($date)) {
1418 $found = $cnt;
1419 break;
1420 }
1421 ++$cnt;
1422 }
1423
1424 // Weekday found
1425 if ($cnt < 7) {
1426 return $this->_assign($calc, $this->mktime(0, 0, 0, 1, 1 + $found, 1970, true),
1427 $this->mktime(0, 0, 0, 1, 1 + $weekday, 1970, true), $hour);
1428 }
1429
1430 // Weekday not found
1431 require_once 'Zend/Date/Exception.php';
1432 throw new Zend_Date_Exception("invalid date ($date) operand, weekday expected", 0, null, $date);
1433
1434 case self::WEEKDAY_8601:
1435 $weekday = (int) $this->toString(self::WEEKDAY_8601, 'iso', $locale);
1436 if ((int)$date < 8 && (int)$date > 0) {
1437 return $this->_assign($calc, $this->mktime(0, 0, 0, 1, 1 + (int) $date, 1970, true),
1438 $this->mktime(0, 0, 0, 1, 1 + $weekday, 1970, true), $hour);
1439 }
1440
1441 // Weekday not found
1442 require_once 'Zend/Date/Exception.php';
1443 throw new Zend_Date_Exception("invalid date ($date) operand, weekday expected", 0, null, $date);
1444
1445 case self::DAY_SUFFIX:
1446 require_once 'Zend/Date/Exception.php';
1447 throw new Zend_Date_Exception('day suffix not supported', 0, null, $date);
1448
1449 case self::WEEKDAY_DIGIT:
1450 $weekday = (int) $this->toString(self::WEEKDAY_DIGIT, 'iso', $locale);
1451 if (is_numeric($date) && (int)$date >= 0 && (int)$date < 7) {
1452 return $this->_assign($calc, $this->mktime(0, 0, 0, 1, 1 + $date, 1970, true),
1453 $this->mktime(0, 0, 0, 1, 1 + $weekday, 1970, true), $hour);
1454 }
1455
1456 // Weekday not found
1457 require_once 'Zend/Date/Exception.php';
1458 throw new Zend_Date_Exception("invalid date ($date) operand, weekday expected", 0, null, $date);
1459
1460 case self::DAY_OF_YEAR:
1461 if (is_numeric($date)) {
1462 if (($calc == 'add') || ($calc == 'sub')) {
1463 $year = 1970;
1464 ++$date;
1465 ++$day;
1466 }
1467
1468 return $this->_assign($calc, $this->mktime(0, 0, 0, 1, $date, $year, true),
1469 $this->mktime(0, 0, 0, $month, $day, $year, true), $hour);
1470 }
1471
1472 require_once 'Zend/Date/Exception.php';
1473 throw new Zend_Date_Exception("invalid date ($date) operand, day expected", 0, null, $date);
1474
1475 case self::WEEKDAY_NARROW:
1476 $daylist = Zend_Locale_Data::getList($locale, 'day', ['gregorian', 'format', 'abbreviated']);
1477 $weekday = (int) $this->toString(self::WEEKDAY_DIGIT, 'iso', $locale);
1478 $cnt = 0;
1479 foreach ($daylist as $key => $value) {
1480 if (strtoupper(iconv_substr($value, 0, 1, 'UTF-8')) == strtoupper($date)) {
1481 $found = $cnt;
1482 break;
1483 }
1484 ++$cnt;
1485 }
1486
1487 // Weekday found
1488 if ($cnt < 7) {
1489 return $this->_assign($calc, $this->mktime(0, 0, 0, 1, 1 + $found, 1970, true),
1490 $this->mktime(0, 0, 0, 1, 1 + $weekday, 1970, true), $hour);
1491 }
1492
1493 // Weekday not found
1494 require_once 'Zend/Date/Exception.php';
1495 throw new Zend_Date_Exception("invalid date ($date) operand, weekday expected", 0, null, $date);
1496
1497 case self::WEEKDAY_NAME:
1498 $daylist = Zend_Locale_Data::getList($locale, 'day', ['gregorian', 'format', 'abbreviated']);
1499 $weekday = (int) $this->toString(self::WEEKDAY_DIGIT, 'iso', $locale);
1500 $cnt = 0;
1501 foreach ($daylist as $key => $value) {
1502 if (strtoupper($value) == strtoupper($date)) {
1503 $found = $cnt;
1504 break;
1505 }
1506 ++$cnt;
1507 }
1508
1509 // Weekday found
1510 if ($cnt < 7) {
1511 return $this->_assign($calc, $this->mktime(0, 0, 0, 1, 1 + $found, 1970, true),
1512 $this->mktime(0, 0, 0, 1, 1 + $weekday, 1970, true), $hour);
1513 }
1514
1515 // Weekday not found
1516 require_once 'Zend/Date/Exception.php';
1517 throw new Zend_Date_Exception("invalid date ($date) operand, weekday expected", 0, null, $date);
1518
1519 // week formats
1520 case self::WEEK:
1521 if (is_numeric($date)) {
1522 $week = (int) $this->toString(self::WEEK, 'iso', $locale);
1523 return $this->_assign($calc, parent::mktime(0, 0, 0, 1, 1 + ($date * 7), 1970, true),
1524 parent::mktime(0, 0, 0, 1, 1 + ($week * 7), 1970, true), $hour);
1525 }
1526
1527 require_once 'Zend/Date/Exception.php';
1528 throw new Zend_Date_Exception("invalid date ($date) operand, week expected", 0, null, $date);
1529
1530 // month formats
1531 case self::MONTH_NAME:
1532 $monthlist = Zend_Locale_Data::getList($locale, 'month');
1533 $cnt = 0;
1534 foreach ($monthlist as $key => $value) {
1535 if (strtoupper($value) == strtoupper($date)) {
1536 $found = $key;
1537 break;
1538 }
1539 ++$cnt;
1540 }
1541 $date = array_search($date, $monthlist);
1542
1543 // Monthname found
1544 if ($cnt < 12) {
1545 $fixday = 0;
1546 if ($calc == 'add') {
1547 $date += $found;
1548 $calc = 'set';
1549 if (self::$_options['extend_month'] == false) {
1550 $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false));
1551 if ($parts['mday'] != $day) {
1552 $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day);
1553 }
1554 }
1555 } else if ($calc == 'sub') {
1556 $date = $month - $found;
1557 $calc = 'set';
1558 if (self::$_options['extend_month'] == false) {
1559 $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false));
1560 if ($parts['mday'] != $day) {
1561 $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day);
1562 }
1563 }
1564 }
1565 return $this->_assign($calc, $this->mktime(0, 0, 0, $date, $day + $fixday, $year, true),
1566 $this->mktime(0, 0, 0, $month, $day, $year, true), $hour);
1567 }
1568
1569 // Monthname not found
1570 require_once 'Zend/Date/Exception.php';
1571 throw new Zend_Date_Exception("invalid date ($date) operand, month expected", 0, null, $date);
1572
1573 case self::MONTH:
1574 if (is_numeric($date)) {
1575 $fixday = 0;
1576 if ($calc == 'add') {
1577 $date += $month;
1578 $calc = 'set';
1579 if (self::$_options['extend_month'] == false) {
1580 $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false));
1581 if ($parts['mday'] != $day) {
1582 $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day);
1583 }
1584 }
1585 } else if ($calc == 'sub') {
1586 $date = $month - $date;
1587 $calc = 'set';
1588 if (self::$_options['extend_month'] == false) {
1589 $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false));
1590 if ($parts['mday'] != $day) {
1591 $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day);
1592 }
1593 }
1594 }
1595 return $this->_assign($calc, $this->mktime(0, 0, 0, $date, $day + $fixday, $year, true),
1596 $this->mktime(0, 0, 0, $month, $day, $year, true), $hour);
1597 }
1598
1599 require_once 'Zend/Date/Exception.php';
1600 throw new Zend_Date_Exception("invalid date ($date) operand, month expected", 0, null, $date);
1601
1602 case self::MONTH_NAME_SHORT:
1603 $monthlist = Zend_Locale_Data::getList($locale, 'month', ['gregorian', 'format', 'abbreviated']);
1604 $cnt = 0;
1605 foreach ($monthlist as $key => $value) {
1606 if (strtoupper($value) == strtoupper($date)) {
1607 $found = $key;
1608 break;
1609 }
1610 ++$cnt;
1611 }
1612 $date = array_search($date, $monthlist);
1613
1614 // Monthname found
1615 if ($cnt < 12) {
1616 $fixday = 0;
1617 if ($calc == 'add') {
1618 $date += $found;
1619 $calc = 'set';
1620 if (self::$_options['extend_month'] === false) {
1621 $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false));
1622 if ($parts['mday'] != $day) {
1623 $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day);
1624 }
1625 }
1626 } else if ($calc == 'sub') {
1627 $date = $month - $found;
1628 $calc = 'set';
1629 if (self::$_options['extend_month'] === false) {
1630 $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false));
1631 if ($parts['mday'] != $day) {
1632 $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day);
1633 }
1634 }
1635 }
1636 return $this->_assign($calc, $this->mktime(0, 0, 0, $date, $day + $fixday, $year, true),
1637 $this->mktime(0, 0, 0, $month, $day, $year, true), $hour);
1638 }
1639
1640 // Monthname not found
1641 require_once 'Zend/Date/Exception.php';
1642 throw new Zend_Date_Exception("invalid date ($date) operand, month expected", 0, null, $date);
1643
1644 case self::MONTH_SHORT:
1645 if (is_numeric($date) === true) {
1646 $fixday = 0;
1647 if ($calc === 'add') {
1648 $date += $month;
1649 $calc = 'set';
1650 if (self::$_options['extend_month'] === false) {
1651 $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false));
1652 if ($parts['mday'] != $day) {
1653 $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day);
1654 }
1655 }
1656 } else if ($calc === 'sub') {
1657 $date = $month - $date;
1658 $calc = 'set';
1659 if (self::$_options['extend_month'] === false) {
1660 $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false));
1661 if ($parts['mday'] != $day) {
1662 $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day);
1663 }
1664 }
1665 }
1666
1667 return $this->_assign($calc, $this->mktime(0, 0, 0, $date, $day + $fixday, $year, true),
1668 $this->mktime(0, 0, 0, $month, $day, $year, true), $hour);
1669 }
1670
1671 require_once 'Zend/Date/Exception.php';
1672 throw new Zend_Date_Exception("invalid date ($date) operand, month expected", 0, null, $date);
1673
1674 case self::MONTH_DAYS:
1675 require_once 'Zend/Date/Exception.php';
1676 throw new Zend_Date_Exception('month days not supported', 0, null, $date);
1677
1678 case self::MONTH_NAME_NARROW:
1679 $monthlist = Zend_Locale_Data::getList($locale, 'month', ['gregorian', 'stand-alone', 'narrow']);
1680 $cnt = 0;
1681 foreach ($monthlist as $key => $value) {
1682 if (strtoupper($value) === strtoupper($date)) {
1683 $found = $key;
1684 break;
1685 }
1686 ++$cnt;
1687 }
1688 $date = array_search($date, $monthlist);
1689
1690 // Monthname found
1691 if ($cnt < 12) {
1692 $fixday = 0;
1693 if ($calc === 'add') {
1694 $date += $found;
1695 $calc = 'set';
1696 if (self::$_options['extend_month'] === false) {
1697 $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false));
1698 if ($parts['mday'] != $day) {
1699 $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day);
1700 }
1701 }
1702 } else if ($calc === 'sub') {
1703 $date = $month - $found;
1704 $calc = 'set';
1705 if (self::$_options['extend_month'] === false) {
1706 $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false));
1707 if ($parts['mday'] != $day) {
1708 $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day);
1709 }
1710 }
1711 }
1712 return $this->_assign($calc, $this->mktime(0, 0, 0, $date, $day + $fixday, $year, true),
1713 $this->mktime(0, 0, 0, $month, $day, $year, true), $hour);
1714 }
1715
1716 // Monthname not found
1717 require_once 'Zend/Date/Exception.php';
1718 throw new Zend_Date_Exception("invalid date ($date) operand, month expected", 0, null, $date);
1719
1720 // year formats
1721 case self::LEAPYEAR:
1722 require_once 'Zend/Date/Exception.php';
1723 throw new Zend_Date_Exception('leap year not supported', 0, null, $date);
1724
1725 case self::YEAR_8601:
1726 if (is_numeric($date)) {
1727 if ($calc === 'add') {
1728 $date += $year;
1729 $calc = 'set';
1730 } else if ($calc === 'sub') {
1731 $date = $year - $date;
1732 $calc = 'set';
1733 }
1734
1735 return $this->_assign($calc, $this->mktime(0, 0, 0, $month, $day, (int)$date, true),
1736 $this->mktime(0, 0, 0, $month, $day, $year, true), false);
1737 }
1738
1739 require_once 'Zend/Date/Exception.php';
1740 throw new Zend_Date_Exception("invalid date ($date) operand, year expected", 0, null, $date);
1741
1742 case self::YEAR:
1743 if (is_numeric($date)) {
1744 if ($calc === 'add') {
1745 $date += $year;
1746 $calc = 'set';
1747 } else if ($calc === 'sub') {
1748 $date = $year - $date;
1749 $calc = 'set';
1750 }
1751
1752 return $this->_assign($calc, $this->mktime(0, 0, 0, $month, $day, (int)$date, true),
1753 $this->mktime(0, 0, 0, $month, $day, $year, true), false);
1754 }
1755
1756 require_once 'Zend/Date/Exception.php';
1757 throw new Zend_Date_Exception("invalid date ($date) operand, year expected", 0, null, $date);
1758
1759 case self::YEAR_SHORT:
1760 if (is_numeric($date)) {
1761 $date = (int)$date;
1762 if (($calc == 'set') || ($calc == 'cmp')) {
1763 $date = self::getFullYear($date);
1764 }
1765 if ($calc === 'add') {
1766 $date += $year;
1767 $calc = 'set';
1768 } else if ($calc === 'sub') {
1769 $date = $year - $date;
1770 $calc = 'set';
1771 }
1772
1773 return $this->_assign($calc, $this->mktime(0, 0, 0, $month, $day, $date, true),
1774 $this->mktime(0, 0, 0, $month, $day, $year, true), false);
1775 }
1776
1777 require_once 'Zend/Date/Exception.php';
1778 throw new Zend_Date_Exception("invalid date ($date) operand, year expected", 0, null, $date);
1779
1780 case self::YEAR_SHORT_8601:
1781 if (is_numeric($date)) {
1782 $date = (int)$date;
1783 if (($calc === 'set') || ($calc === 'cmp')) {
1784 $date = self::getFullYear($date);
1785 }
1786 if ($calc === 'add') {
1787 $date += $year;
1788 $calc = 'set';
1789 } else if ($calc === 'sub') {
1790 $date = $year - $date;
1791 $calc = 'set';
1792 }
1793
1794 return $this->_assign($calc, $this->mktime(0, 0, 0, $month, $day, $date, true),
1795 $this->mktime(0, 0, 0, $month, $day, $year, true), false);
1796 }
1797
1798 require_once 'Zend/Date/Exception.php';
1799 throw new Zend_Date_Exception("invalid date ($date) operand, year expected", 0, null, $date);
1800
1801 // time formats
1802 case self::MERIDIEM:
1803 require_once 'Zend/Date/Exception.php';
1804 throw new Zend_Date_Exception('meridiem not supported', 0, null, $date);
1805
1806 case self::SWATCH:
1807 if (is_numeric($date)) {
1808 $rest = (int)$date;
1809 $hours = floor($rest * 24 / 1000);
1810 $rest = $rest - ($hours * 1000 / 24);
1811 $minutes = floor($rest * 1440 / 1000);
1812 $rest = $rest - ($minutes * 1000 / 1440);
1813 $seconds = floor($rest * 86400 / 1000);
1814 return $this->_assign($calc, $this->mktime($hours, $minutes, $seconds, 1, 1, 1970, true),
1815 $this->mktime($hour, $minute, $second, 1, 1, 1970, true), false);
1816 }
1817
1818 require_once 'Zend/Date/Exception.php';
1819 throw new Zend_Date_Exception("invalid date ($date) operand, swatchstamp expected", 0, null, $date);
1820
1821 case self::HOUR_SHORT:
1822 case self::HOUR_SHORT_AM:
1823 if (is_numeric($date)) {
1824 return $this->_assign($calc, $this->mktime((int)$date, 0, 0, 1, 1, 1970, true),
1825 $this->mktime($hour, 0, 0, 1, 1, 1970, true), false);
1826 }
1827
1828 require_once 'Zend/Date/Exception.php';
1829 throw new Zend_Date_Exception("invalid date ($date) operand, hour expected", 0, null, $date);
1830
1831 case self::HOUR_AM:
1832 if (is_numeric($date)) {
1833 return $this->_assign($calc, $this->mktime((int)$date, 0, 0, 1, 1, 1970, true),
1834 $this->mktime($hour, 0, 0, 1, 1, 1970, true), false);
1835 }
1836
1837 require_once 'Zend/Date/Exception.php';
1838 throw new Zend_Date_Exception("invalid date ($date) operand, hour expected", 0, null, $date);
1839
1840 case self::HOUR:
1841 if (is_numeric($date)) {
1842 return $this->_assign($calc, $this->mktime((int)$date, 0, 0, 1, 1, 1970, true),
1843 $this->mktime($hour, 0, 0, 1, 1, 1970, true), false);
1844 }
1845
1846 require_once 'Zend/Date/Exception.php';
1847 throw new Zend_Date_Exception("invalid date ($date) operand, hour expected", 0, null, $date);
1848
1849 case self::MINUTE:
1850 if (is_numeric($date)) {
1851 return $this->_assign($calc, $this->mktime(0, (int)$date, 0, 1, 1, 1970, true),
1852 $this->mktime(0, $minute, 0, 1, 1, 1970, true), false);
1853 }
1854
1855 require_once 'Zend/Date/Exception.php';
1856 throw new Zend_Date_Exception("invalid date ($date) operand, minute expected", 0, null, $date);
1857
1858 case self::SECOND:
1859 if (is_numeric($date)) {
1860 return $this->_assign($calc, $this->mktime(0, 0, (int)$date, 1, 1, 1970, true),
1861 $this->mktime(0, 0, $second, 1, 1, 1970, true), false);
1862 }
1863
1864 require_once 'Zend/Date/Exception.php';
1865 throw new Zend_Date_Exception("invalid date ($date) operand, second expected", 0, null, $date);
1866
1867 case self::MILLISECOND:
1868 if (is_numeric($date)) {
1869 switch($calc) {
1870 case 'set' :
1871 return $this->setMilliSecond($date);
1872 case 'add' :
1873 return $this->addMilliSecond($date);
1874 case 'sub' :
1875 return $this->subMilliSecond($date);
1876 }
1877
1878 return $this->compareMilliSecond($date);
1879 }
1880
1881 require_once 'Zend/Date/Exception.php';
1882 throw new Zend_Date_Exception("invalid date ($date) operand, milliseconds expected", 0, null, $date);
1883
1884 case self::MINUTE_SHORT:
1885 if (is_numeric($date)) {
1886 return $this->_assign($calc, $this->mktime(0, (int)$date, 0, 1, 1, 1970, true),
1887 $this->mktime(0, $minute, 0, 1, 1, 1970, true), false);
1888 }
1889
1890 require_once 'Zend/Date/Exception.php';
1891 throw new Zend_Date_Exception("invalid date ($date) operand, minute expected", 0, null, $date);
1892
1893 case self::SECOND_SHORT:
1894 if (is_numeric($date)) {
1895 return $this->_assign($calc, $this->mktime(0, 0, (int)$date, 1, 1, 1970, true),
1896 $this->mktime(0, 0, $second, 1, 1, 1970, true), false);
1897 }
1898
1899 require_once 'Zend/Date/Exception.php';
1900 throw new Zend_Date_Exception("invalid date ($date) operand, second expected", 0, null, $date);
1901
1902 // timezone formats
1903 // break intentionally omitted
1904 case self::TIMEZONE_NAME:
1905 case self::TIMEZONE:
1906 case self::TIMEZONE_SECS:
1907 require_once 'Zend/Date/Exception.php';
1908 throw new Zend_Date_Exception('timezone not supported', 0, null, $date);
1909
1910 case self::DAYLIGHT:
1911 require_once 'Zend/Date/Exception.php';
1912 throw new Zend_Date_Exception('daylight not supported', 0, null, $date);
1913
1914 case self::GMT_DIFF:
1915 case self::GMT_DIFF_SEP:
1916 require_once 'Zend/Date/Exception.php';
1917 throw new Zend_Date_Exception('gmtdiff not supported', 0, null, $date);
1918
1919 // date strings
1920 case self::ISO_8601:
1921
1922 /////////////////////////////////////////////////
1923 //first validate minimal lengts of given formats
1924
1925 // do we have enough of a date? minimum is Y-MM-dd
1926 if( strpos($date, '-') !== FALSE && strlen($date) <9) {
1927 require_once 'Zend/Date/Exception.php';
1928 throw new Zend_Date_Exception("unsupported ISO8601 format ($date)", 0, null, $date);
1929 }
1930
1931 if( strpos($date, '-') === FALSE && strlen($date) <6) {
1932 require_once 'Zend/Date/Exception.php';
1933 throw new Zend_Date_Exception("unsupported ISO8601 format ($date)", 0, null, $date);
1934 }
1935
1936
1937 // (-)YYYY-MM-dd
1938 preg_match('/^(-{0,1}\d{4})-(\d{2})-(\d{2})/', $date, $datematch);
1939 // (-)YY-MM-dd
1940 if (empty($datematch)) {
1941 preg_match('/^(-{0,1}\d{2})-(\d{2})-(\d{2})/', $date, $datematch);
1942 }
1943 // (-)YYYYMMdd
1944 if (empty($datematch)) {
1945 preg_match('/^(-{0,1}\d{4})(\d{2})(\d{2})/', $date, $datematch);
1946 }
1947 // (-)YYMMdd
1948 if (empty($datematch)) {
1949 preg_match('/^(-{0,1}\d{2})(\d{2})(\d{2})/', $date, $datematch);
1950 }
1951 $tmpdate = $date;
1952 if (!empty($datematch)) {
1953 $dateMatchCharCount = iconv_strlen($datematch[0], 'UTF-8');
1954 $tmpdate = iconv_substr($date,
1955 $dateMatchCharCount,
1956 iconv_strlen($date, 'UTF-8') - $dateMatchCharCount,
1957 'UTF-8');
1958 }
1959 // (T)hh:mm:ss
1960 preg_match('/[T,\s]{0,1}(\d{2}):(\d{2}):(\d{2})/', $tmpdate, $timematch);
1961 // (T)hhmmss
1962 if (empty($timematch)) {
1963 preg_match('/[T,\s]{0,1}(\d{2})(\d{2})(\d{2})/', $tmpdate, $timematch);
1964 }
1965 // (T)hh:mm
1966 if (empty($timematch)) {
1967 preg_match('/[T,\s]{0,1}(\d{2}):(\d{2})/', $tmpdate, $timematch);
1968 }
1969 // (T)hhmm
1970 if (empty($timematch)) {
1971 preg_match('/[T,\s]{0,1}(\d{2})(\d{2})/', $tmpdate, $timematch);
1972 }
1973 if (empty($datematch) && empty($timematch)) {
1974 require_once 'Zend/Date/Exception.php';
1975 throw new Zend_Date_Exception("unsupported ISO8601 format ($date)", 0, null, $date);
1976 }
1977 if (!empty($timematch)) {
1978 $timeMatchCharCount = iconv_strlen($timematch[0], 'UTF-8');
1979 $tmpdate = iconv_substr($tmpdate,
1980 $timeMatchCharCount,
1981 iconv_strlen($tmpdate, 'UTF-8') - $timeMatchCharCount,
1982 'UTF-8');
1983 }
1984 if (empty($datematch)) {
1985 $datematch[1] = 1970;
1986 $datematch[2] = 1;
1987 $datematch[3] = 1;
1988 } else if (iconv_strlen($datematch[1], 'UTF-8') === 2) {
1989 $datematch[1] = self::getFullYear($datematch[1]);
1990 }
1991 if (empty($timematch)) {
1992 $timematch[1] = 0;
1993 $timematch[2] = 0;
1994 $timematch[3] = 0;
1995 }
1996 if (!isset($timematch[3])) {
1997 $timematch[3] = 0;
1998 }
1999
2000 if (($calc == 'set') || ($calc == 'cmp')) {
2001 --$datematch[2];
2002 --$month;
2003 --$datematch[3];
2004 --$day;
2005 $datematch[1] -= 1970;
2006 $year -= 1970;
2007 }
2008 return $this->_assign($calc, $this->mktime($timematch[1], $timematch[2], $timematch[3], 1 + $datematch[2], 1 + $datematch[3], 1970 + $datematch[1], false),
2009 $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, false), false);
2010
2011 case self::RFC_2822:
2012 $result = preg_match('/^\w{3},\s(\d{1,2})\s(\w{3})\s(\d{4})\s'
2013 . '(\d{2}):(\d{2}):{0,1}(\d{0,2})\s([+-]'
2014 . '{1}\d{4}|\w{1,20})$/', $date, $match);
2015
2016 if (!$result) {
2017 require_once 'Zend/Date/Exception.php';
2018 throw new Zend_Date_Exception("no RFC 2822 format ($date)", 0, null, $date);
2019 }
2020
2021 $months = $this->_getDigitFromName($match[2]);
2022
2023 if (($calc == 'set') || ($calc == 'cmp')) {
2024 --$months;
2025 --$month;
2026 --$match[1];
2027 --$day;
2028 $match[3] -= 1970;
2029 $year -= 1970;
2030 }
2031 return $this->_assign($calc, $this->mktime($match[4], $match[5], $match[6], 1 + $months, 1 + $match[1], 1970 + $match[3], false),
2032 $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, false), false);
2033
2034 case self::TIMESTAMP:
2035 if (is_numeric($date)) {
2036 return $this->_assign($calc, $date, $this->getUnixTimestamp());
2037 }
2038
2039 require_once 'Zend/Date/Exception.php';
2040 throw new Zend_Date_Exception("invalid date ($date) operand, timestamp expected", 0, null, $date);
2041
2042 // additional formats
2043 // break intentionally omitted
2044 case self::ERA:
2045 case self::ERA_NAME:
2046 require_once 'Zend/Date/Exception.php';
2047 throw new Zend_Date_Exception('era not supported', 0, null, $date);
2048
2049 case self::DATES:
2050 try {
2051 $parsed = Zend_Locale_Format::getDate($date, ['locale' => $locale, 'format_type' => 'iso', 'fix_date' => true]);
2052
2053 if (($calc == 'set') || ($calc == 'cmp')) {
2054 --$parsed['month'];
2055 --$month;
2056 --$parsed['day'];
2057 --$day;
2058 $parsed['year'] -= 1970;
2059 $year -= 1970;
2060 }
2061
2062 return $this->_assign($calc, $this->mktime(0, 0, 0, 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true),
2063 $this->mktime(0, 0, 0, 1 + $month, 1 + $day, 1970 + $year, true), $hour);
2064 } catch (Zend_Locale_Exception $e) {
2065 require_once 'Zend/Date/Exception.php';
2066 throw new Zend_Date_Exception($e->getMessage(), 0, $e, $date);
2067 }
2068
2069 case self::DATE_FULL:
2070 try {
2071 $format = Zend_Locale_Data::getContent($locale, 'date', ['gregorian', 'full']);
2072 $parsed = Zend_Locale_Format::getDate($date, ['date_format' => $format, 'format_type' => 'iso', 'locale' => $locale]);
2073
2074 if (($calc == 'set') || ($calc == 'cmp')) {
2075 --$parsed['month'];
2076 --$month;
2077 --$parsed['day'];
2078 --$day;
2079 $parsed['year'] -= 1970;
2080 $year -= 1970;
2081 }
2082 return $this->_assign($calc, $this->mktime(0, 0, 0, 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true),
2083 $this->mktime(0, 0, 0, 1 + $month, 1 + $day, 1970 + $year, true), $hour);
2084 } catch (Zend_Locale_Exception $e) {
2085 require_once 'Zend/Date/Exception.php';
2086 throw new Zend_Date_Exception($e->getMessage(), 0, $e, $date);
2087 }
2088
2089 case self::DATE_LONG:
2090 try {
2091 $format = Zend_Locale_Data::getContent($locale, 'date', ['gregorian', 'long']);
2092 $parsed = Zend_Locale_Format::getDate($date, ['date_format' => $format, 'format_type' => 'iso', 'locale' => $locale]);
2093
2094 if (($calc == 'set') || ($calc == 'cmp')){
2095 --$parsed['month'];
2096 --$month;
2097 --$parsed['day'];
2098 --$day;
2099 $parsed['year'] -= 1970;
2100 $year -= 1970;
2101 }
2102 return $this->_assign($calc, $this->mktime(0, 0, 0, 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true),
2103 $this->mktime(0, 0, 0, 1 + $month, 1 + $day, 1970 + $year, true), $hour);
2104 } catch (Zend_Locale_Exception $e) {
2105 require_once 'Zend/Date/Exception.php';
2106 throw new Zend_Date_Exception($e->getMessage(), 0, $e, $date);
2107 }
2108
2109 case self::DATE_MEDIUM:
2110 try {
2111 $format = Zend_Locale_Data::getContent($locale, 'date', ['gregorian', 'medium']);
2112 $parsed = Zend_Locale_Format::getDate($date, ['date_format' => $format, 'format_type' => 'iso', 'locale' => $locale]);
2113
2114 if (($calc == 'set') || ($calc == 'cmp')) {
2115 --$parsed['month'];
2116 --$month;
2117 --$parsed['day'];
2118 --$day;
2119 $parsed['year'] -= 1970;
2120 $year -= 1970;
2121 }
2122 return $this->_assign($calc, $this->mktime(0, 0, 0, 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true),
2123 $this->mktime(0, 0, 0, 1 + $month, 1 + $day, 1970 + $year, true), $hour);
2124 } catch (Zend_Locale_Exception $e) {
2125 require_once 'Zend/Date/Exception.php';
2126 throw new Zend_Date_Exception($e->getMessage(), 0, $e, $date);
2127 }
2128
2129 case self::DATE_SHORT:
2130 try {
2131 $format = Zend_Locale_Data::getContent($locale, 'date', ['gregorian', 'short']);
2132 $parsed = Zend_Locale_Format::getDate($date, ['date_format' => $format, 'format_type' => 'iso', 'locale' => $locale]);
2133
2134 $parsed['year'] = self::getFullYear($parsed['year']);
2135
2136 if (($calc == 'set') || ($calc == 'cmp')) {
2137 --$parsed['month'];
2138 --$month;
2139 --$parsed['day'];
2140 --$day;
2141 $parsed['year'] -= 1970;
2142 $year -= 1970;
2143 }
2144 return $this->_assign($calc, $this->mktime(0, 0, 0, 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true),
2145 $this->mktime(0, 0, 0, 1 + $month, 1 + $day, 1970 + $year, true), $hour);
2146 } catch (Zend_Locale_Exception $e) {
2147 require_once 'Zend/Date/Exception.php';
2148 throw new Zend_Date_Exception($e->getMessage(), 0, $e, $date);
2149 }
2150
2151 case self::TIMES:
2152 try {
2153 if ($calc != 'set') {
2154 $month = 1;
2155 $day = 1;
2156 $year = 1970;
2157 }
2158 $parsed = Zend_Locale_Format::getTime($date, ['locale' => $locale, 'format_type' => 'iso', 'fix_date' => true]);
2159 return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], $month, $day, $year, true),
2160 $this->mktime($hour, $minute, $second, $month, $day, $year, true), false);
2161 } catch (Zend_Locale_Exception $e) {
2162 require_once 'Zend/Date/Exception.php';
2163 throw new Zend_Date_Exception($e->getMessage(), 0, $e, $date);
2164 }
2165
2166 case self::TIME_FULL:
2167 try {
2168 $format = Zend_Locale_Data::getContent($locale, 'time', ['gregorian', 'full']);
2169 $parsed = Zend_Locale_Format::getTime($date, ['date_format' => $format, 'format_type' => 'iso', 'locale' => $locale]);
2170 if ($calc != 'set') {
2171 $month = 1;
2172 $day = 1;
2173 $year = 1970;
2174 }
2175
2176 if (!isset($parsed['second'])) {
2177 $parsed['second'] = 0;
2178 }
2179
2180 return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], $month, $day, $year, true),
2181 $this->mktime($hour, $minute, $second, $month, $day, $year, true), false);
2182 } catch (Zend_Locale_Exception $e) {
2183 require_once 'Zend/Date/Exception.php';
2184 throw new Zend_Date_Exception($e->getMessage(), 0, $e, $date);
2185 }
2186
2187 case self::TIME_LONG:
2188 try {
2189 $format = Zend_Locale_Data::getContent($locale, 'time', ['gregorian', 'long']);
2190 $parsed = Zend_Locale_Format::getTime($date, ['date_format' => $format, 'format_type' => 'iso', 'locale' => $locale]);
2191 if ($calc != 'set') {
2192 $month = 1;
2193 $day = 1;
2194 $year = 1970;
2195 }
2196 return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], $month, $day, $year, true),
2197 $this->mktime($hour, $minute, $second, $month, $day, $year, true), false);
2198 } catch (Zend_Locale_Exception $e) {
2199 require_once 'Zend/Date/Exception.php';
2200 throw new Zend_Date_Exception($e->getMessage(), 0, $e, $date);
2201 }
2202
2203 case self::TIME_MEDIUM:
2204 try {
2205 $format = Zend_Locale_Data::getContent($locale, 'time', ['gregorian', 'medium']);
2206 $parsed = Zend_Locale_Format::getTime($date, ['date_format' => $format, 'format_type' => 'iso', 'locale' => $locale]);
2207 if ($calc != 'set') {
2208 $month = 1;
2209 $day = 1;
2210 $year = 1970;
2211 }
2212 return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], $month, $day, $year, true),
2213 $this->mktime($hour, $minute, $second, $month, $day, $year, true), false);
2214 } catch (Zend_Locale_Exception $e) {
2215 require_once 'Zend/Date/Exception.php';
2216 throw new Zend_Date_Exception($e->getMessage(), 0, $e, $date);
2217 }
2218
2219 case self::TIME_SHORT:
2220 try {
2221 $format = Zend_Locale_Data::getContent($locale, 'time', ['gregorian', 'short']);
2222 $parsed = Zend_Locale_Format::getTime($date, ['date_format' => $format, 'format_type' => 'iso', 'locale' => $locale]);
2223 if ($calc != 'set') {
2224 $month = 1;
2225 $day = 1;
2226 $year = 1970;
2227 }
2228
2229 if (!isset($parsed['second'])) {
2230 $parsed['second'] = 0;
2231 }
2232
2233 return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], $month, $day, $year, true),
2234 $this->mktime($hour, $minute, $second, $month, $day, $year, true), false);
2235 } catch (Zend_Locale_Exception $e) {
2236 require_once 'Zend/Date/Exception.php';
2237 throw new Zend_Date_Exception($e->getMessage(), 0, $e, $date);
2238 }
2239
2240 case self::DATETIME:
2241 try {
2242 $parsed = Zend_Locale_Format::getDateTime($date, ['locale' => $locale, 'format_type' => 'iso', 'fix_date' => true]);
2243 if (($calc == 'set') || ($calc == 'cmp')) {
2244 --$parsed['month'];
2245 --$month;
2246 --$parsed['day'];
2247 --$day;
2248 $parsed['year'] -= 1970;
2249 $year -= 1970;
2250 }
2251 return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true),
2252 $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), $hour);
2253 } catch (Zend_Locale_Exception $e) {
2254 require_once 'Zend/Date/Exception.php';
2255 throw new Zend_Date_Exception($e->getMessage(), 0, $e, $date);
2256 }
2257
2258 case self::DATETIME_FULL:
2259 try {
2260 $format = Zend_Locale_Data::getContent($locale, 'datetime', ['gregorian', 'full']);
2261 $parsed = Zend_Locale_Format::getDateTime($date, ['date_format' => $format, 'format_type' => 'iso', 'locale' => $locale]);
2262
2263 if (($calc == 'set') || ($calc == 'cmp')) {
2264 --$parsed['month'];
2265 --$month;
2266 --$parsed['day'];
2267 --$day;
2268 $parsed['year'] -= 1970;
2269 $year -= 1970;
2270 }
2271
2272 if (!isset($parsed['second'])) {
2273 $parsed['second'] = 0;
2274 }
2275
2276 return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true),
2277 $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), $hour);
2278 } catch (Zend_Locale_Exception $e) {
2279 require_once 'Zend/Date/Exception.php';
2280 throw new Zend_Date_Exception($e->getMessage(), 0, $e, $date);
2281 }
2282
2283 case self::DATETIME_LONG:
2284 try {
2285 $format = Zend_Locale_Data::getContent($locale, 'datetime', ['gregorian', 'long']);
2286 $parsed = Zend_Locale_Format::getDateTime($date, ['date_format' => $format, 'format_type' => 'iso', 'locale' => $locale]);
2287
2288 if (($calc == 'set') || ($calc == 'cmp')){
2289 --$parsed['month'];
2290 --$month;
2291 --$parsed['day'];
2292 --$day;
2293 $parsed['year'] -= 1970;
2294 $year -= 1970;
2295 }
2296 return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true),
2297 $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), $hour);
2298 } catch (Zend_Locale_Exception $e) {
2299 require_once 'Zend/Date/Exception.php';
2300 throw new Zend_Date_Exception($e->getMessage(), 0, $e, $date);
2301 }
2302
2303 case self::DATETIME_MEDIUM:
2304 try {
2305 $format = Zend_Locale_Data::getContent($locale, 'datetime', ['gregorian', 'medium']);
2306 $parsed = Zend_Locale_Format::getDateTime($date, ['date_format' => $format, 'format_type' => 'iso', 'locale' => $locale]);
2307 if (($calc == 'set') || ($calc == 'cmp')) {
2308 --$parsed['month'];
2309 --$month;
2310 --$parsed['day'];
2311 --$day;
2312 $parsed['year'] -= 1970;
2313 $year -= 1970;
2314 }
2315 return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true),
2316 $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), $hour);
2317 } catch (Zend_Locale_Exception $e) {
2318 require_once 'Zend/Date/Exception.php';
2319 throw new Zend_Date_Exception($e->getMessage(), 0, $e, $date);
2320 }
2321
2322 case self::DATETIME_SHORT:
2323 try {
2324 $format = Zend_Locale_Data::getContent($locale, 'datetime', ['gregorian', 'short']);
2325 $parsed = Zend_Locale_Format::getDateTime($date, ['date_format' => $format, 'format_type' => 'iso', 'locale' => $locale]);
2326
2327 $parsed['year'] = self::getFullYear($parsed['year']);
2328
2329 if (($calc == 'set') || ($calc == 'cmp')) {
2330 --$parsed['month'];
2331 --$month;
2332 --$parsed['day'];
2333 --$day;
2334 $parsed['year'] -= 1970;
2335 $year -= 1970;
2336 }
2337
2338 if (!isset($parsed['second'])) {
2339 $parsed['second'] = 0;
2340 }
2341
2342 return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true),
2343 $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), $hour);
2344 } catch (Zend_Locale_Exception $e) {
2345 require_once 'Zend/Date/Exception.php';
2346 throw new Zend_Date_Exception($e->getMessage(), 0, $e, $date);
2347 }
2348
2349 // ATOM and RFC_3339 are identical
2350 case self::ATOM:
2351 case self::RFC_3339:
2352 $result = preg_match('/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})\d{0,4}([+-]{1}\d{2}:\d{2}|Z)$/', $date, $match);
2353 if (!$result) {
2354 require_once 'Zend/Date/Exception.php';
2355 throw new Zend_Date_Exception("invalid date ($date) operand, ATOM format expected", 0, null, $date);
2356 }
2357
2358 if (($calc == 'set') || ($calc == 'cmp')) {
2359 --$match[2];
2360 --$month;
2361 --$match[3];
2362 --$day;
2363 $match[1] -= 1970;
2364 $year -= 1970;
2365 }
2366 return $this->_assign($calc, $this->mktime($match[4], $match[5], $match[6], 1 + $match[2], 1 + $match[3], 1970 + $match[1], true),
2367 $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), false);
2368
2369 case self::COOKIE:
2370 $result = preg_match("/^\w{6,9},\s(\d{2})-(\w{3})-(\d{2})\s(\d{2}):(\d{2}):(\d{2})\s.{3,20}$/", $date, $match);
2371 if (!$result) {
2372 require_once 'Zend/Date/Exception.php';
2373 throw new Zend_Date_Exception("invalid date ($date) operand, COOKIE format expected", 0, null, $date);
2374 }
2375 $matchStartPos = iconv_strpos($match[0], ' ', 0, 'UTF-8') + 1;
2376 $match[0] = iconv_substr($match[0],
2377 $matchStartPos,
2378 iconv_strlen($match[0], 'UTF-8') - $matchStartPos,
2379 'UTF-8');
2380
2381 $months = $this->_getDigitFromName($match[2]);
2382 $match[3] = self::getFullYear($match[3]);
2383
2384 if (($calc == 'set') || ($calc == 'cmp')) {
2385 --$months;
2386 --$month;
2387 --$match[1];
2388 --$day;
2389 $match[3] -= 1970;
2390 $year -= 1970;
2391 }
2392 return $this->_assign($calc, $this->mktime($match[4], $match[5], $match[6], 1 + $months, 1 + $match[1], 1970 + $match[3], true),
2393 $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), false);
2394
2395 case self::RFC_822:
2396 case self::RFC_1036:
2397 // new RFC 822 format, identical to RFC 1036 standard
2398 $result = preg_match('/^\w{0,3},{0,1}\s{0,1}(\d{1,2})\s(\w{3})\s(\d{2})\s(\d{2}):(\d{2}):{0,1}(\d{0,2})\s([+-]{1}\d{4}|\w{1,20})$/', $date, $match);
2399 if (!$result) {
2400 require_once 'Zend/Date/Exception.php';
2401 throw new Zend_Date_Exception("invalid date ($date) operand, RFC 822 date format expected", 0, null, $date);
2402 }
2403
2404 $months = $this->_getDigitFromName($match[2]);
2405 $match[3] = self::getFullYear($match[3]);
2406
2407 if (($calc == 'set') || ($calc == 'cmp')) {
2408 --$months;
2409 --$month;
2410 --$match[1];
2411 --$day;
2412 $match[3] -= 1970;
2413 $year -= 1970;
2414 }
2415 return $this->_assign($calc, $this->mktime($match[4], $match[5], $match[6], 1 + $months, 1 + $match[1], 1970 + $match[3], false),
2416 $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, false), false);
2417
2418 case self::RFC_850:
2419 $result = preg_match('/^\w{6,9},\s(\d{2})-(\w{3})-(\d{2})\s(\d{2}):(\d{2}):(\d{2})\s.{3,21}$/', $date, $match);
2420 if (!$result) {
2421 require_once 'Zend/Date/Exception.php';
2422 throw new Zend_Date_Exception("invalid date ($date) operand, RFC 850 date format expected", 0, null, $date);
2423 }
2424
2425 $months = $this->_getDigitFromName($match[2]);
2426 $match[3] = self::getFullYear($match[3]);
2427
2428 if (($calc == 'set') || ($calc == 'cmp')) {
2429 --$months;
2430 --$month;
2431 --$match[1];
2432 --$day;
2433 $match[3] -= 1970;
2434 $year -= 1970;
2435 }
2436 return $this->_assign($calc, $this->mktime($match[4], $match[5], $match[6], 1 + $months, 1 + $match[1], 1970 + $match[3], true),
2437 $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), false);
2438
2439 case self::RFC_1123:
2440 $result = preg_match('/^\w{0,3},{0,1}\s{0,1}(\d{1,2})\s(\w{3})\s(\d{2,4})\s(\d{2}):(\d{2}):{0,1}(\d{0,2})\s([+-]{1}\d{4}|\w{1,20})$/', $date, $match);
2441 if (!$result) {
2442 require_once 'Zend/Date/Exception.php';
2443 throw new Zend_Date_Exception("invalid date ($date) operand, RFC 1123 date format expected", 0, null, $date);
2444 }
2445
2446 $months = $this->_getDigitFromName($match[2]);
2447
2448 if (($calc == 'set') || ($calc == 'cmp')) {
2449 --$months;
2450 --$month;
2451 --$match[1];
2452 --$day;
2453 $match[3] -= 1970;
2454 $year -= 1970;
2455 }
2456 return $this->_assign($calc, $this->mktime($match[4], $match[5], $match[6], 1 + $months, 1 + $match[1], 1970 + $match[3], true),
2457 $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), false);
2458
2459 case self::RSS:
2460 $result = preg_match('/^\w{3},\s(\d{2})\s(\w{3})\s(\d{2,4})\s(\d{1,2}):(\d{2}):(\d{2})\s.{1,21}$/', $date, $match);
2461 if (!$result) {
2462 require_once 'Zend/Date/Exception.php';
2463 throw new Zend_Date_Exception("invalid date ($date) operand, RSS date format expected", 0, null, $date);
2464 }
2465
2466 $months = $this->_getDigitFromName($match[2]);
2467 $match[3] = self::getFullYear($match[3]);
2468
2469 if (($calc == 'set') || ($calc == 'cmp')) {
2470 --$months;
2471 --$month;
2472 --$match[1];
2473 --$day;
2474 $match[3] -= 1970;
2475 $year -= 1970;
2476 }
2477 return $this->_assign($calc, $this->mktime($match[4], $match[5], $match[6], 1 + $months, 1 + $match[1], 1970 + $match[3], true),
2478 $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), false);
2479
2480 case self::W3C:
2481 $result = preg_match('/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})[+-]{1}\d{2}:\d{2}$/', $date, $match);
2482 if (!$result) {
2483 require_once 'Zend/Date/Exception.php';
2484 throw new Zend_Date_Exception("invalid date ($date) operand, W3C date format expected", 0, null, $date);
2485 }
2486
2487 if (($calc == 'set') || ($calc == 'cmp')) {
2488 --$match[2];
2489 --$month;
2490 --$match[3];
2491 --$day;
2492 $match[1] -= 1970;
2493 $year -= 1970;
2494 }
2495 return $this->_assign($calc, $this->mktime($match[4], $match[5], $match[6], 1 + $match[2], 1 + $match[3], 1970 + $match[1], true),
2496 $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), false);
2497
2498 default:
2499 if (!is_numeric($date) || !empty($part)) {
2500 try {
2501 if (empty($part)) {
2502 $part = Zend_Locale_Format::getDateFormat($locale) . " ";
2503 $part .= Zend_Locale_Format::getTimeFormat($locale);
2504 }
2505
2506 $parsed = Zend_Locale_Format::getDate($date, ['date_format' => $part, 'locale' => $locale, 'fix_date' => true, 'format_type' => 'iso']);
2507 if ((strpos(strtoupper($part), 'YY') !== false) && (strpos(strtoupper($part), 'YYYY') === false)) {
2508 $parsed['year'] = self::getFullYear($parsed['year']);
2509 }
2510
2511 if (($calc == 'set') || ($calc == 'cmp')) {
2512 if (isset($parsed['month']) && is_numeric($parsed['month']) && $parsed['month'] > 0) {
2513 $parsed['month'] = (int) str_decrement(ltrim((string) $parsed['month'], '0'));
2514 } else {
2515 $parsed['month'] = 0;
2516 }
2517
2518 if (isset($parsed['day']) && is_numeric($parsed['day']) && $parsed['day'] > 0) {
2519 $parsed['day'] = (int) str_decrement(ltrim((string) $parsed['day'], '0'));
2520 } else {
2521 $parsed['day'] = 0;
2522 }
2523
2524 if (!isset($parsed['year'])) {
2525 $parsed['year'] = 1970;
2526 }
2527 }
2528
2529 return $this->_assign($calc, $this->mktime(
2530 isset($parsed['hour']) ? $parsed['hour'] : 0,
2531 isset($parsed['minute']) ? $parsed['minute'] : 0,
2532 isset($parsed['second']) ? $parsed['second'] : 0,
2533 isset($parsed['month']) ? (1 + $parsed['month']) : 1,
2534 isset($parsed['day']) ? (1 + $parsed['day']) : 1,
2535 $parsed['year'],
2536 false), $this->getUnixTimestamp(), false);
2537 } catch (Zend_Locale_Exception $e) {
2538 if (!is_numeric($date)) {
2539 require_once 'Zend/Date/Exception.php';
2540 throw new Zend_Date_Exception($e->getMessage(), 0, $e, $date);
2541 }
2542 }
2543 }
2544
2545 return $this->_assign($calc, $date, $this->getUnixTimestamp(), false);
2546 }
2547 }
2548
2549 /**
2550 * Returns true when both date objects or date parts are equal.
2551 * For example:
2552 * 15.May.2000 <-> 15.June.2000 Equals only for Day or Year... all other will return false
2553 *
2554 * @param string|integer|array|Zend_Date $date Date or datepart to equal with
2555 * @param string $part OPTIONAL Part of the date to compare, if null the timestamp is used
2556 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
2557 * @return boolean
2558 * @throws Zend_Date_Exception
2559 */
2560 public function equals($date, $part = self::TIMESTAMP, $locale = null)
2561 {
2562 return $this->compare($date, $part, $locale) === 0;
2563 }
2564
2565 /**
2566 * Returns if the given date or datepart is earlier
2567 * For example:
2568 * 15.May.2000 <-> 13.June.1999 will return true for day, year and date, but not for month
2569 *
2570 * @param string|integer|array|Zend_Date $date Date or datepart to compare with
2571 * @param string $part OPTIONAL Part of the date to compare, if null the timestamp is used
2572 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
2573 * @return boolean
2574 * @throws Zend_Date_Exception
2575 */
2576 public function isEarlier($date, $part = null, $locale = null)
2577 {
2578 $result = $this->compare($date, $part, $locale);
2579
2580 if ($result == -1) {
2581 return true;
2582 }
2583
2584 return false;
2585 }
2586
2587 /**
2588 * Returns if the given date or datepart is later
2589 * For example:
2590 * 15.May.2000 <-> 13.June.1999 will return true for month but false for day, year and date
2591 * Returns if the given date is later
2592 *
2593 * @param string|integer|array|Zend_Date $date Date or datepart to compare with
2594 * @param string $part OPTIONAL Part of the date to compare, if null the timestamp is used
2595 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
2596 * @return boolean
2597 * @throws Zend_Date_Exception
2598 */
2599 public function isLater($date, $part = null, $locale = null)
2600 {
2601 return $this->compare($date, $part, $locale) === 1;
2602 }
2603
2604 /**
2605 * Returns only the time of the date as new Zend_Date object
2606 * For example:
2607 * 15.May.2000 10:11:23 will return a dateobject equal to 01.Jan.1970 10:11:23
2608 *
2609 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
2610 * @return Zend_Date
2611 */
2612 public function getTime($locale = null)
2613 {
2614 if (self::$_options['format_type'] == 'php') {
2615 $format = 'H:i:s';
2616 } else {
2617 $format = self::TIME_MEDIUM;
2618 }
2619
2620 return $this->copyPart($format, $locale);
2621 }
2622
2623 /**
2624 * Returns the calculated time
2625 *
2626 * @param string $calc Calculation to make
2627 * @param string|integer|array|Zend_Date $time Time to calculate with, if null the actual time is taken
2628 * @param string $format Timeformat for parsing input
2629 * @param string|Zend_Locale $locale Locale for parsing input
2630 * @return integer|Zend_Date new time
2631 * @throws Zend_Date_Exception
2632 */
2633 private function _time($calc, $time, $format, $locale)
2634 {
2635 if ($time === null) {
2636 require_once 'Zend/Date/Exception.php';
2637 throw new Zend_Date_Exception('parameter $time must be set, null is not allowed');
2638 }
2639
2640 if ($time instanceof Zend_Date) {
2641 // extract time from object
2642 $time = $time->toString('HH:mm:ss', 'iso');
2643 } else {
2644 if (is_array($time)) {
2645 if ((isset($time['hour']) === true) || (isset($time['minute']) === true) ||
2646 (isset($time['second']) === true)) {
2647 $parsed = $time;
2648 } else {
2649 require_once 'Zend/Date/Exception.php';
2650 throw new Zend_Date_Exception("no hour, minute or second given in array");
2651 }
2652 } else {
2653 if (self::$_options['format_type'] == 'php') {
2654 $format = Zend_Locale_Format::convertPhpToIsoFormat($format);
2655 }
2656 try {
2657 if ($locale === null) {
2658 $locale = $this->getLocale();
2659 }
2660
2661 $parsed = Zend_Locale_Format::getTime($time, ['date_format' => $format, 'locale' => $locale, 'format_type' => 'iso']);
2662 } catch (Zend_Locale_Exception $e) {
2663 require_once 'Zend/Date/Exception.php';
2664 throw new Zend_Date_Exception($e->getMessage(), 0, $e);
2665 }
2666 }
2667
2668 if (!array_key_exists('hour', $parsed)) {
2669 $parsed['hour'] = 0;
2670 }
2671
2672 if (!array_key_exists('minute', $parsed)) {
2673 $parsed['minute'] = 0;
2674 }
2675
2676 if (!array_key_exists('second', $parsed)) {
2677 $parsed['second'] = 0;
2678 }
2679
2680 $time = str_pad($parsed['hour'], 2, '0', STR_PAD_LEFT) . ":";
2681 $time .= str_pad($parsed['minute'], 2, '0', STR_PAD_LEFT) . ":";
2682 $time .= str_pad($parsed['second'], 2, '0', STR_PAD_LEFT);
2683 }
2684
2685 $return = $this->_calcdetail($calc, $time, self::TIMES, 'de');
2686 if ($calc != 'cmp') {
2687 return $this;
2688 }
2689
2690 return $return;
2691 }
2692
2693
2694 /**
2695 * Sets a new time for the date object. Format defines how to parse the time string.
2696 * Also a complete date can be given, but only the time is used for setting.
2697 * For example: dd.MMMM.yyTHH:mm' and 'ss sec'-> 10.May.07T25:11 and 44 sec => 1h11min44sec + 1 day
2698 * Returned is the new date object and the existing date is left as it was before
2699 *
2700 * @param string|integer|array|Zend_Date $time Time to set
2701 * @param string $format OPTIONAL Timeformat for parsing input
2702 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
2703 * @return $this
2704 * @throws Zend_Date_Exception
2705 */
2706 public function setTime($time, $format = null, $locale = null)
2707 {
2708 return $this->_time('set', $time, $format, $locale);
2709 }
2710
2711
2712 /**
2713 * Adds a time to the existing date. Format defines how to parse the time string.
2714 * If only parts are given the other parts are set to 0.
2715 * If no format is given, the standardformat of this locale is used.
2716 * For example: HH:mm:ss -> 10 -> +10 hours
2717 *
2718 * @param string|integer|array|Zend_Date $time Time to add
2719 * @param string $format OPTIONAL Timeformat for parsing input
2720 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
2721 * @return $this
2722 * @throws Zend_Date_Exception
2723 */
2724 public function addTime($time, $format = null, $locale = null)
2725 {
2726 return $this->_time('add', $time, $format, $locale);
2727 }
2728
2729
2730 /**
2731 * Subtracts a time from the existing date. Format defines how to parse the time string.
2732 * If only parts are given the other parts are set to 0.
2733 * If no format is given, the standardformat of this locale is used.
2734 * For example: HH:mm:ss -> 10 -> -10 hours
2735 *
2736 * @param string|integer|array|Zend_Date $time Time to sub
2737 * @param string $format OPTIONAL Timeformat for parsing input
2738 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
2739 * @return $this
2740 * @throws Zend_Date_Exception
2741 */
2742 public function subTime($time, $format = null, $locale = null)
2743 {
2744 return $this->_time('sub', $time, $format, $locale);
2745 }
2746
2747
2748 /**
2749 * Compares the time from the existing date. Format defines how to parse the time string.
2750 * If only parts are given the other parts are set to default.
2751 * If no format us given, the standardformat of this locale is used.
2752 * For example: HH:mm:ss -> 10 -> 10 hours
2753 *
2754 * @param string|integer|array|Zend_Date $time Time to compare
2755 * @param string $format OPTIONAL Timeformat for parsing input
2756 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
2757 * @return integer 0 = equal, 1 = later, -1 = earlier
2758 * @throws Zend_Date_Exception
2759 */
2760 public function compareTime($time, $format = null, $locale = null)
2761 {
2762 return $this->_time('cmp', $time, $format, $locale);
2763 }
2764
2765 /**
2766 * Returns a clone of $this, with the time part set to 00:00:00.
2767 *
2768 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
2769 * @return Zend_Date
2770 */
2771 public function getDate($locale = null)
2772 {
2773 $orig = self::$_options['format_type'];
2774 if (self::$_options['format_type'] == 'php') {
2775 self::$_options['format_type'] = 'iso';
2776 }
2777
2778 $date = $this->copyPart(self::DATE_MEDIUM, $locale);
2779 $date->addTimestamp($this->getGmtOffset());
2780 self::$_options['format_type'] = $orig;
2781
2782 return $date;
2783 }
2784
2785 /**
2786 * Returns the calculated date
2787 *
2788 * @param string $calc Calculation to make
2789 * @param string|integer|array|Zend_Date $date Date to calculate with, if null the actual date is taken
2790 * @param string $format Date format for parsing
2791 * @param string|Zend_Locale $locale Locale for parsing input
2792 * @return integer|Zend_Date new date
2793 * @throws Zend_Date_Exception
2794 */
2795 private function _date($calc, $date, $format, $locale)
2796 {
2797 if ($date === null) {
2798 require_once 'Zend/Date/Exception.php';
2799 throw new Zend_Date_Exception('parameter $date must be set, null is not allowed');
2800 }
2801
2802 if ($date instanceof Zend_Date) {
2803 // extract date from object
2804 $date = $date->toString('d.M.y', 'iso');
2805 } else {
2806 if (is_array($date)) {
2807 if ((isset($date['year']) === true) || (isset($date['month']) === true) ||
2808 (isset($date['day']) === true)) {
2809 $parsed = $date;
2810 } else {
2811 require_once 'Zend/Date/Exception.php';
2812 throw new Zend_Date_Exception("no day,month or year given in array");
2813 }
2814 } else {
2815 if ((self::$_options['format_type'] == 'php') && !defined($format)) {
2816 $format = Zend_Locale_Format::convertPhpToIsoFormat($format);
2817 }
2818 try {
2819 if ($locale === null) {
2820 $locale = $this->getLocale();
2821 }
2822
2823 $parsed = Zend_Locale_Format::getDate($date, ['date_format' => $format, 'locale' => $locale, 'format_type' => 'iso']);
2824 if ((strpos(strtoupper((string) $format), 'YY') !== false) && (strpos(strtoupper((string) $format), 'YYYY') === false)) {
2825 $parsed['year'] = self::getFullYear($parsed['year']);
2826 }
2827 } catch (Zend_Locale_Exception $e) {
2828 require_once 'Zend/Date/Exception.php';
2829 throw new Zend_Date_Exception($e->getMessage(), 0, $e);
2830 }
2831 }
2832
2833 if (!array_key_exists('day', $parsed)) {
2834 $parsed['day'] = 1;
2835 }
2836
2837 if (!array_key_exists('month', $parsed)) {
2838 $parsed['month'] = 1;
2839 }
2840
2841 if (!array_key_exists('year', $parsed)) {
2842 $parsed['year'] = 0;
2843 }
2844
2845 $date = $parsed['day'] . "." . $parsed['month'] . "." . $parsed['year'];
2846 }
2847
2848 $return = $this->_calcdetail($calc, $date, self::DATE_MEDIUM, 'de');
2849 if ($calc != 'cmp') {
2850 return $this;
2851 }
2852 return $return;
2853 }
2854
2855
2856 /**
2857 * Sets a new date for the date object. Format defines how to parse the date string.
2858 * Also a complete date with time can be given, but only the date is used for setting.
2859 * For example: MMMM.yy HH:mm-> May.07 22:11 => 01.May.07 00:00
2860 * Returned is the new date object and the existing time is left as it was before
2861 *
2862 * @param string|integer|array|Zend_Date $date Date to set
2863 * @param string $format OPTIONAL Date format for parsing
2864 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
2865 * @return $this
2866 * @throws Zend_Date_Exception
2867 */
2868 public function setDate($date, $format = null, $locale = null)
2869 {
2870 return $this->_date('set', $date, $format, $locale);
2871 }
2872
2873
2874 /**
2875 * Adds a date to the existing date object. Format defines how to parse the date string.
2876 * If only parts are given the other parts are set to 0.
2877 * If no format is given, the standardformat of this locale is used.
2878 * For example: MM.dd.YYYY -> 10 -> +10 months
2879 *
2880 * @param string|integer|array|Zend_Date $date Date to add
2881 * @param string $format OPTIONAL Date format for parsing input
2882 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
2883 * @return $this
2884 * @throws Zend_Date_Exception
2885 */
2886 public function addDate($date, $format = null, $locale = null)
2887 {
2888 return $this->_date('add', $date, $format, $locale);
2889 }
2890
2891
2892 /**
2893 * Subtracts a date from the existing date object. Format defines how to parse the date string.
2894 * If only parts are given the other parts are set to 0.
2895 * If no format is given, the standardformat of this locale is used.
2896 * For example: MM.dd.YYYY -> 10 -> -10 months
2897 * Be aware: Subtracting 2 months is not equal to Adding -2 months !!!
2898 *
2899 * @param string|integer|array|Zend_Date $date Date to sub
2900 * @param string $format OPTIONAL Date format for parsing input
2901 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
2902 * @return $this
2903 * @throws Zend_Date_Exception
2904 */
2905 public function subDate($date, $format = null, $locale = null)
2906 {
2907 return $this->_date('sub', $date, $format, $locale);
2908 }
2909
2910
2911 /**
2912 * Compares the date from the existing date object, ignoring the time.
2913 * Format defines how to parse the date string.
2914 * If only parts are given the other parts are set to 0.
2915 * If no format is given, the standardformat of this locale is used.
2916 * For example: 10.01.2000 => 10.02.1999 -> false
2917 *
2918 * @param string|integer|array|Zend_Date $date Date to compare
2919 * @param string $format OPTIONAL Date format for parsing input
2920 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
2921 * @return integer 0 = equal, 1 = later, -1 = earlier
2922 * @throws Zend_Date_Exception
2923 */
2924 public function compareDate($date, $format = null, $locale = null)
2925 {
2926 return $this->_date('cmp', $date, $format, $locale);
2927 }
2928
2929
2930 /**
2931 * Returns the full ISO 8601 date from the date object.
2932 * Always the complete ISO 8601 specifiction is used. If an other ISO date is needed
2933 * (ISO 8601 defines several formats) use toString() instead.
2934 * This function does not return the ISO date as object. Use copy() instead.
2935 *
2936 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
2937 * @return string
2938 */
2939 public function getIso($locale = null)
2940 {
2941 return $this->toString(self::ISO_8601, 'iso', $locale);
2942 }
2943
2944
2945 /**
2946 * Sets a new date for the date object. Not given parts are set to default.
2947 * Only supported ISO 8601 formats are accepted.
2948 * For example: 050901 -> 01.Sept.2005 00:00:00, 20050201T10:00:30 -> 01.Feb.2005 10h00m30s
2949 * Returned is the new date object
2950 *
2951 * @param string|integer|Zend_Date $date ISO Date to set
2952 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
2953 * @return $this
2954 * @throws Zend_Date_Exception
2955 */
2956 public function setIso($date, $locale = null)
2957 {
2958 return $this->_calcvalue('set', $date, 'iso', self::ISO_8601, $locale);
2959 }
2960
2961
2962 /**
2963 * Adds a ISO date to the date object. Not given parts are set to default.
2964 * Only supported ISO 8601 formats are accepted.
2965 * For example: 050901 -> + 01.Sept.2005 00:00:00, 10:00:00 -> +10h
2966 * Returned is the new date object
2967 *
2968 * @param string|integer|Zend_Date $date ISO Date to add
2969 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
2970 * @return $this
2971 * @throws Zend_Date_Exception
2972 */
2973 public function addIso($date, $locale = null)
2974 {
2975 return $this->_calcvalue('add', $date, 'iso', self::ISO_8601, $locale);
2976 }
2977
2978
2979 /**
2980 * Subtracts a ISO date from the date object. Not given parts are set to default.
2981 * Only supported ISO 8601 formats are accepted.
2982 * For example: 050901 -> - 01.Sept.2005 00:00:00, 10:00:00 -> -10h
2983 * Returned is the new date object
2984 *
2985 * @param string|integer|Zend_Date $date ISO Date to sub
2986 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
2987 * @return $this
2988 * @throws Zend_Date_Exception
2989 */
2990 public function subIso($date, $locale = null)
2991 {
2992 return $this->_calcvalue('sub', $date, 'iso', self::ISO_8601, $locale);
2993 }
2994
2995
2996 /**
2997 * Compares a ISO date with the date object. Not given parts are set to default.
2998 * Only supported ISO 8601 formats are accepted.
2999 * For example: 050901 -> - 01.Sept.2005 00:00:00, 10:00:00 -> -10h
3000 * Returns if equal, earlier or later
3001 *
3002 * @param string|integer|Zend_Date $date ISO Date to sub
3003 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3004 * @return integer 0 = equal, 1 = later, -1 = earlier
3005 * @throws Zend_Date_Exception
3006 */
3007 public function compareIso($date, $locale = null)
3008 {
3009 return $this->_calcvalue('cmp', $date, 'iso', self::ISO_8601, $locale);
3010 }
3011
3012
3013 /**
3014 * Returns a RFC 822 compilant datestring from the date object.
3015 * This function does not return the RFC date as object. Use copy() instead.
3016 *
3017 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3018 * @return string
3019 */
3020 public function getArpa($locale = null)
3021 {
3022 if (self::$_options['format_type'] == 'php') {
3023 $format = 'D\, d M y H\:i\:s O';
3024 } else {
3025 $format = self::RFC_822;
3026 }
3027
3028 return $this->toString($format, 'iso', $locale);
3029 }
3030
3031
3032 /**
3033 * Sets a RFC 822 date as new date for the date object.
3034 * Only RFC 822 compilant date strings are accepted.
3035 * For example: Sat, 14 Feb 09 00:31:30 +0100
3036 * Returned is the new date object
3037 *
3038 * @param string|integer|Zend_Date $date RFC 822 to set
3039 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3040 * @return $this
3041 * @throws Zend_Date_Exception
3042 */
3043 public function setArpa($date, $locale = null)
3044 {
3045 return $this->_calcvalue('set', $date, 'arpa', self::RFC_822, $locale);
3046 }
3047
3048
3049 /**
3050 * Adds a RFC 822 date to the date object.
3051 * ARPA messages are used in emails or HTTP Headers.
3052 * Only RFC 822 compilant date strings are accepted.
3053 * For example: Sat, 14 Feb 09 00:31:30 +0100
3054 * Returned is the new date object
3055 *
3056 * @param string|integer|Zend_Date $date RFC 822 Date to add
3057 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3058 * @return $this
3059 * @throws Zend_Date_Exception
3060 */
3061 public function addArpa($date, $locale = null)
3062 {
3063 return $this->_calcvalue('add', $date, 'arpa', self::RFC_822, $locale);
3064 }
3065
3066
3067 /**
3068 * Subtracts a RFC 822 date from the date object.
3069 * ARPA messages are used in emails or HTTP Headers.
3070 * Only RFC 822 compilant date strings are accepted.
3071 * For example: Sat, 14 Feb 09 00:31:30 +0100
3072 * Returned is the new date object
3073 *
3074 * @param string|integer|Zend_Date $date RFC 822 Date to sub
3075 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3076 * @return $this
3077 * @throws Zend_Date_Exception
3078 */
3079 public function subArpa($date, $locale = null)
3080 {
3081 return $this->_calcvalue('sub', $date, 'arpa', self::RFC_822, $locale);
3082 }
3083
3084
3085 /**
3086 * Compares a RFC 822 compilant date with the date object.
3087 * ARPA messages are used in emails or HTTP Headers.
3088 * Only RFC 822 compilant date strings are accepted.
3089 * For example: Sat, 14 Feb 09 00:31:30 +0100
3090 * Returns if equal, earlier or later
3091 *
3092 * @param string|integer|Zend_Date $date RFC 822 Date to sub
3093 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3094 * @return integer 0 = equal, 1 = later, -1 = earlier
3095 * @throws Zend_Date_Exception
3096 */
3097 public function compareArpa($date, $locale = null)
3098 {
3099 return $this->_calcvalue('cmp', $date, 'arpa', self::RFC_822, $locale);
3100 }
3101
3102 /**
3103 * Check if location is supported
3104 *
3105 * @param array $location locations array
3106 * @throws Zend_Date_Exception
3107 * @return float $horizon float
3108 */
3109 private function _checkLocation($location)
3110 {
3111 if (!isset($location['longitude']) || !isset($location['latitude'])) {
3112 require_once 'Zend/Date/Exception.php';
3113 throw new Zend_Date_Exception('Location must include \'longitude\' and \'latitude\'', 0, null, $location);
3114 }
3115 if (($location['longitude'] > 180) || ($location['longitude'] < -180)) {
3116 require_once 'Zend/Date/Exception.php';
3117 throw new Zend_Date_Exception('Longitude must be between -180 and 180', 0, null, $location);
3118 }
3119 if (($location['latitude'] > 90) || ($location['latitude'] < -90)) {
3120 require_once 'Zend/Date/Exception.php';
3121 throw new Zend_Date_Exception('Latitude must be between -90 and 90', 0, null, $location);
3122 }
3123
3124 if (!isset($location['horizon'])){
3125 $location['horizon'] = 'effective';
3126 }
3127
3128 switch ($location['horizon']) {
3129 case 'civil' :
3130 return -0.104528;
3131 case 'nautic' :
3132 return -0.207912;
3133 case 'astronomic' :
3134 return -0.309017;
3135 default :
3136 return -0.0145439;
3137 }
3138 }
3139
3140
3141 /**
3142 * Returns the time of sunrise for this date and a given location as new date object
3143 * For a list of cities and correct locations use the class Zend_Date_Cities
3144 *
3145 * @param array $location location of sunrise
3146 * ['horizon'] -> civil, nautic, astronomical, effective (default)
3147 * ['longitude'] -> longitude of location
3148 * ['latitude'] -> latitude of location
3149 * @return Zend_Date
3150 * @throws Zend_Date_Exception
3151 */
3152 public function getSunrise($location)
3153 {
3154 $horizon = $this->_checkLocation($location);
3155 $result = clone $this;
3156 $result->set($this->calcSun($location, $horizon, true), self::TIMESTAMP);
3157 return $result;
3158 }
3159
3160
3161 /**
3162 * Returns the time of sunset for this date and a given location as new date object
3163 * For a list of cities and correct locations use the class Zend_Date_Cities
3164 *
3165 * @param array $location location of sunset
3166 * ['horizon'] -> civil, nautic, astronomical, effective (default)
3167 * ['longitude'] -> longitude of location
3168 * ['latitude'] -> latitude of location
3169 * @return Zend_Date
3170 * @throws Zend_Date_Exception
3171 */
3172 public function getSunset($location)
3173 {
3174 $horizon = $this->_checkLocation($location);
3175 $result = clone $this;
3176 $result->set($this->calcSun($location, $horizon, false), self::TIMESTAMP);
3177 return $result;
3178 }
3179
3180
3181 /**
3182 * Returns an array with the sunset and sunrise dates for all horizon types
3183 * For a list of cities and correct locations use the class Zend_Date_Cities
3184 *
3185 * @param array $location location of suninfo
3186 * ['horizon'] -> civil, nautic, astronomical, effective (default)
3187 * ['longitude'] -> longitude of location
3188 * ['latitude'] -> latitude of location
3189 * @return array - [sunset|sunrise][effective|civil|nautic|astronomic]
3190 * @throws Zend_Date_Exception
3191 */
3192 public function getSunInfo($location)
3193 {
3194 $suninfo = [];
3195 for ($i = 0; $i < 4; ++$i) {
3196 switch ($i) {
3197 case 0 :
3198 $location['horizon'] = 'effective';
3199 break;
3200 case 1 :
3201 $location['horizon'] = 'civil';
3202 break;
3203 case 2 :
3204 $location['horizon'] = 'nautic';
3205 break;
3206 case 3 :
3207 $location['horizon'] = 'astronomic';
3208 break;
3209 }
3210 $horizon = $this->_checkLocation($location);
3211 $result = clone $this;
3212 $result->set($this->calcSun($location, $horizon, true), self::TIMESTAMP);
3213 $suninfo['sunrise'][$location['horizon']] = $result;
3214 $result = clone $this;
3215 $result->set($this->calcSun($location, $horizon, false), self::TIMESTAMP);
3216 $suninfo['sunset'][$location['horizon']] = $result;
3217 }
3218 return $suninfo;
3219 }
3220
3221 /**
3222 * Check a given year for leap year.
3223 *
3224 * @param integer|array|Zend_Date $year Year to check
3225 * @throws Zend_Date_Exception
3226 * @return boolean
3227 */
3228 public static function checkLeapYear($year)
3229 {
3230 if ($year instanceof Zend_Date) {
3231 $year = (int) $year->toString(self::YEAR, 'iso');
3232 }
3233
3234 if (is_array($year)) {
3235 if (isset($year['year']) === true) {
3236 $year = $year['year'];
3237 } else {
3238 require_once 'Zend/Date/Exception.php';
3239 throw new Zend_Date_Exception("no year given in array");
3240 }
3241 }
3242
3243 if (!is_numeric($year)) {
3244 require_once 'Zend/Date/Exception.php';
3245 throw new Zend_Date_Exception("year ($year) has to be integer for checkLeapYear()", 0, null, $year);
3246 }
3247
3248 return (bool) parent::isYearLeapYear($year);
3249 }
3250
3251
3252 /**
3253 * Returns true, if the year is a leap year.
3254 *
3255 * @return boolean
3256 */
3257 public function isLeapYear()
3258 {
3259 return self::checkLeapYear($this);
3260 }
3261
3262
3263 /**
3264 * Returns if the set date is todays date
3265 *
3266 * @return boolean
3267 */
3268 public function isToday()
3269 {
3270 $today = $this->date('Ymd', $this->_getTime());
3271 $day = $this->date('Ymd', $this->getUnixTimestamp());
3272 return ($today == $day);
3273 }
3274
3275
3276 /**
3277 * Returns if the set date is yesterdays date
3278 *
3279 * @return boolean
3280 */
3281 public function isYesterday()
3282 {
3283 [$year, $month, $day] = explode('-', $this->date('Y-m-d', $this->_getTime()));
3284 // adjusts for leap days and DST changes that are timezone specific
3285 $yesterday = $this->date('Ymd', $this->mktime(0, 0, 0, $month, $day -1, $year));
3286 $day = $this->date('Ymd', $this->getUnixTimestamp());
3287 return $day == $yesterday;
3288 }
3289
3290
3291 /**
3292 * Returns if the set date is tomorrows date
3293 *
3294 * @return boolean
3295 */
3296 public function isTomorrow()
3297 {
3298 [$year, $month, $day] = explode('-', $this->date('Y-m-d', $this->_getTime()));
3299 // adjusts for leap days and DST changes that are timezone specific
3300 $tomorrow = $this->date('Ymd', $this->mktime(0, 0, 0, $month, $day +1, $year));
3301 $day = $this->date('Ymd', $this->getUnixTimestamp());
3302 return $day == $tomorrow;
3303 }
3304
3305 /**
3306 * Returns the actual date as new date object
3307 *
3308 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3309 * @return Zend_Date
3310 */
3311 public static function now($locale = null)
3312 {
3313 return new Zend_Date(time(), self::TIMESTAMP, $locale);
3314 }
3315
3316 /**
3317 * Calculate date details
3318 *
3319 * @param string $calc Calculation to make
3320 * @param string|integer|array|Zend_Date $date Date or Part to calculate
3321 * @param string $type Datepart for Calculation
3322 * @param string|Zend_Locale $locale Locale for parsing input
3323 * @return integer|Zend_Date new date
3324 * @throws Zend_Date_Exception
3325 */
3326 private function _calcdetail($calc, $date, $type, $locale)
3327 {
3328 $old = false;
3329 if (self::$_options['format_type'] == 'php') {
3330 self::$_options['format_type'] = 'iso';
3331 $old = true;
3332 }
3333
3334 switch($calc) {
3335 case 'set' :
3336 $return = $this->set($date, $type, $locale);
3337 break;
3338 case 'add' :
3339 $return = $this->add($date, $type, $locale);
3340 break;
3341 case 'sub' :
3342 $return = $this->sub($date, $type, $locale);
3343 break;
3344 default :
3345 $return = $this->compare($date, $type, $locale);
3346 break;
3347 }
3348
3349 if ($old) {
3350 self::$_options['format_type'] = 'php';
3351 }
3352
3353 return $return;
3354 }
3355
3356 /**
3357 * Internal calculation, returns the requested date type
3358 *
3359 * @param string $calc Calculation to make
3360 * @param string|integer|Zend_Date $value Datevalue to calculate with, if null the actual value is taken
3361 * @param string $type
3362 * @param string $parameter
3363 * @param string|Zend_Locale $locale Locale for parsing input
3364 * @throws Zend_Date_Exception
3365 * @return integer|Zend_Date new date
3366 */
3367 private function _calcvalue($calc, $value, $type, $parameter, $locale)
3368 {
3369 if ($value === null) {
3370 require_once 'Zend/Date/Exception.php';
3371 throw new Zend_Date_Exception("parameter $type must be set, null is not allowed");
3372 }
3373
3374 if ($locale === null) {
3375 $locale = $this->getLocale();
3376 }
3377
3378 if ($value instanceof Zend_Date) {
3379 // extract value from object
3380 $value = $value->toString($parameter, 'iso', $locale);
3381 } else if (!is_array($value) && !is_numeric($value) && ($type != 'iso') && ($type != 'arpa')) {
3382 require_once 'Zend/Date/Exception.php';
3383 throw new Zend_Date_Exception("invalid $type ($value) operand", 0, null, $value);
3384 }
3385
3386 $return = $this->_calcdetail($calc, $value, $parameter, $locale);
3387 if ($calc != 'cmp') {
3388 return $this;
3389 }
3390 return $return;
3391 }
3392
3393
3394 /**
3395 * Returns only the year from the date object as new object.
3396 * For example: 10.May.2000 10:30:00 -> 01.Jan.2000 00:00:00
3397 *
3398 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3399 * @return Zend_Date
3400 */
3401 public function getYear($locale = null)
3402 {
3403 if (self::$_options['format_type'] == 'php') {
3404 $format = 'Y';
3405 } else {
3406 $format = self::YEAR;
3407 }
3408
3409 return $this->copyPart($format, $locale);
3410 }
3411
3412
3413 /**
3414 * Sets a new year
3415 * If the year is between 0 and 69, 2000 will be set (2000-2069)
3416 * If the year if between 70 and 99, 1999 will be set (1970-1999)
3417 * 3 or 4 digit years are set as expected. If you need to set year 0-99
3418 * use set() instead.
3419 * Returned is the new date object
3420 *
3421 * @param string|integer|array|Zend_Date $year Year to set
3422 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3423 * @return $this
3424 * @throws Zend_Date_Exception
3425 */
3426 public function setYear($year, $locale = null)
3427 {
3428 return $this->_calcvalue('set', $year, 'year', self::YEAR, $locale);
3429 }
3430
3431
3432 /**
3433 * Adds the year to the existing date object
3434 * If the year is between 0 and 69, 2000 will be added (2000-2069)
3435 * If the year if between 70 and 99, 1999 will be added (1970-1999)
3436 * 3 or 4 digit years are added as expected. If you need to add years from 0-99
3437 * use add() instead.
3438 * Returned is the new date object
3439 *
3440 * @param string|integer|array|Zend_Date $year Year to add
3441 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3442 * @return $this
3443 * @throws Zend_Date_Exception
3444 */
3445 public function addYear($year, $locale = null)
3446 {
3447 return $this->_calcvalue('add', $year, 'year', self::YEAR, $locale);
3448 }
3449
3450
3451 /**
3452 * Subs the year from the existing date object
3453 * If the year is between 0 and 69, 2000 will be subtracted (2000-2069)
3454 * If the year if between 70 and 99, 1999 will be subtracted (1970-1999)
3455 * 3 or 4 digit years are subtracted as expected. If you need to subtract years from 0-99
3456 * use sub() instead.
3457 * Returned is the new date object
3458 *
3459 * @param string|integer|array|Zend_Date $year Year to sub
3460 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3461 * @return $this
3462 * @throws Zend_Date_Exception
3463 */
3464 public function subYear($year, $locale = null)
3465 {
3466 return $this->_calcvalue('sub', $year, 'year', self::YEAR, $locale);
3467 }
3468
3469
3470 /**
3471 * Compares the year with the existing date object, ignoring other date parts.
3472 * For example: 10.03.2000 -> 15.02.2000 -> true
3473 * Returns if equal, earlier or later
3474 *
3475 * @param string|integer|array|Zend_Date $year Year to compare
3476 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3477 * @return integer 0 = equal, 1 = later, -1 = earlier
3478 * @throws Zend_Date_Exception
3479 */
3480 public function compareYear($year, $locale = null)
3481 {
3482 return $this->_calcvalue('cmp', $year, 'year', self::YEAR, $locale);
3483 }
3484
3485
3486 /**
3487 * Returns only the month from the date object as new object.
3488 * For example: 10.May.2000 10:30:00 -> 01.May.1970 00:00:00
3489 *
3490 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3491 * @return Zend_Date
3492 */
3493 public function getMonth($locale = null)
3494 {
3495 if (self::$_options['format_type'] == 'php') {
3496 $format = 'm';
3497 } else {
3498 $format = self::MONTH;
3499 }
3500
3501 return $this->copyPart($format, $locale);
3502 }
3503
3504
3505 /**
3506 * Returns the calculated month
3507 *
3508 * @param string $calc Calculation to make
3509 * @param string|integer|array|Zend_Date $month Month to calculate with, if null the actual month is taken
3510 * @param string|Zend_Locale $locale Locale for parsing input
3511 * @return integer|Zend_Date new time
3512 * @throws Zend_Date_Exception
3513 */
3514 private function _month($calc, $month, $locale)
3515 {
3516 if ($month === null) {
3517 require_once 'Zend/Date/Exception.php';
3518 throw new Zend_Date_Exception('parameter $month must be set, null is not allowed');
3519 }
3520
3521 if ($locale === null) {
3522 $locale = $this->getLocale();
3523 }
3524
3525 if ($month instanceof Zend_Date) {
3526 // extract month from object
3527 $found = $month->toString(self::MONTH_SHORT, 'iso', $locale);
3528 } else {
3529 if (is_numeric($month)) {
3530 $found = $month;
3531 } else if (is_array($month)) {
3532 if (isset($month['month']) === true) {
3533 $month = $month['month'];
3534 } else {
3535 require_once 'Zend/Date/Exception.php';
3536 throw new Zend_Date_Exception("no month given in array");
3537 }
3538 } else {
3539 $monthlist = Zend_Locale_Data::getList($locale, 'month');
3540 $monthlist2 = Zend_Locale_Data::getList($locale, 'month', ['gregorian', 'format', 'abbreviated']);
3541
3542 $monthlist = array_merge($monthlist, $monthlist2);
3543 $found = 0;
3544 $cnt = 0;
3545 foreach ($monthlist as $key => $value) {
3546 if (strtoupper($value) == strtoupper($month)) {
3547 $found = ($key % 12) + 1;
3548 break;
3549 }
3550 ++$cnt;
3551 }
3552 if ($found == 0) {
3553 foreach ($monthlist2 as $key => $value) {
3554 if (strtoupper(iconv_substr($value, 0, 1, 'UTF-8')) == strtoupper($month)) {
3555 $found = $key + 1;
3556 break;
3557 }
3558 ++$cnt;
3559 }
3560 }
3561 if ($found == 0) {
3562 require_once 'Zend/Date/Exception.php';
3563 throw new Zend_Date_Exception("unknown month name ($month)", 0, null, $month);
3564 }
3565 }
3566 }
3567 $return = $this->_calcdetail($calc, $found, self::MONTH_SHORT, $locale);
3568 if ($calc != 'cmp') {
3569 return $this;
3570 }
3571 return $return;
3572 }
3573
3574
3575 /**
3576 * Sets a new month
3577 * The month can be a number or a string. Setting months lower then 0 and greater then 12
3578 * will result in adding or subtracting the relevant year. (12 months equal one year)
3579 * If a localized monthname is given it will be parsed with the default locale or the optional
3580 * set locale.
3581 * Returned is the new date object
3582 *
3583 * @param string|integer|array|Zend_Date $month Month to set
3584 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3585 * @return $this
3586 * @throws Zend_Date_Exception
3587 */
3588 public function setMonth($month, $locale = null)
3589 {
3590 return $this->_month('set', $month, $locale);
3591 }
3592
3593
3594 /**
3595 * Adds months to the existing date object.
3596 * The month can be a number or a string. Adding months lower then 0 and greater then 12
3597 * will result in adding or subtracting the relevant year. (12 months equal one year)
3598 * If a localized monthname is given it will be parsed with the default locale or the optional
3599 * set locale.
3600 * Returned is the new date object
3601 *
3602 * @param string|integer|array|Zend_Date $month Month to add
3603 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3604 * @return $this
3605 * @throws Zend_Date_Exception
3606 */
3607 public function addMonth($month, $locale = null)
3608 {
3609 return $this->_month('add', $month, $locale);
3610 }
3611
3612
3613 /**
3614 * Subtracts months from the existing date object.
3615 * The month can be a number or a string. Subtracting months lower then 0 and greater then 12
3616 * will result in adding or subtracting the relevant year. (12 months equal one year)
3617 * If a localized monthname is given it will be parsed with the default locale or the optional
3618 * set locale.
3619 * Returned is the new date object
3620 *
3621 * @param string|integer|array|Zend_Date $month Month to sub
3622 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3623 * @return $this
3624 * @throws Zend_Date_Exception
3625 */
3626 public function subMonth($month, $locale = null)
3627 {
3628 return $this->_month('sub', $month, $locale);
3629 }
3630
3631
3632 /**
3633 * Compares the month with the existing date object, ignoring other date parts.
3634 * For example: 10.03.2000 -> 15.03.1950 -> true
3635 * Returns if equal, earlier or later
3636 *
3637 * @param string|integer|array|Zend_Date $month Month to compare
3638 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3639 * @return integer 0 = equal, 1 = later, -1 = earlier
3640 * @throws Zend_Date_Exception
3641 */
3642 public function compareMonth($month, $locale = null)
3643 {
3644 return $this->_month('cmp', $month, $locale);
3645 }
3646
3647
3648 /**
3649 * Returns the day as new date object
3650 * Example: 20.May.1986 -> 20.Jan.1970 00:00:00
3651 *
3652 * @param Zend_Locale $locale OPTIONAL Locale for parsing input
3653 * @return Zend_Date
3654 */
3655 public function getDay($locale = null)
3656 {
3657 return $this->copyPart(self::DAY_SHORT, $locale);
3658 }
3659
3660 /**
3661 * Returns the calculated day
3662 *
3663 * @param string $calc Type of calculation to make
3664 * @param Zend_Date $day Day to calculate, when null the actual day is calculated
3665 * @param Zend_Locale $locale Locale for parsing input
3666 * @throws Zend_Date_Exception
3667 * @return Zend_Date|integer
3668 */
3669 private function _day($calc, $day, $locale)
3670 {
3671 if ($day === null) {
3672 require_once 'Zend/Date/Exception.php';
3673 throw new Zend_Date_Exception('parameter $day must be set, null is not allowed');
3674 }
3675
3676 if ($locale === null) {
3677 $locale = $this->getLocale();
3678 }
3679
3680 if ($day instanceof Zend_Date) {
3681 $day = $day->toString(self::DAY_SHORT, 'iso', $locale);
3682 }
3683
3684 if (is_numeric($day)) {
3685 $type = self::DAY_SHORT;
3686 } else if (is_array($day)) {
3687 if (isset($day['day']) === true) {
3688 $day = $day['day'];
3689 $type = self::WEEKDAY;
3690 } else {
3691 require_once 'Zend/Date/Exception.php';
3692 throw new Zend_Date_Exception("no day given in array");
3693 }
3694 } else {
3695 switch (iconv_strlen($day, 'UTF-8')) {
3696 case 1 :
3697 $type = self::WEEKDAY_NARROW;
3698 break;
3699 case 2:
3700 $type = self::WEEKDAY_NAME;
3701 break;
3702 case 3:
3703 $type = self::WEEKDAY_SHORT;
3704 break;
3705 default:
3706 $type = self::WEEKDAY;
3707 break;
3708 }
3709 }
3710 $return = $this->_calcdetail($calc, $day, $type, $locale);
3711 if ($calc != 'cmp') {
3712 return $this;
3713 }
3714 return $return;
3715 }
3716
3717
3718 /**
3719 * Sets a new day
3720 * The day can be a number or a string. Setting days lower then 0 or greater than the number of this months days
3721 * will result in adding or subtracting the relevant month.
3722 * If a localized dayname is given it will be parsed with the default locale or the optional
3723 * set locale.
3724 * Returned is the new date object
3725 * Example: setDay('Montag', 'de_AT'); will set the monday of this week as day.
3726 *
3727 * @param string|integer|array|Zend_Date $day Day to set
3728 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3729 * @return $this
3730 * @throws Zend_Date_Exception
3731 */
3732 public function setDay($day, $locale = null)
3733 {
3734 return $this->_day('set', $day, $locale);
3735 }
3736
3737
3738 /**
3739 * Adds days to the existing date object.
3740 * The day can be a number or a string. Adding days lower then 0 or greater than the number of this months days
3741 * will result in adding or subtracting the relevant month.
3742 * If a localized dayname is given it will be parsed with the default locale or the optional
3743 * set locale.
3744 *
3745 * @param string|integer|array|Zend_Date $day Day to add
3746 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3747 * @return $this
3748 * @throws Zend_Date_Exception
3749 */
3750 public function addDay($day, $locale = null)
3751 {
3752 return $this->_day('add', $day, $locale);
3753 }
3754
3755
3756 /**
3757 * Subtracts days from the existing date object.
3758 * The day can be a number or a string. Subtracting days lower then 0 or greater than the number of this months days
3759 * will result in adding or subtracting the relevant month.
3760 * If a localized dayname is given it will be parsed with the default locale or the optional
3761 * set locale.
3762 *
3763 * @param string|integer|array|Zend_Date $day Day to sub
3764 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3765 * @return $this
3766 * @throws Zend_Date_Exception
3767 */
3768 public function subDay($day, $locale = null)
3769 {
3770 return $this->_day('sub', $day, $locale);
3771 }
3772
3773
3774 /**
3775 * Compares the day with the existing date object, ignoring other date parts.
3776 * For example: 'Monday', 'en' -> 08.Jan.2007 -> 0
3777 * Returns if equal, earlier or later
3778 *
3779 * @param string|integer|array|Zend_Date $day Day to compare
3780 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3781 * @return integer 0 = equal, 1 = later, -1 = earlier
3782 * @throws Zend_Date_Exception
3783 */
3784 public function compareDay($day, $locale = null)
3785 {
3786 return $this->_day('cmp', $day, $locale);
3787 }
3788
3789
3790 /**
3791 * Returns the weekday as new date object
3792 * Weekday is always from 1-7
3793 * Example: 09-Jan-2007 -> 2 = Tuesday -> 02-Jan-1970 (when 02.01.1970 is also Tuesday)
3794 *
3795 * @param Zend_Locale $locale OPTIONAL Locale for parsing input
3796 * @return Zend_Date
3797 */
3798 public function getWeekday($locale = null)
3799 {
3800 if (self::$_options['format_type'] == 'php') {
3801 $format = 'l';
3802 } else {
3803 $format = self::WEEKDAY;
3804 }
3805
3806 return $this->copyPart($format, $locale);
3807 }
3808
3809
3810 /**
3811 * Returns the calculated weekday
3812 *
3813 * @param string $calc Type of calculation to make
3814 * @param Zend_Date $weekday Weekday to calculate, when null the actual weekday is calculated
3815 * @param Zend_Locale $locale Locale for parsing input
3816 * @return Zend_Date|integer
3817 * @throws Zend_Date_Exception
3818 */
3819 private function _weekday($calc, $weekday, $locale)
3820 {
3821 if ($weekday === null) {
3822 require_once 'Zend/Date/Exception.php';
3823 throw new Zend_Date_Exception('parameter $weekday must be set, null is not allowed');
3824 }
3825
3826 if ($locale === null) {
3827 $locale = $this->getLocale();
3828 }
3829
3830 if ($weekday instanceof Zend_Date) {
3831 $weekday = $weekday->toString(self::WEEKDAY_8601, 'iso', $locale);
3832 }
3833
3834 if (is_numeric($weekday)) {
3835 $type = self::WEEKDAY_8601;
3836 } else if (is_array($weekday)) {
3837 if (isset($weekday['weekday']) === true) {
3838 $weekday = $weekday['weekday'];
3839 $type = self::WEEKDAY;
3840 } else {
3841 require_once 'Zend/Date/Exception.php';
3842 throw new Zend_Date_Exception("no weekday given in array");
3843 }
3844 } else {
3845 switch(iconv_strlen($weekday, 'UTF-8')) {
3846 case 1:
3847 $type = self::WEEKDAY_NARROW;
3848 break;
3849 case 2:
3850 $type = self::WEEKDAY_NAME;
3851 break;
3852 case 3:
3853 $type = self::WEEKDAY_SHORT;
3854 break;
3855 default:
3856 $type = self::WEEKDAY;
3857 break;
3858 }
3859 }
3860 $return = $this->_calcdetail($calc, $weekday, $type, $locale);
3861 if ($calc != 'cmp') {
3862 return $this;
3863 }
3864 return $return;
3865 }
3866
3867
3868 /**
3869 * Sets a new weekday
3870 * The weekday can be a number or a string. If a localized weekday name is given,
3871 * then it will be parsed as a date in $locale (defaults to the same locale as $this).
3872 * Returned is the new date object.
3873 * Example: setWeekday(3); will set the wednesday of this week as day.
3874 *
3875 * @param string|integer|array|Zend_Date $weekday Weekday to set
3876 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3877 * @return $this
3878 * @throws Zend_Date_Exception
3879 */
3880 public function setWeekday($weekday, $locale = null)
3881 {
3882 return $this->_weekday('set', $weekday, $locale);
3883 }
3884
3885
3886 /**
3887 * Adds weekdays to the existing date object.
3888 * The weekday can be a number or a string.
3889 * If a localized dayname is given it will be parsed with the default locale or the optional
3890 * set locale.
3891 * Returned is the new date object
3892 * Example: addWeekday(3); will add the difference of days from the beginning of the month until
3893 * wednesday.
3894 *
3895 * @param string|integer|array|Zend_Date $weekday Weekday to add
3896 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3897 * @return $this
3898 * @throws Zend_Date_Exception
3899 */
3900 public function addWeekday($weekday, $locale = null)
3901 {
3902 return $this->_weekday('add', $weekday, $locale);
3903 }
3904
3905
3906 /**
3907 * Subtracts weekdays from the existing date object.
3908 * The weekday can be a number or a string.
3909 * If a localized dayname is given it will be parsed with the default locale or the optional
3910 * set locale.
3911 * Returned is the new date object
3912 * Example: subWeekday(3); will subtract the difference of days from the beginning of the month until
3913 * wednesday.
3914 *
3915 * @param string|integer|array|Zend_Date $weekday Weekday to sub
3916 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3917 * @return $this
3918 * @throws Zend_Date_Exception
3919 */
3920 public function subWeekday($weekday, $locale = null)
3921 {
3922 return $this->_weekday('sub', $weekday, $locale);
3923 }
3924
3925
3926 /**
3927 * Compares the weekday with the existing date object, ignoring other date parts.
3928 * For example: 'Monday', 'en' -> 08.Jan.2007 -> 0
3929 * Returns if equal, earlier or later
3930 *
3931 * @param string|integer|array|Zend_Date $weekday Weekday to compare
3932 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3933 * @return integer 0 = equal, 1 = later, -1 = earlier
3934 * @throws Zend_Date_Exception
3935 */
3936 public function compareWeekday($weekday, $locale = null)
3937 {
3938 return $this->_weekday('cmp', $weekday, $locale);
3939 }
3940
3941
3942 /**
3943 * Returns the day of year as new date object
3944 * Example: 02.Feb.1986 10:00:00 -> 02.Feb.1970 00:00:00
3945 *
3946 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3947 * @return Zend_Date
3948 */
3949 public function getDayOfYear($locale = null)
3950 {
3951 if (self::$_options['format_type'] == 'php') {
3952 $format = 'D';
3953 } else {
3954 $format = self::DAY_OF_YEAR;
3955 }
3956
3957 return $this->copyPart($format, $locale);
3958 }
3959
3960
3961 /**
3962 * Sets a new day of year
3963 * The day of year is always a number.
3964 * Returned is the new date object
3965 * Example: 04.May.2004 -> setDayOfYear(10) -> 10.Jan.2004
3966 *
3967 * @param string|integer|array|Zend_Date $day Day of Year to set
3968 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3969 * @return $this
3970 * @throws Zend_Date_Exception
3971 */
3972 public function setDayOfYear($day, $locale = null)
3973 {
3974 return $this->_calcvalue('set', $day, 'day of year', self::DAY_OF_YEAR, $locale);
3975 }
3976
3977
3978 /**
3979 * Adds a day of year to the existing date object.
3980 * The day of year is always a number.
3981 * Returned is the new date object
3982 * Example: addDayOfYear(10); will add 10 days to the existing date object.
3983 *
3984 * @param string|integer|array|Zend_Date $day Day of Year to add
3985 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
3986 * @return $this
3987 * @throws Zend_Date_Exception
3988 */
3989 public function addDayOfYear($day, $locale = null)
3990 {
3991 return $this->_calcvalue('add', $day, 'day of year', self::DAY_OF_YEAR, $locale);
3992 }
3993
3994
3995 /**
3996 * Subtracts a day of year from the existing date object.
3997 * The day of year is always a number.
3998 * Returned is the new date object
3999 * Example: subDayOfYear(10); will subtract 10 days from the existing date object.
4000 *
4001 * @param string|integer|array|Zend_Date $day Day of Year to sub
4002 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
4003 * @return $this
4004 * @throws Zend_Date_Exception
4005 */
4006 public function subDayOfYear($day, $locale = null)
4007 {
4008 return $this->_calcvalue('sub', $day, 'day of year', self::DAY_OF_YEAR, $locale);
4009 }
4010
4011
4012 /**
4013 * Compares the day of year with the existing date object.
4014 * For example: compareDayOfYear(33) -> 02.Feb.2007 -> 0
4015 * Returns if equal, earlier or later
4016 *
4017 * @param string|integer|array|Zend_Date $day Day of Year to compare
4018 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
4019 * @return integer 0 = equal, 1 = later, -1 = earlier
4020 * @throws Zend_Date_Exception
4021 */
4022 public function compareDayOfYear($day, $locale = null)
4023 {
4024 return $this->_calcvalue('cmp', $day, 'day of year', self::DAY_OF_YEAR, $locale);
4025 }
4026
4027
4028 /**
4029 * Returns the hour as new date object
4030 * Example: 02.Feb.1986 10:30:25 -> 01.Jan.1970 10:00:00
4031 *
4032 * @param Zend_Locale $locale OPTIONAL Locale for parsing input
4033 * @return Zend_Date
4034 */
4035 public function getHour($locale = null)
4036 {
4037 return $this->copyPart(self::HOUR, $locale);
4038 }
4039
4040
4041 /**
4042 * Sets a new hour
4043 * The hour is always a number.
4044 * Returned is the new date object
4045 * Example: 04.May.1993 13:07:25 -> setHour(7); -> 04.May.1993 07:07:25
4046 *
4047 * @param string|integer|array|Zend_Date $hour Hour to set
4048 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
4049 * @return $this
4050 * @throws Zend_Date_Exception
4051 */
4052 public function setHour($hour, $locale = null)
4053 {
4054 return $this->_calcvalue('set', $hour, 'hour', self::HOUR_SHORT, $locale);
4055 }
4056
4057
4058 /**
4059 * Adds hours to the existing date object.
4060 * The hour is always a number.
4061 * Returned is the new date object
4062 * Example: 04.May.1993 13:07:25 -> addHour(12); -> 05.May.1993 01:07:25
4063 *
4064 * @param string|integer|array|Zend_Date $hour Hour to add
4065 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
4066 * @return $this
4067 * @throws Zend_Date_Exception
4068 */
4069 public function addHour($hour, $locale = null)
4070 {
4071 return $this->_calcvalue('add', $hour, 'hour', self::HOUR_SHORT, $locale);
4072 }
4073
4074
4075 /**
4076 * Subtracts hours from the existing date object.
4077 * The hour is always a number.
4078 * Returned is the new date object
4079 * Example: 04.May.1993 13:07:25 -> subHour(6); -> 05.May.1993 07:07:25
4080 *
4081 * @param string|integer|array|Zend_Date $hour Hour to sub
4082 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
4083 * @return $this
4084 * @throws Zend_Date_Exception
4085 */
4086 public function subHour($hour, $locale = null)
4087 {
4088 return $this->_calcvalue('sub', $hour, 'hour', self::HOUR_SHORT, $locale);
4089 }
4090
4091
4092 /**
4093 * Compares the hour with the existing date object.
4094 * For example: 10:30:25 -> compareHour(10) -> 0
4095 * Returns if equal, earlier or later
4096 *
4097 * @param string|integer|array|Zend_Date $hour Hour to compare
4098 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
4099 * @return integer 0 = equal, 1 = later, -1 = earlier
4100 * @throws Zend_Date_Exception
4101 */
4102 public function compareHour($hour, $locale = null)
4103 {
4104 return $this->_calcvalue('cmp', $hour, 'hour', self::HOUR_SHORT, $locale);
4105 }
4106
4107
4108 /**
4109 * Returns the minute as new date object
4110 * Example: 02.Feb.1986 10:30:25 -> 01.Jan.1970 00:30:00
4111 *
4112 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
4113 * @return Zend_Date
4114 */
4115 public function getMinute($locale = null)
4116 {
4117 if (self::$_options['format_type'] == 'php') {
4118 $format = 'i';
4119 } else {
4120 $format = self::MINUTE;
4121 }
4122
4123 return $this->copyPart($format, $locale);
4124 }
4125
4126
4127 /**
4128 * Sets a new minute
4129 * The minute is always a number.
4130 * Returned is the new date object
4131 * Example: 04.May.1993 13:07:25 -> setMinute(29); -> 04.May.1993 13:29:25
4132 *
4133 * @param string|integer|array|Zend_Date $minute Minute to set
4134 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
4135 * @return $this
4136 * @throws Zend_Date_Exception
4137 */
4138 public function setMinute($minute, $locale = null)
4139 {
4140 return $this->_calcvalue('set', $minute, 'minute', self::MINUTE_SHORT, $locale);
4141 }
4142
4143
4144 /**
4145 * Adds minutes to the existing date object.
4146 * The minute is always a number.
4147 * Returned is the new date object
4148 * Example: 04.May.1993 13:07:25 -> addMinute(65); -> 04.May.1993 13:12:25
4149 *
4150 * @param string|integer|array|Zend_Date $minute Minute to add
4151 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
4152 * @return $this
4153 * @throws Zend_Date_Exception
4154 */
4155 public function addMinute($minute, $locale = null)
4156 {
4157 return $this->_calcvalue('add', $minute, 'minute', self::MINUTE_SHORT, $locale);
4158 }
4159
4160
4161 /**
4162 * Subtracts minutes from the existing date object.
4163 * The minute is always a number.
4164 * Returned is the new date object
4165 * Example: 04.May.1993 13:07:25 -> subMinute(9); -> 04.May.1993 12:58:25
4166 *
4167 * @param string|integer|array|Zend_Date $minute Minute to sub
4168 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
4169 * @return $this
4170 * @throws Zend_Date_Exception
4171 */
4172 public function subMinute($minute, $locale = null)
4173 {
4174 return $this->_calcvalue('sub', $minute, 'minute', self::MINUTE_SHORT, $locale);
4175 }
4176
4177
4178 /**
4179 * Compares the minute with the existing date object.
4180 * For example: 10:30:25 -> compareMinute(30) -> 0
4181 * Returns if equal, earlier or later
4182 *
4183 * @param string|integer|array|Zend_Date $minute Hour to compare
4184 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
4185 * @return integer 0 = equal, 1 = later, -1 = earlier
4186 * @throws Zend_Date_Exception
4187 */
4188 public function compareMinute($minute, $locale = null)
4189 {
4190 return $this->_calcvalue('cmp', $minute, 'minute', self::MINUTE_SHORT, $locale);
4191 }
4192
4193
4194 /**
4195 * Returns the second as new date object
4196 * Example: 02.Feb.1986 10:30:25 -> 01.Jan.1970 00:00:25
4197 *
4198 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
4199 * @return Zend_Date
4200 */
4201 public function getSecond($locale = null)
4202 {
4203 if (self::$_options['format_type'] == 'php') {
4204 $format = 's';
4205 } else {
4206 $format = self::SECOND;
4207 }
4208
4209 return $this->copyPart($format, $locale);
4210 }
4211
4212
4213 /**
4214 * Sets new seconds to the existing date object.
4215 * The second is always a number.
4216 * Returned is the new date object
4217 * Example: 04.May.1993 13:07:25 -> setSecond(100); -> 04.May.1993 13:08:40
4218 *
4219 * @param string|integer|array|Zend_Date $second Second to set
4220 * @param string|Zend_Locale $locale (Optional) Locale for parsing input
4221 * @return $this
4222 * @throws Zend_Date_Exception
4223 */
4224 public function setSecond($second, $locale = null)
4225 {
4226 return $this->_calcvalue('set', $second, 'second', self::SECOND_SHORT, $locale);
4227 }
4228
4229
4230 /**
4231 * Adds seconds to the existing date object.
4232 * The second is always a number.
4233 * Returned is the new date object
4234 * Example: 04.May.1993 13:07:25 -> addSecond(65); -> 04.May.1993 13:08:30
4235 *
4236 * @param string|integer|array|Zend_Date $second Second to add
4237 * @param string|Zend_Locale $locale (Optional) Locale for parsing input
4238 * @return $this
4239 * @throws Zend_Date_Exception
4240 */
4241 public function addSecond($second, $locale = null)
4242 {
4243 return $this->_calcvalue('add', $second, 'second', self::SECOND_SHORT, $locale);
4244 }
4245
4246
4247 /**
4248 * Subtracts seconds from the existing date object.
4249 * The second is always a number.
4250 * Returned is the new date object
4251 * Example: 04.May.1993 13:07:25 -> subSecond(10); -> 04.May.1993 13:07:15
4252 *
4253 * @param string|integer|array|Zend_Date $second Second to sub
4254 * @param string|Zend_Locale $locale (Optional) Locale for parsing input
4255 * @return $this
4256 * @throws Zend_Date_Exception
4257 */
4258 public function subSecond($second, $locale = null)
4259 {
4260 return $this->_calcvalue('sub', $second, 'second', self::SECOND_SHORT, $locale);
4261 }
4262
4263
4264 /**
4265 * Compares the second with the existing date object.
4266 * For example: 10:30:25 -> compareSecond(25) -> 0
4267 * Returns if equal, earlier or later
4268 *
4269 * @param string|integer|array|Zend_Date $second Second to compare
4270 * @param string|Zend_Locale $locale (Optional) Locale for parsing input
4271 * @return integer 0 = equal, 1 = later, -1 = earlier
4272 * @throws Zend_Date_Exception
4273 */
4274 public function compareSecond($second, $locale = null)
4275 {
4276 return $this->_calcvalue('cmp', $second, 'second', self::SECOND_SHORT, $locale);
4277 }
4278
4279
4280 /**
4281 * Returns the precision for fractional seconds
4282 *
4283 * @return integer
4284 */
4285 public function getFractionalPrecision()
4286 {
4287 return $this->_precision;
4288 }
4289
4290
4291 /**
4292 * Sets a new precision for fractional seconds
4293 *
4294 * @param integer $precision Precision for the fractional datepart 3 = milliseconds
4295 * @throws Zend_Date_Exception
4296 * @return $this
4297 */
4298 public function setFractionalPrecision($precision)
4299 {
4300 if (!(int)$precision || ($precision < 0) || ($precision > 9)) {
4301 require_once 'Zend/Date/Exception.php';
4302 throw new Zend_Date_Exception("precision ($precision) must be a positive integer less than 10", 0, null, $precision);
4303 }
4304
4305 $this->_precision = (int) $precision;
4306 if ($this->_precision < strlen($this->_fractional)) {
4307 $this->_fractional = substr($this->_fractional, 0, $this->_precision);
4308 } else {
4309 $this->_fractional = str_pad($this->_fractional, $this->_precision, '0', STR_PAD_RIGHT);
4310 }
4311
4312 return $this;
4313 }
4314
4315
4316 /**
4317 * Returns the milliseconds of the date object
4318 *
4319 * @return int
4320 */
4321 public function getMilliSecond()
4322 {
4323 return $this->_fractional;
4324 }
4325
4326 /**
4327 * Sets new milliseconds for the date object
4328 * Example: setMilliSecond(550, 2) -> equals +5 Sec +50 MilliSec
4329 *
4330 * @param integer|Zend_Date $milli (Optional) Millisecond to set, when null the actual millisecond is set
4331 * @param integer $precision (Optional) Fraction precision of the given milliseconds
4332 * @throws Zend_Date_Exception
4333 * @return $this
4334 */
4335 public function setMilliSecond($milli = null, $precision = null)
4336 {
4337 if ($milli === null) {
4338 [$milli, $time] = explode(" ", microtime());
4339 $milli = (int)$milli;
4340 $precision = 6;
4341 } else if (!is_numeric($milli)) {
4342 require_once 'Zend/Date/Exception.php';
4343 throw new Zend_Date_Exception("invalid milli second ($milli) operand", 0, null, $milli);
4344 }
4345
4346 if ($precision === null) {
4347 $precision = $this->_precision;
4348 }
4349
4350 if (!is_int($precision) || $precision < 1 || $precision > 9) {
4351 require_once 'Zend/Date/Exception.php';
4352 throw new Zend_Date_Exception("precision ($precision) must be a positive integer less than 10", 0, null, $precision);
4353 }
4354
4355 $this->_fractional = 0;
4356 $this->addMilliSecond($milli, $precision);
4357 return $this;
4358 }
4359
4360 /**
4361 * Adds milliseconds to the date object
4362 *
4363 * @param integer|Zend_Date $milli (Optional) Millisecond to add, when null the actual millisecond is added
4364 * @param integer $precision (Optional) Fractional precision for the given milliseconds
4365 * @throws Zend_Date_Exception
4366 * @return $this
4367 */
4368 public function addMilliSecond($milli = null, $precision = null)
4369 {
4370 if ($milli === null) {
4371 [$milli, $time] = explode(" ", microtime());
4372 $milli = (int)$milli;
4373 } else if (!is_numeric($milli)) {
4374 require_once 'Zend/Date/Exception.php';
4375 throw new Zend_Date_Exception("invalid milli second ($milli) operand", 0, null, $milli);
4376 }
4377
4378 if ($precision === null) {
4379 // Use internal default precision
4380 // Is not as logic as using the length of the input. But this would break tests and maybe other things
4381 // as an input value of integer 10, which is used in tests, must be parsed as 10 milliseconds (real milliseconds, precision 3)
4382 // but with auto-detect of precision, 100 milliseconds would be added.
4383 $precision = $this->_precision;
4384 }
4385
4386 if (!is_int($precision) || $precision < 1 || $precision > 9) {
4387 require_once 'Zend/Date/Exception.php';
4388 throw new Zend_Date_Exception(
4389 "precision ($precision) must be a positive integer less than 10", 0, null, $precision
4390 );
4391 }
4392
4393 if ($this->_precision > $precision) {
4394 $milli = $milli * pow(10, $this->_precision - $precision);
4395 } elseif ($this->_precision < $precision) {
4396 $milli = round($milli / pow(10, $precision - $this->_precision));
4397 }
4398
4399 $this->_fractional += $milli;
4400
4401 // Add/sub milliseconds + add/sub seconds
4402 $max = pow(10, $this->_precision);
4403 // Milli includes seconds
4404 if ($this->_fractional >= $max) {
4405 while ($this->_fractional >= $max) {
4406 $this->addSecond(1);
4407 $this->_fractional -= $max;
4408 }
4409 }
4410
4411 if ($this->_fractional < 0) {
4412 while ($this->_fractional < 0) {
4413 $this->subSecond(1);
4414 $this->_fractional += $max;
4415 }
4416 }
4417
4418 if ($this->_precision > strlen($this->_fractional)) {
4419 $this->_fractional = str_pad($this->_fractional, $this->_precision, '0', STR_PAD_LEFT);
4420 }
4421
4422 return $this;
4423 }
4424
4425
4426 /**
4427 * Subtracts a millisecond
4428 *
4429 * @param integer|Zend_Date $milli (Optional) Millisecond to sub, when null the actual millisecond is subtracted
4430 * @param integer $precision (Optional) Fractional precision for the given milliseconds
4431 * @return $this
4432 */
4433 public function subMilliSecond($milli = null, $precision = null)
4434 {
4435 $this->addMilliSecond(0 - $milli, $precision);
4436 return $this;
4437 }
4438
4439 /**
4440 * Compares only the millisecond part, returning the difference
4441 *
4442 * @param integer|Zend_Date $milli OPTIONAL Millisecond to compare, when null the actual millisecond is compared
4443 * @param integer $precision OPTIONAL Fractional precision for the given milliseconds
4444 * @throws Zend_Date_Exception On invalid input
4445 * @return integer 0 = equal, 1 = later, -1 = earlier
4446 */
4447 public function compareMilliSecond($milli = null, $precision = null)
4448 {
4449 if ($milli === null) {
4450 [$milli, $time] = explode(" ", microtime());
4451 $milli = (int)$milli;
4452 } else if (is_numeric($milli) === false) {
4453 require_once 'Zend/Date/Exception.php';
4454 throw new Zend_Date_Exception("invalid milli second ($milli) operand", 0, null, $milli);
4455 }
4456
4457 if ($precision === null) {
4458 $precision = strlen($milli);
4459 } else if (!is_int($precision) || $precision < 1 || $precision > 9) {
4460 require_once 'Zend/Date/Exception.php';
4461 throw new Zend_Date_Exception("precision ($precision) must be a positive integer less than 10", 0, null, $precision);
4462 }
4463
4464 if ($precision === 0) {
4465 require_once 'Zend/Date/Exception.php';
4466 throw new Zend_Date_Exception('precision is 0');
4467 }
4468
4469 if ($precision != $this->_precision) {
4470 if ($precision > $this->_precision) {
4471 $diff = $precision - $this->_precision;
4472 $milli = (int) ($milli / (10 * $diff));
4473 } else {
4474 $diff = $this->_precision - $precision;
4475 $milli = (int) ($milli * (10 * $diff));
4476 }
4477 }
4478
4479 $comp = $this->_fractional - $milli;
4480 if ($comp < 0) {
4481 return -1;
4482 } else if ($comp > 0) {
4483 return 1;
4484 }
4485 return 0;
4486 }
4487
4488 /**
4489 * Returns the week as new date object using monday as beginning of the week
4490 * Example: 12.Jan.2007 -> 08.Jan.1970 00:00:00
4491 *
4492 * @param Zend_Locale $locale OPTIONAL Locale for parsing input
4493 * @return Zend_Date
4494 */
4495 public function getWeek($locale = null)
4496 {
4497 if (self::$_options['format_type'] == 'php') {
4498 $format = 'W';
4499 } else {
4500 $format = self::WEEK;
4501 }
4502
4503 return $this->copyPart($format, $locale);
4504 }
4505
4506 /**
4507 * Sets a new week. The week is always a number. The day of week is not changed.
4508 * Returned is the new date object
4509 * Example: 09.Jan.2007 13:07:25 -> setWeek(1); -> 02.Jan.2007 13:07:25
4510 *
4511 * @param string|integer|array|Zend_Date $week Week to set
4512 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
4513 * @return $this
4514 * @throws Zend_Date_Exception
4515 */
4516 public function setWeek($week, $locale = null)
4517 {
4518 return $this->_calcvalue('set', $week, 'week', self::WEEK, $locale);
4519 }
4520
4521 /**
4522 * Adds a week. The week is always a number. The day of week is not changed.
4523 * Returned is the new date object
4524 * Example: 09.Jan.2007 13:07:25 -> addWeek(1); -> 16.Jan.2007 13:07:25
4525 *
4526 * @param string|integer|array|Zend_Date $week Week to add
4527 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
4528 * @return $this
4529 * @throws Zend_Date_Exception
4530 */
4531 public function addWeek($week, $locale = null)
4532 {
4533 return $this->_calcvalue('add', $week, 'week', self::WEEK, $locale);
4534 }
4535
4536 /**
4537 * Subtracts a week. The week is always a number. The day of week is not changed.
4538 * Returned is the new date object
4539 * Example: 09.Jan.2007 13:07:25 -> subWeek(1); -> 02.Jan.2007 13:07:25
4540 *
4541 * @param string|integer|array|Zend_Date $week Week to sub
4542 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
4543 * @return $this
4544 * @throws Zend_Date_Exception
4545 */
4546 public function subWeek($week, $locale = null)
4547 {
4548 return $this->_calcvalue('sub', $week, 'week', self::WEEK, $locale);
4549 }
4550
4551 /**
4552 * Compares only the week part, returning the difference
4553 * Returned is the new date object
4554 * Returns if equal, earlier or later
4555 * Example: 09.Jan.2007 13:07:25 -> compareWeek(2); -> 0
4556 *
4557 * @param string|integer|array|Zend_Date $week Week to compare
4558 * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input
4559 * @return integer 0 = equal, 1 = later, -1 = earlier
4560 */
4561 public function compareWeek($week, $locale = null)
4562 {
4563 return $this->_calcvalue('cmp', $week, 'week', self::WEEK, $locale);
4564 }
4565
4566 /**
4567 * Sets a new standard locale for the date object.
4568 * This locale will be used for all functions
4569 * Returned is the really set locale.
4570 * Example: 'de_XX' will be set to 'de' because 'de_XX' does not exist
4571 * 'xx_YY' will be set to 'root' because 'xx' does not exist
4572 *
4573 * @param string|Zend_Locale $locale (Optional) Locale for parsing input
4574 * @throws Zend_Date_Exception When the given locale does not exist
4575 * @return $this
4576 */
4577 public function setLocale($locale = null)
4578 {
4579 try {
4580 $this->_locale = Zend_Locale::findLocale($locale);
4581 } catch (Zend_Locale_Exception $e) {
4582 require_once 'Zend/Date/Exception.php';
4583 throw new Zend_Date_Exception($e->getMessage(), 0, $e);
4584 }
4585
4586 return $this;
4587 }
4588
4589 /**
4590 * Returns the actual set locale
4591 *
4592 * @return string|null
4593 */
4594 public function getLocale()
4595 {
4596 return $this->_locale;
4597 }
4598
4599 /**
4600 * Checks if the given date is a real date or datepart.
4601 * Returns false if a expected datepart is missing or a datepart exceeds its possible border.
4602 * But the check will only be done for the expected dateparts which are given by format.
4603 * If no format is given the standard dateformat for the actual locale is used.
4604 * f.e. 30.February.2007 will return false if format is 'dd.MMMM.YYYY'
4605 *
4606 * @param string|array|Zend_Date $date Date to parse for correctness
4607 * @param string $format (Optional) Format for parsing the date string
4608 * @param string|Zend_Locale $locale (Optional) Locale for parsing date parts
4609 * @return boolean True when all date parts are correct
4610 */
4611 public static function isDate($date, $format = null, $locale = null)
4612 {
4613 if (!is_string($date) && !is_numeric($date) && !($date instanceof Zend_Date) &&
4614 !is_array($date)) {
4615 return false;
4616 }
4617
4618 if (($format !== null) && ($format != 'ee') && ($format != 'ss') && ($format != 'GG') && ($format != 'MM') && ($format != 'EE') && ($format != 'TT')
4619 && (Zend_Locale::isLocale($format, null, false))) {
4620 $locale = $format;
4621 $format = null;
4622 }
4623
4624 $locale = Zend_Locale::findLocale($locale);
4625
4626 if ($format === null) {
4627 $format = Zend_Locale_Format::getDateFormat($locale);
4628 } else if ((self::$_options['format_type'] == 'php') && !defined($format)) {
4629 $format = Zend_Locale_Format::convertPhpToIsoFormat($format);
4630 }
4631
4632 $format = self::_getLocalizedToken($format, $locale);
4633 if (!is_array($date)) {
4634 try {
4635 $parsed = Zend_Locale_Format::getDate($date, ['locale' => $locale,
4636 'date_format' => $format, 'format_type' => 'iso',
4637 'fix_date' => false]);
4638 } catch (Zend_Locale_Exception $e) {
4639 // Date can not be parsed
4640 return false;
4641 }
4642 } else {
4643 $parsed = $date;
4644 }
4645
4646 if (((strpos($format, 'Y') !== false) || (strpos($format, 'y') !== false)) &&
4647 (!isset($parsed['year']))) {
4648 // Year expected but not found
4649 return false;
4650 }
4651
4652 if ((strpos($format, 'M') !== false) && (!isset($parsed['month']))) {
4653 // Month expected but not found
4654 return false;
4655 }
4656
4657 if ((strpos($format, 'd') !== false) && (!isset($parsed['day']))) {
4658 // Day expected but not found
4659 return false;
4660 }
4661
4662 if (((strpos($format, 'H') !== false) || (strpos($format, 'h') !== false)) &&
4663 (!isset($parsed['hour']))) {
4664 // Hour expected but not found
4665 return false;
4666 }
4667
4668 if ((strpos($format, 'm') !== false) && (!isset($parsed['minute']))) {
4669 // Minute expected but not found
4670 return false;
4671 }
4672
4673 if ((strpos($format, 's') !== false) && (!isset($parsed['second']))) {
4674 // Second expected but not found
4675 return false;
4676 }
4677
4678 // Set not given dateparts
4679 if (isset($parsed['hour']) === false) {
4680 $parsed['hour'] = 12;
4681 }
4682
4683 if (isset($parsed['minute']) === false) {
4684 $parsed['minute'] = 0;
4685 }
4686
4687 if (isset($parsed['second']) === false) {
4688 $parsed['second'] = 0;
4689 }
4690
4691 if (isset($parsed['month']) === false) {
4692 $parsed['month'] = 1;
4693 }
4694
4695 if (isset($parsed['day']) === false) {
4696 $parsed['day'] = 1;
4697 }
4698
4699 if (isset($parsed['year']) === false) {
4700 $parsed['year'] = 1970;
4701 }
4702
4703 if (self::isYearLeapYear($parsed['year'])) {
4704 $parsed['year'] = 1972;
4705 } else {
4706 $parsed['year'] = 1971;
4707 }
4708
4709 $date = new self($parsed, null, $locale);
4710 $timestamp = $date->mktime($parsed['hour'], $parsed['minute'], $parsed['second'],
4711 $parsed['month'], $parsed['day'], $parsed['year']);
4712
4713 if ($parsed['year'] != $date->date('Y', $timestamp)) {
4714 // Given year differs from parsed year
4715 return false;
4716 }
4717
4718 if ($parsed['month'] != $date->date('n', $timestamp)) {
4719 // Given month differs from parsed month
4720 return false;
4721 }
4722
4723 if ($parsed['day'] != $date->date('j', $timestamp)) {
4724 // Given day differs from parsed day
4725 return false;
4726 }
4727
4728 if ($parsed['hour'] != $date->date('G', $timestamp)) {
4729 // Given hour differs from parsed hour
4730 return false;
4731 }
4732
4733 if ($parsed['minute'] != $date->date('i', $timestamp)) {
4734 // Given minute differs from parsed minute
4735 return false;
4736 }
4737
4738 if ($parsed['second'] != $date->date('s', $timestamp)) {
4739 // Given second differs from parsed second
4740 return false;
4741 }
4742
4743 return true;
4744 }
4745
4746 /**
4747 * Returns the ISO Token for all localized constants
4748 *
4749 * @param string $token Token to normalize
4750 * @param string $locale Locale to search
4751 * @return string
4752 */
4753 protected static function _getLocalizedToken($token, $locale)
4754 {
4755 switch($token) {
4756 case self::ISO_8601 :
4757 return "yyyy-MM-ddThh:mm:ss";
4758 case self::RFC_2822 :
4759 return "EEE, dd MMM yyyy HH:mm:ss";
4760 case self::DATES :
4761 return Zend_Locale_Data::getContent($locale, 'date');
4762 case self::DATE_FULL :
4763 return Zend_Locale_Data::getContent($locale, 'date', ['gregorian', 'full']);
4764 case self::DATE_LONG :
4765 return Zend_Locale_Data::getContent($locale, 'date', ['gregorian', 'long']);
4766 case self::DATE_MEDIUM :
4767 return Zend_Locale_Data::getContent($locale, 'date', ['gregorian', 'medium']);
4768 case self::DATE_SHORT :
4769 return Zend_Locale_Data::getContent($locale, 'date', ['gregorian', 'short']);
4770 case self::TIMES :
4771 return Zend_Locale_Data::getContent($locale, 'time');
4772 case self::TIME_FULL :
4773 return Zend_Locale_Data::getContent($locale, 'time', ['gregorian', 'full']);
4774 case self::TIME_LONG :
4775 return Zend_Locale_Data::getContent($locale, 'time', ['gregorian', 'long']);
4776 case self::TIME_MEDIUM :
4777 return Zend_Locale_Data::getContent($locale, 'time', ['gregorian', 'medium']);
4778 case self::TIME_SHORT :
4779 return Zend_Locale_Data::getContent($locale, 'time', ['gregorian', 'short']);
4780 case self::DATETIME :
4781 return Zend_Locale_Data::getContent($locale, 'datetime');
4782 case self::DATETIME_FULL :
4783 return Zend_Locale_Data::getContent($locale, 'datetime', ['gregorian', 'full']);
4784 case self::DATETIME_LONG :
4785 return Zend_Locale_Data::getContent($locale, 'datetime', ['gregorian', 'long']);
4786 case self::DATETIME_MEDIUM :
4787 return Zend_Locale_Data::getContent($locale, 'datetime', ['gregorian', 'medium']);
4788 case self::DATETIME_SHORT :
4789 return Zend_Locale_Data::getContent($locale, 'datetime', ['gregorian', 'short']);
4790 case self::ATOM :
4791 case self::RFC_3339 :
4792 case self::W3C :
4793 return "yyyy-MM-DD HH:mm:ss";
4794 case self::COOKIE :
4795 case self::RFC_850 :
4796 return "EEEE, dd-MM-yyyy HH:mm:ss";
4797 case self::RFC_822 :
4798 case self::RFC_1036 :
4799 case self::RFC_1123 :
4800 case self::RSS :
4801 return "EEE, dd MM yyyy HH:mm:ss";
4802 }
4803
4804 return $token;
4805 }
4806 }
4807