= $r) $year += $c - 100; else $year += $c; } return $year; } /** * corriger une année à deux chiffres et retourner l'année à 4 chiffres. * l'année charnière entre année passée et année future est 70 * * par exemple, si l'année courante est 2019, alors: * - fix_past_year('18') === '2018' * - fix_past_year('19') === '2019' * - fix_past_year('20') === '2020' * - fix_past_year('69') === '2069' * - fix_past_year('70') === '1970' * - fix_past_year('71') === '1971' */ static function fix_any_year(int $year): int { if ($year < 100) { $y = getdate(); $y = $y["year"]; $r = $y % 100; $c = $y - $r; if ($year >= 70) $year += $c - 100; else $year += $c; } return $year; } static function parse_datetime($datetime): int { if ($datetime instanceof Datetime) { $datetime = $datetime->getTime(); } elseif ($datetime === null || is_int($datetime)) { if ($datetime === null) $datetime = time(); } elseif (is_array($datetime)) { [$y, $m, $d, $H, $M, $S] = $datetime; $datetime = mktime($H, $M, $S, $m, $d, $y); } elseif (is_string($datetime) && preg_match(self::PATTERN, $datetime, $ms)) { $d = intval($ms[1]); $m = intval($ms[2]); $y = intval($ms[3]); $H = intval($ms[4]); $M = intval($ms[5]); $S = intval($ms[6]); $datetime = mktime($H, $M, $S, $m, $d, $y); } else { throw ValueException::invalid_value($datetime, "datetime"); } return $datetime; } function __construct($datetime=null) { if ($datetime !== false) { $this->setTime(self::parse_datetime($datetime)); } } /** cet objet est-il l'instance nulle? */ function isNull(): bool { return false; } /** cet objet est-il l'heure indéfinie? */ function isUndef(): bool { return false; } /** * modifier la date pour que l'heure soit à 00:00:00 ce qui la rend propice à * l'utilisation comme borne inférieure d'une période */ function wrapStart(): self { $time = new Time(date("H:i:s", $this->time)); $this->time -= $time->getSeconds(); return $this; } /** * modifier la date pour que l'heure soit à 23:59:59 ce qui la rend propice à * l'utilisation comme borne supérieure d'une période */ function wrapEnd(): self { [$d, $m, $y] = explode("/", date("d/m/Y", $this->time)); $this->time = mktime(0, 0, 0, intval($m), intval($d) + 1, intval($y)) - 1; return $this; } protected function afterUpdate(): void { } /** @var int */ protected $time; function getTime(): int { return $this->time; } protected function setTime(?int $time): int { if ($time === null) $time = time(); $this->time = $time; $this->afterUpdate(); return $this->time; } protected static function new_d(int $time): \DateTime { $d = new \DateTime(); return $d->setTimestamp($time); } protected static function parse_d(string $date, $format="d/m/Y"): \DateTime { return date_create_from_format($format, $date); } protected static function wday(\DateTime $d): int { return intval($d->format("N")); } /** obtenir le numéro de jour de la semaine de 1 (lundi) à 7 (dimanche) */ function getWday(): int { return self::wday(self::new_d($this->time)); } protected static function wnum(\DateTime $d): int { return intval($d->format("W")); } /** obtenir le numéro de la semaine 1-52 */ function getWnum(): int { return self::wnum(self::new_d($this->time)); } function getPrevDay(int $nbdays=1, bool $skipWeekend=false): self { $d = self::new_d($this->time); if ($nbdays == 1 && $skipWeekend) { $wday = self::wday($d); if ($wday == 1) $nbdays = 3; } $d->sub(new \DateInterval("P".$nbdays."D")); return new static($d->getTimestamp()); } function getNextDay(int $nbdays=1, bool $skipWeekend=false): self { $d = self::new_d($this->time); if ($nbdays == 1 && $skipWeekend) { $wday = self::wday($d); if ($wday >= 5) $nbdays = 8 - $wday; } $d->add(new \DateInterval("P".$nbdays."D")); return new static($d->getTimestamp()); } function format(?string $format=null) { if ($format === null) $format = static::FORMAT; return date($format, $this->time); } function formatRfc4517(): string { return gmdate("YmdHis", $this->time)."Z"; } function __toString(): string { return $this->format(); } /** * comparer avec la datetime spécifiée. retourner une valeur négative, égale à * zéro ou positive suivant le résultat de la comparaison */ function cmp(Datetime $other): int { return $this->time - $other->getTime(); } /** tester si cette datetime est avant la datetime spécifiée */ function before(Datetime $other): bool { return $this->time <= $other->getTime(); } /** tester si cette datetime est après la datetime spécifiée */ function after(Datetime $other): bool { return $this->time >= $other->getTime(); } function getElapsed(?Datetime $now=null, int $resolution=Elapsed::RES_SECONDS): Elapsed { if ($now === null) $now = new Datetime(); if ($resolution === Elapsed::RES_DAYS) { $now = (new static($now))->wrapStart(); $self = (new static($this))->wrapStart(); } else { $self = $this; } return new Elapsed($now->getTime() - $self->getTime(), $resolution); } ############################################################################# private static $null; /** * @return Datetime une instance immutable représentant la valeur nulle. * * En général, on utilise directement null pour indiquer qu'il n'y a pas de * valeur, mais cette instance peut etre utilisée dans les contextes où null * n'est pas autorisé */ static final function null(): self { if (self::$null === null) { self::$null = new class extends Datetime { function __construct() { parent::__construct(false); $this->seconds = 0; self::$null = $this; } function isNull(): bool { return true; } function setTime(?int $time): int { throw IllegalAccessException::immutable_object(); } function __toString(): string { return ""; } }; } return self::$null; } private static $undef; /** * @return Datetime une instance immutable représentant une date non définie, * (c'est à dire qu'on ne sait pas de quelle date il s'agit). Cette * instance peut etre utilisée s'il faut pouvoir faire la différence entre * pas de valeur (null) et une valeur non définie (false) */ static final function undef(): self { if (self::$undef === null) { self::$undef = new class extends Datetime { function __construct() { parent::__construct(false); $this->seconds = 0; self::$undef = $this; } function isUndef(): bool { return true; } function setTime(?int $time): int { throw IllegalAccessException::immutable_object(); } function __toString(): string { return ""; } }; } return self::$undef; } }