sebastianbergmann/comparator · error · ComparisonFailure
Failed asserting that two DateInterval objects are equal.
Error message
Failed asserting that two DateInterval objects are equal.
What it means
ComparisonFailure thrown by DateIntervalComparator::assertEquals when two DateInterval objects differ by more than $delta in total seconds (each interval converted via toSeconds). DateInterval equality is duration-based, not property-based, since ISO 8601 durations can be expressed in many equivalent ways.
Solutions
- Increase $delta to the tolerance your use case allows (e.g. 3600 for one hour).
- Normalize both intervals to a common unit before comparing (e.g. compare toSeconds yourself).
- Fix the source string so the parsed interval is the intended duration.
- If DST is involved, construct intervals in UTC or compare fixed seconds rather than calendar days.
Example fix
// before
$c->assertEquals(new DateInterval('P1D'), new DateInterval('PT23H'), 0.0); // throws
// after
$c->assertEquals(new DateInterval('P1D'), new DateInterval('PT23H'), 3600.0); // allow 1h tolerance Defensive patterns
Strategy: validation
Validate before calling
// compare durations in seconds first
$secs = fn(DateInterval $i) => (new DateTime('@0'))->add($i)->getTimestamp();
if (abs($secs($expected) - $secs($actual)) > $toleranceSeconds) { /* will fail; adjust delta or data */ } Type guard
function isDateInterval(mixed $v): bool { return $v instanceof DateInterval; } Try / catch
try {
$c->assertEquals($expectedInterval, $actualInterval, 60.0);
} catch (ComparisonFailure $e) {
// inspect $e->getExpectedAsString()/getActualAsString() (formatted intervals)
} Prevention
- Always pass an explicit delta for interval comparisons.
- Convert both intervals to seconds yourself when you need precise semantics.
- Be aware DST/day-based intervals may not equal the same number of seconds.
When it happens
Trigger: assertEquals on two DateInterval instances where abs(toSeconds(expected) - toSeconds(actual)) > abs(delta) — e.g. comparing 'P1D' with 'PT24H' plus timezone/DST-influenced conversions, or passing too small a delta.
Common situations: Comparing durations parsed from ISO 8601 strings against DateInterval::createFromDateString results; DST transitions making day-based and second-based intervals unequal; asserting expiry/timeout intervals in tests with an overly tight delta.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- Failed asserting that two DateTime objects are equal.
- Failed asserting that two arrays are equal.
- Failed asserting that closure declared at
- Failed asserting that two DOM
- Failed asserting that two values of enumeration
AI-assisted analysis of sebastianbergmann/comparator@00837a9d22 (2026-09-15).
Data as JSON: /api/errors/1fc91bbac23c5cd6.
Report an issue: GitHub.
Appendix: source
Thrown at src/DateIntervalComparator.php:52
/**
* @param array<mixed> $processed
*
* @throws ComparisonFailure
*/
public function assertEquals(mixed $expected, mixed $actual, float $delta = 0.0, bool $canonicalize = false, bool $ignoreCase = false, array &$processed = []): void
{
assert($expected instanceof DateInterval);
assert($actual instanceof DateInterval);
if (in_array([$actual, $expected], $processed, true) ||
in_array([$expected, $actual], $processed, true)) {
return;
}
$processed[] = [$actual, $expected];
if (abs($this->toSeconds($expected) - $this->toSeconds($actual)) > abs($delta)) {
throw new ComparisonFailure(
$expected,
$actual,
$this->format($expected),
$this->format($actual),
'Failed asserting that two DateInterval objects are equal.',
$this->contextLines(),
);
}
}
/**
* Converts a DateInterval to a duration in seconds by applying it to the
* Unix epoch. Month and year components are therefore evaluated against a
* fixed anchor (a month is not always 30 days, a year not always 365), so
* two intervals whose calendar components differ may still be considered
* equal within a delta when the resulting durations match.
*/
private function toSeconds(DateInterval $interval): floatView on GitHub (pinned to 00837a9d22)