Obsługa daty i czasu w PHP
05.04.2012 02:19
Każdy programista PHP zapewne zna funkcje date(), time() itp. Każdy kto ich używał wie też, że często ich użycie jest niewygodne i osiągniecie niektórych rzeczy jest trudne (np. policzenie różnicy w dniach miedzy określonymi datami). Dzisiaj chciałbym Wam przybliżyć wprowadzoną w PHP 5.2 klasę DateTime, która moim zdaniem upraszcza zadanie związane z obsługą czasu.
Konstruktor
Konstruktor klasy DateTime wygląda następująco:
public DateTime::__construct() ([string $time="now" [,DateTimeZone $timezone=NULL]])
Pierwszy argument to łańcuch tekstowy przedstawiający datę, która będzie użyta jako podstawa operacji. Jeśli nie podamy tego argumentu zostaną użyte bieżąca data i czas. Czas możemy podawać w wielu różnych formatach np: "2012-04-12 14:45:21" albo "04/12/12". Możemy tez użyć słów np: "now" lub "tomorrow 14:25". To oczywiście nie wszystkie możliwości, a jedynie przykłady. Wszystkie możliwe formaty opisane są tutaj: PHP: Supported Date and Time Formats - Manual Drugi argument to obiekt DateTimeZone, który ustawia strefę czasową (The DateTimeZone class ), jesli go pominiemy zostanie użyta strefa ustawiona w konfiguracji PHP.
Pierwsze użycie
OK, ale przejdźmy do użycia. Kiedy stworzymy nowy obiekt, wówczas możemy wyświetlić przechowywany przez niego czas za pomocą metody format():
string DateTime::format ( string $format )
Jako argument metoda przyjmuje tekst opisujący w jaki sposób ma być sformatowany zwracany czas. Akceptowane są formaty takie same jak w przypadku funkcji date(). Przykład:
$date = new DateTime('2012-04-12 14:45'); echo $date->format("d-m-Y H:i"); echo " "; echo $date->format("Y/m/d h:i A"); echo " "; echo $date->format('U');
Otrzymamy wydruk:
12-04-2012 14:45 2012/04/12 02:45 PM 1334234700
W ostatnim wierszu mamy znacznik czasu Uniksa, czyli liczbę sekund jaka upłynęła od 1 stycznia 1970 roku. Możemy go też pobrać w inny sposób:
echo $date->getTimestamp();
Otrzymamy to samo:
1334234700
Modyfikacja daty i czasu
Spróbujmy teraz zmodyfikować podany czas przez dodanie lub odjęcie określonego czasu. Jest do tego dedykowana metoda, która za nas dba by nie było pomyłki przy liczeniu dni miesiąca, dni przestępnych w lutym itd.:modify () Jak argument podajmy wartość do dodania lub odjęcia w formatach akceptowanych przez konstruktor w pierwszym argumencie (patrz wyżej).
$date->modify('+1 month'); echo $date->format('Y-m-d H:i')." "; $date->modify('-15 days'); echo $date->format("Y-m-d H:i")." "; $date->modify('+1 year +3 month -1 day +3 hours -5 minute'); echo $date->format("Y-m-d H:i");
Naturalnie operacje wykonywane na czasie są przechowywane w obiekcie, więc każda kolejna odnosi się do daty otrzymanej po poprzedniej modyfikacji:
2012-05-12 14:45 2012-04-27 14:45 2013-07-26 17:40
Do dodawania czasu możemy tez użyć metody add(), a do odejmowania metody sub(). Obie jako argument przyjmują obiekt klasy DateInterval():
DateInterval::__construct() ( string $interval_spec )
Argument konstruktora to ciąg tekstowy odpowiednio sformatowany w którym po literze P podajemy ilość lat(Y), miesięcy(M) i dni(D) do przesunięcia, a po literze T ilość czasu w godzinach(H), minutach(M) i sekundach(S). Przykładowo, żeby przesunąć datę o 2 lata, 3 miesiące, 10 dni, 5 godzin, 20minut i 30 sekund tworzymy kod:
$date = new DateTime('2012-04-12 14:45:00'); $interval = new DateInterval('P2Y3M10DT5H20M30S'); $date->add($interval); echo $date->format('Y-m-d H:i:s');
W wyniku otrzymujemy:
2014-07-22 20:05:30
Możemy jeszcze odjąć trochę czasu:
$interval = new DateInterval('P1Y2MT2H15S'); $date->sub($interval); echo $date->format('Y-m-d H:i:s');
Wynik:
2013-05-22 18:05:15
Porównywanie dat
Od wersji PHP 5.2.2 można porównywać ze sobą dwa obiekty DateTime za pomocą zwykłych operatorów porównań:
$date = new DateTime('2012-04-12 14:45:00'); $date2 = new DateTime('2006-12-12 15:00'); var_dump($date == $date2); var_dump($date < $date2); var_dump($date > $date2);
Wynik działania takich porównań:
bool(false) bool(false) bool(true)
Obliczanie różnicy między datami
Do obliczania różnicy między tatami służy metoda:
DateInterval DateTime::diff ( DateTime $datetime2 [, bool $absolute = false ] )
Jako pierwszy argument podajemy obiekt DateTime, od którego różnicę liczymy. Drugi argument ustala czy zwrócony wynik ma być podany jako wartość bezwzględna. Metoda zwraca obiekt klasy DateInterval, który przechowuje informacje o różnicy w latach, dniach, miesiącach itd.
Przykładowy kod:
$date = new DateTime('2012-04-20 14:45:00'); $date2 = new DateTime('2011-12-12 15:00'); $diff=$date->diff($date2); echo "<pre>"; var_dump($diff); echo "</pre>";
Wygeneruje taki wydruk:
object(DateInterval)#3 (8) { ["y"]=> int(0) ["m"]=> int(4) ["d"]=> int(7) ["h"]=> int(23) ["i"]=> int(45) ["s"]=> int(0) ["invert"]=> int(1) ["days"]=> int(129) }
Kolejne pola oznaczają, że różnica wynosi 0 lat, 4 miesiące i 7 dni oraz 23 godziny, 45 minut i 0 sekund. Pole invert informuje nas o tym, czy różnica jest ujemna (1) czy dodatni (0) - jeśli przy porównaniu ustawimy wyświetlanie absolutnych wartości, to wartość invert zawsze będzie wynosić 0. Ostatnie pole to całkowita ilość dni między datami
Uwaga
W Windowsie (chyba w wersjach PHP 5.3.x - ale tego pewny nie jestem) jest błąd, który powoduje, że niezależnie od prawdziwego wyniku zwracana ilość dni zawsze wynosi 6015
Klasa DateInterval również ma metodę format, dzięki której możemy wyświetlić różnicę w ładniejszy sposób. Jako argument przyjmuje ciąg tekstowy określając format wyświetlania różnicy. Akceptowane formaty: DateInterval::format Przykład dla poprzedniej różnicy:
echo $diff->format('%R%a dni')." "; echo $diff->format("Różnica: %m miesięcy, %d dni, %h godzin, %i minut i %s sekund");
Wynik działania kodu:
-129 dni Różnica: 4 miesiące, 7 dni, 23 godzin, 45 minut i 0 sekund
Podsumowanie
To oczywiście nie wszystkie możliwość klasy DateTime. Opisałem te metody, które przynajmniej w moim wykonaniu najczęściej są używane. Mam nadzieję, że zachęciłem Was do używania tej klasy i dostrzegacie jak wiele pracy można nieraz dzięki niej zaoszczędzić. Dla porządku podaję jeszcze link do manuala PHP, gdzie można więcej wyczytać na temat klasy (polecam prześledzić podawane tam przykłady): The DateTime class