nulib/php/src_php/time/Delay.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));
}
}