diff --git a/src/DateTimeMock/DateTimeMock.php b/src/DateTimeMock/DateTimeMock.php index 54dcd9f..fab5135 100644 --- a/src/DateTimeMock/DateTimeMock.php +++ b/src/DateTimeMock/DateTimeMock.php @@ -28,12 +28,15 @@ public function __construct(?string $datetime = 'now', ?DateTimeZone $timezone = if ($timezone !== null && !$isDateTimeStringRelative) { // When there's a timezone and the provided date is absolute, the timestamp must be calculated with that // specific timezone in order to mimic behavior of the original \DateTime (which does not modify time). - $this->setTimestamp( - strtotime( - "$datetime {$timezone->getName()}", - ClockMock::getFrozenDateTime()->getTimestamp() - ) - ); + $timestamp = strtotime("$datetime {$timezone->getName()}", ClockMock::getFrozenDateTime()->getTimestamp()); + if ($timestamp === false) { + // Some non-canonical timezone names (e.g. US/Eastern) are not supported by `strtotime`. In these cases, + // apply the same workaround by using the offset in seconds. + $offset = -$timezone->getOffset(new \DateTime('now')); + $timestamp = strtotime("$datetime $offset seconds", ClockMock::getFrozenDateTime()->getTimestamp()); + } + + $this->setTimestamp($timestamp); } else { $this->setTimestamp(strtotime($datetime, ClockMock::getFrozenDateTime()->getTimestamp())); } diff --git a/tests/ClockMockTest.php b/tests/ClockMockTest.php index c835a4a..e06faba 100644 --- a/tests/ClockMockTest.php +++ b/tests/ClockMockTest.php @@ -104,7 +104,7 @@ public function test_DateTime_constructor_with_absolute_mocked_date() /** * @see https://github.com/slope-it/clock-mock/issues/26 */ - public function test_DateTime_constructor_with_absolute_date_and_timezone() + public function test_DateTime_constructor_with_absolute_date_and_canonical_timezone() { // The mocked date, either aboslute or relative, is irrelevant for this test. Having a mocked date is enough. ClockMock::freeze(new \DateTime('now')); @@ -119,6 +119,25 @@ public function test_DateTime_constructor_with_absolute_date_and_timezone() $this->assertSame('1986-06-05 12:13:14', $absoluteDateTimeWithTimezone->format('Y-m-d H:i:s')); } + /** + * @see https://github.com/slope-it/clock-mock/issues/37 + * @see https://en.wikipedia.org/wiki/List_of_tz_database_time_zones + */ + public function test_DateTime_constructor_with_absolute_date_and_non_canonical_timezone() + { + // The mocked date, either aboslute or relative, is irrelevant for this test. Having a mocked date is enough. + ClockMock::freeze(new \DateTime('now')); + + $absoluteDateTimeWithTimezone = new \DateTime( + '1986-06-05 12:13:14', + $usEasternTimezone = new \DateTimeZone('US/Eastern') + ); + + // Verification: when date is absolute and timezone is specified, the mocked clock should have no effect. + $this->assertEquals($usEasternTimezone, $absoluteDateTimeWithTimezone->getTimezone()); + $this->assertSame('1986-06-05 12:13:14', $absoluteDateTimeWithTimezone->format('Y-m-d H:i:s')); + } + /** * @see https://github.com/slope-it/clock-mock/issues/31 */