175 lines
6.2 KiB
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")));
|
|
}
|
|
}
|