Completed
Push — 3 ( bc9e38...39c73e )
by Robbie
05:15 queued 10s
created

Zend_Date::_calculate()   F

Complexity

Conditions 329
Paths > 20000

Size

Total Lines 1386

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 329
nc 714689
nop 4
dl 0
loc 1386
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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