Hej!
Czy znasz standard ISO 8601? Czy wiesz jak sformatować datę i czas zgodnie z standardem ISO 8601? Czy wiesz który format w PHP jest niepoprawnym formatem ISO 8601? Czy wiesz dlaczego tak jest? Jeśli te pytania Cię zaciekawiły, zapraszam do czytania.
Standard ISO 8601
Międzynarodowa norma ISO określająca sposób zapisu daty i czasu
https://pl.wikipedia.org/wiki/ISO_8601
Jest to standard zapisu daty i czasu, powszechnie używany w internecie. Kilka przykładów:
2021-05-06 2021-05-06T20:17:24+00:00 2021-05-06T20:17:24Z 20210506T201724Z 2021-W18
Dodatkowo, standard definiuje zapis interwałów czasowych, ale to nie temat tego wpisu.
Formatowanie daty ISO 8601 w PHP
Możesz to zrobić na kilka różnych sposobów:
<?php declare(strict_types=1);
echo date('c');
// 2021-05-06T20:08:33+00:00
echo (new DateTimeImmutable())->format(DateTimeInterface::ISO8601);
// 2021-05-06T20:08:33+0000
echo (new DateTimeImmutable())->format(DATE_ISO8601);
// 2021-05-06T20:08:33+0000
echo (new DateTimeImmutable())->format(DateTimeInterface::ATOM);
// 2021-05-06T20:08:33+00:00
echo (new DateTimeImmutable())->format(DATE_ATOM);
// 2021-05-06T20:08:33+00:00
Błędny format ISO 8601
Jeśli dobrze się przyjrzysz jakie wyniki dają powyższe przykład, to zauważysz w nich drobną różnicę.
Tak, formaty dat które definiują stałe DateTimeInterface::ISO8601
oraz DATE_ISO8601
są niepoprawne. Godziny i minuty w offsecie powinny być rozdzielone dwukropkiem.
Dokumentacja PHP o tym wspomina:
Note: This format is not compatible with ISO-8601, but is left this way for backward compatibility reasons. Use DateTime::ATOM or DATE_ATOM for compatibility with ISO-8601 instead.
https://www.php.net/manual/en/class.datetimeinterface.php#datetime.constants.types
W internecie natknąłem się na informację że ten zapis jest niby zgodny z ISO 8601, jednak jest to nieprawda.
Skąd ten błąd?!
Szukałem w internecie informacji na ten temat ale nie udało mi się ich znaleźć. Udało mi się za to znaleźć commit w kodzie źródłowym PHP który dodał owy, felerny format daty:
https://github.com/php/php-src/commit/e6c1ff254d0c1b246d83bdaffda0a9403fa5eeba
Commit jest z 20 lipca 2005. Autorem jest sam Derick Rethans, twórca XDebug. Wydaje mi się że jest to literówka albo błąd wynikający z niepoprawnego zrozumienia standardu ISO 8601. Napisałem e-mail do Dericka, ale póki co brak odpowiedzi. Gdy tylko odpowie to uzupełnię ten wpis. Dlatego warto zapisać się do newslettera 🙂
Co ciekawe, standard ISO 8601 zezwala na brak dwukropka w offset, ale tylko w formacie podstawowym, który nie zezwala na żadne separatory pomiędzy elementami składowymi. Wygląda on tak:
20210506T200833+0000
Niezbyt czytelne, prawda?
Natomiast dużo czytelniejszy jest format rozszerzony który wymaga separatorów:
2021-05-06T20:08:33+00:00
Większość ludzi zna ten format.
Czy zostanie to naprawione?
Póki co nie widziałem żadnego planu oznaczenia tego jako przestarzałe (ang. deprecated) czy usunięcia.
Poprawa tego formatu według mnie nie wchodzi w grę, bo taka zmiana zmieniłaby zachowanie całej masy oprogramowania na świecie – po aktualizacji PHP przestałyby akceptować stary format daty a do tego przestałyby zwracać stary typ daty. Co miałoby fatalne skutki.
Jednak PHP w ostatnim czasie prężnie się rozwija. Być może w kolejnej wersji major opiekunowie oznaczą jako przestarzałe a potem usuną niepoprawny format daty. A jak ktoś będzie nadal go potrzebował zawsze może zadeklarować u siebie stałą z tym formatem 🙂
I to tyle na dzisiaj, dzięki!
moim zdaniem w wersji głównej jak najbardziej mogliby to zmienić, w końcu z definicji łamią one zgodność, jednak dla bezpieczeństwa lepiej odrzucić niepoprawne formaty całkowicie, łatwiej wyłapać błąd jeśli się nieuważnie aktualizuje kod
P.S. warto zaznaczyć obecność kapczy tak, aby użytkownik wiedział, że musi coś odblokować zanim się naprodukuje i go odrzuci
Cześć. W pełni się zgadzam, w wersji major powinni to zrobić. Co do kapczy, pokusie o tym. Już sobie to zapisuje 🙂