Skip to content

Commit 3a56322

Browse files
authored
Merge pull request #28 from slope-it/26-fix-absolute-date-with-timezone
2 parents f0e4edf + 041a4d5 commit 3a56322

File tree

2 files changed

+39
-5
lines changed

2 files changed

+39
-5
lines changed

src/DateTimeMock/DateTimeMock.php

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,24 @@ public function __construct(?string $datetime = 'now', ?DateTimeZone $timezone =
1919

2020
parent::__construct($datetime, $timezone);
2121

22-
$this->setTimestamp(strtotime($datetime, ClockMock::getFrozenDateTime()->getTimestamp()));
22+
$isDateTimeStringRelative = $this->isRelativeDateString($datetime);
2323

24-
if ($this->shouldUseMicrosecondsOfFrozenDate($datetime)) {
24+
if ($timezone !== null && !$isDateTimeStringRelative) {
25+
// When there's a timezone and the provided date is absolute, the timestamp must be calculated with that
26+
// specific timezone in order to mimic behavior of the original \DateTime (which does not modify time).
27+
$this->setTimestamp(
28+
strtotime(
29+
"$datetime {$timezone->getName()}",
30+
ClockMock::getFrozenDateTime()->getTimestamp()
31+
)
32+
);
33+
} else {
34+
$this->setTimestamp(strtotime($datetime, ClockMock::getFrozenDateTime()->getTimestamp()));
35+
}
36+
37+
// After some empirical tests, we've seen that microseconds are set to the current actual ones only when an
38+
// absolute date or time is not provided.
39+
if ($isDateTimeStringRelative) {
2540
$this->setTime(
2641
(int) $this->format('H'),
2742
(int) $this->format('i'),
@@ -31,10 +46,11 @@ public function __construct(?string $datetime = 'now', ?DateTimeZone $timezone =
3146
}
3247
}
3348

34-
private function shouldUseMicrosecondsOfFrozenDate(string $datetime): bool
49+
/**
50+
* Returns whether the provided one is a relative date (e.g. "now", "yesterday", "tomorrow", etc...).
51+
*/
52+
private function isRelativeDateString(string $datetime): bool
3553
{
36-
// After some empirical tests, we've seen that microseconds are set to the current actual ones only when all of
37-
// these variables are false (i.e. when an absolute date or time is not provided).
3854
$parsedDate = date_parse($datetime);
3955
return $parsedDate['year'] === false
4056
&& $parsedDate['month'] === false

tests/ClockMockTest.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,24 @@ public function test_DateTime_constructor_with_absolute_mocked_date()
6969
$this->assertEquals($fakeNow, new \DateTime('now'));
7070
}
7171

72+
/**
73+
* @see https://github.com/slope-it/clock-mock/issues/26
74+
*/
75+
public function test_DateTime_constructor_with_absolute_date_and_timezone()
76+
{
77+
// The mocked date, either aboslute or relative, is irrelevant for this test. Having a mocked date is enough.
78+
ClockMock::freeze(new \DateTime('now'));
79+
80+
$absoluteDateTimeWithTimezone = new \DateTime(
81+
'1986-06-05 12:13:14',
82+
$japanTimezone = new \DateTimeZone('Asia/Tokyo')
83+
);
84+
85+
// Verification: when date is absolute and timezone is specified, the mocked clock should have no effect.
86+
$this->assertEquals($japanTimezone, $absoluteDateTimeWithTimezone->getTimezone());
87+
$this->assertSame('1986-06-05 12:13:14', $absoluteDateTimeWithTimezone->format('Y-m-d H:i:s'));
88+
}
89+
7290
/**
7391
* @see https://github.com/slope-it/clock-mock/issues/7
7492
*/

0 commit comments

Comments
 (0)