7. PHP – obsługa daty i czasu


Funkcje daty i czasu

TaskQuest

Dodatek

Szybki quiz – przypomnienie poprzedniej lekcji

1. Co zostanie wyświetlone?

function podwoj($x) {
    echo $x * 2;
}

$w = podwoj(4);
var_dump($w);

2. Co wyświetli poniższy kod?

function test() {
    return 1;
    echo "A";
}

echo test();

3. Dlaczego ten kod nie wyświetla liczby 250? Jak go poprawić bez użycia global?

$xp = 250;

function pokazXp() {
    echo $xp;
}

pokazXp();

4. Co jest nie tak w definicji tej funkcji?

function powitanie($imie = "Gość", $wiek) {
    return "$imie ma $wiek lat";
}

5. Co zostanie wyświetlone?

function licznik() {
    static $c = 0;
    $c++;
    return $c;
}

echo licznik();
echo licznik();
echo licznik();

6. Co wyświetli kod w wersji A, a co w wersji B?

// Wersja A
function dodajXp($xp) {
    $xp += 50;
}

// Wersja B
function dodajXp(&$xp) {
    $xp += 50;
}

$xp = 100;
dodajXp($xp);
echo $xp;

7. Uzupełnij nagłówek funkcji tak, aby było jasne, że funkcja przyjmuje liczbę całkowitą i zwraca liczbę całkowitą.

function obliczPoziom(____ $xp) ____ {
    // ...
}

8. TaskQuest: XP_NA_POZIOM wynosi 100. Co zwróci obliczPoziom(550), a co ileBrakujeXp(250, 3)?

Odpowiedzi
  1. Wyświetli 8, a potem NULL. Funkcja wyświetla wynik przez echo, ale nic nie zwraca, więc $w ma wartość NULL.
  2. 1. return kończy działanie funkcji – echo "A" nigdy się nie wykona.
  3. Zmienna $xp jest globalna, a wewnątrz funkcji widoczne są tylko zmienne lokalne. PHP zgłosi ostrzeżenie Undefined variable $xp i nic nie wyświetli. Poprawka: przekazać wartość jako argument – function pokazXp($xp) { echo $xp; } i wywołanie pokazXp($xp);.
  4. Parametr z wartością domyślną stoi przed parametrem bez wartości domyślnej. Argumenty domyślne muszą być na końcu listy: function powitanie($wiek, $imie = "Gość"). W PHP 8 taki zapis daje komunikat Deprecated, a wartość domyślna "Gość" i tak nie działa – oba argumenty stają się wymagane.
  5. 123. Zmienna static zachowuje wartość między wywołaniami funkcji.
  6. Wersja A: 100 (przekazanie przez wartość – funkcja zmienia kopię). Wersja B: 150 (przekazanie przez referencję & – funkcja zmienia oryginalną zmienną).
  7. function obliczPoziom(int $xp): int
  8. obliczPoziom(550) zwraca 6. ileBrakujeXp(250, 3) zwraca 50 (próg następnego poziomu: 3 * 100 = 300, 300 - 250 = 50).

PHP oferuje dwa główne sposoby pracy z datą i czasem:

  1. Funkcje proceduralne (starsze, np. `date()`, `time()`, `strtotime()`)
  2. Klasy DateTime (nowoczesne, obiektowe, zalecane od PHP 5.2+)

Era Uniksa (Unix Timestamp)

Aktualny czas, podawany jako liczba sekund, które upłynęły od nastania Ery Unixu: 1 stycznia 1970, 0:00:00 GMT.

Uniwersalny sposób reprezentacji czasu w systemach komputerowych – jedna liczba zamiast wielu składowych (rok, miesiąc, dzień, itd.).

Przykład:
- `0` = 1 stycznia 1970, 00:00:00 GMT
- `1000000000` = 9 września 2001, 01:46:40 GMT
- `1700000000` = 14 listopada 2023, 22:13:20 GMT

time()

Zwraca aktualny uniksowy znacznik czasu

$teraz = time();
echo $teraz; // np. 1714481247

// Za tydzień (7 dni * 24 godziny * 60 minut * 60 sekund)
$zaTydzien = time() + (7 * 24 * 60 * 60);
echo $zaTydzien;

date()

Formatuje lokalny czas/datę na czytelny format.

string date ( string $format [, int $timestamp = time() ] )

Jako $format podajemy odpowiedni schemat zapisu z tabeli poniżej, a $timestamp to znacznik czasowy – nie musimy go podawać, jest ustawiany automatycznie (jest to ilość sekund od nastania Ery Unixu: 1 stycznia 1970, 0:00:00 GMT).

Przykład:

echo date("l");                     // wyświetli Monday
echo date("m.d.y");                 // wyświetli 03.10.01
echo date("j, n, Y");               // wyświetli 10, 3, 2001
echo date('l jS \of F Y h:i:s A');  // wyświetli Monday 8th of August 2005 03:12:46 PM

echo date('Y-m-d', time()+(7*24*60*60)); //wyświetli datę za tydzień (7*24*60*60=604800 tyle sekund ma tydzień)

date() zwraca datę sformatowaną zgodnie z szablonem przedstawionym w poniższej tabeli.

Poniższych znaków używa się jako tekstu w parametrze format

Zawartość parametru formatOpisPrzykład zwróconej wartości
Dzień——
dDzień miesiąca, 2 cyfry z wiodącymi zerami01 do 31
DTekstowy opis angielskiej nazwy dnia, trzy literyMon kończąc na Sun
jDzień miesiąca bez zer wiodących1 do 31
l (mała litera 'L’)Pełen angielski opis dnia tygodniaSunday aż do Saturday
NLiczbowa forma dnia tygodnia, zgodna z normą ISO-8601 (dodana
w PHP 5.1.0)
1 (dla Poniedziałku) aż do 7 (dla Niedzieli)
SAngielski przyrostek porządkowy dla dnia miesiąca, 2 literyst, nd, rd lub
th. Dobrze wygląda w połączeniu z j
wLiczbowa forma dnia tygodnia0 (dla Niedzieli) aż do 6 (dla Soboty)
zDzień roku (Zaczynając od 0)0 aż do 365
Tydzień——
WNumer tygodnia w roku, zgodny z normą ISO-8601, Tygodnie rozpoczynają Poniedziałki (dostępne od PHP 4.1.0)Przykład: 42 (42. tydzień roku)
Miesiąc——
FPełen angielski opis, dnia miesiąca, taki jak January czy MarchJanuary aż do December
mLiczbowa forma miesiąca, z zerami wiodącymi01 aż do 12
MKrótki, angielski opis miesiąca, trzy literyJan a do Dec
nLiczbowa forma miesiąca, bez zer wiodących1 aż do 12
tIlość dni w danym miesiącu28 do 31
Rok——
LInformacja o tym, czy rok jest przestępnym1 jeśli rok jest przestępny, 0 w przeciwnym wypadku.
oNumer roku, zgodny z normą ISO-8601. Zwraca to taką samą wartość jak
Y, z takim wyjątkiem, że numer tygodnia ISO
(W) należy do poprzedniego lub następnego roku, niż rok
użyty w tym miejscu. (dodane w PHP 5.1.0)
Przykłady: 1999 lub 2003
YPełna liczbowa forma roku, 4 cyfryPrzykłady: 1999 lub 2003
yDwie cyfry reprezentujące rokPrzykłady: 99 or 03
Czas——
aPora dnia – dwie małe litery (przed/po południu) (ang. Ante/Post meridiem)am lub pm
APora dnia – dwie duże litery (przed/po południu) (ang. Ante/Post meridiem)AM lub PM
BSwatch Internet Time000 aż do 999
gGodzina, w formacie 12-godzinnym, bez zer wiodących1 aż do 12
GGodzina, w formacie 24-godzinnym, bez zer wiodących0 aż do 23
hGodzina, w formacie 12-godzinnym, z zerami wiodącymi01 aż do 12
HGodzina, w formacie 24-godzinnym, z zerami wiodącymi00 through 23
iMinuty z zerami wiodącymi00 do 59
sSekundy, z zerami wiodącymi00 aż do 59
uMikrosekundy (dodano w PHP 5.2.2)Przykład: 54321
vMilisekundy (dodano w PHP 7.0.0).Przykład: 654
Strefa czasowa——
eIdentyfikator strefy czasowej (dodano w PHP 5.1.0)Przykłady: UTC, GMT, Europe/Zagreb
I (duże i)Informacja o tym, czy czas jest letni1 jeśli czas jest letni, 0 w przeciwnym razie.
ORóżnica z czasem Greenwich (GMT) w godzinachPrzykład: +0200
PRóżnica z czasem Greenwich (GMT) z dwukropkiem pomiędzy godzinami i minutami (dodano w PHP 5.1.3)Przykład: +02:00
TSkrót dla strefy czasowejPrzykłady: EST, MDT …
ZRóżnica dla strefy czasowej w sekundach. Wyrównanie to jest zawsze ujemne dla stref położonych na zachód
od południka 0, oraz dodatnie dla tych leżących na wschódod niego.
-43200 aż do 50400
Pełna Data/Czas——
cData w standardzie ISO 8601 (dodana w PHP 5)2004-02-12T15:19:21+00:00
rData sformatowana zgodnie z » RFC 2822Przykład: Thu, 21 Dec 2000 16:01:07 +0200
USekundy liczone od ery UNIX-a (1 stycznia 1970 00:00:00 czasu Greenwich – GMT)Zobacz także time()

getdate()

Zwraca tablicę asocjacyjną z informacjami o dacie

array getdate ([ int $timestamp = time() ] )

Funkcja zwraca tablicę asocjacyjną, a $timestamp to znacznik czasowy – nie musimy go podawać, jest ustawiany automatycznie (jest to ilość sekund od nastania Ery Unixu: 1 stycznia 1970, 0:00:00 GMT).

Przykład:

$info= getdate();
print_r($info);
echo "Dzisiaj jest {$info['mday']} {$info['month']} {$info['year']}";
// Dzisiaj jest 1 May 2024

Zostanie wyświetlone:

Array
(
[seconds] => 45 // sekundy
[minutes] => 30 // minuty
[hours] => 14 // godziny (24h)
[mday] => 1 // dzień miesiąca (1-31)
[wday] => 1 // dzień tygodnia (0=niedziela, 6=sobota)
[mon] => 5 // miesiąc (1-12)
[year] => 2024 // rok
[yday] => 121 // dzień roku (0-365)
[weekday] => Monday // nazwa dnia (ang.)
[month] => May // nazwa miesiąca (ang.)
[0] => 1714481445 // timestamp
)

microtime()

Zwraca aktualny uniksowy znacznik czasu z mikrosekundami

mixed microtime([bool $asFloat = false])

Przykład

// Jako string (domyślnie)
echo microtime(); // "0.25163900 1714481247"

// Jako float (zalecane)
echo microtime(true); // 1714481247.2516

// Mierzenie czasu wykonania
$start = microtime(true);

// Kod do zmierzenia
for ($i = 0; $i < 1000000; $i++) {
// jakieś operacje
}

$end = microtime(true);
$czas = $end - $start;

echo "Wykonanie trwało: " . round($czas, 4) . " sekund";

mktime()

Zwraca uniksowy znacznik czasu dla konkretnej daty

int mktime(
int $hour = date("H"),
int $minute = date("i"),
int $second = date("s"),
int $month = date("n"),
int $day = date("j"),
int $year = date("Y")
)

Zwraca liczbę sekund, które upłynęły od nastania Ery Unixu: 1 stycznia 1970, 0:00:00 GMT do podanej daty. Należy zwrócić uwagę na kolejność podawanych parametrów!

Poprawna kolejność parametrów to: godziny, minuty, sekundy, miesiąc, dzień, rok.

Aby wyświetlić np dzień tygodnia, w którym się urodziliście wystarczy dostosować poniższy kod

// Sprawdź dzień tygodnia swoich urodzin
$urodziny = mktime(0, 0, 0, 7, 15, 2000); // 15 lipca 2000
echo "Urodziłem się w " . date("l", $urodziny); // Saturday

// Konkretna data i czas
$sylwester = mktime(23, 59, 59, 12, 31, 2024);
echo date("Y-m-d H:i:s", $sylwester); // 2024-12-31 23:59:59

// mktime automatycznie koryguje nieprawidłowe daty
$nastepnyMiesiac = mktime(0, 0, 0, 13, 1, 2024); // miesiąc 13 -> styczeń 2025
echo date("Y-m-d", $nastepnyMiesiac); // 2025-01-01

strtotime()

Parsuje większość angielskich tekstowych opisów daty i czasu do uniksowego znacznika czasu

int strtotime ( string $czas [, int $teraz ] )

Funkcja przyjmuje tekst zawierający datę w formacie angielskim i stara się przeliczyć ją na uniksowy znacznik czasu, zachowuje się zgodnie ze składnią daty wg GNU. W przypadku fiaska, zwracane jest -1.

// Podstawowe użycie
echo strtotime("now"); // aktualny timestamp
echo strtotime("2024-05-01"); // konkretna data
echo strtotime("01 May 2024"); // angielski format
echo strtotime("2024-05-01 14:30:00"); // data i czas

// Relatywne daty
echo strtotime("+1 day"); // jutro
echo strtotime("-1 week"); // tydzień temu
echo strtotime("+2 months"); // za 2 miesiące
echo strtotime("+1 week 2 days"); // za tydzień i 2 dni
echo strtotime("+1 week 2 days 4 hours 2 seconds");

// Słowa kluczowe
echo strtotime("next Monday"); // następny poniedziałek
echo strtotime("last Friday"); // ostatni piątek
echo strtotime("tomorrow"); // jutro
echo strtotime("yesterday"); // wczoraj
echo strtotime("midnight"); // północ dzisiaj
echo strtotime("noon"); // południe dzisiaj

// Kombinacja
$base = strtotime("2024-01-01");
echo strtotime("+3 months", $base); // 3 miesiące od 1 stycznia 2024

// Formatowanie wyniku
echo date("Y-m-d", strtotime("+7 days")); // data za tydzień

Lista formatów dostępna tutaj.

Klasy DateTime (nowoczesne podejście)

Zalety obiektowego podejścia:

  • Łatwiejsze manipulowanie datami
  • Obsługa stref czasowych
  • Immutable warianty (DateTimeImmutable)
  • Lepsze porównywanie dat
  • Bezpieczniejsze dla dat przed 1970 i po 2038
  • Czytelniejszy kod

Klasa DateTime

Tworzenie obiektu:

// Aktualna data i czas
$teraz = new DateTime();
echo $teraz->format('Y-m-d H:i:s');

// Z konkretną datą
$data = new DateTime('2024-05-01');
$data = new DateTime('2024-05-01 14:30:00');
$data = new DateTime('now');
$data = new DateTime('tomorrow');
$data = new DateTime('+1 week');

// Ze strefą czasową
$data = new DateTime('now', new DateTimeZone('Europe/Warsaw'));
$data = new DateTime('2024-05-01', new DateTimeZone('America/New_York'));

Formatowanie (format)

$data = new DateTime('2024-05-01 14:30:45');

echo $data->format('Y-m-d');           // 2024-05-01
echo $data->format('d.m.Y');           // 01.05.2024
echo $data->format('l, j F Y');        // Wednesday, 1 May 2024
echo $data->format('H:i:s');           // 14:30:45
echo $data->format('c');               // 2024-05-01T14:30:45+02:00 (ISO 8601)
echo $data->format('r');               // Wed, 01 May 2024 14:30:45 +0200 (RFC 2822)
echo $data->format('U');               // 1714481445 (timestamp)

Modyfikowanie dat (modify, add, sub)

$data = new DateTime('2024-05-01');

// modify() - używa składni strtotime
$data->modify('+1 day');
$data->modify('-2 weeks');
$data->modify('+3 months');
$data->modify('next Monday');

// add() - używa DateInterval
$data->add(new DateInterval('P1D'));      // +1 dzień
$data->add(new DateInterval('P7D'));      // +7 dni
$data->add(new DateInterval('P1M'));      // +1 miesiąc
$data->add(new DateInterval('PT2H'));     // +2 godziny
$data->add(new DateInterval('P1DT2H'));   // +1 dzień 2 godziny

// sub() - odejmowanie
$data->sub(new DateInterval('P1D'));      // -1 dzień

Format DateInterval:

  • P – prefix (period)
  • Y – lata (years)
  • M – miesiące (months) lub minuty (po T)
  • D – dni (days)
  • T – separator czasu
  • H – godziny (hours)
  • M – minuty (minutes)
  • S – sekundy (seconds)
'P1Y'        // 1 rok
'P3M'        // 3 miesiące
'P2W'        // 2 tygodnie
'P10D'       // 10 dni
'PT5H'       // 5 godzin
'PT30M'      // 30 minut
'PT45S'      // 45 sekund
'P1DT12H'    // 1 dzień i 12 godzin
'P1Y2M3DT4H5M6S' // 1 rok, 2 miesiące, 3 dni, 4 godziny, 5 minut, 6 sekund

Różnica między datami (diff)

$data1 = new DateTime('2024-01-01');
$data2 = new DateTime('2024-12-31');

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

echo $roznica->days;      // 365 (całkowita liczba dni)
echo $roznica->y;         // 0 (lata)
echo $roznica->m;         // 11 (miesiące)
echo $roznica->d;         // 30 (dni)
echo $roznica->h;         // 0 (godziny)
echo $roznica->i;         // 0 (minuty)
echo $roznica->s;         // 0 (sekundy)
echo $roznica->invert;    // 0 (dodatnia) lub 1 (ujemna)

// Formatowanie różnicy
echo $roznica->format('%y lat, %m miesięcy, %d dni');
// 0 lat, 11 miesięcy, 30 dni

Porównywanie dat

$data1 = new DateTime('2024-05-01');
$data2 = new DateTime('2024-06-01');

// Operatory porównania
if ($data1 < $data2) {
    echo "Data1 jest wcześniejsza";
}

if ($data1 == $data2) {
    echo "Daty są równe";
}

if ($data1 > $data2) {
    echo "Data1 jest późniejsza";
}

// Różnica w sekundach
$roznica = $data2->getTimestamp() - $data1->getTimestamp();
echo "Różnica: $roznica sekund";

DateTimeImmutable

Niemodyfikowalna wersja DateTime – każda operacja zwraca NOWY obiekt.

Zapobiega przypadkowym zmianom daty, bezpieczniejsze w kodzie współdzielonym.

// DateTime - modyfikuje oryginalny obiekt
$data = new DateTime('2024-05-01');
$nowData = $data->modify('+1 day');
echo $data->format('Y-m-d');      // 2024-05-02 (zmieniona!)
echo $nowData->format('Y-m-d');   // 2024-05-02 (ta sama!)

// DateTimeImmutable - tworzy nowy obiekt
$data = new DateTimeImmutable('2024-05-01');
$nowData = $data->modify('+1 day');
echo $data->format('Y-m-d');      // 2024-05-01 (NIEzmieniona!)
echo $nowData->format('Y-m-d');   // 2024-05-02 (nowy obiekt!)

Strefy czasowe (DateTimeZone)

// Tworzenie z konkretną strefą
$warszawa = new DateTime('now', new DateTimeZone('Europe/Warsaw'));
$newYork = new DateTime('now', new DateTimeZone('America/New_York'));

echo $warszawa->format('Y-m-d H:i:s T'); // 2024-05-01 14:30:00 CEST
echo $newYork->format('Y-m-d H:i:s T');  // 2024-05-01 08:30:00 EDT

// Zmiana strefy czasowej
$data = new DateTime('2024-05-01 14:30:00', new DateTimeZone('UTC'));
echo $data->format('Y-m-d H:i:s T'); // 2024-05-01 14:30:00 UTC

$data->setTimezone(new DateTimeZone('Europe/Warsaw'));
echo $data->format('Y-m-d H:i:s T'); // 2024-05-01 16:30:00 CEST

// Lista wszystkich stref czasowych
$zones = DateTimeZone::listIdentifiers();
print_r($zones);
// ['Africa/Abidjan', 'Africa/Accra', ..., 'Europe/Warsaw', ...]

Tworzenie DateTime z timestamp

$timestamp = 1714481247;

// Sposób 1
$data = new DateTime();
$data->setTimestamp($timestamp);

// Sposób 2 (lepszy)
$data = (new DateTime())->setTimestamp($timestamp);

// Sposób 3 (najlepszy w PHP 5.3+)
$data = DateTime::createFromFormat('U', $timestamp);

echo $data->format('Y-m-d H:i:s');

Tworzenie DateTime z formatu niestandardowego

// Parsowanie niestandardowego formatu
$data = DateTime::createFromFormat('d/m/Y', '01/05/2024');
echo $data->format('Y-m-d'); // 2024-05-01

$data = DateTime::createFromFormat('d.m.Y H:i', '01.05.2024 14:30');
echo $data->format('Y-m-d H:i:s'); // 2024-05-01 14:30:00

// Z wykrywaniem błędów
$data = DateTime::createFromFormat('Y-m-d', 'nieprawidłowa-data');
if ($data === false) {
    $errors = DateTime::getLastErrors();
    print_r($errors);
}

Przykłady:

Liczenie czasu generowania strony

$start = microtime(true);

// Kod do zmierzenia
for ($i = 0; $i < 10000; $i++) {
$str = 'test';
}

$end = microtime(true);
echo 'Strona wygenerowana w ' . round($end - $start, 4) . ' sekund';

//Nowoczesny sposób
$start = new DateTimeImmutable();

// Kod do zmierzenia
for ($i = 0; $i < 10000; $i++) {
$str = 'test';
}

$end = new DateTimeImmutable();
$roznica = $start->diff($end);

echo 'Strona wygenerowana w ' . $roznica->format('%s.%f sekund');

Tworzenie daty o godzinę w przód

$czas_akt = time();
$za_godz = $czas_akt + 3600;
echo date("r", $za_godz); // Wyświetli datę 'za godzinę'           

Data „za miesiąc”

$day = date('d');
$month = date('m');
$year = date('Y');

$month++;

if ($month == 13) {
$month = 1;
$year++;
}

echo "$day.$month.$year";

//Nowoczesny sposób
$data = new DateTime();
$data->modify('+1 month');
echo $data->format('d.m.Y');

// Lub z add()
$data = new DateTime();
$data->add(new DateInterval('P1M'));
echo $data->format('d.m.Y');

Odliczanie czasu do konkretnego wydarzenia:

function CountDown($hour, $minute, $second, $month, $day, $year) {
$eventDate = mktime($hour, $minute, $second, $month, $day, $year);
$today = time();
$secondsTo = $eventDate - $today;

$minutesTo = round($secondsTo / 60);
$hoursTo = round($minutesTo / 60);
$daysTo = round($hoursTo / 24);
$weeksTo = round($daysTo / 7);
$monthsTo = round($weeksTo / 4);
$yearsTo = round($monthsTo / 12);

return [
'seconds' => $secondsTo,
'minutes' => $minutesTo,
'hours' => $hoursTo,
'days' => $daysTo,
'weeks' => $weeksTo,
'months' => $monthsTo,
'years' => $yearsTo
];
}

$countdown = CountDown(12, 0, 0, 12, 31, 2024);
print_r($countdown);

//Nowoczesny sposób
function countDown(string $targetDate): array {
$teraz = new DateTimeImmutable();
$cel = new DateTimeImmutable($targetDate);
$roznica = $teraz->diff($cel);

return [
'days' => $roznica->days,
'hours' => $roznica->h,
'minutes' => $roznica->i,
'seconds' => $roznica->s,
'formatted' => $roznica->format('%a dni, %h godz, %i min, %s sek')
];
}

$countdown = countDown('2024-12-31 23:59:59');
echo "Do sylwestra zostało: {$countdown['formatted']}";

Baner zależny od pory dnia

function getBannerName() {
$hour = date("G");

if ($hour > 22 || $hour < 4) {
return "banner_noc.gif";
} elseif ($hour >= 4 && $hour < 12) {
return "banner_rano.gif";
} elseif ($hour >= 12 && $hour < 18) {
return "banner_dzien.gif";
} else {
return "banner_wieczor.gif";
}
}

echo '<img src="' . getBannerName() . '">';

//Nowoczesny sposób
function getBannerName(): string {
$teraz = new DateTime();
$godzina = (int)$teraz->format('G');

return match(true) {
$godzina >= 22 || $godzina < 4 => 'banner_noc.gif',
$godzina >= 4 && $godzina < 12 => 'banner_rano.gif',
$godzina >= 12 && $godzina < 18 => 'banner_dzien.gif',
default => 'banner_wieczor.gif'
};
}

echo '<img src="' . getBannerName() . '" alt="Banner">';

Sprawdzanie czy daty są z tego samego dnia

function sameDay($ts1, $ts2) {
return date("Y-m-d", $ts1) === date("Y-m-d", $ts2);
}

$date1 = mktime(19, 30, 0, 12, 10, 2024);
$date2 = mktime(10, 12, 0, 12, 10, 2024);

if (sameDay($date1, $date2)) {
echo "Daty są z tego samego dnia";
}

//Nowoczesny sposób
function sameDay(DateTime $date1, DateTime $date2): bool {
return $date1->format('Y-m-d') === $date2->format('Y-m-d');
}

$date1 = new DateTime('2024-12-10 19:30:00');
$date2 = new DateTime('2024-12-10 10:12:00');
$date3 = new DateTime('2024-12-11 19:30:00');

if (sameDay($date1, $date2)) {
echo "Daty 1 i 2 są z tego samego dnia\n";
}

if (!sameDay($date1, $date3)) {
echo "Daty 1 i 3 NIE są z tego samego dnia\n";
}

Wiek osoby

function obliczWiek(string $dataUrodzenia): int {
    $urodziny = new DateTime($dataUrodzenia);
    $teraz = new DateTime();
    $roznica = $urodziny->diff($teraz);
    
    return $roznica->y;
}

echo "Masz " . obliczWiek('2000-07-15') . " lat";

// Z dodatkowymi informacjami
function szczegolyWieku(string $dataUrodzenia): array {
    $urodziny = new DateTime($dataUrodzenia);
    $teraz = new DateTime();
    $roznica = $urodziny->diff($teraz);
    
    return [
        'lata' => $roznica->y,
        'miesiace' => $roznica->m,
        'dni' => $roznica->d,
        'calkowite_dni' => $roznica->days,
        'formatted' => $roznica->format('%y lat, %m miesięcy, %d dni')
    ];
}

$wiek = szczegolyWieku('2000-07-15');
echo "Żyjesz już: {$wiek['formatted']} ({$wiek['calkowite_dni']} dni)";

Dni robocze między datami

function dniRoboczeMiedzy(DateTime $start, DateTime $end): int {
    $dni = 0;
    $current = clone $start;
    
    while ($current <= $end) {
        $dzienTygodnia = (int)$current->format('N'); // 1-7 (Pn-Nd)
        
        if ($dzienTygodnia < 6) { // Pn-Pt
            $dni++;
        }
        
        $current->modify('+1 day');
    }
    
    return $dni;
}

$poczatek = new DateTime('2024-05-01');
$koniec = new DateTime('2024-05-31');

echo "Dni robocze w maju 2024: " . dniRoboczeMiedzy($poczatek, $koniec);

Pierwszy i ostatni dzień miesiąca

function pierwszyDzienMiesiaca(int $miesiac, int $rok): DateTime {
    return new DateTime("$rok-$miesiac-01");
}

function ostatniDzienMiesiaca(int $miesiac, int $rok): DateTime {
    $data = new DateTime("$rok-$miesiac-01");
    $data->modify('last day of this month');
    return $data;
}

$pierwszy = pierwszyDzienMiesiaca(5, 2024);
$ostatni = ostatniDzienMiesiaca(5, 2024);

echo "Maj 2024: " . $pierwszy->format('Y-m-d') . " - " . $ostatni->format('Y-m-d');
// Maj 2024: 2024-05-01 - 2024-05-31

Czy data jest w przeszłości/przyszłości

function czyPrzeszlosc(DateTime $data): bool {
    return $data < new DateTime();
}

function czyPrzyszlosc(DateTime $data): bool {
    return $data > new DateTime();
}

$wczoraj = new DateTime('yesterday');
$jutro = new DateTime('tomorrow');

var_dump(czyPrzeszlosc($wczoraj));  // true
var_dump(czyPrzyszlosc($jutro));    // true

Zadania do wykonania:

Zadanie 1: Napisz skrypt, który będzie pokazywał aktualna datę i czas w postaci:  Dzisiaj jest 30.10.2018 godzina 16:50:47

Zadanie 2: Napisz skrypt sprawdzający w jaki dzień tygodnia się urodziłeś/łaś oraz sprawdź ile czasu zostało do twoich urodzin.

Zadanie 3: Napisz skrypt sprawdzający czy dany rok jest przestępny wiedząc, że: rok jest przestępny tylko wtedy, jeśli dzieli się przez 4, ale nie dzieli się przez 100, chyba że dzieli się przez 400.
Zadanie 4: Napisz funkcję, która zwróci tablicę wszystkich poniedziałków w danym roku.
Zadanie 5: Napisz funkcję obliczającą ile masz dokładnie sekund, godzin i dni.

Zadanie 6: Napisz funkcję, która sprawdzi, czy podana data jest weekendem.

Zadanie 7: Napisz funkcję, która zwróci liczbę pełnych tygodni między dwiema datami.

TaskQuest — Karta pracy

KARTA PRACY

TaskQuest 0.7 — terminy i prawdziwy streak

Mamy już użytkownika, XP oraz poziomy.

Ale jedna rzecz wciąż jest sztuczna:

$wykonalDzisiajZadanie = true;

Skąd program ma wiedzieć, czy użytkownik naprawdę wykonał zadanie dzisiaj?

Do tego potrzebujemy daty i czasu.

Cel lekcji

Wykorzystać daty do stworzenia dwóch elementów TaskQuest:

  • terminu wykonania zadania,
  • pierwszego prawdziwego mechanizmu streak.

1. Problem

Dotychczas informację o aktywności ustawialiśmy ręcznie:

$wykonalDzisiajZadanie = true;

To nie jest prawdziwy mechanizm.

TaskQuest powinien znać:

dzisiejszą datę 
datę ostatniej aktywności 
termin zadania

2. Jedno zadanie

Nie znamy jeszcze tablic. Dlatego pracujemy tylko na jednym przykładowym zadaniu.

$tytulZadania = "Nauczyć się obsługi daty w PHP"; 
$terminZadania = "2026-09-20"; 
$zadanieWykonane = false;

Na razie:

$zadanieWykonane = false;

oznacza:

zadanie nie zostało wykonane.

Później zmienimy tę wartość na true, aby zasymulować wykonanie zadania.

3. SAMODZIELNIE — ile dni zostało?

Utwórz:

$dzisiaj = new DateTime('today');
$termin = new DateTime($terminZadania);

Następnie oblicz różnicę:

$roznica = $dzisiaj->diff($termin);

Możesz zobaczyć co zostało zwrócone i co zawiera zmienna $roznica:

print_r($roznica);

Spróbuj wyświetlić liczbę dni.

HINT

Obiekt zwrócony przez diff() posiada między innymi:

$roznica->days

4. Zadanie jest przed terminem czy po terminie?

Sprawdź:

if ($termin < $dzisiaj) {
    // termin minął
}

Jeżeli termin jest w przyszłości:

Do terminu pozostało: 5 dni.

Jeżeli minął:

Termin minął 2 dni temu.

A może jest dzisiaj?

Termin jest dzisiaj.

5. Funkcja zwracająca komunikat

Utwórz funkcję:

function komunikatTerminu(string $terminZadania): string

Ma ona zwrócić odpowiedni komunikat, wykorzystując:

$dzisiaj
$termin
$roznica

oraz stworzone warunki if.

Nie używaj wewnątrz funkcji:

echo

Funkcja ma zwrócić tekst przez:

return

Wyświetl odpowiednio zadanie i termin zadania oraz odpowiedni komunikat.

6. Streak — czy passa wciąż trwa

Zanim zaczniemy pisać kod streaka, uporządkujmy jedną rzecz.

W poprzedniej wersji pojawiały się dwie zmienne:

$zadanieWykonane

oraz:

$wykonalDzisiajZadanie

Nie będziemy używać obu.

KROK 1 — ZMIANA $wykonalDzisiajZadanie

W całym kodzie znajdź:

$wykonalDzisiajZadanie

i zmień jej nazwę na:

$zadanieWykonane

Dotyczy to wszystkich miejsc:

  • przykładu,
  • danych używanych przy streaku,
  • warunku if,
  • parametru funkcji aktualizujStreak(),
  • warunku wewnątrz funkcji,
  • wywołania funkcji.

Uwaga

W sekcji z zadaniem mamy już:

$zadanieWykonane = false;

Nie tworzymy drugi raz:

$zadanieWykonane = true;

Jeżeli chcemy zasymulować wykonanie zadania dzisiaj, zmieniamy wartość istniejącej zmiennej:

$zadanieWykonane = true;

Od tej pory w całym TaskQuest używamy tylko jednej zmiennej:

$zadanieWykonane

Oznacza ona:

Czy użytkownik wykonał zadanie?

7. Jak działa streak?

Mamy trzy informacje:

$streak = 5;
$dataOstatniejAktywnosci = "2026-09-14";
$zadanieWykonane = true;

Interesuje nas:

Co powinno stać się ze streakiem, jeśli użytkownik wykona dziś zadanie?

Rozpatrujemy trzy sytuacje.

Sytuacja 1 — ostatnia aktywność była dzisiaj

Przykład:

dzisiaj:              2026-09-17
ostatnia aktywność:   2026-09-17

Użytkownik już dzisiaj wykonał zadanie.

Nie zwiększamy streaka.

streak pozostaje bez zmian

Sytuacja 2 — ostatnia aktywność była wczoraj

Przykład:

dzisiaj:              2026-09-17
ostatnia aktywność:   2026-09-16

Użytkownik zachował ciągłość.

Zwiększamy streak:

$streak++;

Jeżeli było:

5

będzie:

6

Sytuacja 3 — ostatnia aktywność była wcześniej

Przykład:

dzisiaj:              2026-09-17
ostatnia aktywność:   2026-09-14

Między aktywnościami była przerwa.

Jeżeli użytkownik wykona dziś zadanie, rozpoczyna nową serię:

$streak = 1;

8. SAMODZIELNIE — przygotuj daty

Utwórz:

$dzisiaj = new DateTime('today');

$ostatniaAktywnosc =
    new DateTime($dataOstatniejAktywnosci);

$wczoraj = new DateTime('yesterday');

Mamy teraz trzy daty:

dzisiaj
wczoraj
ostatnia aktywność

Porównaj je.

HINT

Możesz porównać daty po sformatowaniu:

$ostatniaAktywnosc->format('Y-m-d')

oraz:

$dzisiaj->format('Y-m-d')

9. POMOC — układ warunków

Najpierw sprawdzamy, czy zadanie zostało wykonane.

if ($zadanieWykonane) {

    // tutaj sprawdzamy datę
}

Dlaczego?

Bo jeśli zadanie nie zostało wykonane:

$zadanieWykonane = false;

to nie powinniśmy zmieniać streaka.

Następnie sprawdzamy, czy ostatnia aktywność była dzisiaj:

if (
    $ostatniaAktywnosc->format('Y-m-d')
    ===
    $dzisiaj->format('Y-m-d')
) {
    // nic nie zmieniamy
}

Jeżeli nie, sprawdzamy wczoraj:

elseif (
    $ostatniaAktywnosc->format('Y-m-d')
    ===
    $wczoraj->format('Y-m-d')
) {
    $streak++;
}

Jeżeli nie było ani dzisiaj, ani wczoraj:

else {
    $streak = 1;
}

10. SAMODZIELNIE — napisz logikę streaka

Spróbuj teraz połączyć wszystko samodzielnie.

Masz:

$streak = 5;

$dataOstatniejAktywnosci = "2026-09-14";

$zadanieWykonane = true;

Utwórz:

$dzisiaj = new DateTime('today');
$wczoraj = new DateTime('yesterday');
$ostatniaAktywnosc =
    new DateTime($dataOstatniejAktywnosci);

Następnie napisz warunki.

11. ROZWIĄZANIE — logika streaka

if ($zadanieWykonane) {

    if (
        $ostatniaAktywnosc->format('Y-m-d')
        ===
        $dzisiaj->format('Y-m-d')
    ) {
        // nic nie zmieniamy

    } elseif (
        $ostatniaAktywnosc->format('Y-m-d')
        ===
        $wczoraj->format('Y-m-d')
    ) {
        $streak++;

    } else {
        $streak = 1;
    }
}

Na tym etapie nie tworzymy jeszcze funkcji.

Najpierw ważne jest, żeby zrozumieć samą logikę.

12. Przenosimy streak do funkcji

Kiedy logika działa, zamykamy ją w funkcji.

Utwórz:

function aktualizujStreak(
    int $streak,
    string $dataOstatniejAktywnosci,
    bool $zadanieWykonane
): int

Funkcja otrzymuje trzy informacje:

$streak
$dataOstatniejAktywnosci
$zadanieWykonane

i zwraca nową wartość streaka.

KROK 1

Jeżeli zadanie nie zostało wykonane:

if (!$zadanieWykonane) {
    return $streak;
}

Streak pozostaje bez zmian.

KROK 2

Utwórz daty wewnątrz funkcji:

$dzisiaj = new DateTime('today');
$wczoraj = new DateTime('yesterday');
$ostatniaAktywnosc =
    new DateTime($dataOstatniejAktywnosci);

KROK 3

Sprawdź, czy aktywność była dzisiaj.

Jeżeli tak:

return $streak;

KROK 4

Sprawdź, czy aktywność była wczoraj.

Jeżeli tak:

return $streak + 1;

KROK 5

Jeżeli aktywność była wcześniej:

return 1;

13. ROZWIĄZANIE — funkcja streaka

function aktualizujStreak(int $streak,string $dataOstatniejAktywnosci,bool $zadanieWykonane): int {
    if (!$zadanieWykonane)  return $streak;

    $dzisiaj = new DateTime('today');
    $wczoraj = new DateTime('yesterday');

    $ostatniaAktywnosc = new DateTime($dataOstatniejAktywnosci);

    if ($ostatniaAktywnosc->format('Y-m-d') === $dzisiaj->format('Y-m-d')) return $streak;

    if ($ostatniaAktywnosc->format('Y-m-d') === $wczoraj->format('Y-m-d')) return $streak + 1;

    return 1;
}

Zwróć uwagę:

nie ma już **$wykonalDzisiajZadanie**.

Mamy tylko:

$zadanieWykonane

14. Wywołanie funkcji

Przygotuj dane:

$streak = 5;

$dataOstatniejAktywnosci = "2026-09-14";

$zadanieWykonane = true;

Następnie:

$streak = aktualizujStreak(
    $streak,
    $dataOstatniejAktywnosci,
    $zadanieWykonane
);

Funkcja oblicza nowy streak i zapisujemy wynik ponownie do:

$streak

15. Ważne — co oznacza data ostatniej aktywności?

W tej lekcji:

$dataOstatniejAktywnosci

oznacza datę poprzedniej zapisanej aktywności, którą przekazujemy do funkcji.

Przykład:

$streak = 5;
$dataOstatniejAktywnosci = "2026-09-16";
$zadanieWykonane = true;

Jeżeli dzisiaj jest:

2026-09-17

wynik będzie:

6

Jeżeli:

$dataOstatniejAktywnosci = "2026-09-17";

wynik pozostanie:

5

bo aktywność z dzisiaj została już uwzględniona.

Jeżeli:

$dataOstatniejAktywnosci = "2026-09-14";

wynik będzie:

1

bo seria została przerwana.

16. Funkcja komunikatu terminu

Pozostawiamy funkcję z wcześniejszej części:

function komunikatTerminu(string $terminZadania): string{
    $dzisiaj = new DateTime('today');
    $termin = new DateTime($terminZadania);
    $roznica = $dzisiaj->diff($termin);
    // print_r($roznica);
    if ($termin < $dzisiaj) {
        return "Termin minął {$roznica->days} dni temu.!";
    } elseif ($termin == $dzisiaj) {
        return "Termin jest dzisiaj.";
    } else{
        return "Do terminu pozostało: {$roznica->days} dni.";
    }
}

17. ROZWIĄZANIE — wersja referencyjna

<?php

function komunikatTerminu(string $terminZadania): string
{
    $dzisiaj = new DateTime('today');
    $termin = new DateTime($terminZadania);

    $roznica = $dzisiaj->diff($termin);

    if ($termin < $dzisiaj) return "Termin minął {$roznica->days} dni temu.";

    if ($termin == $dzisiaj) return "Termin jest dzisiaj!";

    return "Do terminu pozostało: {$roznica->days} dni.";
}


function aktualizujStreak(int $streak,string $dataOstatniejAktywnosci,bool $zadanieWykonane): int {
    if (!$zadanieWykonane) return $streak;

    $dzisiaj = new DateTime('today');
    $wczoraj = new DateTime('yesterday');

    $ostatniaAktywnosc = new DateTime($dataOstatniejAktywnosci);

    if ($ostatniaAktywnosc->format('Y-m-d') === $dzisiaj->format('Y-m-d')) return $streak;
    
    if ($ostatniaAktywnosc->format('Y-m-d') === $wczoraj->format('Y-m-d')) return $streak + 1;

    return 1;
}


$tytulZadania = "Nauczyć się obsługi daty w PHP";

$terminZadania = "2026-09-20";

$zadanieWykonane = true;


$streak = 5;

$dataOstatniejAktywnosci = "2026-09-14";


$streak = aktualizujStreak($streak,$dataOstatniejAktywnosci,$zadanieWykonane);


echo "<h1>TaskQuest</h1>";

echo "<h2>$tytulZadania</h2>";

echo "<p>"
    . komunikatTerminu($terminZadania)
    . "</p>";

echo "<p>Streak: $streak dni</p>";

echo "<p>Stan: <strong>"
    . ($zadanieWykonane ? "Wykonane" : "W trakcie")
    . "</strong></p>";

18. Co usunęliśmy?

W całym kodzie nie ma już:

$wykonalDzisiajZadanie

Nie tworzymy tej zmiennej.

Nie przekazujemy jej do funkcji.

Nie sprawdzamy jej w if.

19. Co zostało?

Mamy jedną zmienną:

$zadanieWykonane

Ona określa stan zadania.

$zadanieWykonane = false;

oznacza:

zadanie niewykonane

a:

$zadanieWykonane = true;

oznacza:

zadanie wykonane

W tej lekcji true oznacza, że symulujemy wykonanie zadania dzisiaj.

Datę ostatniej wcześniejszej aktywności przechowujemy osobno:

$dataOstatniejAktywnosci

Dzięki temu każda zmienna ma jedno zadanie.

20. Testy streaka

Testuj tylko zmianę:

$dataOstatniejAktywnosci

oraz:

$zadanieWykonane

Test 1 — zadanie niewykonane

$streak = 5;
$dataOstatniejAktywnosci = "2026-09-16";
$zadanieWykonane = false;

Wynik:

Streak: 5

Test 2 — aktywność była dzisiaj

$streak = 5;
$dataOstatniejAktywnosci = "2026-09-17";
$zadanieWykonane = true;

Wynik:

Streak: 5

Test 3 — aktywność była wczoraj

$streak = 5;
$dataOstatniejAktywnosci = "2026-09-16";
$zadanieWykonane = true;

Wynik:

Streak: 6

Test 4 — aktywność była 5 dni temu

$streak = 5;
$dataOstatniejAktywnosci = "2026-09-12";
$zadanieWykonane = true;

Wynik:

Streak: 1

21. Testy terminów

Przetestuj:

wczoraj
dzisiaj
jutro
za 10 dni

Zmieniając:

$terminZadania

Sprawdź, czy komunikat jest prawidłowy.

22. Mini-eksperyment

Sprawdź różnicę między:

new DateTime('now')

i:

new DateTime('today')

Wyświetl oba obiekty przez:

format('Y-m-d H:i:s')

Zwróć uwagę na godzinę.

23. Ważna uwaga dotycząca prawdziwego TaskQuest

Na razie dane są zapisane ręcznie w kodzie:

$streak = 5;
$dataOstatniejAktywnosci = "2026-09-14";

Dlatego jest to symulacja działania streaka.

W prawdziwej aplikacji po wykonaniu zadania trzeba będzie zapisać nową datę aktywności, np.:

dzisiaj → 2026-09-17

i przy kolejnym wejściu na stronę odczytać ją ponownie.

Do tego wykorzystamy później bazę danych.

Na tej lekcji skupiamy się na tym, jak PHP rozpoznaje:

dzisiaj
wczoraj
wcześniej

na podstawie dat.

Do samodzielnego sprawdzenia

  • Potrafię utworzyć obiekt DateTime.
  • Potrafię sformatować datę.
  • Potrafię porównać dwie daty.
  • Użyłem diff().
  • Zadanie informuje o terminie.
  • Streak reaguje na datę ostatniej aktywności.
  • Używam jednej zmiennej $zadanieWykonane.
  • Nie używam $wykonalDzisiajZadanie.
  • Rozumiem, kiedy streak się zwiększa.
  • Rozumiem, kiedy streak pozostaje bez zmian.
  • Rozumiem, kiedy streak zostaje ustawiony na 1.
  • Nadal nie używam tablic.

Pytania kontrolne

  1. Czym różni się data zapisana jako string od obiektu DateTime?
  2. Do czego służy format()?
  3. Co zwraca diff()?
  4. Co powinno stać się ze streakiem po trzydniowej przerwie?
  5. Dlaczego nie możemy zwiększać streaka za każdym odświeżeniem strony?
  6. Dlaczego użyliśmy today, a nie zawsze now?
  7. Do czego służy $zadanieWykonane?
  8. Do czego służy $dataOstatniejAktywnosci?
  9. Dlaczego nie potrzebujemy osobnej zmiennej $wykonalDzisiajZadanie?
  10. Co stanie się ze streakiem, jeżeli zadanie nie zostało wykonane?
  11. Co stanie się ze streakiem, jeżeli ostatnia aktywność była wczoraj?
  12. Co stanie się ze streakiem, jeżeli ostatnia aktywność była dzisiaj?
  13. Co stanie się ze streakiem, jeżeli ostatnia aktywność była 5 dni temu?

PODSUMOWANIE LEKCJI

W skrócie

  • Timestamp to jedna liczba całkowita: sekundy od 1 stycznia 1970, 00:00:00 GMT. time() zwraca timestamp „teraz”. Na timestampach można wykonywać zwykłe działania arytmetyczne (np. time() + 3600 = za godzinę).
  • date() nie liczy, tylko formatuje. Zamienia timestamp na tekst według podanego wzoru. Bez drugiego argumentu formatuje aktualny czas.
  • Litery formatu rozróżniają wielkość znaków. m to miesiąc, i to minuty. H to godzina 0–23, h to 1–12. Y to rok 4-cyfrowy, y 2-cyfrowy. d ma zero wiodące, j nie ma. l (małe L) to nazwa dnia, L to informacja o roku przestępnym.
  • mktime() ma nietypową kolejność argumentów: godzina, minuta, sekunda, miesiąc, dzień, rok. Błędne wartości nie powodują błędu – PHP je „przelicza” (miesiąc 13 = styczeń następnego roku), więc pomyłka w kolejności daje po cichu inną datę.
  • strtotime() rozumie tekst po angielsku ("+1 day", "next Monday", "2026-09-20") i zwraca timestamp. Drugi argument to punkt odniesienia.
  • Obiekt DateTime to nie tekst. Nie wyświetlisz go przez echo $data – zawsze używasz ->format('...'). Litery formatu są takie same jak w date().
  • DateTime zmienia sam siebie (modify(), add(), sub()), a DateTimeImmutable zostawia oryginał i zwraca nowy obiekt.
  • diff() zwraca obiekt DateInterval. ->days to całkowita liczba dni między datami. ->y, ->m, ->d to składowe (lata, miesiące, dni) – ->d to nie jest liczba wszystkich dni.
  • ->days jest zawsze dodatnie. Kierunek różnicy mówi ->invert albo zwykłe porównanie dat < / >. Dlatego w TaskQuest osobno sprawdzamy, czy termin minął.
  • Obiekty DateTime porównuje się operatorami <, >, == – porównywana jest data razem z godziną.
  • 'now' ma aktualną godzinę, 'today' ma godzinę 00:00:00. Jeśli porównujesz tylko dni, używaj 'today' albo porównuj teksty format('Y-m-d').
  • DateInterval: zaczyna się od P, część czasowa po T. M przed T to miesiące, po T – minuty.
  • Streak w TaskQuest zależy od daty ostatniej aktywności: dzisiaj → bez zmian, wczoraj → +1, wcześniej → 1. Gdy zadanie nie jest wykonane, streak się nie zmienia.

Co trzeba umieć na INF.03?

  • uczeń powinien umieć wyświetlić aktualną datę i godzinę w wymaganym formacie, np. 17.09.2026 16:50,
  • dobrać litery formatu na podstawie opisu (np. z dokumentacji lub tabeli) i rozpoznać pomyłkę typu m zamiast i,
  • odczytać działanie nieznanej funkcji wbudowanej z jej opisu (kolejność argumentów, typ zwracanej wartości) – na egzaminie funkcje PHP są podawane w tabeli,
  • przetestować skrypt dla kilku wartości wejściowych i sprawdzić wynik.

Minimum, które powinno wejść w pamięć

  1. date("d.m.Y H:i:s") – aktualna data i godzina. m = miesiąc, i = minuty.
  2. time() – teraz w sekundach. time() + 24*60*60 – ta sama godzina jutro.
  3. mktime(godz, min, sek, MIESIĄC, DZIEŃ, rok) – najpierw miesiąc, potem dzień.
  4. new DateTime('2026-09-20') tworzy datę, ->format('d.m.Y') ją wyświetla. echo $obiekt nie działa.
  5. $a->diff($b)->days – ile dni między datami (zawsze liczba dodatnia).
  6. $termin < $dzisiaj – porównanie dat obiektów DateTime.
  7. 'today' = dzisiaj o północy, 'now' = teraz z godziną.
  8. DateTime modyfikuje oryginał, DateTimeImmutable zwraca nowy obiekt.

Ściągawka – najważniejsze polecenia i składnia

Funkcje proceduralne

FunkcjaCo robiPrzykład
time()aktualny timestamptime() + 3600
date(format, [timestamp])timestamp → tekstdate("Y-m-d")
mktime(h, i, s, m, d, Y)konkretna data → timestampmktime(0, 0, 0, 7, 15, 2000)
strtotime(tekst, [baza])tekst ang. → timestampstrtotime("+7 days")
getdate([timestamp])tablica z częściami datygetdate()['year']
microtime(true)timestamp z ułamkiem sekundypomiar czasu wykonania

Najczęstsze litery formatu

LiteraZnaczeniePrzykład
d / jdzień z zerem / bez zera05 / 5
m / nmiesiąc z zerem / bez zera09 / 9
Y / yrok 4 / 2 cyfry2026 / 26
H / Ggodzina 24h z zerem / bez zera08 / 8
iminuty07
ssekundy09
lnazwa dnia (ang.)Thursday
Ndzień tygodnia 1 (pn) – 7 (nd)4
tliczba dni w miesiącu30
Lrok przestępny (1/0)0

Obiektowo – DateTime

$d = new DateTime('today');            // dziś 00:00
$d = new DateTime('2026-09-20');       // konkretna data
echo $d->format('d.m.Y');              // wyświetlenie

$d->modify('+1 day');                  // zmiana (składnia jak w strtotime)
$d->add(new DateInterval('P1M'));      // +1 miesiąc
$d->sub(new DateInterval('PT2H'));     // -2 godziny

$r = $a->diff($b);                     // różnica
$r->days;                              // wszystkie dni
$r->invert;                            // 1, gdy $b jest wcześniej niż $a

if ($a < $b) { }                       // porównanie
if ($a->format('Y-m-d') === $b->format('Y-m-d')) { }   // ten sam dzień

DateInterval

P1D     1 dzień          PT1H    1 godzina
P2W     2 tygodnie       PT30M   30 minut
P3M     3 miesiące       PT45S   45 sekund
P1Y     1 rok            P1DT12H 1 dzień i 12 godzin

Schemat z TaskQuest – czy termin minął

$dzisiaj = new DateTime('today');
$termin  = new DateTime($terminZadania);
$roznica = $dzisiaj->diff($termin);

if ($termin < $dzisiaj)       // termin minął $roznica->days dni temu
elseif ($termin == $dzisiaj)  // termin jest dzisiaj
else                          // zostało $roznica->days dni

Quiz – sprawdź się

1. Co oznacza liczba 0 jako uniksowy znacznik czasu? Co zwraca time()?

2. Co zostanie wyświetlone?

echo date("j.n.y G:i", mktime(14, 7, 9, 3, 5, 2026));

3. Uczeń chciał wyświetlić godzinę w formacie 16:05. Znajdź błąd.

echo date("H:m");

4. Uczeń chciał zapisać datę 15 lipca 2000 r. Jaką datę faktycznie otrzyma? Dlaczego PHP nie zgłosi błędu?

$urodziny = mktime(0, 0, 0, 15, 7, 2000);
echo date("Y-m-d", $urodziny);

5. Co zostanie wyświetlone?

$sylwester = mktime(0, 0, 0, 12, 31, 2025);
echo date("Y-m-d", strtotime("+1 day", $sylwester));

6. Dlaczego ten kod kończy się błędem? Popraw go.

$data = new DateTime('2026-09-17');
echo $data;

7. Co zostanie wyświetlone w wersji A, a co w wersji B?

// Wersja A
$a = new DateTime('2026-09-17');

// Wersja B
$a = new DateTimeImmutable('2026-09-17');

$b = $a->modify('+1 day');
echo $a->format('d.m') . ' ' . $b->format('d.m');

8. Co zostanie wyświetlone?

$od = new DateTime('2026-01-01');
$do = new DateTime('2026-03-15');
$r = $od->diff($do);

echo $r->days . ' / ' . $r->m . ' / ' . $r->d;

9. Co zostanie wyświetlone? Co z tego wynika dla funkcji komunikatTerminu()?

$r = (new DateTime('2026-09-20'))->diff(new DateTime('2026-09-17'));
echo $r->days . ' ' . $r->invert;

10. Który zapis oznacza „2 godziny i 30 minut”?

  • a) 'P2H30M'
  • b) 'PT2H30M'
  • c) 'P2HT30M'
  • d) 'PT2H30'

11. O ile przesunie datę add(new DateInterval('P3M')), a o ile add(new DateInterval('PT3M'))?

12. Co zostanie wyświetlone?

$a = new DateTime('2026-09-17 08:00');
$b = new DateTime('2026-09-17 20:30');

var_dump($a == $b);
var_dump($a->format('Y-m-d') === $b->format('Y-m-d'));

13. W funkcji komunikatTerminu() ktoś zamienił 'today' na 'now'. Termin zadania to dzisiejsza data. Jaki komunikat się wyświetli i dlaczego?

$dzisiaj = new DateTime('now');
$termin = new DateTime($terminZadania);   // dzisiejsza data
$roznica = $dzisiaj->diff($termin);

if ($termin < $dzisiaj) return "Termin minął {$roznica->days} dni temu.";
if ($termin == $dzisiaj) return "Termin jest dzisiaj!";
return "Do terminu pozostało: {$roznica->days} dni.";

14. TaskQuest. Załóż, że dzisiaj jest 2026-09-17. Co zwróci aktualizujStreak() w każdym przypadku?

 $streak$dataOstatniejAktywnosci$zadanieWykonane
a)3"2026-09-16"true
b)3"2026-09-17"true
c)3"2026-09-10"false
d)3"2026-09-10"true

15. Uzupełnij kod tak, aby wyświetlił angielską nazwę dnia tygodnia, w którym wypada 1 maja 2026 r.

echo date("___", mktime(0, 0, 0, ___, ___, 2026));

16. Zadanie praktyczne. Napisz funkcję czyPoTerminie(string $terminZadania): bool, która zwraca true, jeżeli termin był przed dzisiejszym dniem, a false w pozostałych przypadkach (także gdy termin jest dzisiaj). Użyj DateTime. Przetestuj ją dla daty wczorajszej, dzisiejszej i jutrzejszej.


Odpowiedzi
  1. 0 to 1 stycznia 1970, 00:00:00 GMT (początek ery Uniksa). time() zwraca liczbę sekund, które upłynęły od tego momentu do teraz.
  2. 5.3.26 14:07 – j i n bez zer wiodących, y dwucyfrowo, G godzina bez zera, i minuty.
  3. m oznacza miesiąc, a nie minuty. Wyświetli się np. 16:09 (wrzesień). Poprawnie: date("H:i").
  4. 2001-03-07. Argumenty mktime() to godzina, minuta, sekunda, miesiąc, dzień, rok – uczeń zamienił miesiąc z dniem. PHP traktuje „miesiąc 15” jako marzec kolejnego roku i przelicza datę zamiast zgłaszać błąd. Poprawnie: mktime(0, 0, 0, 7, 15, 2000).
  5. 2026-01-01. strtotime() liczy „+1 dzień” względem 31 grudnia 2025 i przechodzi na nowy rok.
  6. Obiektu DateTime nie można zamienić na tekst (Error: Object of class DateTime could not be converted to string). Poprawnie: echo $data->format('Y-m-d');.
  7. Wersja A: 18.09 18.09 – modify() zmienia oryginalny obiekt, a $b wskazuje ten sam obiekt. Wersja B: 17.09 18.09 – DateTimeImmutable zostawia oryginał bez zmian i zwraca nowy obiekt.
  8. 73 / 2 / 14. days to wszystkie dni (31 + 28 + 14), a m i d to składowe: 2 miesiące i 14 dni.
  9. 3 1. days jest zawsze dodatnie, a invert = 1 oznacza, że druga data jest wcześniejsza. Dlatego w komunikatTerminu() sama liczba dni nie wystarczy – trzeba osobno porównać $termin < $dzisiaj, żeby wiedzieć, czy termin minął.
  10. b) 'PT2H30M'. Godziny i minuty muszą stać po T. Zapis a) powoduje błąd (wyjątek) przy tworzeniu DateInterval.
  11. P3M – o 3 miesiące (np. z 2026-09-17 na 2026-12-17). PT3M – o 3 minuty (z 00:00 na 00:03). M przed T to miesiące, po T – minuty.
  12. bool(false) i bool(true). == porównuje datę razem z godziną, a porównanie tekstów Y-m-d sprawdza tylko dzień.
  13. Termin minął 0 dni temu. new DateTime($terminZadania) ma godzinę 00:00, a 'now' – aktualną godzinę. Termin jest więc „wcześniej” niż teraz, a warunek == nigdy nie będzie spełniony. Dlatego w TaskQuest używamy 'today'.
  14. a) 4 – ostatnia aktywność wczoraj, seria trwa. b) 3 – aktywność z dzisiaj już była uwzględniona. c) 3 – zadanie niewykonane, streak bez zmian. d) 1 – była przerwa, zaczyna się nowa seria.
  15. echo date("l", mktime(0, 0, 0, 5, 1, 2026)); – wyświetli Friday.
  16. Przykładowe rozwiązanie:
function czyPoTerminie(string $terminZadania): bool {
    $dzisiaj = new DateTime('today');
    $termin = new DateTime($terminZadania);

    return $termin < $dzisiaj;
}

Oczekiwane wyniki: wczoraj → true, dzisiaj → false, jutro → false. Typowy błąd: użycie 'now' zamiast 'today' – wtedy dzisiejsza data da true.