diff --git a/src/php/time/Date.php b/src/php/time/Date.php new file mode 100644 index 0000000..60f6fa7 --- /dev/null +++ b/src/php/time/Date.php @@ -0,0 +1,20 @@ +setTime(0, 0, 0, 0); + } + + function format($format=self::DEFAULT_FORMAT): string { + return \DateTime::format($format); + } +} diff --git a/src/php/time/DateInterval.php b/src/php/time/DateInterval.php new file mode 100644 index 0000000..3fdc7f0 --- /dev/null +++ b/src/php/time/DateInterval.php @@ -0,0 +1,49 @@ +y; + $m = $interval->m; + $d = $interval->d; + if ($y > 0) $string .= "${y}Y"; + if ($m > 0) $string .= "${m}M"; + if ($d > 0) $string .= "${d}D"; + $string .= "T"; + $h = $interval->h; + $i = $interval->i; + $s = $interval->s; + if ($h > 0) $string .= "${h}H"; + if ($i > 0) $string .= "${i}M"; + if ($s > 0 || $string == "PT") $string .= "${s}S"; + if ($interval->invert == 1) $string = "-$string"; + return $string; + } + + function __construct($duration) { + if ($duration instanceof DateInterval) { + $this->y = $duration->y; + $this->m = $duration->m; + $this->d = $duration->d; + $this->h = $duration->h; + $this->i = $duration->i; + $this->s = $duration->s; + $this->invert = $duration->invert; + $this->days = $duration->days; + } else { + if (substr($duration, 0, 1) == "-") { + $duration = substr($duration, 1); + $invert = true; + } else { + $invert = false; + } + parent::__construct($duration); + if ($invert) $this->invert = 1; + } + } + + function __toString(): string { + return self::to_string($this); + } +} diff --git a/src/php/time/DateTime.php b/src/php/time/DateTime.php new file mode 100644 index 0000000..8d61dc4 --- /dev/null +++ b/src/php/time/DateTime.php @@ -0,0 +1,65 @@ +setTimestamp($dateTime->getTimestamp()); + $clone->setTimezone($dateTime->getTimezone()); + return $clone; + } + + function __construct($datetime="now", DateTimeZone $timezone=null) { + if ($datetime instanceof \DateTimeInterface) { + if ($timezone === null) $timezone = $datetime->getTimezone(); + parent::__construct(); + $this->setTimestamp($datetime->getTimestamp()); + $this->setTimezone($timezone); + } else { + parent::__construct($datetime, $timezone); + } + } + + function diff($target, $absolute=false): DateInterval { + return new DateInterval(parent::diff($target, $absolute)); + } + + function format($format=self::DEFAULT_FORMAT): string { + return \DateTime::format($format); + } + + function __toString(): string { + return $this->format(); + } + + function __get($name) { + switch ($name) { + case "year": return $this->format("Y"); + case "month": return $this->format("m"); + case "day": return $this->format("d"); + case "hour": return $this->format("H"); + case "minute": return $this->format("i"); + case "second": return $this->format("s"); + case "timezone": return $this->format("P"); + default: throw new InvalidArgumentException("Unknown property $name"); + } + } +} diff --git a/src/php/time/Delay.php b/src/php/time/Delay.php new file mode 100644 index 0000000..1df71ae --- /dev/null +++ b/src/php/time/Delay.php @@ -0,0 +1,139 @@ + [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)); + } +} diff --git a/tests/php/time/DateTest.php b/tests/php/time/DateTest.php new file mode 100644 index 0000000..a9c1a68 --- /dev/null +++ b/tests/php/time/DateTest.php @@ -0,0 +1,31 @@ +format()); + self::assertEquals("05/04/2024", strval($date)); + self::assertEquals("2024", $date->year); + self::assertEquals("04", $date->month); + self::assertEquals("05", $date->day); + self::assertEquals("00", $date->hour); + self::assertEquals("00", $date->minute); + self::assertEquals("00", $date->second); + self::assertEquals("+04:00", $date->timezone); + } + + function testClone() { + $date = self::dt("now"); + $clone = Date::clone($date); + self::assertInstanceOf(DateTime::class, $clone); + } +} diff --git a/tests/php/time/DateTimeTest.php b/tests/php/time/DateTimeTest.php new file mode 100644 index 0000000..d2bc5f2 --- /dev/null +++ b/tests/php/time/DateTimeTest.php @@ -0,0 +1,33 @@ +format()); + self::assertEquals("05/04/2024 09:15:23", strval($date)); + self::assertEquals("2024", $date->year); + self::assertEquals("04", $date->month); + self::assertEquals("05", $date->day); + self::assertEquals("09", $date->hour); + self::assertEquals("15", $date->minute); + self::assertEquals("23", $date->second); + self::assertEquals("+04:00", $date->timezone); + } + + function testClone() { + $date = self::dt("now"); + $clone = DateTime::clone($date); + self::assertInstanceOf(DateTime::class, $clone); + } +} diff --git a/tests/php/time/DelayTest.php b/tests/php/time/DelayTest.php new file mode 100644 index 0000000..f2fc5cf --- /dev/null +++ b/tests/php/time/DelayTest.php @@ -0,0 +1,85 @@ +getDest()); + + $delay = new Delay("10", $from); + self::assertEquals(self::dt("2024-04-05 09:15:33"), $delay->getDest()); + + $delay = new Delay("10s", $from); + self::assertEquals(self::dt("2024-04-05 09:15:33"), $delay->getDest()); + + $delay = new Delay("s", $from); + self::assertEquals(self::dt("2024-04-05 09:15:24"), $delay->getDest()); + + $delay = new Delay("5m", $from); + self::assertEquals(self::dt("2024-04-05 09:20:00"), $delay->getDest()); + + $delay = new Delay("5m0", $from); + self::assertEquals(self::dt("2024-04-05 09:20:00"), $delay->getDest()); + + $delay = new Delay("5m2", $from); + self::assertEquals(self::dt("2024-04-05 09:20:02"), $delay->getDest()); + + $delay = new Delay("m", $from); + self::assertEquals(self::dt("2024-04-05 09:16:00"), $delay->getDest()); + + $delay = new Delay("5h", $from); + self::assertEquals(self::dt("2024-04-05 14:00:00"), $delay->getDest()); + + $delay = new Delay("5h0", $from); + self::assertEquals(self::dt("2024-04-05 14:00:00"), $delay->getDest()); + + $delay = new Delay("5h2", $from); + self::assertEquals(self::dt("2024-04-05 14:02:00"), $delay->getDest()); + + $delay = new Delay("h", $from); + self::assertEquals(self::dt("2024-04-05 10:00:00"), $delay->getDest()); + + $delay = new Delay("5d", $from); + self::assertEquals(self::dt("2024-04-10 05:00:00"), $delay->getDest()); + + $delay = new Delay("5d2", $from); + self::assertEquals(self::dt("2024-04-10 02:00:00"), $delay->getDest()); + + $delay = new Delay("5d0", $from); + self::assertEquals(self::dt("2024-04-10 00:00:00"), $delay->getDest()); + + $delay = new Delay("d", $from); + self::assertEquals(self::dt("2024-04-06 05:00:00"), $delay->getDest()); + + $delay = new Delay("2w", $from); + self::assertEquals(self::dt("2024-04-21 05:00:00"), $delay->getDest()); + + $delay = new Delay("2w2", $from); + self::assertEquals(self::dt("2024-04-21 02:00:00"), $delay->getDest()); + + $delay = new Delay("2w0", $from); + self::assertEquals(self::dt("2024-04-21 00:00:00"), $delay->getDest()); + + $delay = new Delay("w", $from); + self::assertEquals(self::dt("2024-04-07 05:00:00"), $delay->getDest()); + } + + function testElapsed() { + $delay = new Delay(5); + sleep(2); + self::assertFalse($delay->isElapsed()); + sleep(5); + self::assertTrue($delay->isElapsed()); + } +}