Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP: Datetime::Diff results comparison

i was trying to compare the difference between 2 dates, but it seems the results are pretty wrong, for example this code:

$datetime1 = new DateTime('2009-10-11');
$datetime2 = new DateTime('2009-10-13');
$interval = $datetime1->diff($datetime2);
echo $interval->format('%R%a days')."<br />";

$datetime1 = new DateTime('2009-10-11');
$datetime2 = new DateTime('2009-10-15');
$interval2 = $datetime1->diff($datetime2);
echo $interval2->format('%R%a days')."<br />";

if($interval == $interval2){ echo "true"; }else{echo "false"; }

Returns true, but above you can see the date differences are not the same, in fact echo prints +2 and +4. Any idea in how to compare 2 date differences?

EDIT: the datetime::diff returns a dateinterval object, in fact it doesn't implement comparison operators, https://bugs.php.net/bug.php?id=49914 I'll use dateinterval vars to check the difference, thanks for the answers

like image 709
alex88 Avatar asked Jan 04 '12 09:01

alex88


3 Answers

It seems that DateInterval doesn't implement a comparison function internally. Extensions are allowed to define custom comparison rules for their predefined classes. Evidently it falls back to a loose comparison that the objects are of the same class.

This feature request provides a patch to add this functionality in, but it doesn't seem to have made it into the source at any point.

To get around this issue, you can either compare each member variable of your objects yourself (years, months etc.) or you can cast each object to an array:

if ((array) $interval == (array) $interval2) {
    echo 'true';
} else {
    echo 'false';
}
like image 153
cmbuckley Avatar answered Oct 14 '22 03:10

cmbuckley


You are only comparing that the two objects­Docs are of the same type (and same value of props), but not that they are identical:

if ($interval === $interval2) {echo "true";} else {echo "false";}
              ^^^

Take note, that you are doing an object comparison, not a value comparison, like with a string.

like image 45
hakre Avatar answered Oct 14 '22 03:10

hakre


I have extended the php class. Method compare makes a value comparison. It uses the "natural" order of the variables in php DateInterval class. The foreach cycle goes at first through years, then months, then days, etc. It is probably not a very portable solution, but it seems to be working just fine in php 5.3.

/**
 * Description of DateInterval
 *
 * @author Santhos
 */
class DateInterval extends \DateInterval 
{    
    /**
     * compares two date intervals
     * returns:
     *   0 - when they are equal
     *   less than zero - $a is less than $b
     *   greater than zero - $a is greater than $b
     * 
     * @param \Designeo\Utils\DateInterval $dateInterval
     * @return int
     */
    public static function compare($a, $b) 
    {
        // check parameters
        self::isDateInterval($a);
        self::isDateInterval($b);

        foreach ($a as $key => $value) {            
            // after seconds 's' comes 'invert' and other crap we do not care about
            // and it means that the date intervals are the same
            if ($key == 'invert') {                
                return 0;
            }

            // when the values are the same we can move on
            if ($a->$key == $b->$key) {
                continue;
            }

            // finally a level where we see a difference, return accordingly
            if ($a->$key < $b->$key) {
                return -1;
            } else {
                return 1;
            }
        }
    }

    private static function isDateInterval($object) 
    {
        if (!is_a($object, 'DateInterval')) {
            throw new \Exception('Parameter dateInterval type has to be a Dateinterval.');
        }
    }

    public function compareToAnother($dateInterval) {
        return self::compare($this, $dateInterval);
    }
}
like image 26
Santhos Avatar answered Oct 14 '22 04:10

Santhos