668 lines
21 KiB
PHP
668 lines
21 KiB
PHP
<?php
|
|
// DateTime.php
|
|
// Created: 2021-06-11
|
|
// Updated: 2023-01-01
|
|
|
|
namespace Index;
|
|
|
|
use DateInterval;
|
|
use DateTimeImmutable;
|
|
use DateTimeInterface;
|
|
use DateTimeZone;
|
|
use InvalidArgumentException;
|
|
use JsonSerializable;
|
|
use RuntimeException;
|
|
use Stringable;
|
|
|
|
/**
|
|
* Represents a date and time
|
|
*/
|
|
class DateTime extends DateTimeImmutable implements JsonSerializable, Stringable, IComparable, IEquatable {
|
|
/**
|
|
* Represents Sunday for getDayOfWeek.
|
|
*
|
|
* @var int
|
|
*/
|
|
public const SUNDAY = 0;
|
|
|
|
/**
|
|
* Represents Monday for getDayOfWeek.
|
|
*
|
|
* @var int
|
|
*/
|
|
public const MONDAY = 1;
|
|
|
|
/**
|
|
* Represents Tuesday for getDayOfWeek.
|
|
*
|
|
* @var int
|
|
*/
|
|
public const TUESDAY = 2;
|
|
|
|
/**
|
|
* Represents Wednesday for getDayOfWeek.
|
|
*
|
|
* @var int
|
|
*/
|
|
public const WEDNESDAY = 3;
|
|
|
|
/**
|
|
* Represents Thursday for getDayOfWeek.
|
|
*
|
|
* @var int
|
|
*/
|
|
public const THURSDAY = 4;
|
|
|
|
/**
|
|
* Represents Friday for getDayOfWeek.
|
|
*
|
|
* @var int
|
|
*/
|
|
public const FRIDAY = 5;
|
|
|
|
/**
|
|
* Represents Saturday for getDayOfWeek.
|
|
*
|
|
* @var int
|
|
*/
|
|
public const SATURDAY = 6;
|
|
|
|
private const COMPARE = 'YmdHisu';
|
|
|
|
/**
|
|
* Creates a new DateTime object.
|
|
*
|
|
* @see https://www.php.net/manual/en/datetime.formats.php
|
|
* @param string $dateTime A date/time string.
|
|
* @param DateTimeZone|null $timeZone An object representing the desired time zone.
|
|
* @return DateTime A new DateTime instance.
|
|
*/
|
|
public function __construct(string $dateTime = 'now', DateTimeZone|null $timeZone = null) {
|
|
parent::__construct($dateTime, $timeZone);
|
|
}
|
|
|
|
/**
|
|
* Gets the date component of this instance.
|
|
*
|
|
* @return DateTime New instance with the same date but the time set to 00:00:00.
|
|
*/
|
|
public function getDate(): DateTime {
|
|
return self::create($this->getYear(), $this->getMonth(), $this->getDay(), 0, 0, 0, 0, $this->getTimezone());
|
|
}
|
|
|
|
/**
|
|
* Gets the year component of this instance.
|
|
*
|
|
* @return int Year component.
|
|
*/
|
|
public function getYear(): int {
|
|
return (int)$this->format('Y');
|
|
}
|
|
|
|
/**
|
|
* Gets the month component of this instance.
|
|
*
|
|
* @return int Month component, ranging from 1 to 12.
|
|
*/
|
|
public function getMonth(): int {
|
|
return (int)$this->format('n');
|
|
}
|
|
|
|
/**
|
|
* Gets the day component of this instance.
|
|
*
|
|
* @return int Day component, ranging from 1 to 31.
|
|
*/
|
|
public function getDay(): int {
|
|
return (int)$this->format('j');
|
|
}
|
|
|
|
/**
|
|
* Gets the day of the week represented by this instance.
|
|
*
|
|
* See the SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY and SATURDAY constants for the possible return values of this function.
|
|
*
|
|
* @return int Integer between 0 and 6 representing the day of the week.
|
|
*/
|
|
public function getDayOfWeek(): int {
|
|
return (int)$this->format('w');
|
|
}
|
|
|
|
/**
|
|
* Gets the day of the year represented by this instance.
|
|
*
|
|
* @return int Day of the year, ranging from 1-366.
|
|
*/
|
|
public function getDayOfYear(): int {
|
|
return ((int)$this->format('z')) + 1;
|
|
}
|
|
|
|
/**
|
|
* Gets the ISO8601 week number of this instance.
|
|
*
|
|
* @return int Integer representing the current week number.
|
|
*/
|
|
public function getWeek(): int {
|
|
return (int)$this->format('W');
|
|
}
|
|
|
|
/**
|
|
* Gets the time of day for this instance.
|
|
*
|
|
* @return TimeSpan A TimeSpan representing the amount of time elapsed since midnight.
|
|
*/
|
|
public function getTimeOfDay(): TimeSpan {
|
|
return TimeSpan::create(0, $this->getHour(), $this->getMinute(), $this->getSecond(), $this->getMicrosecond());
|
|
}
|
|
|
|
/**
|
|
* Gets the hour component of this instance.
|
|
*
|
|
* @return int Hour component, ranging from 0 to 23.
|
|
*/
|
|
public function getHour(): int {
|
|
return (int)$this->format('G');
|
|
}
|
|
|
|
/**
|
|
* Gets the minute component of this instance.
|
|
*
|
|
* @return int Minute component, ranging from 0 to 59.
|
|
*/
|
|
public function getMinute(): int {
|
|
return (int)$this->format('i');
|
|
}
|
|
|
|
/**
|
|
* Gets the second component of this instance.
|
|
*
|
|
* @return int Second component, ranging from 0 to 59.
|
|
*/
|
|
public function getSecond(): int {
|
|
return (int)$this->format('s');
|
|
}
|
|
|
|
/**
|
|
* Gets the millisecond component of this instance.
|
|
*
|
|
* @return int Millisecond component, ranging from 0 to 999.
|
|
*/
|
|
public function getMillisecond(): int {
|
|
return (int)$this->format('v');
|
|
}
|
|
|
|
/**
|
|
* Gets the microsecond component of this instance.
|
|
*
|
|
* @return int Microsecond component, ranging from 0 to 999999.
|
|
*/
|
|
public function getMicrosecond(): int {
|
|
return (int)$this->format('u');
|
|
}
|
|
|
|
/**
|
|
* Gets the number of seconds that have elapsed since midnight January 1st, 1970 UTC for this instance.
|
|
*
|
|
* @return int Number of seconds.
|
|
*/
|
|
public function getUnixTimeSeconds(): int {
|
|
return (int)$this->format('U');
|
|
}
|
|
|
|
/**
|
|
* Gets the number of milliseconds that have elapsed since midnight January 1st, 1970 UTC for this instance.
|
|
*
|
|
* @return float Number of milliseconds.
|
|
*/
|
|
public function getUnixTimeMilliseconds(): float {
|
|
return (float)$this->format('Uv');
|
|
}
|
|
|
|
/**
|
|
* Gets whether Daylight Savings is in effect during the time this instance represents.
|
|
*
|
|
* @return bool true if DST is in effect, false if not.
|
|
*/
|
|
public function isDaylightSavingTime(): bool {
|
|
return $this->format('I') !== '0';
|
|
}
|
|
|
|
/**
|
|
* Gets whether the year this instance represents is a leap year.
|
|
*
|
|
* @return bool true if the year is a leap year, false if not.
|
|
*/
|
|
public function isLeapYear(): bool {
|
|
return $this->format('L') !== '0';
|
|
}
|
|
|
|
/**
|
|
* Gets whether this DateTime uses UTC date/time.
|
|
*
|
|
* @return bool true if UTC, false if not.
|
|
*/
|
|
public function isUTC(): bool {
|
|
return $this->getTimezone()->equals(TimeZoneInfo::utc());
|
|
}
|
|
|
|
/**
|
|
* Gets the time zone for this instance.
|
|
*
|
|
* @return TimeZoneInfo Time zone for this instance.
|
|
*/
|
|
public function getTimezone(): TimeZoneInfo {
|
|
return TimeZoneInfo::cast(parent::getTimezone());
|
|
}
|
|
|
|
/**
|
|
* Adds a period of time to this date time object.
|
|
*
|
|
* @param DateInterval $timeSpan Time period to add to this DateTime.
|
|
* @return DateTime A DateTime instance which is the sum of this instance and the provided period.
|
|
*/
|
|
public function add(DateInterval $timeSpan): DateTime {
|
|
return self::cast(parent::add($timeSpan));
|
|
}
|
|
|
|
/**
|
|
* Adds a number of years to this instance.
|
|
*
|
|
* @param float $years Number of years to add.
|
|
* @return DateTime New DateTime instance with the years added.
|
|
*/
|
|
public function addYears(float $years): DateTime {
|
|
return $this->add(TimeSpan::fromDays(365 * $years));
|
|
}
|
|
|
|
/**
|
|
* Adds a number of months to this instance.
|
|
*
|
|
* @param float $months Number of months to add.
|
|
* @return DateTime New DateTime instance with the months added.
|
|
*/
|
|
public function addMonths(float $months): DateTime {
|
|
return $this->add(TimeSpan::fromDays(365 * 31 * $months));
|
|
}
|
|
|
|
/**
|
|
* Adds a number of days to this instance.
|
|
*
|
|
* @param float $days Number of days to add.
|
|
* @return DateTime New DateTime instance with the days added.
|
|
*/
|
|
public function addDays(float $days): DateTime {
|
|
return $this->add(TimeSpan::fromDays($days));
|
|
}
|
|
|
|
/**
|
|
* Adds a number of hours to this instance.
|
|
*
|
|
* @param float $hours Number of hours to add.
|
|
* @return DateTime New DateTime instance with the hours added.
|
|
*/
|
|
public function addHours(float $hours): DateTime {
|
|
return $this->add(TimeSpan::fromHours($hours));
|
|
}
|
|
|
|
/**
|
|
* Adds a number of minutes to this instance.
|
|
*
|
|
* @param float $minutes Number of minutes to add.
|
|
* @return DateTime New DateTime instance with the minutes added.
|
|
*/
|
|
public function addMinutes(float $minutes): DateTime {
|
|
return $this->add(TimeSpan::fromMinutes($minutes));
|
|
}
|
|
|
|
/**
|
|
* Adds a number of seconds to this instance.
|
|
*
|
|
* @param float $seconds Number of seconds to add.
|
|
* @return DateTime New DateTime instance with the seconds added.
|
|
*/
|
|
public function addSeconds(float $seconds): DateTime {
|
|
return $this->add(TimeSpan::fromSeconds($seconds));
|
|
}
|
|
|
|
/**
|
|
* Adds a number of milliseconds to this instance.
|
|
*
|
|
* @param float $millis Number of milliseconds to add.
|
|
* @return DateTime New DateTime instance with the milliseconds added.
|
|
*/
|
|
public function addMilliseconds(float $millis): DateTime {
|
|
return $this->add(TimeSpan::fromMilliseconds($millis));
|
|
}
|
|
|
|
/**
|
|
* Adds a number of microseconds to this instance.
|
|
*
|
|
* @param float $micros Number of microseconds to add.
|
|
* @return DateTime New DateTime instance with the microseconds added.
|
|
*/
|
|
public function addMicroseconds(float $micros): DateTime {
|
|
return $this->add(TimeSpan::fromMicroseconds($micros));
|
|
}
|
|
|
|
/**
|
|
* Alias for subtract, must exist because of the DateTimeImmutable inheritance but I don't like short names.
|
|
*
|
|
* @internal
|
|
*/
|
|
public function sub(DateInterval $interval): DateTime {
|
|
return $this->subtract($interval);
|
|
}
|
|
|
|
/**
|
|
* Subtracts a time period from this DateTime.
|
|
*
|
|
* @param DateInterval $timeSpan Time period to be subtracted.
|
|
* @return DateTime A new DateTime instance which is this instance minus the given time period.
|
|
*/
|
|
public function subtract(DateInterval $timeSpan): DateTime {
|
|
return self::cast(parent::sub($timeSpan));
|
|
}
|
|
|
|
/**
|
|
* Alias for difference, must exist because of the DateTimeImmutable inheritance but I don't like short names.
|
|
*
|
|
* @internal
|
|
*/
|
|
public function diff(DateTimeInterface $dateTime, bool $absolute = false): TimeSpan {
|
|
return $this->difference($dateTime, $absolute);
|
|
}
|
|
|
|
/**
|
|
* Subtracts another Date/Time from this DateTime.
|
|
*
|
|
* @param DateTimeInterface $dateTime Date/time to subtract.
|
|
* @return TimeSpan Difference between this DateTime and the provided one.
|
|
*/
|
|
public function difference(DateTimeInterface $dateTime, bool $absolute = false): TimeSpan {
|
|
return TimeSpan::cast(parent::diff($dateTime, $absolute));
|
|
}
|
|
|
|
/**
|
|
* Applies a modifier on this instance and returns the result as a new instance.
|
|
*
|
|
* @see https://www.php.net/manual/en/datetime.formats.php
|
|
* @param string $modifier A date/time format.
|
|
* @return DateTime The modified date/time.
|
|
*/
|
|
public function modify(string $modifier): DateTime {
|
|
return self::cast(parent::modify($modifier));
|
|
}
|
|
|
|
/**
|
|
* Creates a new DateTime with the given date component.
|
|
*
|
|
* @param int $year Desired year component.
|
|
* @param int $month Desired month component.
|
|
* @param int $day Desired day component.
|
|
* @return DateTime A new DateTime instance with the given date component.
|
|
*/
|
|
public function setDate(int $year, int $month, int $day): DateTime {
|
|
return self::cast(parent::setDate($year, $month, $day));
|
|
}
|
|
|
|
/**
|
|
* Creates a new DateTime with the given ISO date for the date component.
|
|
*
|
|
* @param int $year Year of the date.
|
|
* @param int $week Week of the date.
|
|
* @param int $dayOfWeek Offset from the first of the week.
|
|
* @return DateTime A new DateTime instance with the given date component.
|
|
*/
|
|
public function setISODate(int $year, int $week, int $dayOfWeek = 1): DateTime {
|
|
return self::cast(parent::setISODate($year, $week, $dayOfWeek));
|
|
}
|
|
|
|
/**
|
|
* Creates a new DateTime with the given time component.
|
|
*
|
|
* @param int $hour Desired hour component.
|
|
* @param int $minute Desired minute component.
|
|
* @param int $second Desired second component.
|
|
* @param int $microsecond Desired microsecond component.
|
|
* @return DateTime A new DateTime instance with the given time component.
|
|
*/
|
|
public function setTime(int $hour, int $minute, int $second = 0, int $microsecond = 0): DateTime {
|
|
return self::cast(parent::setTime($hour, $minute, $second, $microsecond));
|
|
}
|
|
|
|
/**
|
|
* Creates a new DateTime with the date and time components based on a Unix timestamp.
|
|
*
|
|
* @param int $timestamp Unix timestamp representing the date.
|
|
* @return DateTime A new DateTime instance with the given date and time.
|
|
*/
|
|
public function setTimestamp(int $timestamp): DateTime {
|
|
return self::cast(parent::setTimestamp($timestamp));
|
|
}
|
|
|
|
/**
|
|
* Creates a new DateTime with the given time zone.
|
|
*
|
|
* @param DateTimeZone $timeZone An object representing the desired time zone.
|
|
* @return DateTime A new DateTime with the given time zone.
|
|
*/
|
|
public function setTimezone(DateTimeZone $timeZone): DateTime {
|
|
return self::cast(parent::setTimezone($timeZone));
|
|
}
|
|
|
|
public function compare(mixed $other): int {
|
|
if($other instanceof DateTimeInterface)
|
|
return strcmp($this->format(self::COMPARE), $other->format(self::COMPARE));
|
|
return -1;
|
|
}
|
|
|
|
public function equals(mixed $other): bool {
|
|
if($other instanceof DateTimeInterface)
|
|
return $this->format(self::COMPARE) === $other->format(self::COMPARE);
|
|
return false;
|
|
}
|
|
|
|
public function isLessThan(DateTimeInterface $other): bool {
|
|
return $this->compare($other) < 0;
|
|
}
|
|
|
|
public function isLessThanOrEqual(DateTimeInterface $other): bool {
|
|
return $this->compare($other) <= 0;
|
|
}
|
|
|
|
public function isMoreThan(DateTimeInterface $other): bool {
|
|
return $this->compare($other) > 0;
|
|
}
|
|
|
|
public function isMoreThanOrEqual(DateTimeInterface $other): bool {
|
|
return $this->compare($other) >= 0;
|
|
}
|
|
|
|
/**
|
|
* Formats this DateTime as an ISO8601 date/time string.
|
|
*
|
|
* @return string This object represented as an ISO8601 date/time string.
|
|
*/
|
|
public function toISO8601String(): string {
|
|
return $this->format(DateTimeInterface::ATOM);
|
|
}
|
|
|
|
/**
|
|
* Formats this DateTime as a Cookie date/time string.
|
|
*
|
|
* @return string This object represented as a Cookie date/time string.
|
|
*/
|
|
public function toCookieString(): string {
|
|
return $this->format(DateTimeInterface::COOKIE);
|
|
}
|
|
|
|
/**
|
|
* Formats this DateTime as an RFC 822 date/time string.
|
|
*
|
|
* @return string This object represented as an RFC 822 date/time string.
|
|
*/
|
|
public function toRFC822String(): string {
|
|
return $this->format(DateTimeInterface::RFC822);
|
|
}
|
|
|
|
/**
|
|
* Creates a string representation of this object.
|
|
*
|
|
* @return string Representation of this object.
|
|
*/
|
|
public function __toString(): string {
|
|
return $this->format(DateTimeInterface::ATOM);
|
|
}
|
|
|
|
/**
|
|
* Returns the data which should be serialized as json.
|
|
*
|
|
* @see https://www.php.net/manual/en/jsonserializable.jsonserialize.php
|
|
* @return mixed Data to be passed to json_encode.
|
|
*/
|
|
public function jsonSerialize(): mixed {
|
|
return (string)$this;
|
|
}
|
|
|
|
/**
|
|
* Converts this immutable \Index\DateTime type to a mutable \DateTime type.
|
|
*
|
|
* @return \DateTime A new mutable \DateTime instance.
|
|
*/
|
|
public function toNative(): \DateTime {
|
|
return \DateTime::createFromImmutable($this);
|
|
}
|
|
|
|
/**
|
|
* Creates a DateTime object that is set to the current date and time, expressed in the provided time zone.
|
|
*
|
|
* @param DateTimeZone $timeZone Desired time zone, null for the current default time zone.
|
|
* @return DateTime An instance representing now.
|
|
*/
|
|
public static function now(?DateTimeZone $timeZone = null): DateTime {
|
|
return new DateTime('now', $timeZone);
|
|
}
|
|
|
|
/**
|
|
* Creates a DateTime object that is set to the current date and time, expressed in UTC.
|
|
*
|
|
* @return DateTime An instance representing now in UTC.
|
|
*/
|
|
public static function utcNow(): DateTime {
|
|
return self::now(TimeZoneInfo::utc());
|
|
}
|
|
|
|
/**
|
|
* Converts Unix time seconds to a DateTime object.
|
|
*
|
|
* @param int $seconds Unix time seconds.
|
|
* @return DateTime A DateTime instance representing the Unix time.
|
|
*/
|
|
public static function fromUnixTimeSeconds(int $seconds): DateTime {
|
|
return new DateTime('@' . $seconds);
|
|
}
|
|
|
|
/**
|
|
* Converts Unix time milliseconds to a DateTime object.
|
|
*
|
|
* @param float $millis Unix time milliseconds.
|
|
* @return DateTime A DateTime instance representing the Unix time.
|
|
*/
|
|
public static function fromUnixTimeMilliseconds(float $millis): DateTime {
|
|
return new DateTime('@' . ($millis / 1000));
|
|
}
|
|
|
|
/**
|
|
* Creates a new DateTime instance with the given components.
|
|
*
|
|
* @param int $year Desired year component.
|
|
* @param int $month Desired month component.
|
|
* @param int $day Desired day component.
|
|
* @param int $hour Desired hour component.
|
|
* @param int $minute Desired minute component.
|
|
* @param int $second Desired second component.
|
|
* @param int $micros Desired microsecond component.
|
|
* @param ?DateTimeZone $timeZone Desired time zone.
|
|
*/
|
|
public static function create(int $year, int $month = 1, int $day = 1, int $hour = 0, int $minute = 0, int $second = 0, int $micros = 0, ?DateTimeZone $timeZone = null): DateTime {
|
|
if($year < 1 || $year > 9999)
|
|
throw new InvalidArgumentException('$year may not be less than 1 or more than 9999.');
|
|
if($month < 1 || $month > 12)
|
|
throw new InvalidArgumentException('$month may not be less than 1 or more than 12.');
|
|
if($day < 1 || $day > 31)
|
|
throw new InvalidArgumentException('$day may not be less than 1 or more than 31.');
|
|
if($hour < 0 || $hour > 23)
|
|
throw new InvalidArgumentException('$hour may not be less than 0 or more than 23.');
|
|
if($minute < 0 || $minute > 59)
|
|
throw new InvalidArgumentException('$minute may not be less than 0 or more than 59.');
|
|
if($second < 0 || $second > 59)
|
|
throw new InvalidArgumentException('$second may not be less than 0 or more than 59.');
|
|
if($micros < 0 || $micros > 999999)
|
|
throw new InvalidArgumentException('$micros may not be less than 0 or more than 999999.');
|
|
|
|
return new DateTime(
|
|
sprintf(
|
|
'%04d-%02d-%02dT%02d:%02d:%02d.%06d',
|
|
$year, $month, $day, $hour, $minute, $second, $micros
|
|
),
|
|
$timeZone
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Parses a time string and creates a DateTime using it.
|
|
*
|
|
* @see https://www.php.net/manual/en/datetime.createfromformat
|
|
* @param string $format Format that the passed string should be in.
|
|
* @param string $dateTime String representing the time.
|
|
* @param ?DateTimeZone $timeZone Desired time zone.
|
|
* @return DateTime|false A DateTime instance, or false on failure.
|
|
*/
|
|
public static function createFromFormat(string $format, string $dateTime, ?DateTimeZone $timeZone = null): DateTime|false {
|
|
$instance = parent::createFromFormat($format, $dateTime, $timeZone);
|
|
if($instance === false)
|
|
return false;
|
|
return self::cast($instance);
|
|
}
|
|
|
|
/**
|
|
* Creates a new DateTime instance from an interface implementation.
|
|
*
|
|
* @param DateTimeInterface $object Object that should be sourced.
|
|
* @return DateTime A new DateTime instance.
|
|
*/
|
|
public static function createFromInterface(DateTimeInterface $object): DateTime {
|
|
return self::cast($object);
|
|
}
|
|
|
|
/**
|
|
* Creates a new immutable DateTime instance from a mutable instance.
|
|
*
|
|
* @param \DateTime $object Mutable object that should be sourced.
|
|
* @return DateTime New immutable DateTime representing the same value.
|
|
*/
|
|
#[\ReturnTypeWillChange]
|
|
public static function createFromMutable(\DateTime $object): DateTime {
|
|
return self::cast($object);
|
|
}
|
|
|
|
/**
|
|
* @internal
|
|
*/
|
|
public static function __set_state(array $array): DateTime {
|
|
return self::cast(parent::__set_state($array));
|
|
}
|
|
|
|
/**
|
|
* Makes sure a DateTimeInterface implementing object is a DateTime instance.
|
|
*
|
|
* @param DateTimeInterface $dateTime Input object.
|
|
* @return DateTime If the input was a DateTime, the same instance will be returned.
|
|
* If the input was something else, a new DateTime instance will be returned based on the input.
|
|
*/
|
|
public static function cast(DateTimeInterface $dateTime): DateTime {
|
|
if($dateTime instanceof DateTime)
|
|
return $dateTime;
|
|
return new DateTime($dateTime->format('@U.u'), $dateTime->getTimezone());
|
|
}
|
|
}
|