nulib-base/php/src/php/time/DateTime.php

175 lines
6.2 KiB
PHP

<?php
namespace nulib\php\time;
use DateTimeImmutable;
use DateTimeInterface;
use DateTimeZone;
use InvalidArgumentException;
/**
* Class DateTime: une date et une heure
*
* @property-read int $year
* @property-read int $month
* @property-read int $day
* @property-read int $hour
* @property-read int $minute
* @property-read int $second
* @property-read int $wday
* @property-read int $wnum
* @property-read string $timezone
* @property-read string $datetime
* @property-read string $date
* @property-read string $Ymd
* @property-read string $YmdHMS
* @property-read string $YmdHMSZ
*/
class DateTime extends \DateTimeImmutable {
use _TDateTime;
const DEFAULT_FORMAT = "d/m/Y H:i:s";
/**
* $datetime est une spécification de date, avec ou sans fuseau horaire
*
* si $datetime ne contient pas de fuseau horaire, elle est réputée être dans
* le fuseau $timezone, qui est le fuseau local par défaut
*
* si $datetime contient un fuseau horaire et si $forceTimezone est vrai,
* alors $datetime est réexprimée dans le fuseau $timezone.
* si $timezone est null alors $forceTimezone vaut vrai par défaut.
*
* datetime | timezone | forceTimezone | résultat
* -----------------|----------|---------------|---------
* datetime | any | any | datetime+localtz
* datetime+origtz | null | null | datetime+localtz
* datetime+origtz | null | true | datetime+localtz
* datetime+origtz | null | false | datetime+origtz
* datetime+origtz | newtz | null | datetime+origtz
* datetime+origtz | newtz | false | datetime+origtz
* datetime+origtz | newtz | true | datetime+newtz
*/
function __construct($datetime=null, DateTimeZone $timezone=null, ?bool $forceTimezone=null) {
$resetTimezone = null;
$forceTimezone ??= $timezone === null;
if ($forceTimezone) {
$resetTimezone = $timezone ?? new DateTimeZone(date_default_timezone_get());
$timezone = null;
}
$datetime ??= "now";
if ($datetime instanceof DateTimeImmutable) {
$datetime = \DateTime::createFromImmutable($datetime);
} elseif ($datetime instanceof \DateTime) {
$datetime = clone $datetime;
#XXX sous PHP 8, remplacer les deux commandes ci-dessus par
# DateTime::createFromInterface
} elseif (is_int($datetime)) {
$timestamp = $datetime;
$datetime = new \DateTime("now", $timezone);
$datetime->setTimestamp($timestamp);
} elseif (is_string($datetime)) {
$Y = $H = $Z = null;
if (preg_match(_utils::DMY_PATTERN, $datetime, $ms)) {
$Y = $ms[3] ?? null;
if ($Y !== null) $Y = _utils::fix_any_year(intval($Y));
else $Y = intval(date("Y"));
$m = intval($ms[2]);
$d = intval($ms[1]);
} elseif (preg_match(_utils::YMD_PATTERN, $datetime, $ms)) {
$Y = $ms[1];
if (strlen($Y) == 2) $Y = _utils::fix_any_year(intval($ms[1]));
else $Y = intval($Y);
$m = intval($ms[2]);
$d = intval($ms[3]);
} elseif (preg_match(_utils::DMYHIS_PATTERN, $datetime, $ms)) {
$Y = $ms[3];
if ($Y !== null) $Y = _utils::fix_any_year(intval($Y));
else $Y = intval(date("Y"));
$m = intval($ms[2]);
$d = intval($ms[1]);
$H = intval($ms[4]);
$M = intval($ms[5]);
$S = intval($ms[6] ?? 0);
} elseif (preg_match(_utils::YMDHISZ_PATTERN, $datetime, $ms)) {
$Y = $ms[1];
if (strlen($Y) == 2) $Y = _utils::fix_any_year(intval($ms[1]));
else $Y = intval($Y);
$m = intval($ms[2]);
$d = intval($ms[3]);
$H = intval($ms[4]);
$M = intval($ms[5]);
$S = intval($ms[6] ?? 0);
$Z = $ms[7] ?? null;
}
if ($Y !== null) {
if ($H === null) $datetime = sprintf("%04d-%02d-%02d", $Y, $m, $d);
else $datetime = sprintf("%04d-%02d-%02d %02d:%02d:%02d", $Y, $m, $d, $H, $M, $S);
if ($Z !== null) $timezone = new DateTimeZone(_utils::fix_z($Z));
}
$datetime = new \DateTime($datetime, $timezone);
} elseif (is_array($datetime) && ($datetime = _utils::parse_array($datetime)) !== null) {
[$Y, $m, $d, $H, $M, $S, $Z] = $datetime;
if ($H === null && $M === null && $S === null) {
$datetime = sprintf("%04d-%02d-%02d", $Y, $m, $d);
} else {
$datetime = sprintf("%04d-%02d-%02d %02d:%02d:%02d", $Y, $m, $d, $H ?? 0, $M ?? 0, $S ?? 0);
}
if ($Z !== null) $timezone = new DateTimeZone(_utils::fix_z($Z));
$datetime = new \DateTime($datetime, $timezone);
}
if ($datetime instanceof DateTimeInterface) {
if ($resetTimezone !== null) $datetime->setTimezone($resetTimezone);
$datetime = $this->fix($datetime);
parent::__construct($datetime->format("Y-m-d\\TH:i:s.uP"));
} else {
throw new InvalidArgumentException("datetime must be a string or an instance of DateTimeInterface");
}
}
protected function fix(DateTimeInterface $datetime): DateTimeInterface {
return $datetime;
}
/** @return MutableDateTime|self */
function clone(bool $mutable=false): DateTimeInterface {
if ($mutable) return new MutableDateTime($this);
else return clone $this;
}
/**
* modifier cet objet pour que l'heure soit à 00:00:00 ce qui le rend propice
* à l'utilisation comme borne inférieure d'une période
*/
function getStartOfDay(): self {
return new static($this->setTime(0, 0));
}
/**
* modifier cet objet pour que l'heure soit à 23:59:59.999999 ce qui le rend
* propice à l'utilisation comme borne supérieure d'une période
*/
function getEndOfDay(): self {
return new static($this->setTime(23, 59, 59, 999999));
}
function getPrevDay(int $nbDays=1, bool $skipWeekend=false): self {
if ($nbDays == 1 && $skipWeekend && $this->wday == 1) {
$nbDays = 3;
}
return new static($this->sub(new \DateInterval("P${nbDays}D")));
}
function getNextDay(int $nbDays=1, bool $skipWeekend=false): self {
if ($nbDays == 1 && $skipWeekend) {
$wday = $this->wday;
if ($wday > 5) $nbDays = 8 - $this->wday;
}
return new static($this->add(new \DateInterval("P${nbDays}D")));
}
}