353

Having a look on the PHP documentation, the following two methods of the DateTime object would both seem to solve my problem:

Both these methods are marked in the doco as being available in version >= 5.3 (and, not surprisingly, if I try to call them I find they don't exist). I can't find any specific documentation for 5.2.8 so I am not sure if there are equivalent methods in my version. I have Googled the problem and found an eclectic range of solutions, none of which answer my very simple requirements:

  • How do I compare two DateTime objects?
  • Where can I find the doco for previous PHP versions? Specifically version 5.2.8?

For some context, I have the following code:

$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) 

Apparently there is no comparison operator on this guy.

Edit

Apparently my assumptions were completely false (thanks Milen for illustrating this so effectively). There is a comparison operator and it works just fine thanks. Sometimes I really miss a compiler. The bug is in the code above, I am sure you will find it much faster than I did :).

halfer
  • 19,824
  • 17
  • 99
  • 186
RedBlueThing
  • 42,006
  • 17
  • 96
  • 122
  • 1
    Regarding the lack of compiler - set "error_reporting" to "E_ALL" and you'll get notices like "Notice: Undefined variable: start_dt in ...". – Milen A. Radev Jun 08 '09 at 09:05
  • 5
    Also, please, use htmlentities on your `$_POST` vars, or kitten shall be killed. – Clement Herreman Aug 30 '10 at 08:56
  • 2
    And where is the error? :p , I'm doing it too U_U . Thanks in advance! – castarco Nov 08 '11 at 12:34
  • 2
    @castarco I initialise $st_dt , but I compare against an uninitialised $start_dt. Check your variable names and perhaps follow Milen's suggestion and set error_reporting to E_ALL to get undefined variable warnings. :) – RedBlueThing Nov 08 '11 at 22:20

8 Answers8

502

The following seems to confirm that there are comparison operators for the DateTime class:

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:~#
Milen A. Radev
  • 60,241
  • 22
  • 105
  • 110
  • 10
    Thanks Milen, looks like I just needed my false assumptions removed and suddenly the glaring bug in my code became obvious to me. – RedBlueThing Jun 07 '09 at 05:26
  • 3
    Hmm, this is interesting. Maybe at some point we'll be able to overload operators in user-defined classes. – Ionuț G. Stan Jun 07 '09 at 11:23
  • 1
    From http://www.php.net/manual/en/language.operators.comparison.php Built-in classes can define its own comparison, different classes are uncomparable, same class - compare properties the same way as arrays (PHP 4), PHP 5 has its own explanation – Saul Oct 27 '10 at 11:17
  • 9
    watch out when comparing a datetime with no hour set and one with it set(default constructor) – max4ever Mar 19 '12 at 16:45
  • @max4ever Is there a strange behavior if you do compare DateTime objects with and without hours set? I tried it and if no hour is set it behaves like the time is `00:00:00`. So if you compare `2008-08-03 00:00:00` against `2008-08-03` they are equal. – TiMESPLiNTER Oct 01 '14 at 11:02
  • 1
    TiMESPLiNTER, I believe the warning is that if you're only interested in comparing dates you might overlook the fact that the hours are different, and thus two `DateTime`s with the same date will not be compared as equal when you believe they should. You can remedy this by explicitly setting the time components of the object to zero before comparing them. – Jason Apr 21 '15 at 15:01
  • @Jason And because `DateInterval` doesn't overload the comparison operators like `DateTime` does (how this was overlooked by the PHP internals team I can't even begin to comprehend), you can't even do it the natural way: `if ($datetimeA->diff($datetimeB) < DateInterval::createFromDateString('4 days')) { …` – Adrian Günter Sep 15 '15 at 18:32
  • Checking the behavior and guessing it is as expected ("seems to confirm"?) leads to very obnoxious bugs, especially when the answer is already in the official documentation and could have been quoted without effort. There's a way better answer below. – cprn Sep 19 '16 at 14:21
  • 1
    Just keep in mind that strict comparison (`===`) compares objects, not values so it always evaluates to false in this case. – piotr_cz Feb 24 '17 at 10:34
  • @Saul (11 years late integration) built-in classes can override operators because they enforce that funcionality from C underlayer where they live and operator override is possible. PHP layer still lacks that feature, and we all hope [it'll provide it some day](https://wiki.php.net/rfc/user_defined_operator_overloads). – Niki Romagnoli Dec 27 '21 at 14:21
100

From the official documentation:

As of PHP 5.2.2, DateTime objects can be compared using comparison operators.

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

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

For PHP versions before 5.2.2 (actually for any version), you can use 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
Pang
  • 9,564
  • 146
  • 81
  • 122
Roberto Alonso
  • 1,181
  • 1
  • 7
  • 9
  • 8
    I find this answer best since it quotes the manual instead of just checking the behavior and assuming the outcome is as expected. SO is not a place for guesswork. Bravo Roberto. – cprn Sep 19 '16 at 14:18
  • 4
    @roberto [DateTime::diff](http://php.net/manual/en/datetime.diff.php) has only been added in PHP 5.3 – NeXuS May 16 '17 at 04:19
35

You can also compare epoch seconds :

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

Source : http://laughingmeme.org/2007/02/27/looking-at-php5s-datetime-and-datetimezone/ (quite interesting article about DateTime)

Julien
  • 9,312
  • 10
  • 63
  • 86
  • 19
    Beware that `format` produces a *string*, so that's a string comparison. It's barely a problem after 1000000000 epoch time (roughly Sep 9th, 2001), but if you have to deal with dates *before* that, you may incur into problems due to different number lengths. Either convert the results to numbers (subtracting them works too), or use a truly sortable format like `c`. – MaxArt Jun 18 '15 at 08:25
  • 1
    @MaxArt could you please elaborate on the problems due to different string lengths? The manual, regarding strings in numeric contexts: ["If the string does not contain any of the characters '.', 'e', or 'E' and the numeric value fits into integer type limits (as defined by PHP_INT_MAX), the string will be evaluated as an integer. In all other cases it will be evaluated as a float."](http://php.net/manual/en/language.types.string.php#language.types.string.conversion) Future dates (around 2038) can overflow signed 32-bit integers, but what's the issue with older dates? – Adrian Günter Sep 15 '15 at 18:45
  • 1
    @AdrianGünter The problem is that we wouldn't be in a numeric context, but we'd deal with *strings*. Numeric, but still strings. So a *string* comparison would be made. – MaxArt Sep 16 '15 at 09:28
  • @MaxArt Ah now I see. It would act like `strcmp` in that context. – Adrian Günter Sep 16 '15 at 22:16
  • 2
    @MaxArt: as per the documentation: [If you compare a number with a string or the comparison involves numerical strings, then each string is converted to a number and the comparison performed numerically. These rules also apply to the switch statement. The type conversion does not take place when the comparison is === or !== as this involves comparing the type as well as the value.](http://www.php.net/manual/en/language.operators.comparison.php). – Frédéric Marchal Apr 15 '16 at 09:09
  • 2
    @FrédéricMarchal Yes, I indeed learnt later that my previous comment is in fact false. PHP has a really wicked way to treat these cases, no other language (as I know of) casts to numbers when you have two strings to compare. It really screws your code if you actually want to make a lexicographical comparison. – MaxArt Apr 15 '16 at 14:53
  • is this not going to cause trouble after [2038 hits](https://en.wikipedia.org/wiki/Year_2038_problem)? – ᴍᴇʜᴏᴠ Nov 21 '19 at 13:04
25

If you want to compare dates and not time, you could use this:

$d1->format("Y-m-d") == $d2->format("Y-m-d")
krsteeve
  • 1,794
  • 4
  • 19
  • 29
blablabla
  • 1,468
  • 15
  • 17
1
$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';
}
Kyle Coots
  • 2,041
  • 1
  • 18
  • 24
0

You mentioned DateTime::diff to compare two dates, you can use it to get a more precise value than just a boolean.

For example the number of days:

$date1 = new DateTime('2021-07-09');
$date2 = new DateTime('2020-10-21');

echo $date1->diff($date2)->format('%R%a days');

But you could also use an alias of DateTime::diff which is date_diff (PHP 5 >= 5.3.0, PHP 7, PHP 8)

$date1 = new DateTime('2021-07-09');
$date2 = new DateTime('2020-10-21');

echo date_diff($date1, $date2)->format('%R%a days');
Dylan KAS
  • 4,840
  • 2
  • 15
  • 33
-1

As of PHP 7.x, you can use the following:

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

$aDate <=> $bDate; // => 1, `$aDate` is newer than `$bDate`
jens1o
  • 625
  • 7
  • 14
  • 1
    This answer needs explanation of its unusual notation [backslash and '@'] and how it works [concat '@' with result of time(), ] – Bilbo Nov 12 '20 at 19:18
  • 4
    Answers need to include explanation of any unusual notation, like backslash, At-symbol, and spaceship operator. Code should include comments about how works, like: - concat '@' with result of time(), optionally subtracting one hour's worth of seconds - instantiate DateTime objects - compare DateTime objects, returning 0 if equal, or 1 if left value is greater, or -1 if right value is greater [Comment editing timeout window expired; cannot delete previous comment] – Bilbo Nov 12 '20 at 19:27
-2

This may help you.

$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";
}
Pang
  • 9,564
  • 146
  • 81
  • 122
Tarun Gupta
  • 6,305
  • 2
  • 42
  • 39
  • timestamp has a some limitations, you might want to read this http://stackoverflow.com/a/7229760/2652018 – Steel Brain Aug 02 '14 at 08:56
  • @SteelBrain do you think that timestamp limitation bother above code which is having all current date time, Please read the code again, It basically check for the guy $expectedDate which will always be in the current month. I dont think so we should think about the timestamp limitation here in this case. – Tarun Gupta Aug 04 '14 at 09:58
  • I know, but it's not a recommended way, (I didn't downvote :-) ) – Steel Brain Aug 04 '14 at 13:19
  • Can you suggest a recommended way. – Tarun Gupta Aug 05 '14 at 06:39
  • sure, `$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";}` cheers. – Steel Brain Aug 05 '14 at 07:14