From aa76d613fbfd16576c0c739c09142e037693ea31 Mon Sep 17 00:00:00 2001 From: Jephte Clain Date: Mon, 22 Apr 2024 23:41:19 +0400 Subject: [PATCH] modifs.mineures sans commentaires --- nur_src/path.php | 15 ++++++- nur_tests/pathTest.php | 34 +++++++++++++++ src/os/path.php | 30 +++++++++++-- src/php/time/DateTime.php | 74 +++++++++++++++++++++++++++------ tests/php/time/DateTimeTest.php | 29 +++++++++++++ 5 files changed, 164 insertions(+), 18 deletions(-) diff --git a/nur_src/path.php b/nur_src/path.php index 50490e2..92b1147 100644 --- a/nur_src/path.php +++ b/nur_src/path.php @@ -270,16 +270,27 @@ class path { } /** + * s'assurer que $path a l'extension $new_ext. si $path a l'une des extensions + * de $replace_ext, l'enlever avant de rajouter $new_ext. + * + * si $strict === false alors $new_ext est ajouté à la liste $replace_ext + * c'est à dire que si $path a déjà l'extension $new_ext, elle n'est pas + * rajoutée de nouveau. + * + * si $strict === true alors seules les extensions de $replace_ext sont + * enlevées le cas échéant, et $new_ext est systématiquement rajouté + * * @param string $path * @param string $new_ext * @param string|array|null $replace_ext * @return string */ - static final function ensure_ext(string $path, string $new_ext, $replace_ext=null): string { + static final function ensure_ext(string $path, string $new_ext, $replace_ext=null, bool $strict=false): string { [$dir, $filename] = self::split($path); $ext = self::ext($filename); + if (is_string($replace_ext)) $replace_ext = [$replace_ext]; + if (!$strict) $replace_ext[] = $new_ext; if ($ext !== null && $replace_ext !== null) { - if (is_string($replace_ext)) $replace_ext = [$replace_ext]; foreach ($replace_ext as $old_ext) { if ($ext === $old_ext) { $filename = self::basename($filename); diff --git a/nur_tests/pathTest.php b/nur_tests/pathTest.php index 28f2d8e..2c293e9 100644 --- a/nur_tests/pathTest.php +++ b/nur_tests/pathTest.php @@ -47,4 +47,38 @@ class pathTest extends TestCase { self::assertSame("/b", path::reljoin("a", "/b")); self::assertSame("/b", path::reljoin("a/", "/b")); } + + function testEnsure_ext() { + # non strict + self::assertSame("a", path::ensure_ext("a", "", null)); + self::assertSame("a.x", path::ensure_ext("a", ".x", null)); + self::assertSame("a.x", path::ensure_ext("a.x", ".x", null)); + self::assertSame("a.x", path::ensure_ext("a", ".x", ".y")); + self::assertSame("a.x", path::ensure_ext("a.x", ".x", ".y")); + self::assertSame("a.x", path::ensure_ext("a.y", ".x", ".y")); + self::assertSame("a.x", path::ensure_ext("a", ".x", [".y", ".z"])); + self::assertSame("a.x", path::ensure_ext("a.x", ".x", [".y", ".z"])); + self::assertSame("a.x", path::ensure_ext("a.y", ".x", [".y", ".z"])); + self::assertSame("a.x", path::ensure_ext("a.z", ".x", [".y", ".z"])); + self::assertSame("a.x", path::ensure_ext("a", ".x", [".x", ".y", ".z"])); + self::assertSame("a.x", path::ensure_ext("a.x", ".x", [".x", ".y", ".z"])); + self::assertSame("a.x", path::ensure_ext("a.y", ".x", [".x", ".y", ".z"])); + self::assertSame("a.x", path::ensure_ext("a.z", ".x", [".x", ".y", ".z"])); + + # strict + self::assertSame("a", path::ensure_ext("a", "", null, true)); + self::assertSame("a.x", path::ensure_ext("a", ".x", null, true)); + self::assertSame("a.x.x", path::ensure_ext("a.x", ".x", null, true)); + self::assertSame("a.x", path::ensure_ext("a", ".x", ".y", true)); + self::assertSame("a.x.x", path::ensure_ext("a.x", ".x", ".y", true)); + self::assertSame("a.x", path::ensure_ext("a.y", ".x", ".y", true)); + self::assertSame("a.x", path::ensure_ext("a", ".x", [".y", ".z"], true)); + self::assertSame("a.x.x", path::ensure_ext("a.x", ".x", [".y", ".z"], true)); + self::assertSame("a.x", path::ensure_ext("a.y", ".x", [".y", ".z"], true)); + self::assertSame("a.x", path::ensure_ext("a.z", ".x", [".y", ".z"], true)); + self::assertSame("a.x", path::ensure_ext("a", ".x", [".x", ".y", ".z"], true)); + self::assertSame("a.x", path::ensure_ext("a.x", ".x", [".x", ".y", ".z"], true)); + self::assertSame("a.x", path::ensure_ext("a.y", ".x", [".x", ".y", ".z"], true)); + self::assertSame("a.x", path::ensure_ext("a.z", ".x", [".x", ".y", ".z"], true)); + } } diff --git a/src/os/path.php b/src/os/path.php index 20356ee..fa44eb3 100644 --- a/src/os/path.php +++ b/src/os/path.php @@ -264,10 +264,34 @@ class path { return strpos($file, ".", $pos) !== false; } - static final function ensure_ext(string $path, string $new_ext, ?string $replace_ext=null): string { + /** + * s'assurer que $path a l'extension $new_ext. si $path a l'une des extensions + * de $replace_ext, l'enlever avant de rajouter $new_ext. + * + * si $strict === false alors $new_ext est ajouté à la liste $replace_ext + * c'est à dire que si $path a déjà l'extension $new_ext, elle n'est pas + * rajoutée de nouveau. + * + * si $strict === true alors seules les extensions de $replace_ext sont + * enlevées le cas échéant, et $new_ext est systématiquement rajouté + * + * @param string $path + * @param string $new_ext + * @param string|array|null $replace_ext + * @return string + */ + static final function ensure_ext(string $path, string $new_ext, $replace_ext=null, bool $strict=false): string { [$dir, $filename] = self::split($path); - if (self::ext($filename) === $replace_ext) { - $filename = self::basename($filename); + $ext = self::ext($filename); + if (is_string($replace_ext)) $replace_ext = [$replace_ext]; + if (!$strict) $replace_ext[] = $new_ext; + if ($ext !== null && $replace_ext !== null) { + foreach ($replace_ext as $old_ext) { + if ($ext === $old_ext) { + $filename = self::basename($filename); + break; + } + } } $filename .= $new_ext; return self::join($dir, $filename); diff --git a/src/php/time/DateTime.php b/src/php/time/DateTime.php index 8090f9d..91cfdd0 100644 --- a/src/php/time/DateTime.php +++ b/src/php/time/DateTime.php @@ -19,8 +19,23 @@ use InvalidArgumentException; * @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 \DateTime { + const DMY_PATTERN = '/^(\d+)\/(\d+)(?:\/(\d+))?$/'; + const YMD_PATTERN = '/^((?:\d{2})?\d{2})(\d{2})(\d{2})$/'; + const DMYHIS_PATTERN = '/^(\d+)\/(\d+)(?:\/(\d+))? +(\d+)[h:.](\d+)(?:[:.](\d+))?$/'; + const YMDHISZ_PATTERN = '/^((?:\d{2})?\d{2})(\d{2})(\d{2})[tT](\d{2})(\d{2})(\d{2})?([zZ])?$/'; + + static function _YmdHMSZ_format(\DateTime $datetime): string { + $YmdHMS = $datetime->format("Ymd\\THis"); + $Z = $datetime->format("P"); + if ($Z === "+00:00") $Z = "Z"; + return "$YmdHMS$Z"; + } + const DEFAULT_FORMAT = "d/m/Y H:i:s"; const INT_FORMATS = [ "year" => "Y", @@ -36,6 +51,9 @@ class DateTime extends \DateTime { "timezone" => "P", "datetime" => "d/m/Y H:i:s", "date" => "d/m/Y", + "Ymd" => "Ymd", + "YmdHMS" => "Ymd\\THis", + "YmdHMSZ" => [self::class, "_YmdHMSZ_format"], ]; static function clone(DateTimeInterface $dateTime): self { @@ -101,18 +119,44 @@ class DateTime extends \DateTime { } elseif (!is_string($datetime)) { throw new InvalidArgumentException("datetime must be a string or an instance of DateTimeInterface"); } else { - if (preg_match('/^(\d+)\/(\d+)\/(\d+)$/', $datetime, $ms)) { - $y = self::fix_any_year(intval($ms[3])); - $datetime = sprintf("%04d-%02d-%02d", $y, intval($ms[2]), intval($ms[1])); - } elseif (preg_match('/^(\d+)\/(\d+)$/', $datetime, $ms)) { - $datetime = sprintf("%04d-%02d-%02d", intval(date("Y")), intval($ms[2]), intval($ms[1])); - } elseif (preg_match('/^(\d{4})(\d{2})(\d{2})$/', $datetime, $ms)) { - $datetime = sprintf("%04d-%02d-%02d", intval($ms[1]), intval($ms[2]), intval($ms[3])); - } elseif (preg_match('/^(\d{2})(\d{2})(\d{2})$/', $datetime, $ms)) { - $y = self::fix_any_year(intval($ms[1])); - $datetime = sprintf("%04d-%02d-%02d", $y, intval($ms[2]), intval($ms[3])); + $Y = $H = $Z = null; + if (preg_match(self::DMY_PATTERN, $datetime, $ms)) { + $Y = $ms[3] ?? null; + if ($Y !== null) $Y = self::fix_any_year(intval($Y)); + else $Y = intval(date("Y")); + $m = intval($ms[2]); + $d = intval($ms[1]); + } elseif (preg_match(self::YMD_PATTERN, $datetime, $ms)) { + $Y = $ms[1]; + if (strlen($Y) == 2) $Y = self::fix_any_year(intval($ms[1])); + else $Y = intval($Y); + $m = intval($ms[2]); + $d = intval($ms[3]); + } elseif (preg_match(self::DMYHIS_PATTERN, $datetime, $ms)) { + $Y = $ms[3]; + if ($Y !== null) $Y = self::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(self::YMDHISZ_PATTERN, $datetime, $ms)) { + $Y = $ms[1]; + if (strlen($Y) == 2) $Y = self::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("UTC"); } - #XXX ajouter datetime et YYYYmmddTHHMMSS[Z] parent::__construct($datetime, $timezone); } } @@ -131,9 +175,13 @@ class DateTime extends \DateTime { function __get($name) { if (array_key_exists($name, self::INT_FORMATS)) { - return intval($this->format(self::INT_FORMATS[$name])); + $format = self::INT_FORMATS[$name]; + if (is_callable($format)) return $format($this); + else return intval($this->format($format)); } elseif (array_key_exists($name, self::STRING_FORMATS)) { - return $this->format(self::STRING_FORMATS[$name]); + $format = self::STRING_FORMATS[$name]; + if (is_callable($format)) return $format($this); + else return $this->format($format); } throw new InvalidArgumentException("Unknown property $name"); } diff --git a/tests/php/time/DateTimeTest.php b/tests/php/time/DateTimeTest.php index e5815e7..7e004ca 100644 --- a/tests/php/time/DateTimeTest.php +++ b/tests/php/time/DateTimeTest.php @@ -25,6 +25,15 @@ class DateTimeTest extends TestCase { self::assertEquals("+04:00", $date->timezone); self::assertSame("05/04/2024 09:15:23", $date->datetime); self::assertSame("05/04/2024", $date->date); + self::assertSame("20240405", $date->Ymd); + self::assertSame("20240405T091523", $date->YmdHMS); + self::assertSame("20240405T091523+04:00", $date->YmdHMSZ); + } + + function testDateTimeZ() { + $date = new DateTime("20240405T091523Z"); + self::assertSame("20240405T091523", $date->YmdHMS); + self::assertSame("20240405T091523Z", $date->YmdHMSZ); } function testClone() { @@ -32,4 +41,24 @@ class DateTimeTest extends TestCase { $clone = DateTime::clone($date); self::assertInstanceOf(DateTime::class, $clone); } + + function testConstruct() { + $y = date("Y"); + self::assertSame("05/04/$y 00:00:00", strval(new DateTime("5/4"))); + self::assertSame("05/04/2024 00:00:00", strval(new DateTime("5/4/24"))); + self::assertSame("05/04/2024 00:00:00", strval(new DateTime("5/4/2024"))); + self::assertSame("05/04/2024 00:00:00", strval(new DateTime("05/04/2024"))); + self::assertSame("05/04/2024 00:00:00", strval(new DateTime("20240405"))); + self::assertSame("05/04/2024 00:00:00", strval(new DateTime("240405"))); + self::assertSame("05/04/2024 09:15:23", strval(new DateTime("20240405T091523"))); + self::assertSame("05/04/2024 09:15:23", strval(new DateTime("20240405T091523Z"))); + self::assertSame("05/04/2024 09:15:23", strval(new DateTime("5/4/2024 9:15:23"))); + self::assertSame("05/04/2024 09:15:23", strval(new DateTime("5/4/2024 9.15.23"))); + self::assertSame("05/04/2024 09:15:00", strval(new DateTime("5/4/2024 9:15"))); + self::assertSame("05/04/2024 09:15:00", strval(new DateTime("5/4/2024 9.15"))); + self::assertSame("05/04/2024 09:15:00", strval(new DateTime("5/4/2024 9h15"))); + self::assertSame("05/04/2024 09:15:23", strval(new DateTime("5/4/2024 09:15:23"))); + self::assertSame("05/04/2024 09:15:00", strval(new DateTime("5/4/2024 09:15"))); + self::assertSame("05/04/2024 09:15:00", strval(new DateTime("5/4/2024 09h15"))); + } }