Jak porównać dwa obiekty DateTime w PHP 5.2.8?


294

Po zapoznaniu się z dokumentacją PHP DateTimewydaje się , że dwie następujące metody obiektu rozwiązałyby mój problem:

Obie te metody są oznaczone w doco jako dostępne w wersji> = 5.3 (i, co nie jest zaskoczeniem, jeśli spróbuję je wywołać, stwierdzę, że nie istnieją). Nie mogę znaleźć żadnej konkretnej dokumentacji dla 5.2.8, więc nie jestem pewien, czy w mojej wersji istnieją równoważne metody. I Googled problem i znaleźć eklektyczny gamę rozwiązań, z których żadna nie jest odpowiedź na moje bardzo proste wymagania:

  • Jak porównać dwa obiekty DateTime?
  • Gdzie mogę znaleźć dokumentację dla poprzednich wersji PHP? W szczególności wersja 5.2.8?

W pewnym kontekście mam następujący kod:

$st_dt = new DateTime(verifyParam ('start_date'));
$end_dt = new DateTime(verifyParam ('end_date'));

// is the end date more ancient than the start date?
if ($end_dt < $start_dt) 

Najwyraźniej ten facet nie ma operatora porównania.

Edytować

Najwyraźniej moje założenia były całkowicie fałszywe (dziękuję Milenowi za tak skuteczne zilustrowanie tego). Jest operator porównania i działa dobrze dzięki. Czasami naprawdę brakuje mi kompilatora. Błąd znajduje się w powyższym kodzie, jestem pewien, że znajdziesz go znacznie szybciej niż ja :).


1
Jeśli chodzi o brak kompilatora - ustaw „raportowanie błędów” na „E_ALL”, a otrzymasz powiadomienia takie jak „Uwaga: Zmienna niezdefiniowana: start_dt w ...”.
Milen A. Radev,

5
Proszę również używać htmlentities na swoich warach $_POST, w przeciwnym razie kotek zostanie zabity.
Clement Herreman

2
A gdzie jest błąd? : p, ja też to robię U_U. Z góry dziękuję!
castarco

2
@castarco Inicjuję $ st_dt, ale porównuję z niezainicjowanym $ start_dt. Sprawdź nazwy zmiennych i być może zastosuj się do sugestii Milena i ustaw raportowanie błędów na E_ALL, aby otrzymać niezdefiniowane ostrzeżenia o zmiennej. :)
RedBlueThing

Odpowiedzi:


432

Poniższe wydaje się potwierdzać, że istnieją operatory porównania dla klasy DateTime:

dev:~# php
<?php
date_default_timezone_set('Europe/London');

$d1 = new DateTime('2008-08-03 14:52:10');
$d2 = new DateTime('2008-01-03 11:11:10');
var_dump($d1 == $d2);
var_dump($d1 > $d2);
var_dump($d1 < $d2);
?>
bool(false)
bool(true)
bool(false)
dev:~# php -v
PHP 5.2.6-1+lenny3 with Suhosin-Patch 0.9.6.2 (cli) (built: Apr 26 2009 20:09:03)
Copyright (c) 1997-2008 The PHP Group
Zend Engine v2.2.0, Copyright (c) 1998-2008 Zend Technologies
dev:~#

7
Dzięki Milen, wygląda na to, że po prostu potrzebowałem usunąć moje fałszywe założenia i nagle rażący błąd w moim kodzie stał się dla mnie oczywisty.
RedBlueThing

2
Hmm, to interesujące. Może w pewnym momencie będziemy w stanie przeciążać operatorów w klasach zdefiniowanych przez użytkownika.
Ionuț G. Stan

1
Z php.net/manual/en/language.operators.comparison.php Wbudowane klasy mogą definiować własne porównanie, różne klasy są nieporównywalne, ta sama klasa - porównuje właściwości tak samo jak tablice (PHP 4), PHP 5 ma swoje własne wyjaśnienie
Saul

7
uważaj, porównując datę i godzinę bez ustawionej godziny i ustawioną godzinę (domyślny konstruktor)
max4ever

1
TiMESPLiNTER, uważam, że ostrzeżenie jest takie, że jeśli jesteś zainteresowany jedynie porównywaniem dat, możesz przeoczyć fakt, że godziny są różne, a zatem dwie DateTimesekundy z tą samą datą nie będą porównywane jako równe, jeśli uważasz, że powinny. Można temu zaradzić poprzez jawne ustawienie składników czasu obiektu na zero przed ich porównaniem.
Jason

52

Z oficjalnej dokumentacji :

Począwszy od PHP 5.2.2, obiekty DateTime można porównywać za pomocą operatorów porównania .

$date1 = new DateTime("now");
$date2 = new DateTime("tomorrow");

var_dump($date1 == $date2); // false
var_dump($date1 < $date2); // true
var_dump($date1 > $date2); // false

Dla wersji PHP wcześniejszych niż 5.2.2 (właściwie dla każdej wersji) możesz użyć diff .

$datetime1 = new DateTime('2009-10-11'); // 11 October 2013
$datetime2 = new DateTime('2009-10-13'); // 13 October 2013

$interval = $datetime1->diff($datetime2);
echo $interval->format('%R%a days'); // +2 days

3
Uważam tę odpowiedź za najlepszą, ponieważ cytuje ona instrukcję, a nie tylko sprawdza zachowanie i zakłada, że ​​wynik jest zgodny z oczekiwaniami. SO nie jest miejscem do zgadywania. Bravo Roberto.
cprn

3
@roberto DateTime :: diff został dodany tylko w PHP 5.3
NeXuS

30

Możesz także porównać epokowe sekundy:

$d1->format('U') < $d2->format('U')

Źródło: http://laughingmeme.org/2007/02/27/looking-at-php5s-datetime-and-datetimezone/ (dość interesujący artykuł o DateTime)


16
Strzeż się, że formattworzy ciąg , więc to porównanie ciągów. Po epoce 1000000000 to prawie problem (mniej więcej 9 września 2001 r.), Ale jeśli masz do czynienia z datami wcześniej , możesz mieć problemy z powodu różnych długości liczb. Albo przekonwertuj wyniki na liczby (odejmowanie ich też działa), albo użyj prawdziwie sortowalnego formatu, takiego jak c.
MaxArt,

1
@ MaxArt, czy mógłbyś wyjaśnić problemy wynikające z różnych długości łańcucha? Podręcznik dotyczący ciągów w kontekstach numerycznych: „Jeśli ciąg nie zawiera żadnego ze znaków”. ”,„ E ”lub„ E ”, a wartość liczbowa jest zgodna z ograniczeniami liczb całkowitych (zgodnie z definicją PHP_INT_MAX), ciąg zostanie oceniony jako liczba całkowita. We wszystkich innych przypadkach zostanie oceniony jako liczba zmiennoprzecinkowa. ” Przyszłe daty (około 2038 r.) Mogą spowodować przepełnienie 32-bitowych liczb całkowitych, ale jaki jest problem ze starszymi datami?
Adrian Günter,

1
@ AdrianGünter Problem polega na tym, że nie bylibyśmy w kontekście liczbowym, ale mielibyśmy do czynienia z łańcuchami . Liczbowe, ale wciąż ciągi znaków. Tak więc ciąg porównanie będzie wykonana.
MaxArt,


2
@ FrédéricMarchal Tak, rzeczywiście dowiedziałem się później, że mój poprzedni komentarz jest w rzeczywistości fałszywy. PHP ma naprawdę zły sposób na traktowanie tych przypadków, żaden inny język (jak wiem) nie rzuca na liczby, gdy masz dwa ciągi do porównania. Naprawdę psuje twój kod, jeśli naprawdę chcesz dokonać porównania leksykograficznego.
MaxArt

20

Jeśli chcesz porównać daty, a nie godzinę, możesz użyć tego:

$d1->format("Y-m-d") == $d2->format("Y-m-d")

5
Możesz także ustawić czas resetowania. $d1->setTime(0, 0, 0);
Athlan

3

Począwszy od wersji PHP 7.x, możesz używać następujących opcji:

$aDate = new \DateTime('@'.(time()));
$bDate = new \DateTime('@'.(time() - 3600));

$aDate <=> $bDate; // => 1, `$aDate` is newer than `$bDate`

0
$elapsed = '2592000';
// Time in the past
$time_past = '2014-07-16 11:35:33';
$time_past = strtotime($time_past);

// Add a month to that time
$time_past = $time_past + $elapsed;

// Time NOW
$time_now = time();

// Check if its been a month since time past
if($time_past > $time_now){
    echo 'Hasnt been a month';    
}else{
    echo 'Been longer than a month';
}

znacznik czasu ma pewne ograniczenia, możesz przeczytać ten stackoverflow.com/a/7229760/2652018
Steel Brain

Dobrze wiedzieć! To był po prostu prosty sposób na porównanie czasów.
Kyle Coots

-1

To może ci pomóc.

$today = date("m-d-Y H:i:s");
$thisMonth =date("m");
$thisYear = date("y");
$expectedDate = ($thisMonth+1)."-08-$thisYear 23:58:00";


if (strtotime($expectedDate) > strtotime($today)) {
    echo "Expected date is greater then current date";
    return ;
} else
{
 echo "Expected date is lesser then current date";
}

znacznik czasu ma pewne ograniczenia, możesz przeczytać ten stackoverflow.com/a/7229760/2652018
Steel Brain

@ SteelBrain, czy uważasz, że ograniczenie znacznika czasu przeszkadza nad kodem, który ma całą aktualną datę i godzinę, przeczytaj kod ponownie, to po prostu sprawdź, czy facet nie spodziewał się $ Data, która zawsze będzie w bieżącym miesiącu. Nie sądzę, więc w tym przypadku powinniśmy pomyśleć o ograniczeniu znacznika czasu.
Tarun Gupta

Wiem, ale to nie jest zalecany sposób (nie głosowałem za :-))
Steel Brain

Czy możesz zasugerować zalecany sposób.
Tarun Gupta,

$today = new DateTime("now"); $time = DateTime::createFromFormat('d-m-Y',"26-October-1998"); if ($today > $time){echo "today is greater";}else{echo "other time is greater";}jasne , na zdrowie.
Steel Brain
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.