140 lines
3.9 KiB
PHP
140 lines
3.9 KiB
PHP
|
<?php
|
||
|
namespace nulib\php\time;
|
||
|
|
||
|
use DateTimeInterface;
|
||
|
use InvalidArgumentException;
|
||
|
|
||
|
/**
|
||
|
* Class Delay: une durée jusqu'à un moment destination. le moment destination
|
||
|
* est calculé à la création de l'objet en fonction du moment courant.
|
||
|
*
|
||
|
* La durée peut-être:
|
||
|
* - un nombre, qui est le nombre de secondes jusqu'au moment destination
|
||
|
* - une chaine de la forme "x[WDHMS]y" où x et y sont des nombres et la lettre
|
||
|
* est l'unité de temps: W représente une semaine, D une journée, H une heure,
|
||
|
* M une minute et S une seconde.
|
||
|
*
|
||
|
* Dans cette dernière forme, le timestamp destination est calculé en ajoutant x
|
||
|
* unités. puis l'unité inférieure est ramenée à (0 + y)
|
||
|
* par exemple,
|
||
|
* - "1D5" signifie le lendemain à 5h (+1 jour, puis ramené à 5h)
|
||
|
* - "2H0" signifie au plus deux heures plus tard
|
||
|
* - "0W5" signifie à 5 le dimanche de la semaine en cours
|
||
|
*
|
||
|
* NB: la valeur y pour l'unité S est ignorée
|
||
|
*/
|
||
|
class Delay {
|
||
|
/** valeurs par défaut de x et y pour les unités supportées */
|
||
|
const DEFAULTS = [
|
||
|
"w" => [0, 5],
|
||
|
"d" => [1, 5],
|
||
|
"h" => [1, 0],
|
||
|
"m" => [1, 0],
|
||
|
"s" => [1, 0],
|
||
|
];
|
||
|
|
||
|
static function compute_dest(int $x, string $u, ?int $y, DateTime $from): array {
|
||
|
$dest = DateTime::clone($from);
|
||
|
switch ($u) {
|
||
|
case "w":
|
||
|
if ($x > 0) {
|
||
|
$x *= 7;
|
||
|
$dest->add(new \DateInterval("P${x}D"));
|
||
|
}
|
||
|
$w = 7 - intval($dest->format("w"));
|
||
|
$dest->add(new \DateInterval("P${w}D"));
|
||
|
$u = "h";
|
||
|
break;
|
||
|
case "d":
|
||
|
$dest->add(new \DateInterval("P${x}D"));
|
||
|
$u = "h";
|
||
|
break;
|
||
|
case "h":
|
||
|
$dest->add(new \DateInterval("PT${x}H"));
|
||
|
$u = "m";
|
||
|
break;
|
||
|
case "m":
|
||
|
$dest->add(new \DateInterval("PT${x}M"));
|
||
|
$u = "s";
|
||
|
break;
|
||
|
case "s":
|
||
|
$dest->add(new \DateInterval("PT${x}S"));
|
||
|
$u = null;
|
||
|
break;
|
||
|
}
|
||
|
if ($y !== null && $u !== null) {
|
||
|
$h = intval($dest->format("H"));
|
||
|
$m = intval($dest->format("i"));
|
||
|
switch ($u) {
|
||
|
case "h":
|
||
|
$dest->setTime($y, 0, 0, 0);
|
||
|
break;
|
||
|
case "m":
|
||
|
$dest->setTime($h, $y, 0, 0);
|
||
|
break;
|
||
|
case "s":
|
||
|
$dest->setTime($h, $m, $y, 0);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
$repr = $y !== null? "$x$y$y": "$x";
|
||
|
return [$dest, $repr];
|
||
|
}
|
||
|
|
||
|
function __construct($delay, ?DateTimeInterface $from=null) {
|
||
|
if ($from === null) $from = new DateTime();
|
||
|
if (is_int($delay)) {
|
||
|
[$dest, $repr] = self::compute_dest($delay, "s", null, $from);
|
||
|
} elseif (is_string($delay) && preg_match('/^\d+$/', $delay)) {
|
||
|
$x = intval($delay);
|
||
|
[$dest, $repr] = self::compute_dest($x, "s", null, $from);
|
||
|
} elseif (is_string($delay) && preg_match('/^(\d*)([wdhms])(\d*)$/i', $delay, $ms)) {
|
||
|
[$x, $u, $y] = [$ms[1], $ms[2], $ms[3]];
|
||
|
$u = strtolower($u);
|
||
|
$default = self::DEFAULTS[$u];
|
||
|
if ($x === "") $x = $default[0];
|
||
|
else $x = intval($x);
|
||
|
if ($y === "") $y = $default[1];
|
||
|
else $y = intval($y);
|
||
|
[$dest, $repr] = self::compute_dest($x, $u, $y, $from);
|
||
|
} else {
|
||
|
throw new InvalidArgumentException("invalid delay");
|
||
|
}
|
||
|
$this->dest = $dest;
|
||
|
$this->repr = $repr;
|
||
|
}
|
||
|
|
||
|
/** @var DateTime */
|
||
|
protected $dest;
|
||
|
|
||
|
function getDest(): DateTime {
|
||
|
return $this->dest;
|
||
|
}
|
||
|
|
||
|
/** @var string */
|
||
|
protected $repr;
|
||
|
|
||
|
function __toString(): string {
|
||
|
return $this->repr;
|
||
|
}
|
||
|
|
||
|
protected function _getDiff(?DateTimeInterface $now=null): \DateInterval {
|
||
|
if ($now === null) $now = new DateTime();
|
||
|
return $this->dest->diff($now);
|
||
|
}
|
||
|
|
||
|
/** retourner true si le délai imparti est écoulé */
|
||
|
function isElapsed(?DateTimeInterface $now=null): bool {
|
||
|
return $this->_getDiff($now)->invert == 0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* retourner l'intervalle entre le moment courant et la destination.
|
||
|
*
|
||
|
* l'intervalle est négatif si le délai n'est pas écoulé, positif sinon
|
||
|
*/
|
||
|
function getDiff(?DateTimeInterface $now=null): DateInterval {
|
||
|
return new DateInterval($this->_getDiff($now));
|
||
|
}
|
||
|
}
|