@@ -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
0 commit comments