Overview

Namespaces

  • Jyxo
    • Beholder
      • TestCase
    • Gettext
      • Parser
    • Input
      • Chain
      • Filter
      • Validator
    • Mail
      • Email
        • Attachment
      • Parser
      • Sender
    • Rpc
      • Json
      • Xml
    • Shell
    • Spl
    • Svn
    • Time
    • Webdav
  • PHP

Classes

  • Composer
  • Time
  • Util

Exceptions

  • ComposerException
  • Overview
  • Namespace
  • Class
  • Tree
  • Deprecated
  1: <?php
  2: 
  3: /**
  4:  * Jyxo PHP Library
  5:  *
  6:  * LICENSE
  7:  *
  8:  * This source file is subject to the new BSD license that is bundled
  9:  * with this package in the file license.txt.
 10:  * It is also available through the world-wide-web at this URL:
 11:  * https://github.com/jyxo/php/blob/master/license.txt
 12:  */
 13: 
 14: namespace Jyxo\Time;
 15: 
 16: /**
 17:  * Class for working with date and time.
 18:  * Internally uses a \DateTime object.
 19:  * Initialization is possible using almost any date/time format (unix timestamp, SQL form, ...).
 20:  *
 21:  * Requires the Gettext PHP extension or any other implementation of the _(string) translation function.
 22:  *
 23:  * @category Jyxo
 24:  * @package Jyxo\Time
 25:  * @copyright Copyright (c) 2005-2011 Jyxo, s.r.o.
 26:  * @license https://github.com/jyxo/php/blob/master/license.txt
 27:  * @author Jaroslav Hanslík
 28:  * @author Jan Kolibač
 29:  * @author Roman Řáha
 30:  * @author Martin Šamšula
 31:  * @author Ondřej Nešpor
 32:  */
 33: class Time implements \Serializable
 34: {
 35:     /**
 36:      * Second.
 37:      *
 38:      * @var string
 39:      */
 40:     const SECOND = 'second';
 41: 
 42:     /**
 43:      * Minute.
 44:      *
 45:      * @var string
 46:      */
 47:     const MINUTE = 'minute';
 48: 
 49:     /**
 50:      * Hour.
 51:      *
 52:      * @var string
 53:      */
 54:     const HOUR = 'hour';
 55: 
 56:     /**
 57:      * Day.
 58:      *
 59:      * @var string
 60:      */
 61:     const DAY = 'day';
 62: 
 63:     /**
 64:      * Week.
 65:      *
 66:      * @var string
 67:      */
 68:     const WEEK = 'week';
 69: 
 70:     /**
 71:      * Month.
 72:      *
 73:      * @var string
 74:      */
 75:     const MONTH = 'month';
 76: 
 77:     /**
 78:      * Year.
 79:      *
 80:      * @var string
 81:      */
 82:     const YEAR = 'year';
 83: 
 84:     /**
 85:      * Number of seconds in a second.
 86:      *
 87:      * @var integer
 88:      */
 89:     const INTERVAL_SECOND = 1;
 90: 
 91:     /**
 92:      * Number of seconds in a minute.
 93:      *
 94:      * @var integer
 95:      */
 96:     const INTERVAL_MINUTE = 60;
 97: 
 98:     /**
 99:      * Number of seconds in an hour.
100:      *
101:      * @var integer
102:      */
103:     const INTERVAL_HOUR = 3600;
104: 
105:     /**
106:      * Number of seconds in a day.
107:      *
108:      * @var integer
109:      */
110:     const INTERVAL_DAY = 86400;
111: 
112:     /**
113:      * Number of seconds in a week.
114:      *
115:      * @var integer
116:      */
117:     const INTERVAL_WEEK = 604800;
118: 
119:     /**
120:      * Number of seconds in a month.
121:      *
122:      * @var integer
123:      */
124:     const INTERVAL_MONTH = 2592000;
125: 
126:     /**
127:      * Number of seconds in a year.
128:      *
129:      * @var integer
130:      */
131:     const INTERVAL_YEAR = 31536000;
132: 
133:     /**
134:      * \DateTime instance.
135:      *
136:      * @var \DateTime
137:      */
138:     private $dateTime;
139: 
140:     /**
141:      * \DateTimeZone instance of the original timezone.
142:      *
143:      * @var \DateTimeZone
144:      */
145:     private $originalTimeZone;
146: 
147:     /**
148:      * Constructor.
149:      *
150:      * Creates an instance and initializes the internal date/time representation.
151:      *
152:      * @param string|integer|\Jyxo\Time\Time|\DateTime $time Date/time definition
153:      * @param string|\DateTimeZone $timeZone Time zone definition
154:      * @throws \InvalidArgumentException If an incompatible date/time format or time zone definition was provided
155:      */
156:     public function __construct($time, $timeZone = null)
157:     {
158:         if (!is_object($time)) {
159:             $timeZone = $this->createTimeZone($timeZone ? $timeZone : date_default_timezone_get());
160: 
161:             if (is_numeric($time)) {
162:                 // Unix timestamp as an integer or string
163:                 $this->dateTime = new \DateTime(null, $timeZone);
164:                 $this->dateTime->setTimestamp($time);
165:             } elseif (is_string($time)) {
166:                 // Textual representation
167:                 try {
168:                     $this->dateTime = new \DateTime($time, $timeZone);
169:                 } catch (\Exception $e) {
170:                     throw new \InvalidArgumentException(sprintf('Provided textual date/time definition "%s" is invalid', $time), 0, $e);
171:                 }
172:             } else {
173:                 throw new \InvalidArgumentException('Provided date/time must be a number, \Jyxo\Time\Time or \DateTime instance or a parameter compatible with PHP function strtotime().');
174:             }
175:         } elseif ($time instanceof self) {
176:             // \Jyxo\Time\Time
177:             $this->dateTime = new \DateTime($time->format('Y-m-d H:i:s'), $time->getTimeZone());
178:             if ($timeZone) {
179:                 $this->dateTime->setTimezone($this->createTimeZone($timeZone));
180:             }
181:         } elseif ($time instanceof \DateTime) {
182:             // \DateTime
183:             $this->dateTime = clone ($time);
184:             if ($timeZone) {
185:                 $this->dateTime->setTimezone($this->createTimeZone($timeZone));
186:             }
187:         } else {
188:             throw new \InvalidArgumentException('Provided date/time must be a number, \Jyxo\Time\Time or \DateTime instance or a parameter compatible with PHP function strtotime().');
189:         }
190:     }
191: 
192:     /**
193:      * Creates a \DateTimeZone object from a time zone definition
194:      *
195:      * @param string|\DateTimeZone $definition Time zone definition
196:      * @return \DateTimeZone
197:      * @throws \InvalidArgumentException If an invalid time zone definition was provided
198:      */
199:     protected function createTimeZone($definition)
200:     {
201:         if (is_string($definition)) {
202:             try {
203:                 return new \DateTimeZone($definition);
204:             } catch (\Exception $e) {
205:                 throw new \InvalidArgumentException(sprintf('Invalid timezone definition "%s"', $definition), 0, $e);
206:             }
207:         } elseif (!$definition instanceof \DateTimeZone) {
208:             throw new \InvalidArgumentException('Invalid timezone definition');
209:         }
210: 
211:         return $definition;
212:     }
213: 
214:     /**
215:      * Helper function for creating an instance with the given date/time.
216:      *
217:      * Useful for one-time usage.
218:      *
219:      * @param string|integer|\Jyxo\Time\Time|\DateTime $time Date/time definition
220:      * @param string|\DateTimeZone $timeZone Time zone definition
221:      * @return \Jyxo\Time\Time
222:      */
223:     public static function get($time, $timeZone = null)
224:     {
225:         return new self($time, $timeZone);
226:     }
227: 
228:     /**
229:      * Returns an instance with the current date/time.
230:      *
231:      * @return \Jyxo\Time\Time
232:      */
233:     public static function now()
234:     {
235:         return new self(time());
236:     }
237: 
238:     /**
239:      * Creates an instance using a date/time definition in the given format.
240:      *
241:      * @param string $format Date/time format
242:      * @param string $time Date/time definition
243:      * @return \Jyxo\Time\Time
244:      */
245:     public static function createFromFormat($format, $time)
246:     {
247:         return new self(\DateTime::createFromFormat($format, $time));
248:     }
249: 
250:     /**
251:      * Returns date/time in the requested format.
252:      *
253:      * @param string $name Format name
254:      * @return mixed
255:      * @throws \InvalidArgumentException If an unknown format is requested
256:      */
257:     public function __get($name)
258:     {
259:         switch ($name) {
260:             case 'sql':
261:                 return $this->dateTime->format(\DateTime::ISO8601);
262:             case 'email':
263:                 return $this->dateTime->format(\DateTime::RFC822);
264:             case 'web':
265:                 return $this->dateTime->format(\DateTime::W3C);
266:             case 'cookie':
267:                 return $this->dateTime->format(\DateTime::COOKIE);
268:             case 'rss':
269:                 return $this->dateTime->format(\DateTime::RSS);
270:             case 'unix':
271:                 // Returns false if the stored date/time has no valid unix timestamp representation
272:                 return $this->dateTime->getTimestamp();
273:             case 'http':
274:                 $this->setTemporaryTimeZone('GMT');
275:                 $result = $this->dateTime->format('D, d M Y H:i:s') . ' GMT';
276:                 $this->revertOriginalTimeZone();
277:                 return $result;
278:             case 'extended':
279:                 return $this->formatExtended();
280:             case 'interval':
281:                 return $this->formatAsInterval();
282:             case 'full':
283:                 if ((int) $this->dateTime->diff(new \DateTime())->format('%y%m%d%h') > 0) {
284:                     // If the difference between now and the stored date/time if greater than one hour
285:                     return $this->formatExtended();
286:                 } else {
287:                     return $this->formatAsInterval();
288:                 }
289:             default:
290:                 throw new \InvalidArgumentException(sprintf('Unknown format %s.', $name));
291:         }
292:     }
293: 
294:     /**
295:      * Calls a method directly on the internal \DateTime object.
296:      *
297:      * @param string $method Method name
298:      * @param array $args Method arguments
299:      * @return mixed
300:      */
301:     public function __call($method, $args)
302:     {
303:         return call_user_func_array(array($this->dateTime, $method), $args);
304:     }
305: 
306:     /**
307:      * Returns date/time in the unix timestamp format.
308:      *
309:      * @return string Returns empty string if the stored date/time has no valid UT representation
310:      */
311:     public function __toString()
312:     {
313:         return (string) $this->dateTime->getTimestamp();
314:     }
315: 
316:     /**
317:      * Returns the actual time zone.
318:      *
319:      * @return \DateTimeZone
320:      */
321:     public function getTimeZone()
322:     {
323:         return $this->dateTime->getTimezone();
324:     }
325: 
326:     /**
327:      * Sets a new time zone.
328:      *
329:      * @param string|\DateTimeZone $timeZone The new time zone
330:      * @return \Jyxo\Time\Time
331:      */
332:     public function setTimeZone($timeZone)
333:     {
334:         $this->dateTime->setTimezone($this->createTimeZone($timeZone));
335:         return $this;
336:     }
337: 
338:     /**
339:      * Sets a time zone temporarily.
340:      *
341:      * @param string|\DateTimeZone $timeZone Temporary time zone definition
342:      * @throws \InvalidArgumentException If an invalid time zone definition was provided
343:      */
344:     protected function setTemporaryTimeZone($timeZone)
345:     {
346:         $this->originalTimeZone = $this->dateTime->getTimezone();
347:         try {
348:             $this->setTimeZone($this->createTimeZone($timeZone));
349:         } catch (\InvalidArgumentException $e) {
350:             $this->originalTimeZone = null;
351:             throw $e;
352:         }
353:     }
354: 
355:     /**
356:      * Reverts the original time zone.
357:      *
358:      * @return \Jyxo\Time\Time
359:      * @throws \InvalidArgumentException If there is no time zone to return to
360:      */
361:     protected function revertOriginalTimeZone()
362:     {
363:         if (null !== $this->originalTimeZone) {
364:             $this->dateTime->setTimezone($this->originalTimeZone);
365:             $this->originalTimeZone = null;
366:         }
367: 
368:         return $this;
369:     }
370: 
371:     /**
372:      * Returns date/time in the given format with months and days translated.
373:      *
374:      * @param string $format Requested format
375:      * @param string|\DateTimeZone $timeZone Result time zone definition
376:      * @return string
377:      */
378:     public function format($format, $timeZone = null)
379:     {
380:         // Prepares the right result time zone if needed
381:         if ($timeZone) {
382:             $this->setTemporaryTimeZone($timeZone);
383:         }
384: 
385:         // Translation required?
386:         if (preg_match('~(?:^|[^\\\])[lDFM]~', $format)) {
387:             static $days = array();
388:             if (empty($days)) {
389:                 $days = array(_('Monday'), _('Tuesday'), _('Wednesday'), _('Thursday'), _('Friday'), _('Saturday'), _('Sunday'));
390:             }
391: 
392:             static $daysShort = array();
393:             if (empty($daysShort)) {
394:                 $daysShort = array(_('Mon'), _('Tue'), _('Wed'), _('Thu'), _('Fri'), _('Sat'), _('Sun'));
395:             }
396: 
397:             static $months = array();
398:             if (empty($months)) {
399:                 $months = array(
400:                     _('January'), _('February'), _('March'), _('April'), _('May'), _('June'), _('July'), _('August'),
401:                     _('September'), _('October'), _('November'), _('December')
402:                 );
403:             }
404:             static $monthsGen = array();
405:             if (empty($monthsGen)) {
406:                 $monthsGen = array(
407:                     _('January#~Genitive'), _('February#~Genitive'), _('March#~Genitive'), _('April#~Genitive'), _('May#~Genitive'),
408:                     _('June#~Genitive'), _('July#~Genitive'), _('August#~Genitive'), _('September#~Genitive'),
409:                     _('October#~Genitive'), _('November#~Genitive'), _('December#~Genitive')
410:                 );
411:             }
412:             static $monthsShort = array();
413:             if (empty($monthsShort)) {
414:                 $monthsShort = array(_('Jan'), _('Feb'), _('Mar'), _('Apr'), _('May#~Shortcut'), _('Jun'), _('Jul'), _('Aug'), _('Sep'), _('Oct'), _('Nov'), _('Dec'));
415:             }
416: 
417:             // Replace certain identifiers with fake ones
418:             $search = array('~(^|[^\\\])l~', '~(^|[^\\\])D~', '~(^|[^\\\])F~', '~(^|[^\\\])M~');
419:             $replace = array('$1<===>', '$1<___>', '$1<--->', '$1<...>');
420:             $format = preg_replace($search, $replace, $format);
421: 
422:             // Format the rest of the date
423:             $date = $this->dateTime->format($format);
424: 
425:             // Calculate day and month
426:             $day = $this->dateTime->format('N') - 1;
427:             $month = $this->dateTime->format('n') - 1;
428: 
429:             // If the month is not at the beginning, the genitive case and lowercase will be used
430:             $monthName = 0 !== strpos($format, '<--->') ? mb_strtolower($monthsGen[$month], 'utf-8') : $months[$month];
431: 
432:             // Add translated days and months into the result
433:             $result = strtr(
434:                 $date,
435:                 array(
436:                     '<===>' => $days[$day],
437:                     '<___>' => $daysShort[$day],
438:                     '<--->' => $monthName,
439:                     '<...>' => $monthsShort[$month]
440:                 )
441:             );
442:         } else {
443:             // No need to translate
444:             $result = $this->dateTime->format($format);
445:         }
446: 
447:         // If a custom result timezone was specified, revert the original one
448:         if ($timeZone) {
449:             $this->revertOriginalTimeZone();
450:         }
451: 
452:         return $result;
453:     }
454: 
455:     /**
456:      * Returns date/time in the form of:
457:      *
458:      * Today at 10:00
459:      * Yesterday at 10:00
460:      * Friday at 10:00
461:      * 21. March 2009 at 10:00
462:      *
463:      * @param string $dateFormat Date format
464:      * @param string $timeFormat Time format
465:      * @param string|\DateTimeZone $timeZone Result time zone definition
466:      * @return string
467:      */
468:     public function formatExtended($dateFormat = 'j. F Y', $timeFormat = 'G:i', $timeZone = null)
469:     {
470:         // Sets a custom result time zone if needed
471:         if ($timeZone) {
472:             $this->setTemporaryTimeZone($timeZone);
473:         }
474: 
475:         if (($this->dateTime < new \DateTime('midnight - 6 days', $this->dateTime->getTimezone())) || ($this->dateTime >= new \DateTime('midnight + 24 hours', $this->dateTime->getTimezone()))) {
476:             // Past and future dates
477:             $date = $this->format($dateFormat);
478:         } elseif ($this->dateTime >= new \DateTime('midnight', $this->dateTime->getTimezone())) {
479:             // Today
480:             $date = _('Today');
481:         } elseif ($this->dateTime >= new \DateTime('midnight - 24 hours', $this->dateTime->getTimezone())) {
482:             // Yesterday
483:             $date = _('Yesterday');
484:         } else {
485:             // Last week
486:             static $days = array();
487:             if (empty($days)) {
488:                 $days = array(_('Monday'), _('Tuesday'), _('Wednesday'), _('Thursday'), _('Friday'), _('Saturday'), _('Sunday'));
489:             }
490:             $date = $days[$this->dateTime->format('N') - 1];
491:         }
492: 
493:         // If no time format is provided, only date will be returned
494:         if (empty($timeFormat)) {
495:             $result = $date;
496:         } else {
497:             // Returns date along with time
498:             $result = $date . ' ' . _('at') . ' ' . $this->dateTime->format($timeFormat);
499:         }
500: 
501:         // If a custom result timezone was specified, revert the original one
502:         if ($timeZone) {
503:             $this->revertOriginalTimeZone();
504:         }
505: 
506:         return $result;
507:     }
508: 
509:     /**
510:      * Function for formatting time differences into human readable forms.
511:      *
512:      * $t < 10 seconds = Now
513:      * 10 seconds <= $t < 60 seconds
514:      * 1 minute <= $t < 1 hour
515:      * 1 hour <= $t < 24 hours
516:      * 1 day <= $t < 7 days
517:      * 1 week <= $t < 4 weeks
518:      * 1 month <= $t < 12 months
519:      * 1 year <= $t < n years
520:      *
521:      * @param boolean $useTense Defines if declension should be used
522:      * @param string|\DateTimeZone $timeZone Result time zone definition
523:      * @return string
524:      */
525:     public function formatAsInterval($useTense = true, $timeZone = null)
526:     {
527:         static $intervalList = array(
528:             self::YEAR => self::INTERVAL_YEAR,
529:             self::MONTH => self::INTERVAL_MONTH,
530:             self::WEEK => self::INTERVAL_WEEK,
531:             self::DAY => self::INTERVAL_DAY,
532:             self::HOUR => self::INTERVAL_HOUR,
533:             self::MINUTE => self::INTERVAL_MINUTE,
534:             self::SECOND => self::INTERVAL_SECOND
535:         );
536: 
537:         // Comparison time zone
538:         $timeZone = $timeZone ? $this->createTimeZone($timeZone) : $this->dateTime->getTimezone();
539: 
540:         // Difference between the stored date/time and now
541:         $differenceObject = $this->dateTime->diff(new \DateTime(null, $timeZone));
542:         $diffArray = array_combine(
543:             array_keys($intervalList),
544:             explode('-', $differenceObject->format('%y-%m-0-%d-%h-%i-%s'))
545:         );
546: 
547:         // Compute the difference in seconds
548:         $diff = 0;
549:         foreach ($diffArray as $interval => $intervalCount) {
550:             $diff += $intervalList[$interval] * $intervalCount;
551:         }
552: 
553:         // If the difference is less than 10 seconds, "now" is returned
554:         if ($diff < 10) {
555:             return _('Now');
556:         }
557: 
558:         // Find the appropriate unit and calculate number of units
559:         foreach ($intervalList as $interval => $seconds) {
560:             if ($seconds <= $diff) {
561:                 $num = round($diff / $seconds);
562:                 break;
563:             }
564:         }
565: 
566:         // Past or future
567:         $period = '+' === $differenceObject->format('%R') ? 'past' : 'future';
568: 
569:         // Dictionary - this part could be written shorter but this implementation is faster
570:         $tense = $useTense ? $period : 'infinitive';
571:         switch ($tense) {
572:             // Past
573:             case 'past':
574:                 switch ($interval) {
575:                     case self::YEAR:
576:                         return sprintf(ngettext('Year ago', '%s years ago', $num), $num);
577:                     case self::MONTH:
578:                         return sprintf(ngettext('Month ago', '%s months ago', $num), $num);
579:                     case self::WEEK:
580:                         return sprintf(ngettext('Week ago', '%s weeks ago', $num), $num);
581:                     case self::DAY:
582:                         return sprintf(ngettext('Day ago', '%s days ago', $num), $num);
583:                     case self::HOUR:
584:                         return sprintf(ngettext('Hour ago', '%s hours ago', $num), $num);
585:                     case self::MINUTE:
586:                         return sprintf(ngettext('Minute ago', '%s minutes ago', $num), $num);
587:                     case self::SECOND:
588:                     default:
589:                         return sprintf(ngettext('Second ago', '%s seconds ago', $num), $num);
590:                 }
591:                 break;
592: 
593:             // Future
594:             case 'future':
595:                 switch ($interval) {
596:                     case self::YEAR:
597:                         return sprintf(ngettext('In year', 'In %s years', $num), $num);
598:                     case self::MONTH:
599:                         return sprintf(ngettext('In month', 'In %s months', $num), $num);
600:                     case self::WEEK:
601:                         return sprintf(ngettext('In week', 'In %s weeks', $num), $num);
602:                     case self::DAY:
603:                         return sprintf(ngettext('In day', 'In %s days', $num), $num);
604:                     case self::HOUR:
605:                         return sprintf(ngettext('In hour', 'In %s hours', $num), $num);
606:                     case self::MINUTE:
607:                         return sprintf(ngettext('In minute', 'In %s minutes', $num), $num);
608:                     case self::SECOND:
609:                     default:
610:                         return sprintf(ngettext('In second', 'In %s seconds', $num), $num);
611:                 }
612:                 break;
613: 
614:             // Infinitive
615:             case 'infinitive':
616:                 switch ($interval) {
617:                     case self::YEAR:
618:                         return sprintf(ngettext('Year', '%s years', $num), $num);
619:                     case self::MONTH:
620:                         return sprintf(ngettext('Month', '%s months', $num), $num);
621:                     case self::WEEK:
622:                         return sprintf(ngettext('Week', '%s weeks', $num), $num);
623:                     case self::DAY:
624:                         return sprintf(ngettext('Day', '%s days', $num), $num);
625:                     case self::HOUR:
626:                         return sprintf(ngettext('Hour', '%s hours', $num), $num);
627:                     case self::MINUTE:
628:                         return sprintf(ngettext('Minute', '%s minutes', $num), $num);
629:                     case self::SECOND:
630:                     default:
631:                         return sprintf(ngettext('Second', '%s seconds', $num), $num);
632:                 }
633:                 break;
634:             default:
635:                 break;
636:         }
637:     }
638: 
639:     /**
640:      * Returns a new date/time object and adds with the given interval added.
641:      *
642:      * @param integer|string $interval Number of seconds or a string compatible with the strtotime() function
643:      * @return \Jyxo\Time\Time
644:      */
645:     public function plus($interval)
646:     {
647:         if (is_numeric($interval)) {
648:             $interval .= ' seconds';
649:         }
650: 
651:         $dateTime = clone $this->dateTime;
652:         $dateTime->modify('+' . (string) $interval);
653: 
654:         return new self($dateTime);
655:     }
656: 
657:     /**
658:      * Returns a new date/time object and adds with the given interval subtracted.
659:      *
660:      * @param integer|string $interval Number of seconds or a string compatible with the strtotime() function
661:      * @return \Jyxo\Time\Time
662:      */
663:     public function minus($interval)
664:     {
665:         if (is_numeric($interval)) {
666:             $interval .= ' seconds';
667:         }
668: 
669:         $dateTime = clone $this->dateTime;
670:         $dateTime->modify('-' . (string) $interval);
671: 
672:         return new self($dateTime);
673:     }
674: 
675:     /**
676:      * Checks if the date/time already happened.
677:      *
678:      * Compares the internal date/time with the current local time of the appropriate time zone.
679:      *
680:      * @return boolean
681:      */
682:     public function hasHappened()
683:     {
684:         return '+' === $this->dateTime->diff(\DateTime::createFromFormat('U', time(), $this->dateTime->getTimezone()))->format('%R');
685:     }
686: 
687:     /**
688:      * Returns a new instance with date/time truncated to the given unit.
689:      *
690:      * @param string $unit Unit to truncate the date/time to
691:      * @return \Jyxo\Time\Time
692:      * @throws \InvalidArgumentException If an invalid unit is provided
693:      */
694:     public function truncate($unit)
695:     {
696:         $dateTime = array(
697:             self::YEAR => 0,
698:             self::MONTH => 1,
699:             self::DAY => 1,
700:             self::HOUR => 0,
701:             self::MINUTE => 0,
702:             self::SECOND => 0
703:         );
704: 
705:         switch ((string) $unit) {
706:             case self::SECOND:
707:                 $dateTime[self::SECOND] = $this->dateTime->format('s');
708:                 // Intentionally missing break
709:             case self::MINUTE:
710:                 $dateTime[self::MINUTE] = $this->dateTime->format('i');
711:                 // Intentionally missing break
712:             case self::HOUR:
713:                 $dateTime[self::HOUR] = $this->dateTime->format('H');
714:                 // Intentionally missing break
715:             case self::DAY:
716:                 $dateTime[self::DAY] = $this->dateTime->format('d');
717:                 // Intentionally missing break
718:             case self::MONTH:
719:                 $dateTime[self::MONTH] = $this->dateTime->format('m');
720:                 // Intentionally missing break
721:             case self::YEAR:
722:                 $dateTime[self::YEAR] = $this->dateTime->format('Y');
723:                 break;
724:             default:
725:                 throw new \InvalidArgumentException(sprintf('Time unit %s is not defined.', $unit));
726:         }
727: 
728:         return new self(vsprintf('%s-%s-%sT%s:%s:%s', $dateTime), $this->dateTime->getTimezone());
729:     }
730: 
731:     /**
732:      * Object serialization.
733:      *
734:      * @return string
735:      */
736:     public function serialize()
737:     {
738:         return $this->dateTime->format('Y-m-d H:i:s ') . $this->dateTime->getTimezone()->getName();
739:     }
740: 
741:     /**
742:      * Object deserialization.
743:      *
744:      * @param string $serialized Serialized data
745:      * @throws \InvalidArgumentException On deserialization error
746:      */
747:     public function unserialize($serialized)
748:     {
749:         try {
750:             $data = explode(' ', $serialized);
751:             if (count($data) != 3) {
752:                 throw new \Exception('Serialized data have to be in the "Y-m-d H:i:s TimeZone" format');
753:             }
754: 
755:             if (preg_match('~([+-]\d{2}):?([\d]{2})~', $data[2], $matches)) {
756:                 // Timezone defined by an UTC offset
757: 
758:                 if ($matches[2] < 0 || $matches[2] > 59 || intval($matches[1] . $matches[2]) < -1200 || intval($matches[1] . $matches[2]) > 1200) {
759:                     // Invalid offset - minutes part is invalid or the whole offset is not <= 12:00 and >= -12:00
760:                     throw new \Exception(sprintf('Invalid time zone UTC offset definition: %s', $matches[0]));
761:                 }
762: 
763:                 $data[1] .= ' ' . $matches[1] . $matches[2];
764:                 $this->dateTime = new \DateTime($data[0] . ' ' . $data[1]);
765:             } else {
766:                 $this->dateTime = new \DateTime($data[0] . ' ' . $data[1], $this->createTimeZone($data[2]));
767:             }
768: 
769:         } catch (\Exception $e) {
770:             throw new \InvalidArgumentException('Deserialization error', 0, $e);
771:         }
772:     }
773: }
774: 
Jyxo PHP Library API documentation generated by ApiGen 2.3.0