{"record":{"id":"7a64d5fd500bf739","repo":"sebastianbergmann/comparator","slug":"failed-asserting-that-two-datetime-objects-are-equal","errorCode":null,"errorMessage":"Failed asserting that two DateTime objects are equal.","messagePattern":"Failed asserting that two DateTime objects are equal\\.","errorType":"exception","errorClass":"ComparisonFailure","httpStatus":null,"severity":"error","filePath":"src/DateTimeComparator.php","lineNumber":74,"sourceCode":"        $absDelta = abs($delta);\n\n        /** @phpstan-ignore argument.type */\n        $delta    = new DateInterval(sprintf('PT%dS', $absDelta));\n        $delta->f = $absDelta - floor($absDelta);\n\n        $actualClone = (clone $actual)\n            ->setTimezone(new DateTimeZone('UTC'));\n\n        $expectedLower = (clone $expected)\n            ->setTimezone(new DateTimeZone('UTC'))\n            ->sub($delta);\n\n        $expectedUpper = (clone $expected)\n            ->setTimezone(new DateTimeZone('UTC'))\n            ->add($delta);\n\n        if ($actualClone < $expectedLower || $actualClone > $expectedUpper) {\n            throw new ComparisonFailure(\n                $expected,\n                $actual,\n                $expected->format('Y-m-d\\TH:i:s.uO'),\n                $actual->format('Y-m-d\\TH:i:s.uO'),\n                'Failed asserting that two DateTime objects are equal.',\n                $this->contextLines(),\n            );\n        }\n    }\n}\n","sourceCodeStart":56,"sourceCodeEnd":85,"githubUrl":"https://github.com/sebastianbergmann/comparator/blob/00837a9d227b4e123b0b42a91736960f6b0b3583/src/DateTimeComparator.php#L56-L85","documentation":"ComparisonFailure thrown by DateTimeComparator::assertEquals when the actual DateTime/DateTimeInterface falls outside the window [expected - delta, expected + delta] after both are normalized to UTC. The exported strings are ISO-8601 formatted with microseconds and offset.","triggerScenarios":"assertEquals on two DateTime objects whose UTC timestamps differ by more than $delta; common when one side uses a different timezone (only the instant matters after UTC normalization), or when delta defaults to 0.0 for times generated with different precision.","commonSituations":"Testing timestamps with sub-second truncation; comparing 'now'-based values with clock skew; mixing timezones (e.g. '+02:00' vs 'UTC' representations of the same instant pass, but genuinely different instants fail); fixtures hard-coded in a different TZ environment.","solutions":["Pass an appropriate $delta (e.g. 1.0 second) to tolerate clock/precision differences.","Normalize both values to the same timezone before comparing if wall-clock time is what matters.","Diff the ISO-8601 strings in the exception to see the exact instant difference.","Freeze time in tests (inject a clock or use a time-shim) instead of comparing against new DateTime('now')."],"exampleFix":"// before\n$c->assertEquals(new DateTime('2024-01-01T00:00:00+00:00'), $actual); // fails for 200ms drift\n// after\n$c->assertEquals(new DateTime('2024-01-01T00:00:00+00:00'), $actual, 1.0); // 1s tolerance","handlingStrategy":"validation","validationCode":"// both instants within tolerance (UTC-normalized)?\n$diff = abs($expected->getTimestamp() - $actual->getTimestamp());\nif ($diff > (int) $delta) { /* comparator will throw */ }","typeGuard":"function isDateTimeLike(mixed $v): bool { return $v instanceof DateTimeInterface; }","tryCatchPattern":"try {\n    $c->assertEquals($expected, $actual, 1.0);\n} catch (ComparisonFailure $e) {\n    // ISO-8601 strings of both instants are in getExpectedAsString()/getActualAsString()\n}","preventionTips":["Pass an explicit delta for 'now'-based or precision-sensitive timestamps.","Normalize to UTC when comparing instants; only the instant matters to this comparator.","Freeze or inject time in tests instead of relying on real clock."],"tags":["phpunit","datetime","timezone","comparison"],"backgroundTag":"value-out-of-range","analyzedSha":"00837a9d227b4e123b0b42a91736960f6b0b3583","analyzedAt":"2026-09-15T03:36:55.154Z","contentChangedAt":"2026-09-15T03:36:55.154Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}