implémentation de Time et Hour
This commit is contained in:
parent
c1adebdbd3
commit
ce21bbc451
8
src/php/time/Hour.php
Normal file
8
src/php/time/Hour.php
Normal file
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
namespace nulib\php\time;
|
||||
|
||||
class Hour extends Time {
|
||||
const UNIT = self::UNIT_MINUTES;
|
||||
|
||||
const FORMAT = "%hh%M";
|
||||
}
|
||||
@ -1,6 +1,9 @@
|
||||
<?php
|
||||
namespace nulib\php\time;
|
||||
|
||||
use DateTimeInterface;
|
||||
use nulib\exceptions;
|
||||
|
||||
/**
|
||||
* Class Time: une heure allant de 0h à 24h inclus.
|
||||
*
|
||||
@ -8,6 +11,15 @@ namespace nulib\php\time;
|
||||
* plage horaire.
|
||||
*/
|
||||
class Time {
|
||||
const UNIT_HOURS = 3600;
|
||||
const UNIT_MINUTES = 60;
|
||||
const UNIT_SECONDS = 1;
|
||||
|
||||
const PATTERN = '/^(\d+):(\d+)(?::(\d+))?$/';
|
||||
|
||||
/** @var string format par défaut pour l'affichage */
|
||||
const FORMAT = "%H:%M:%S";
|
||||
|
||||
static function with($time): self {
|
||||
if ($time instanceof static) return $time;
|
||||
else return new static($time);
|
||||
@ -18,4 +30,219 @@ class Time {
|
||||
elseif ($time instanceof static) return $time;
|
||||
else return new static($time);
|
||||
}
|
||||
|
||||
static function ensure(&$time): void {
|
||||
$time = static::withn($time);
|
||||
}
|
||||
|
||||
static function seconds_now(): int {
|
||||
$hms = date('His');
|
||||
return intval(substr($hms, 0, 2)) * 3600
|
||||
+ intval(substr($hms, 2, 2)) * 60
|
||||
+ intval(substr($hms, 4, 2));
|
||||
}
|
||||
|
||||
static function seconds_get($time, int $unit=self::UNIT_SECONDS): int {
|
||||
if ($time instanceof self) {
|
||||
return $time->getSeconds();
|
||||
} elseif (is_int($time)) {
|
||||
return $time * $unit;
|
||||
} elseif (is_array($time)) {
|
||||
[$h, $m, $s] = $time;
|
||||
return $h * 3600 + $m * 60 + $s;
|
||||
} elseif (is_string($time) && preg_match(self::PATTERN, $time, $ms)) {
|
||||
$h = $ms[1];
|
||||
$m = $ms[2];
|
||||
$s = $ms[3] ?? 0;
|
||||
return intval($h) * 3600 + intval($m) * 60 + intval($s);
|
||||
} elseif ($time instanceof DateTimeInterface) {
|
||||
$hms = $time->format('His');
|
||||
return intval(substr($hms, 0, 2)) * 3600
|
||||
+ intval(substr($hms, 2, 2)) * 60
|
||||
+ intval(substr($hms, 4, 2));
|
||||
} elseif ($time === null) {
|
||||
return 0;
|
||||
} else {
|
||||
throw exceptions::invalid_value($time, "time");
|
||||
}
|
||||
}
|
||||
|
||||
static function seconds_adjust(int &$seconds, int $unit=self::UNIT_SECONDS, ?int $step=null): int {
|
||||
if ($step !== null) $unit *= $step;
|
||||
$adjust = $seconds % $unit;
|
||||
if ($seconds < 0) $adjust = -$adjust;
|
||||
$seconds -= $adjust;
|
||||
return $seconds;
|
||||
}
|
||||
|
||||
static function seconds_wrap_start(int &$seconds): int {
|
||||
while ($seconds < 0) $seconds += 86400;
|
||||
if ($seconds >= 86400) $seconds %= 86400;
|
||||
return $seconds;
|
||||
}
|
||||
|
||||
static function seconds_wrap_end(int &$seconds): int {
|
||||
while ($seconds < 0) $seconds += 86400;
|
||||
if ($seconds > 86400) $seconds %= 86400;
|
||||
return $seconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int la valeur de l'unité en secondes, pour le constructeur et les
|
||||
* méthodes {@link newu()}, {@link addu()} et {@link subu()}
|
||||
*/
|
||||
function UNIT(): int {
|
||||
return static::UNIT;
|
||||
} const UNIT = self::UNIT_SECONDS;
|
||||
|
||||
/**
|
||||
* @return int|null un nombre d'unité dont l'heure doit être multiple. par
|
||||
* exemple, si l'unité est la minute, une valeur 5 permet d'avoir des heures
|
||||
* qui vont de 5 en 5 minutes (0h00, 0h05, 0h10, etc.)
|
||||
*/
|
||||
protected function STEP(): ?int {
|
||||
return static::STEP;
|
||||
} const STEP = null;
|
||||
|
||||
/** @return bool s'il faut garder les heures dans la plage [0, 24h] */
|
||||
protected function WRAP(): bool {
|
||||
return static::WRAP;
|
||||
} const WRAP = true;
|
||||
|
||||
function __construct($time=null) {
|
||||
if ($time === null) $seconds = self::seconds_now();
|
||||
else $seconds = self::seconds_get($time, $this->UNIT());
|
||||
$this->setSeconds($seconds);
|
||||
}
|
||||
|
||||
protected int $seconds;
|
||||
|
||||
function getSeconds(): int {
|
||||
return $this->seconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* mettre à jour cet objet avec le nombre de secondes spécifié
|
||||
*
|
||||
* le nombre effectif de secondes est calculé en tenant compte de l'unité
|
||||
* actuelle
|
||||
*
|
||||
* @return int le nombre de seconde effectif, après correction
|
||||
*/
|
||||
protected function setSeconds(?int $seconds): int {
|
||||
$this->seconds = $seconds ?? self::seconds_now();
|
||||
return $this->afterUpdate();
|
||||
}
|
||||
|
||||
protected function afterUpdate(): int {
|
||||
self::seconds_adjust($this->seconds, $this->UNIT(), $this->STEP());
|
||||
if ($this->WRAP()) $this->wrapEnd();
|
||||
return $this->seconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper l'heure pour la garder dans la plage [0h, 24h[ ce qui la rend
|
||||
* propice à l'utilisation comme borne inférieure d'une période
|
||||
*/
|
||||
function wrapStart(): self {
|
||||
self::seconds_wrap_start($this->seconds);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper l'heure pour la garder dans la plage [0h, 24h] ce qui la rend
|
||||
* propice à l'utilisation comme borne supérieure d'une période
|
||||
*/
|
||||
function wrapEnd(): self {
|
||||
self::seconds_wrap_end($this->seconds);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** formatter cette heure pour affichage */
|
||||
function format(?string $format=null): string {
|
||||
if ($format === null) $format = static::FORMAT;
|
||||
$v = $this->seconds;
|
||||
$h = intdiv($v, 3600); $v = $v % 3600;
|
||||
$m = intdiv($v, 60);
|
||||
$s = $v % 60;
|
||||
$searches = [
|
||||
"%H", "%h",
|
||||
"%M", "%m",
|
||||
"%S", "%s",
|
||||
];
|
||||
$replaces = [
|
||||
sprintf("%02u", $h), strval($h),
|
||||
sprintf("%02u", $m), strval($m),
|
||||
sprintf("%02u", $s), strval($s),
|
||||
];
|
||||
return str_replace($searches, $replaces, $format);
|
||||
}
|
||||
|
||||
function __toString(): string {
|
||||
return $this->format();
|
||||
}
|
||||
|
||||
/** @return int le nombre d'unités */
|
||||
function getu(): int {
|
||||
return intdiv($this->seconds, $this->UNIT());
|
||||
}
|
||||
|
||||
/** créer une nouvelle heure avec le nombre d'unités spécifiées */
|
||||
function newu(int $count): self {
|
||||
$this->setSeconds($count * $this->UNIT());
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** créer une nouvelle heure en ajoutant à cette heure le nombre d'unités spécifiées */
|
||||
function addu(int $count=1): self {
|
||||
$this->setSeconds($this->seconds + $count * $this->UNIT());
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** créer une nouvelle heure en soustrayant à cette heure le nombre d'unités spécifiées */
|
||||
function subu(int $count=1): self {
|
||||
$this->setSeconds($this->seconds - $count * $this->UNIT());
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** créer une nouvelle heure en ajoutant à cette heure l'heure spécifiée */
|
||||
function add(?self $time): self {
|
||||
if ($time !== null) {
|
||||
$this->setSeconds($this->seconds + $time->getSeconds());
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** créer une nouvelle heure en soustrayant à cette heure l'heure spécifiée */
|
||||
function sub(?self $time): self {
|
||||
if ($time !== null) {
|
||||
$this->setSeconds($this->seconds - $time->getSeconds());
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* comparer avec l'heure spécifiée. retourner une valeur négative, égale à
|
||||
* zéro ou positive suivant le résultat de la comparaison
|
||||
*/
|
||||
function compare(?self $time): int {
|
||||
if ($time === null) return 1;
|
||||
else return $this->seconds - $time->getSeconds();
|
||||
}
|
||||
|
||||
/**
|
||||
* tester si cette heure est avant ou égale à l'heure spécifiée
|
||||
*/
|
||||
function before(?self $other): bool {
|
||||
if ($other === null) return false;
|
||||
else return $this->seconds <= $other->getSeconds();
|
||||
}
|
||||
|
||||
/**
|
||||
* tester si cette heure est après ou égale à l'heure spécifiée
|
||||
*/
|
||||
function after(?self $other): bool {
|
||||
if ($other === null) return true;
|
||||
else return $this->seconds >= $other->getSeconds();
|
||||
}
|
||||
}
|
||||
|
||||
25
tests/php/time/HourTest.php
Normal file
25
tests/php/time/HourTest.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
namespace nulib\php\time;
|
||||
|
||||
use nulib\tests\TestCase;
|
||||
|
||||
class HourTest extends TestCase {
|
||||
function testFormat() {
|
||||
self::assertSame("0h00", (new Hour(0))->format());
|
||||
self::assertSame("0h56", (new Hour(56))->format());
|
||||
self::assertSame("2h00", (new Hour(120))->format());
|
||||
self::assertSame("23h59", (new Hour(1439))->format());
|
||||
self::assertSame("24h00", (new Hour(1440))->format());
|
||||
self::assertSame("0h01", (new Hour(1441))->format());
|
||||
}
|
||||
|
||||
function testStep() {
|
||||
$h = new class extends Hour {
|
||||
const STEP = 5;
|
||||
};
|
||||
$h->newu(10); self::assertSame("0h10", strval($h));
|
||||
$h->newu(12); self::assertSame("0h10", strval($h));
|
||||
$h->newu(15); self::assertSame("0h15", strval($h));
|
||||
$h->newu(17); self::assertSame("0h15", strval($h));
|
||||
}
|
||||
}
|
||||
47
tests/php/time/TimeTest.php
Normal file
47
tests/php/time/TimeTest.php
Normal file
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
namespace nulib\php\time;
|
||||
|
||||
use nulib\tests\TestCase;
|
||||
|
||||
class TimeTest extends TestCase {
|
||||
function testGetc() {
|
||||
self::assertSame(0, (new Time(0))->getu());
|
||||
self::assertSame(86399, (new Time(-1))->getu());
|
||||
self::assertSame(1, (new Time(1))->getu());
|
||||
self::assertSame(120, (new Time(120))->getu());
|
||||
self::assertSame(86400, (new Time(86400))->getu());
|
||||
self::assertSame(0, (new Time(-86400))->getu());
|
||||
}
|
||||
|
||||
function testAddc() {
|
||||
$t = new Time(0);
|
||||
$t->addu(0); self::assertSame(0, $t->getu());
|
||||
$t->addu(10); self::assertSame(10, $t->getu());
|
||||
$t->addu(10); self::assertSame(20, $t->getu());
|
||||
$t->addu(100); self::assertSame(120, $t->getu());
|
||||
$t->addu(86280); self::assertSame(86400, $t->getu());
|
||||
$t->addu(86400); self::assertSame(0, $t->getu());
|
||||
$t->addu(-86400); self::assertSame(0, $t->getu());
|
||||
}
|
||||
|
||||
function testSubc() {
|
||||
$t = new Time(0);
|
||||
$t->subu(-86400); self::assertSame(86400, $t->getu());
|
||||
$t->subu(86400); self::assertSame(0, $t->getu());
|
||||
|
||||
$t = new Time(120);
|
||||
$t->subu(100); self::assertSame(20, $t->getu());
|
||||
$t->subu(10); self::assertSame(10, $t->getu());
|
||||
$t->subu(10); self::assertSame(0, $t->getu());
|
||||
$t->subu(0); self::assertSame(0, $t->getu());
|
||||
}
|
||||
|
||||
function testFormat() {
|
||||
self::assertSame("00:00:00", (new Time(0))->format());
|
||||
self::assertSame("00:00:56", (new Time(56))->format());
|
||||
self::assertSame("00:02:00", (new Time(120))->format());
|
||||
self::assertSame("23:59:59", (new Time(86399))->format());
|
||||
self::assertSame("24:00:00", (new Time(86400))->format());
|
||||
self::assertSame("00:00:01", (new Time(86401))->format());
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user