263 lines
		
	
	
		
			7.9 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			263 lines
		
	
	
		
			7.9 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| 
 | |
| namespace Safe;
 | |
| 
 | |
| use DateInterval;
 | |
| use DateTime;
 | |
| use DateTimeInterface;
 | |
| use DateTimeZone;
 | |
| use Safe\Exceptions\DatetimeException;
 | |
| 
 | |
| /**
 | |
|  * This class is used to implement a safe version of the DatetimeImmutable class.
 | |
|  * While it technically overloads \DateTimeImmutable for typehint compatibility,
 | |
|  * it is actually used as a wrapper of \DateTimeImmutable, mostly to be able to overwrite functions like getTimestamp() while still being able to edit milliseconds via setTime().
 | |
|  */
 | |
| class DateTimeImmutable extends \DateTimeImmutable
 | |
| {
 | |
|     /**
 | |
|      * @var \DateTimeImmutable
 | |
|      */
 | |
|     private $innerDateTime;
 | |
| 
 | |
|     /**
 | |
|      * DateTimeImmutable constructor.
 | |
|      * @param string $time
 | |
|      * @param DateTimeZone|null $timezone
 | |
|      * @throws \Exception
 | |
|      */
 | |
|     public function __construct($time = 'now', $timezone = null)
 | |
|     {
 | |
|         parent::__construct($time, $timezone);
 | |
|         $this->innerDateTime = new parent($time, $timezone);
 | |
|     }
 | |
| 
 | |
|     //switch between regular datetime and safe version
 | |
|     public static function createFromRegular(\DateTimeImmutable $datetime): self
 | |
|     {
 | |
|         $safeDatetime = new self($datetime->format('Y-m-d H:i:s.u'), $datetime->getTimezone()); //we need to also update the wrapper to not break the operators '<' and '>'
 | |
|         $safeDatetime->innerDateTime = $datetime; //to make sure we don't lose information because of the format().
 | |
|         return $safeDatetime;
 | |
|     }
 | |
| 
 | |
|     //usefull if you need to switch back to regular DateTimeImmutable (for example when using DatePeriod)
 | |
|     public function getInnerDateTime(): \DateTimeImmutable
 | |
|     {
 | |
|         return $this->innerDateTime;
 | |
|     }
 | |
| 
 | |
|     /////////////////////////////////////////////////////////////////////////////
 | |
|     // overload functions with false errors
 | |
| 
 | |
|     /**
 | |
|      * @param string $format
 | |
|      * @param string $time
 | |
|      * @param DateTimeZone|null $timezone
 | |
|      * @throws DatetimeException
 | |
|      */
 | |
|     public static function createFromFormat($format, $time, $timezone = null): self
 | |
|     {
 | |
|         $datetime = parent::createFromFormat($format, $time, $timezone);
 | |
|         if ($datetime === false) {
 | |
|             throw DatetimeException::createFromPhpError();
 | |
|         }
 | |
|         return self::createFromRegular($datetime);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @param string $format
 | |
|      * @return string
 | |
|      * @throws DatetimeException
 | |
|      */
 | |
|     public function format($format): string
 | |
|     {
 | |
|         /** @var string|false $result */
 | |
|         $result = $this->innerDateTime->format($format);
 | |
|         if ($result === false) {
 | |
|             throw DatetimeException::createFromPhpError();
 | |
|         }
 | |
|         return $result;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @param DateTimeInterface $datetime2
 | |
|      * @param bool $absolute
 | |
|      * @return DateInterval
 | |
|      * @throws DatetimeException
 | |
|      */
 | |
|     public function diff($datetime2, $absolute = false): DateInterval
 | |
|     {
 | |
|         /** @var \DateInterval|false $result */
 | |
|         $result = $this->innerDateTime->diff($datetime2, $absolute);
 | |
|         if ($result === false) {
 | |
|             throw DatetimeException::createFromPhpError();
 | |
|         }
 | |
|         return $result;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @param string $modify
 | |
|      * @return DateTimeImmutable
 | |
|      * @throws DatetimeException
 | |
|      */
 | |
|     public function modify($modify): self
 | |
|     {
 | |
|         /** @var \DateTimeImmutable|false $result */
 | |
|         $result = $this->innerDateTime->modify($modify);
 | |
|         if ($result === false) {
 | |
|             throw DatetimeException::createFromPhpError();
 | |
|         }
 | |
|         return self::createFromRegular($result); //we have to recreate a safe datetime because modify create a new instance of \DateTimeImmutable
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @param int $year
 | |
|      * @param int $month
 | |
|      * @param int $day
 | |
|      * @return DateTimeImmutable
 | |
|      * @throws DatetimeException
 | |
|      */
 | |
|     public function setDate($year, $month, $day): self
 | |
|     {
 | |
|         /** @var \DateTimeImmutable|false $result */
 | |
|         $result = $this->innerDateTime->setDate($year, $month, $day);
 | |
|         if ($result === false) {
 | |
|             throw DatetimeException::createFromPhpError();
 | |
|         }
 | |
|         return self::createFromRegular($result); //we have to recreate a safe datetime because modify create a new instance of \DateTimeImmutable
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @param int $year
 | |
|      * @param int $week
 | |
|      * @param int $day
 | |
|      * @return DateTimeImmutable
 | |
|      * @throws DatetimeException
 | |
|      */
 | |
|     public function setISODate($year, $week, $day = 1): self
 | |
|     {
 | |
|         /** @var \DateTimeImmutable|false $result */
 | |
|         $result = $this->innerDateTime->setISODate($year, $week, $day);
 | |
|         if ($result === false) {
 | |
|             throw DatetimeException::createFromPhpError();
 | |
|         }
 | |
|         return self::createFromRegular($result); //we have to recreate a safe datetime because modify create a new instance of \DateTimeImmutable
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @param int $hour
 | |
|      * @param int $minute
 | |
|      * @param int $second
 | |
|      * @param int $microseconds
 | |
|      * @return DateTimeImmutable
 | |
|      * @throws DatetimeException
 | |
|      */
 | |
|     public function setTime($hour, $minute, $second = 0, $microseconds = 0): self
 | |
|     {
 | |
|         /** @var \DateTimeImmutable|false $result */
 | |
|         $result = $this->innerDateTime->setTime($hour, $minute, $second, $microseconds);
 | |
|         if ($result === false) {
 | |
|             throw DatetimeException::createFromPhpError();
 | |
|         }
 | |
|         return self::createFromRegular($result);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @param int $unixtimestamp
 | |
|      * @return DateTimeImmutable
 | |
|      * @throws DatetimeException
 | |
|      */
 | |
|     public function setTimestamp($unixtimestamp): self
 | |
|     {
 | |
|         /** @var \DateTimeImmutable|false $result */
 | |
|         $result = $this->innerDateTime->setTimestamp($unixtimestamp);
 | |
|         if ($result === false) {
 | |
|             throw DatetimeException::createFromPhpError();
 | |
|         }
 | |
|         return self::createFromRegular($result);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @param DateTimeZone $timezone
 | |
|      * @return DateTimeImmutable
 | |
|      * @throws DatetimeException
 | |
|      */
 | |
|     public function setTimezone($timezone): self
 | |
|     {
 | |
|         /** @var \DateTimeImmutable|false $result */
 | |
|         $result = $this->innerDateTime->setTimezone($timezone);
 | |
|         if ($result === false) {
 | |
|             throw DatetimeException::createFromPhpError();
 | |
|         }
 | |
|         return self::createFromRegular($result);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @param DateInterval $interval
 | |
|      * @return DateTimeImmutable
 | |
|      * @throws DatetimeException
 | |
|      */
 | |
|     public function sub($interval): self
 | |
|     {
 | |
|         /** @var \DateTimeImmutable|false $result */
 | |
|         $result = $this->innerDateTime->sub($interval);
 | |
|         if ($result === false) {
 | |
|             throw DatetimeException::createFromPhpError();
 | |
|         }
 | |
|         return self::createFromRegular($result);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @throws DatetimeException
 | |
|      */
 | |
|     public function getOffset(): int
 | |
|     {
 | |
|         /** @var int|false $result */
 | |
|         $result = $this->innerDateTime->getOffset();
 | |
|         if ($result === false) {
 | |
|             throw DatetimeException::createFromPhpError();
 | |
|         }
 | |
|         return $result;
 | |
|     }
 | |
| 
 | |
|     //////////////////////////////////////////////////////////////////////////////////////////
 | |
|     //overload getters to use the inner datetime immutable instead of itself
 | |
| 
 | |
|     /**
 | |
|      * @param DateInterval $interval
 | |
|      * @return DateTimeImmutable
 | |
|      */
 | |
|     public function add($interval): self
 | |
|     {
 | |
|         return self::createFromRegular($this->innerDateTime->add($interval));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @param DateTime $dateTime
 | |
|      * @return DateTimeImmutable
 | |
|      */
 | |
|     public static function createFromMutable($dateTime): self
 | |
|     {
 | |
|         return self::createFromRegular(parent::createFromMutable($dateTime));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @param mixed[] $array
 | |
|      * @return DateTimeImmutable
 | |
|      */
 | |
|     public static function __set_state($array): self
 | |
|     {
 | |
|         return self::createFromRegular(parent::__set_state($array));
 | |
|     }
 | |
| 
 | |
|     public function getTimezone(): DateTimeZone
 | |
|     {
 | |
|         return $this->innerDateTime->getTimezone();
 | |
|     }
 | |
| 
 | |
|     public function getTimestamp(): int
 | |
|     {
 | |
|         return $this->innerDateTime->getTimestamp();
 | |
|     }
 | |
| }
 |