Spis treści
PHP posiada wiele funkcji, dzięki którym można przetwarzać zapis daty.
Podstawowym sposobem zapisu daty w systemie Unix i pochodnych jest tzw. timestamp. Jest to ilość sekund jaka upÅ‚ynęła od 1.1.1970 (moment ten nazywany jest Epoch). Zapis taki daje najwiÄ™cej możliwoÅ›ci – Å‚atwo go przetwarzać na inne zapisy, dodawać, odjemować odpowiednie przedziaÅ‚y czasu i zapisywać w bazach danych.
JednÄ… z podstawowych spraw przy odbieraniu danych od użytkownika to sprawdzenie ich poprawnoÅ›ci. Funkcja checkdate() przyjmuje 3 argumenty – odpowiedno miesiÄ…c, dzieÅ„ i rok (kolejność może siÄ™ wydawać nielogiczna, lecz w takiej kolejnoÅ›ci Amerykanie zapisujÄ™ datÄ™), których poprawność ma być sprawdzony. Funkcja zwraca logicznÄ… wartość TRUE jeÅ›li data jest poprawna.
Funkcja ta sprawdza, czy rok ma wartoÅ›ci pomiÄ™dzy 1 a 32767, miesiÄ…c miÄ™dzy 1 a 12 a dzieÅ„ od jeden do liczby zależnej od danego miesiÄ…ca. UwzglÄ™dniane sÄ… lata przestÄ™pne. W poniższym przykÅ‚adzie sprawdzane sÄ… dane przekazane metodÄ… GET. Dla wywoÅ‚ania test.php?dzien=12&miesiac=10&rok=1992 skrypt wyÅ›wietli „Data jest poprawna” a dla test.php?dzien=2&miesiac=14&rok=1980 – „Data jest niepoprawna”.
AktualnÄ… datÄ™ można uzyskać tylko w formacie timestamp. DatÄ™ takÄ… zwraca funkcja time(). DokÅ‚adniejszy czas można uzyskać dziÄ™ki funkcji microtime() – dane zwracane przez tÄ… funkcjÄ™ zapisane sÄ… nieco dziwnie, ponieważ zwracany jest string zawierajÄ…cy oddzielone spacjÄ… odpowiednio część mikrosekundowÄ… i sekundowÄ…, czyli „msec sec”.
Przykład 12.2. Funkcja zwracająca czas z mikrosekundami
<?php function getmicrotime() { list($usec, $sec) = explode(" ",microtime()); return ((float)$usec + (float)$sec); } ?>
Informacja ta może zostać użyta do sprawdzenia czasu wykonania danego skryptu.
Przykład 12.3. Liczenie czasu generowania strony
<?php $start = getmicrotime(); for ($i = 0; $i < 10000; $i++) { $str = 'test'; } $end = getmicrotime(); echo '<!-- strona wygenerowana w '.($end - $start).' sekund -->'; ?>
W ten sposób można też sprawdzać wydajność różnych rozwiązań. Skrypty wykonywane są zazwyczaj tak szybko, że mikrosekundy to za duża jednostka. Ograniczenie to można obejść przez wykonywanie konkretnych instrukcji w pętli, 100 czy nawet 1000 razy, podobnie jak w powyższym przykładzie.
Funkcję konwertujące datę do podanego formatu jako parametr przyjmują timestamp daty do przekonwertowania. Parametr ten można jednak pominąć i zamiast określonej daty użyta zostanie aktualna data i czas. Pozwala to na uzyskanie aktualnego czasu w formacie innym niż timestamp.
Timestamp inny niż aktualny można uzyskać na różne sposoby, które trzeba wykorzystać odpowiednio do zastosowania.
JeÅ›li dostÄ™pna jest 'rozbita’ data, czyli w osobnych zmiennych dzieÅ„, miesiÄ…c, rok itp., lub można do takiej sytuacji doprowadzić przez odpowiednie użycie funkcji explode() lub substr(), można użyć funkcji mktime(). Funkcja ta jako argumenty przyjmuje odpowiednio godzinÄ™, minutÄ™, sekundÄ™, miesiÄ…c, dzieÅ„, rok i opcjonalnie informacjÄ™ o „daylight saving”, czyli czasie letnim (wartość 1 oznacza czas letni, 0 w przeciwnym przypadku, lub -1, wartość domyÅ›lnÄ…, jeÅ›li PHP ma samo zgadywać).
Przykład 12.4. Generowanie timestampu
<?php $dzien = 10; $miesiac = 4; $rok = 2002; $godzina = 12; $minuta = 32; $sekunda = 0; $ts = mktime($godzina, $minuta, $sekunda, $miesiac, $dzien, $rok); ?>
Jeśli data jest zapisana jako string, lecz w jednym z formatów rozpoznawanych przez PHP, string ten można przekonwertować do timestamp używając funkcji strtotime(). Data składa się z kilku elementów, oddzielonych „białymi znakami†(spacja, znak tabulacji). Białe znaki można pominąć, jeśli nie powoduje to żadnych wieloznaczności. Elementy daty to część kalendarzowa, część zegarowa, strefa czasowa, część wyłącznie liczbowa. Kolejność tych elementów nie ma znaczenia. Dwa inne elementy, dzień tygodnia i przesunięcie czasowe, zostaną opisane w dalszej części rozdziału.
Część ta określa konkretny dzień roku. Może być podana na jeden z wielu sposobów.
1970-09-17 # Zapis zgodny z ISO 8601. 70-9-17 # Domyślnie przyjmuje się bieżący wiek 70-09-17 # Wszystkie początkowe zera są ignorowane 9/17/72 24 September 1972 24 Sept 72 # Specjalny skrót słowa September 24 Sep 72 # Wszędzie dopuszczalne są trzyliterowe skróty Sep 24, 1972 24-sep-72 24sep72
Dopuszczalne sÄ… angielskie nazwy miesiÄ™cy: `January’, `February’, `March’, `April’, `May’, `June’, `July’, `August’, `September’, `October’, `November’ `December’ oraz ich trzyliterowe skróty.
Dopuszczalne formaty:
<pre> 20:02:0 20:02 8:02pm 20:02-0500 # z podaniem strefy czasowej
MówiÄ…c ogólnie, podstawowy format to gg:mm:ss, przy czym część sekundowÄ… można pominąć. JeÅ›li na koÅ„cu dodany zostanie wskażnik am (rano – inna forma to a.m.) lub pm (po poÅ‚udniu – p.m.), to część godzinowa ograniczona jest do zakresu 1-12. W takim zapisie północ to 12am, poÅ‚udnie – 12pm; część minutowa może być pominÄ™ta.
Opcjonalnie, od razu po czasie może zostać podana strefa czasowa w formacie „zggmm”, gdzie „z” to odpowiedni znak + lub -, zależnie od strefy, gg to ilość godzin a mm ilość minut przesuniÄ™cia.
Strefa czasowa może zostać okreÅ›lona tak samo jak w przypadku informacji „doklejonej” do części zegarowej.
Liczby w postaci rrrrmmdd, jeśli wcześniej nie było części kalendarzowej, traktowane są jako te części. Podobnie liczby w postaci ggmm jest traktowana jako część zegarowa, jeśli nie było takiej wcześniej.
Dokładny opis formatów rozpoznawanych przez funkcję strtotime() można znaleźć pod adresem http://www.gnu.org/software/tar/manual/html_chapter/tar_7.html
PHP udostÄ™pnia kilka funkcji sÅ‚użących do zapisywania daty w preferowanym formacie. Podstawowa to date. Pierwszym jej argumentem jest ciÄ…g tekstowy, który sÅ‚uży jako opis formatu. Każda litera wstawiona do tego ciÄ…gu zostanie zamieniona na pewien element daty. Na przykÅ‚ad litera 'Y’ zostanie zamieniona na rok w postaci czterocyfrowej. PeÅ‚nÄ… listÄ™ elementów formatu można znaleźć w opisie funkcji date().
Przykład 12.5. Przykład użycia funkcji date
<?php // Zakładając, że dzisiaj jest 7 luty 2005, 22:31:44 $today = date("F j, Y, g:i a"); // February 7, 2005, 22:31 pm $today = date("m.d.y"); // 07.02.05 $today = date("j, n, Y"); // 7, 2, 2005 $today = date("Ymd"); // 20050207 $today = date('h-i-s, j-m-y, it is w Day z '); // 22-31-44, 7-02-05, 3128 3144 1 Monpm05 37 $today = date('\i\t \i\s \t\h\e jS \d\a\y.'); // It is the 7th day. $today = date("D M j G:i:s T Y"); // Mon Feb 7 22:31:44 CET 2005 $today = date('H:m:s \m \t\o\ \m\i\e\s\i\a\c'); // 22:02:44 m to miesiac $today = date("H:i:s"); // 22:02:44 ?>
Jak widać, większość liter ma swoje znaczenie, więc nie ma możliwości wstawienia zwykłego tekstu, oprócz zamieniania ich na sekwencje escape.
DomyÅ›lnie wyÅ›wietlana jest odpowiednio sformatowana data i czas bieżący. Można to zmienić podajÄ…c opcjonalny, drugi parametr – czas w formacie timestamp. Wtedy format bÄ™dzie dotyczyÅ‚ wÅ‚aÅ›nie tego czasu.
Funkcja date wszelkie „tekstowe” wartoÅ›ci zwraca w jÄ™zyku angielskim. Istnieje jednak inna funkcja, strftime, która, podobnie jak funkcja date, sÅ‚uży do formatowania daty, jednak różni siÄ™ trochÄ™ zachowaniem. Po pierwsze, elementy formatu (inne niż w funkcji date) sÄ… nie pojedyÅ„czymi literami, ale zawsze poprzedzone sÄ… znakiem procenta, przez co można wstawiać do formatu zwykÅ‚y tekst. Druga ważna różnica to uwzglÄ™dnianie ustwieÅ„ regionalnych systemu locale. Wystarczy ustawić odpowiednie locale (dla jÄ™zyka polskiego – pl_PL i strftime zacznie mówić po naszemu).
W PHP niejako standardowym sposobem przechowywania informacji o dacie jest wspomniany wcześniej format timestamp. Modyfikacje takiego zapisu przeprowadza się przez dodanie lub odjęcie odpowiedniej liczby sekund. Na przykład, aby stworzyć datę o godzinę w przód od aktualnej, wystarczy dodać do niej 3600 sekund, czyli tyle, ile jest w sekund w godzinie.
Przykład 12.7. Tworzenie daty o godzinę w przód
<?php $czas_akt = time(); $za_godz = $czas_akt + 3600; echo date("r", $za_godz); // Wyświetli datę 'za godzinę' ?>
Podobnie sprawa wyglÄ…da z dodawaniem dni czy tygodni. Gorzej jest w przypadku miesiÄ™cy – przecież nie wiadomo z góry ile sekund ma miesiÄ…c. Problem ten można rozwiÄ…zać na kilka sposobów. Można rozbić datÄ™ na poszczególne części (dzieÅ„, miesiÄ…c, rok), dodać jedynkÄ™ do miesiÄ…ca, sprawdzić, czy przypadkiem nie wyszedÅ‚ nam miesiÄ…c trzynasty (co siÄ™ stanie jeÅ›li dodamy miesiÄ…c do grudnia) i w takim przypadku odpowiednio zareagować.
PrzykÅ‚ad 12.8. Data „za miesiÄ…c”
<?php $day = date('d'); // dzień $month = date('m'); // miesiąc $year = date('Y'); // rok // dodanie jedynki do miesiąca $month++; // sprawdzenie czy licznik się nie przekręcił if ($month == 13) { $month = 1; $year++; } ?>
Jest jednak prostrza metoda tworzenia daty względnej. Można do tego użyć funkcji strtotime(). Jako jej argument można podać względny czas.
Przykład 12.9. Tworzenie względnej daty za pomocą funkcji strtotime
<?php echo strtotime("now"), "\n"; // teraz echo strtotime("+1 day"), "\n"; // jutro echo strtotime("+1 week"), "\n"; // za tydzień echo strtotime("+1 week 2 days 4 hours 2 seconds"), "\n"; // za tydzień, dwa dni, // 4 godziny i 2 sekundy echo strtotime("next Thursday"), "\n"; // następny czwartek echo strtotime("last Monday"), "\n"; // poprzedni poniedziałek ?>
Daty mogÄ… być porównywane tylko i wyÅ‚Ä…cznie jeÅ›li sÄ… przechowywane w tym samym formacie. Jako że w PHP nie ma zmiennej typu „data”, musi być ona przechowywana jako timestamp lub tekst. Z kolei postać tekstowa może być skrajnie różna zależnie od standardów narodowych czy też fantazji programisty – tu widać przewagÄ™ formatu timestamp.
JeÅ›li daty sÄ… już w tej samej postaci, można je porównać po prostu przez operator porównania. Dodatkowo, jeÅ›li data jest w formacie timestamp, można użyć operatorów matematycznych (< czy >) dla ustalenia która data jest „nowsza”.
Przykład 12.10. Porównywanie daty w formacie timestamp
<?php $time1 = mktime(19, 30, 0); $time2 = mktime(20, 0, 0); if ($time1 > $time2) { echo "Czas w zmiennej time1 jest późniejszy"; } else { echo "Czas w zmiennej time2 jest późniejszy"; } ?>
Porównywanie dat w formacie timestamp jest Å‚atwe, jeÅ›li potrzebne jest porównanie z dokÅ‚adnoÅ›ciÄ… „co do sekundy”. Sprawa siÄ™ komplikuje, jeÅ›li potrzebne jest stwierdzenie, na przykÅ‚ad czy dwie daty sÄ… z tego samego dnia. Aby to stwierdzić, trzeba rozbić datÄ™ i porównywać skÅ‚adowe. Kod taki można przenieść do osobnej funkcji, aby wygodnie porównywać daty.
Przykład 12.11. Sprawdzanie czy daty są z tego samego dnia
<?php function sameDay($ts1, $ts2) { if (date("Y", $ts1) != date("Y", $ts2)) { return False; } if (date("m", $ts1) != date("m", $ts2)) { return False; } if (date("d", $ts1) != date("d", $ts2)) { return False; } return True; } $date1 = mktime(19, 30, 0, 12, 10, 2001); $date2 = mktime(10, 12, 0, 12, 10, 2001); $date3 = mktime(19, 30, 0, 12, 11, 2001); if (sameDay($date1, $date2)) { echo "Daty 1 i 2 sÄ… z tego samego dnia"; } if (sameDay($date1, $date3)) { echo "Daty 1 i 3 sÄ… z tego samego dnia"; } ?>