Lekcja 18: Praca z Datą i Czasem w PHP

Witaj w osiemnastej lekcji kursu PHP! Manipulowanie datami i czasem jest fundamentalnym aspektem wielu aplikacji internetowych. Od wyświetlania aktualnej daty, przez obliczanie różnic czasowych, formatowanie dat dla użytkownika, aż po planowanie zadań (cron jobs) czy zarządzanie datami ważności – PHP dostarcza bogaty zestaw narzędzi do pracy z tymi danymi. W tej lekcji zgłębimy zarówno tradycyjne funkcje związane z datą i czasem, jak i potężny, obiektowy interfejs dostarczany przez klasę DateTime i jej pochodne.

Podstawowe Funkcje Daty i Czasu

PHP od dawna oferuje zestaw prostych funkcji do pracy z datą i czasem, które są nadal użyteczne w wielu sytuacjach, szczególnie do szybkich operacji lub w starszym kodzie.

Funkcja time()

Funkcja time() jest jedną z najprostszych i najczęściej używanych. Zwraca ona aktualny uniksowy znacznik czasu (Unix timestamp), czyli liczbę sekund, które upłynęły od początku epoki Uniksa (Unix Epoch), czyli od 1 stycznia 1970 roku, godziny 00:00:00 czasu uniwersalnego koordynowanego (UTC).

<?php
$aktualny_timestamp = time();
echo "Aktualny uniksowy znacznik czasu: $aktualny_timestamp sekund.<br>";
// Przykład: 1678886400 (co odpowiada jakiejś dacie w marcu 2023)
?>

Timestamp jest bardzo użyteczny do przechowywania momentów w czasie w bazach danych (jako liczba całkowita) oraz do wykonywania obliczeń na datach (np. dodawanie lub odejmowanie sekund).

Funkcja date()

Funkcja date() służy do formatowania daty i czasu na podstawie podanego formatu i opcjonalnie znacznika czasu. Jeśli znacznik czasu nie zostanie podany, używany jest aktualny czas (wynik time()).

Składnia: string date(string $format, ?int $timestamp = null)

Argument $format to string określający, jak data i czas mają być sformatowane. Używa się do tego specjalnych znaków formatujących. Oto niektóre z najczęściej używanych:

<?php
// Ustawienie domyślnej strefy czasowej (ważne dla spójności)
// Najlepiej ustawić w php.ini: date.timezone = "Europe/Warsaw"
// Lub na początku skryptu:
date_default_timezone_set("Europe/Warsaw");

$teraz = time();

echo "Dziś jest: " . date("Y-m-d") . "<br>"; // np. 2023-03-15
echo "Pełna data i czas: " . date("l, j F Y, H:i:s") . "<br>"; // np. Wednesday, 15 March 2023, 14:30:00
echo "Format polski: " . date("d.m.Y H:i") . "<br>"; // np. 15.03.2023 14:30
echo "Numer tygodnia: " . date("W") . "<br>"; // np. 11
echo "Czas z AM/PM: " . date("h:i:s a") . "<br>"; // np. 02:30:00 pm

// Formatowanie konkretnego timestampu
$timestamp_urodzin = 946684800; // 1 stycznia 2000, 00:00:00 UTC
echo "Data urodzin (z timestampu): " . date("d F Y", $timestamp_urodzin) . "<br>"; // np. 01 January 2000 (zależne od strefy czasowej serwera!)

// Aby uzyskać datę z timestampu UTC niezależnie od strefy serwera, użyj gmdate()
// echo "Data urodzin (UTC): " . gmdate("d F Y", $timestamp_urodzin) . "<br>";
?>

Funkcja gmdate()

Funkcja gmdate() działa identycznie jak date(), ale zawsze zwraca datę sformatowaną według czasu uniwersalnego koordynowanego (UTC), znanego również jako Greenwich Mean Time (GMT), ignorując domyślną strefę czasową serwera.

<?php
date_default_timezone_set("Europe/Warsaw"); // Strefa +01:00 lub +02:00 (DST)
$teraz = time();

echo "Czas lokalny (Warszawa): " . date("Y-m-d H:i:sP", $teraz) . "<br>";
echo "Czas UTC (gmdate):       " . gmdate("Y-m-d H:i:sP", $teraz) . "<br>";
?>

Funkcja strtotime()

Funkcja strtotime() jest niezwykle potężna i elastyczna. Próbuje ona przekształcić tekstowy opis daty/czasu w języku angielskim na uniksowy znacznik czasu. Akceptuje wiele formatów, takich jak "now", "+1 day", "next Thursday", "last Monday", "10 September 2000", "2023-03-15 14:30:00".

Składnia: int|false strtotime(string $datetime, ?int $baseTimestamp = null)

Drugi, opcjonalny argument $baseTimestamp pozwala określić bazowy znacznik czasu, względem którego obliczany jest relatywny czas (np. "+1 day" od podanego $baseTimestamp).

<?php
date_default_timezone_set("Europe/Warsaw");

echo "Timestamp dla \"now\": " . strtotime("now") . " ( " . date("Y-m-d H:i:s", strtotime("now")) . " )<br>";
echo "Timestamp dla \"+1 day\": " . strtotime("+1 day") . " ( " . date("Y-m-d H:i:s", strtotime("+1 day")) . " )<br>";
echo "Timestamp dla \"next Monday\": " . strtotime("next Monday") . " ( " . date("Y-m-d H:i:s", strtotime("next Monday")) . " )<br>";
echo "Timestamp dla \"15 July 2024\": " . strtotime("15 July 2024") . " ( " . date("Y-m-d H:i:s", strtotime("15 July 2024")) . " )<br>";

$dzisiaj = strtotime("2023-10-26");
echo "Timestamp dla \"+1 week\" od 2023-10-26: " . strtotime("+1 week", $dzisiaj) . " ( " . date("Y-m-d", strtotime("+1 week", $dzisiaj)) . " )<br>";

// Jeśli strtotime() nie może zinterpretować stringa, zwraca false
$niepoprawny_string = "to nie jest data";
if (strtotime($niepoprawny_string) === false) {
    echo "Nie udało się przekształcić stringa: '" . htmlspecialchars($niepoprawny_string) . "' na timestamp.<br>";
}
?>

Chociaż strtotime() jest bardzo wygodne, należy używać go ostrożnie, ponieważ jego zachowanie może być niejednoznaczne dla niektórych formatów lub ustawień regionalnych. Dla bardziej precyzyjnej i kontrolowanej pracy z datami, zaleca się używanie obiektowego API (klasa DateTime).

Inne Przydatne Funkcje

Obiektowe Podejście: Klasa DateTime, DateTimeImmutable i DateInterval

Od PHP 5.2 wprowadzono obiektowy interfejs do pracy z datą i czasem, który jest znacznie bardziej elastyczny, precyzyjny i mniej podatny na błędy niż tradycyjne funkcje. Główne klasy to:

Tworzenie Obiektów DateTime i DateTimeImmutable

Obiekty te można tworzyć na kilka sposobów:

<?php
date_default_timezone_set("Europe/Warsaw");

// 1. Bez argumentów - tworzy obiekt z aktualną datą i czasem
$teraz_dt = new DateTime();
$teraz_dti = new DateTimeImmutable();
echo "DateTime (teraz): " . $teraz_dt->format("Y-m-d H:i:sP") . "<br>";
echo "DateTimeImmutable (teraz): " . $teraz_dti->format("Y-m-d H:i:sP") . "<br>";

// 2. Z argumentem stringa z datą/czasem (podobnie jak strtotime())
$data_string = "2024-07-15 10:30:00";
$konkretna_data_dt = new DateTime($data_string);
echo "DateTime ($data_string): " . $konkretna_data_dt->format("Y-m-d H:i:s") . "<br>";

// 3. Z argumentem stringa i obiektem DateTimeZone
$strefa_nowy_jork = new DateTimeZone("America/New_York");
$data_w_ny_dt = new DateTime("now", $strefa_nowy_jork);
echo "DateTime (teraz w Nowym Jorku): " . $data_w_ny_dt->format("Y-m-d H:i:sP") . "<br>";

// 4. Metoda statyczna createFromFormat() - bardziej precyzyjne tworzenie z określonego formatu
$format_wejsciowy = "d.m.Y H:i";
$data_string_polski = "20.05.2024 15:45";
$data_z_formatu_dti = DateTimeImmutable::createFromFormat($format_wejsciowy, $data_string_polski);
if ($data_z_formatu_dti) {
    echo "DateTimeImmutable (z formatu '$format_wejsciowy'): " . $data_z_formatu_dti->format("Y-m-d H:i:s") . "<br>";
} else {
    echo "Nie udało się utworzyć daty z formatu: " . htmlspecialchars($data_string_polski) . "<br>";
    // Można sprawdzić błędy: print_r(DateTime::getLastErrors());
}

// 5. Metoda statyczna createFromMutable() (od PHP 7.3) do konwersji DateTime na DateTimeImmutable
// $immutable_z_mutable = DateTimeImmutable::createFromMutable($teraz_dt);

// 6. Metoda statyczna createFromInterface() (od PHP 7.0) do konwersji z dowolnego obiektu implementującego DateTimeInterface
?>

DateTimeInterface jest interfejsem implementowanym zarówno przez DateTime jak i DateTimeImmutable.

Formatowanie Daty i Czasu - Metoda format()

Metoda format() obiektów DateTime i DateTimeImmutable działa podobnie do funkcji date(), przyjmując ten sam zestaw znaków formatujących.

<?php
$data_obiekt = new DateTimeImmutable("2023-12-25 08:00:00");
echo "ISO 8601: " . $data_obiekt->format("c") . "<br>";
echo "Format przyjazny: " . $data_obiekt->format("l, j F Y, g:i A") . "<br>";
?>

Modyfikowanie Daty i Czasu

Dla DateTime (mutowalny):

Dla DateTimeImmutable (niemutowalny):

Metody te mają takie same nazwy (modify, add, sub, setDate, setTime, setTimestamp, setTimezone), ale zwracają nowy obiekt DateTimeImmutable z wprowadzonymi zmianami, pozostawiając oryginalny obiekt nietkniętym.

<?php
// Przykład z DateTime (mutowalny)
$data_mutowalna = new DateTime("2023-01-01");
echo "Oryginalna (mutowalna): " . $data_mutowalna->format("Y-m-d") . "<br>";
$data_mutowalna->modify("+1 month");
echo "Po modify (+1 month): " . $data_mutowalna->format("Y-m-d") . "<br>"; // Oryginalny obiekt zmieniony

// Przykład z DateTimeImmutable (niemutowalny)
$data_niemutowalna_oryg = new DateTimeImmutable("2023-01-01");
echo "Oryginalna (niemutowalna): " . $data_niemutowalna_oryg->format("Y-m-d") . "<br>";
$data_niemutowalna_nowa = $data_niemutowalna_oryg->modify("+1 month");
echo "Oryginalna po modify (niemutowalna): " . $data_niemutowalna_oryg->format("Y-m-d") . "<br>"; // Pozostaje bez zmian
echo "Nowy obiekt po modify (niemutowalna): " . $data_niemutowalna_nowa->format("Y-m-d") . "<br>";
?>

Klasa DateInterval

DateInterval reprezentuje okres czasu. Można go utworzyć na podstawie stringa w formacie interwału ISO 8601 (np. "P2Y4DT6H8M" - 2 lata, 4 dni, 6 godzin, 8 minut) lub za pomocą metody diff() obiektów DateTime/DateTimeImmutable.

Format stringa dla konstruktora DateInterval: P[n]Y[n]M[n]DT[n]H[n]M[n]S lub P[n]W (dla tygodni).

<?php
$interwal_1 = new DateInterval("P2D"); // Interwał 2 dni
$interwal_2 = new DateInterval("PT3H30M"); // Interwał 3 godziny 30 minut
$interwal_3 = DateInterval::createFromDateString("3 weeks and 2 days"); // Od PHP 5.3

$data_start = new DateTimeImmutable("2023-03-10");
$data_plus_2_dni = $data_start->add($interwal_1);
echo "Data + 2 dni: " . $data_plus_2_dni->format("Y-m-d") . "<br>";

$data_plus_3w2d = $data_start->add($interwal_3);
echo "Data + 3 tygodnie i 2 dni: " . $data_plus_3w2d->format("Y-m-d") . "<br>";
?>

Porównywanie Dat i Obliczanie Różnic - Metoda diff()

Metoda diff() obiektów DateTime/DateTimeImmutable zwraca obiekt DateInterval reprezentujący różnicę między dwiema datami.

<?php
$data1_str = "2023-01-15 10:00:00";
$data2_str = "2023-03-20 14:30:00";

$data1 = new DateTimeImmutable($data1_str);
$data2 = new DateTimeImmutable($data2_str);

$roznica_interwal = $data1->diff($data2);

// Formatowanie obiektu DateInterval
echo "Różnica między $data1_str a $data2_str:<br>";
echo $roznica_interwal->format("%R%a dni ogółem") . "<br>"; // %R to znak (+/-), %a to całkowita liczba dni
echo $roznica_interwal->format("%y lat, %m miesięcy, %d dni, %h godzin, %i minut, %s sekund") . "<br>";

if ($roznica_interwal->invert) { // invert = 1 jeśli $data1 > $data2 (różnica ujemna)
    echo "Data pierwsza jest późniejsza.<br>";
} else {
    echo "Data pierwsza jest wcześniejsza lub taka sama.<br>";
}

// Dostęp do właściwości obiektu DateInterval:
// $roznica_interwal->y, $roznica_interwal->m, $roznica_interwal->d, ...
// $roznica_interwal->days (całkowita liczba dni, jeśli obliczona, lub false)

// Porównywanie obiektów DateTime/DateTimeImmutable
if ($data1 < $data2) {
    echo "$data1_str jest wcześniejsza niż $data2_str<br>";
} elseif ($data1 > $data2) {
    echo "$data1_str jest późniejsza niż $data2_str<br>";
} else {
    echo "Daty są identyczne.<br>";
}
?>

Znaki formatujące dla DateInterval::format():

Klasa DateTimeZone

Reprezentuje strefę czasową. Można ją użyć do tworzenia obiektów DateTime w konkretnej strefie lub do zmiany strefy istniejącego obiektu.

<?php
$strefa_warszawa = new DateTimeZone("Europe/Warsaw");
$strefa_londyn = new DateTimeZone("Europe/London");

$teraz_warszawa = new DateTime("now", $strefa_warszawa);
echo "Teraz w Warszawie: " . $teraz_warszawa->format("Y-m-d H:i:s P") . "<br>";

// Konwersja do strefy Londynu
$teraz_londyn = $teraz_warszawa->setTimezone($strefa_londyn);
echo "Ten sam moment w Londynie: " . $teraz_londyn->format("Y-m-d H:i:s P") . "<br>";

// Lista identyfikatorów stref czasowych
// $lista_stref = DateTimeZone::listIdentifiers();
// print_r($lista_stref);
?>

Klasa DatePeriod

Pozwala na iterowanie po zestawie dat i czasów w określonym okresie, z zadanym interwałem.

Konstruktor: DatePeriod(DateTimeInterface $start, DateInterval $interval, DateTimeInterface $end [, int $options = 0]) lub DatePeriod(DateTimeInterface $start, DateInterval $interval, int $recurrences [, int $options = 0]) lub DatePeriod(string $isostr [, int $options = 0]) (dla ISO 8601 repeating interval string).

<?php
$poczatek = new DateTimeImmutable("2023-04-01");
$koniec = new DateTimeImmutable("2023-04-10");
$interwal_dzienny = new DateInterval("P1D"); // Co 1 dzień

$okres = new DatePeriod($poczatek, $interwal_dzienny, $koniec);

echo "Daty od " . $poczatek->format("Y-m-d") . " do " . $koniec->format("Y-m-d") . " (bez końca):<br>";
foreach ($okres as $data_w_okresie) {
    echo $data_w_okresie->format("Y-m-d l") . "<br>";
}

// Opcja DatePeriod::EXCLUDE_START_DATE aby pominąć datę początkową
$okres_z_liczba_powtorzen = new DatePeriod($poczatek, $interwal_dzienny, 5); // 5 powtórzeń (łącznie 6 dat, wliczając startową)
echo "<br>Pierwsze 6 dni od " . $poczatek->format("Y-m-d") . ":<br>";
foreach ($okres_z_liczba_powtorzen as $data_w_okresie) {
    echo $data_w_okresie->format("Y-m-d l") . "<br>";
}
?>

Praca z Lokalizacją (Formatowanie Zależne od Języka)

Standardowe funkcje date() i metody format() klasy DateTime formatują nazwy dni tygodnia i miesięcy w języku angielskim. Aby uzyskać formatowanie zależne od ustawień regionalnych (np. polskie nazwy), można użyć rozszerzenia Intl (Internationalization), a konkretnie klasy IntlDateFormatter.

<?php
// Upewnij się, że rozszerzenie Intl jest włączone w php.ini (extension=intl)
if (class_exists("IntlDateFormatter")) {
    $data_obiekt = new DateTimeImmutable();
    
    // Formatowanie z użyciem IntlDateFormatter
    // Locale: "pl_PL" dla Polski
    // Date type: IntlDateFormatter::FULL, ::LONG, ::MEDIUM, ::SHORT
    // Time type: IntlDateFormatter::FULL, ::LONG, ::MEDIUM, ::SHORT
    // Timezone: można podać, lub użyje domyślnej
    // Calendar: IntlDateFormatter::GREGORIAN
    // Pattern: można podać własny wzorzec (np. "EEEE, d MMMM yyyy, HH:mm")

    $formatter_pelny = new IntlDateFormatter(
        "pl_PL", 
        IntlDateFormatter::FULL, 
        IntlDateFormatter::FULL,
        date_default_timezone_get(), // lub konkretna strefa
        IntlDateFormatter::GREGORIAN
    );
    echo "Intl (pełny): " . $formatter_pelny->format($data_obiekt) . "<br>";
    // np. środa, 15 marca 2023 14:30:00 Czas środkowoeuropejski standardowy

    $formatter_niestandardowy = new IntlDateFormatter(
        "pl_PL", 
        IntlDateFormatter::NONE, // Ignoruj predefiniowany format daty
        IntlDateFormatter::NONE, // Ignoruj predefiniowany format czasu
        date_default_timezone_get(),
        IntlDateFormatter::GREGORIAN,
        "EEEE, d MMMM yyyy HH:mm:ss"
    );
    echo "Intl (niestandardowy): " . $formatter_niestandardowy->format($data_obiekt) . "<br>";
    // np. środa, 15 marca 2023 14:30:00

} else {
    echo "Rozszerzenie Intl nie jest dostępne. Używam formatowania angielskiego.<br>";
    $data_obiekt = new DateTimeImmutable();
    echo "Standardowo: " . $data_obiekt->format("l, j F Y, H:i:s") . "<br>";
}
?>

Wzorce dla IntlDateFormatter są nieco inne niż dla date()/DateTime::format() i są zgodne ze standardem ICU. Przykłady:

Podsumowanie Lekcji

W tej obszernej lekcji nauczyliśmy się, jak efektywnie pracować z datami i czasem w PHP. Poznaliśmy tradycyjne funkcje takie jak time(), date(), strtotime(), oraz ich ograniczenia. Następnie zagłębiliśmy się w potężny, obiektowy interfejs dostarczany przez klasy DateTime, DateTimeImmutable, DateInterval, DateTimeZone i DatePeriod, które oferują znacznie większą precyzję, elastyczność i czytelność kodu. Omówiliśmy tworzenie obiektów daty, formatowanie, modyfikowanie, porównywanie, pracę ze strefami czasowymi oraz iterowanie po okresach. Na koniec dotknęliśmy tematu lokalizacji dat za pomocą rozszerzenia Intl.

Umiejętność manipulowania datami i czasem jest niezbędna w niemal każdej aplikacji webowej. Wybór między tradycyjnymi funkcjami a podejściem obiektowym zależy od konkretnego zadania, ale dla nowych projektów i bardziej złożonych operacji zdecydowanie zalecane jest korzystanie z klas DateTimeImmutable i powiązanych.

W następnej lekcji zajmiemy się pracą z danymi w popularnym formacie JSON.


Zadanie praktyczne

Napisz skrypt, który wykonuje następujące czynności:

  1. Pobiera aktualną datę i czas używając DateTimeImmutable.
  2. Wyświetla aktualną datę w formacie "RRRR-MM-DD".
  3. Wyświetla aktualny czas w formacie "GG:MM:SS AM/PM".
  4. Oblicza datę, która będzie za 7 dni od teraz, i wyświetla ją.
  5. Oblicza datę, która była 1 miesiąc i 3 dni temu, i wyświetla ją.
  6. Tworzy obiekt daty dla "2025-01-01 00:00:00". Oblicza, ile dni, godzin i minut pozostało do tej daty od teraz. Wyświetl wynik w czytelnej formie (np. "Do Nowego Roku 2025 pozostało: X dni, Y godzin, Z minut.").
  7. Wyświetl aktualną datę i czas dla strefy czasowej "America/New_York".

Pokaż przykładowe rozwiązanie
<?php
date_default_timezone_set("Europe/Warsaw");

// 1. Aktualna data i czas
$teraz = new DateTimeImmutable();

// 2. Aktualna data RRRR-MM-DD
echo "Aktualna data: " . $teraz->format("Y-m-d") . "<br>";

// 3. Aktualny czas GG:MM:SS AM/PM
echo "Aktualny czas: " . $teraz->format("h:i:s A") . "<br>";

// 4. Data za 7 dni
$za_7_dni_interwal = new DateInterval("P7D");
$data_za_7_dni = $teraz->add($za_7_dni_interwal);
echo "Data za 7 dni: " . $data_za_7_dni->format("Y-m-d l") . "<br>";
// Alternatywnie: $data_za_7_dni = $teraz->modify("+7 days");

// 5. Data 1 miesiąc i 3 dni temu
$miesiac_3_dni_temu_interwal = new DateInterval("P1M3D");
$data_miesiac_3_dni_temu = $teraz->sub($miesiac_3_dni_temu_interwal);
echo "Data 1 miesiąc i 3 dni temu: " . $data_miesiac_3_dni_temu->format("Y-m-d l") . "<br>";
// Alternatywnie: $data_miesiac_3_dni_temu = $teraz->modify("-1 month -3 days");

// 6. Czas do Nowego Roku 2025
$nowy_rok_2025 = new DateTimeImmutable("2025-01-01 00:00:00");
if ($teraz < $nowy_rok_2025) {
    $roznica_do_nr = $teraz->diff($nowy_rok_2025);
    echo "Do Nowego Roku 2025 pozostało: " . 
         $roznica_do_nr->days . " dni ogółem, lub dokładniej: " . 
         $roznica_do_nr->format("%m miesięcy, %d dni, %h godzin, %i minut, %s sekund") . 
         ".<br>";
} else {
    echo "Nowy Rok 2025 już minął!<br>";
}

// 7. Aktualna data i czas w Nowym Jorku
$strefa_ny = new DateTimeZone("America/New_York");
$teraz_w_ny = $teraz->setTimezone($strefa_ny);
echo "Aktualnie w Nowym Jorku: " . $teraz_w_ny->format("Y-m-d H:i:s P (e)") . "<br>";

?>
            

Zadanie do samodzielnego wykonania

Napisz skrypt, który:

  1. Przyjmuje od użytkownika datę urodzenia w formacie "RRRR-MM-DD" (np. z formularza lub jako stała w kodzie).
  2. Używa DateTimeImmutable::createFromFormat() do stworzenia obiektu daty urodzenia. Sprawdź poprawność formatu.
  3. Oblicza wiek użytkownika w latach, miesiącach i dniach.
  4. Wyświetla obliczony wiek.
  5. Sprawdza, czy użytkownik ma dziś urodziny (porównuje dzień i miesiąc daty urodzenia z aktualną datą). Jeśli tak, wyświetla specjalne życzenia.


FAQ - Praca z Datą i Czasem w PHP

Jaka jest różnica między DateTime a DateTimeImmutable?

DateTime jest mutowalny, co oznacza, że metody modyfikujące (np. add(), modify()) zmieniają sam obiekt. DateTimeImmutable jest niemutowalny – te same metody zwracają nowy obiekt z wprowadzonymi zmianami, pozostawiając oryginalny nietknięty. DateTimeImmutable jest generalnie bezpieczniejsze i prowadzi do bardziej przewidywalnego kodu.

Dlaczego tak ważne jest ustawienie date_default_timezone_set()?

PHP używa domyślnej strefy czasowej do interpretacji i wyświetlania dat. Jeśli nie jest ona jawnie ustawiona, PHP może próbować zgadnąć strefę systemową lub użyć UTC, co może prowadzić do niespójności i błędów, zwłaszcza gdy aplikacja działa na serwerach w różnych lokalizacjach lub obsługuje użytkowników z różnych stref czasowych. Ustawienie jej na początku skryptu lub w php.ini zapewnia spójne zachowanie.

Jak najlepiej przechowywać daty w bazie danych?

Często zaleca się przechowywanie dat w bazie danych w formacie UTC (np. jako timestamp uniksowy lub typ DATETIME/TIMESTAMP bazy danych ustawiony na UTC). Następnie, przy wyświetlaniu daty użytkownikowi, konwertuje się ją na jego lokalną strefę czasową. To upraszcza logikę i zapobiega problemom z DST (czas letni/zimowy).

Czy strtotime() jest bezpieczne do użycia z danymi od użytkownika?

Należy być ostrożnym. Chociaż strtotime() jest elastyczne, może niepoprawnie zinterpretować niektóre niejednoznaczne formaty. Jeśli dane pochodzą od użytkownika, lepiej użyć DateTime::createFromFormat(), które wymaga jawnego podania oczekiwanego formatu, co jest bezpieczniejsze i bardziej przewidywalne.

Jak obsłużyć czas letni (DST)?

Klasy DateTime, DateTimeImmutable i DateTimeZone automatycznie obsługują zmiany czasu letniego/zimowego dla danej strefy czasowej. Jeśli pracujesz z timestampami i funkcją date(), musisz upewnić się, że domyślna strefa czasowa jest poprawnie ustawiona. Przechowywanie dat w UTC i konwersja do lokalnej strefy przy wyświetlaniu to dobra praktyka minimalizująca problemy z DST.

Czy mogę formatować daty na polskie nazwy miesięcy/dni bez rozszerzenia Intl?

Bez rozszerzenia Intl jest to trudniejsze. Można by stworzyć własne tablice z polskimi nazwami i używać ich do zastępowania angielskich nazw uzyskanych z date() lub DateTime::format(), ale jest to mniej eleganckie i bardziej podatne na błędy. Rozszerzenie Intl jest standardowym i zalecanym sposobem na internacjonalizację.

Jak uzyskać timestamp z obiektu DateTime?

Można użyć metody getTimestamp(). Na przykład: $timestamp = $dateTimeObject->getTimestamp();. Zwraca ona uniksowy znacznik czasu.