Skip to content

Instantly share code, notes, and snippets.

@drock
Last active September 8, 2022 15:46
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save drock/6389437 to your computer and use it in GitHub Desktop.
Save drock/6389437 to your computer and use it in GitHub Desktop.
A comparator object for PHPUnit to support asserting that two DateTime objects are logically equaly.
<?php
/**
* Class DateTimeComparator
*
* Custom Comparator for PHPUnit to compare two DateTime objects
* The default object comparator will report some DateTime object pairs
* as not equal even if they are canonically equal because the object
* comparator looks a exact object field values. A DateTime object
* can have multiple timezone values that represent the same timezone
* however. This comparator compares the object's UTC timestamps
*
*/
class DateTimeComparator extends \PHPUnit_Framework_Comparator
{
/**
* Returns whether the comparator can compare two values.
*
* @param mixed $expected The first value to compare
* @param mixed $actual The second value to compare
* @return boolean
*/
public function accepts($expected, $actual)
{
return $expected instanceof \DateTime && $actual instanceof \DateTime;
}
/**
* Asserts that two values are equal.
*
* @param DateTime $expected The first value to compare
* @param DateTime $actual The second value to compare
* @param float|int $delta The allowed numerical distance between two values to
* consider them equal
* @param bool $canonicalize If set to TRUE, arrays are sorted before
* comparison
* @param bool $ignoreCase If set to TRUE, upper- and lowercasing is
* ignored when comparing string values
* @throws \PHPUnit_Framework_ComparisonFailure Thrown when the comparison
* fails. Contains information about the
* specific errors that lead to the failure.
*/
public function assertEquals($expected, $actual, $delta = 0, $canonicalize = FALSE, $ignoreCase = FALSE)
{
/* @var $expected \DateTime */
/* @var $actual \DateTime */
if (abs($expected->getTimestamp() - $actual->getTimestamp()) > $delta)
{
throw new PHPUnit_Framework_ComparisonFailure(
$expected,
$actual,
$expected->format(\DateTime::ISO8601),
$actual->format(\DateTime::ISO8601)
);
}
}
}
//register the comparator with PHPUnit.
//This is typically done in your bootstrap file
PHPUnit_Framework_ComparatorFactory::getDefaultInstance()->register(new DateTimeComparator());
//in a test...
$date1 = new DateTime('2013-01-01 00:00:00', new DateTimeZone('UTC));
$date2 = new DateTime('2012-12-31 19:00:00', new DateTimeZone('America/New_York')); //assuming current DST offest is UTC - 5hrs
$this->assertEquals($date1, $date2);
@t1gor
Copy link

t1gor commented Jun 26, 2018

Version for phpunit 7+ (requires php7):

<?php

namespace TESTS;

use SebastianBergmann\Comparator\Comparator;
use SebastianBergmann\Comparator\ComparisonFailure;

class DateTimeComparator extends Comparator
{
	public function accepts($expected, $actual)
	{
		return $expected instanceof \DateTimeInterface && $actual instanceof \DateTimeInterface;
	}

	public function assertEquals($expected, $actual, $delta = 0, $canonicalize = FALSE, $ignoreCase = FALSE)
	{
		if (abs($expected->getTimestamp() - $actual->getTimestamp()) > $delta) {
			throw new ComparisonFailure(
				$expected,
				$actual,
				$expected->format(\DateTime::ISO8601),
				$actual->format(\DateTime::ISO8601)
			);
		}
	}
}

Comments omitted on purpose.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment