diff --git a/README.md b/README.md index c94c0cb..38d7138 100644 --- a/README.md +++ b/README.md @@ -38,10 +38,12 @@ Note that, as this is not a tool intended for production, it should be required - getdate() - gettimeofday() - gmdate() +- gmmktime() - gmstrftime() - idate() - localtime() - microtime() +- mktime() - strftime() - strtotime() - time() @@ -53,8 +55,6 @@ Note that, as this is not a tool intended for production, it should be required - date_create_from_format() - date_create_immutable_from_format() -- gmmktime() -- mktime() - DateTime::createFromFormat - DateTimeImmutable::createFromFormat - $_SERVER['REQUEST_TIME'] diff --git a/src/ClockMock.php b/src/ClockMock.php index ac2f1d8..997fe70 100644 --- a/src/ClockMock.php +++ b/src/ClockMock.php @@ -56,10 +56,12 @@ public static function reset(): void uopz_unset_return('getdate'); uopz_unset_return('gettimeofday'); uopz_unset_return('gmdate'); + uopz_unset_return('gmmktime'); uopz_unset_return('gmstrftime'); uopz_unset_return('idate'); uopz_unset_return('localtime'); uopz_unset_return('microtime'); + uopz_unset_return('mktime'); uopz_unset_return('strftime'); uopz_unset_return('strtotime'); uopz_unset_return('time'); @@ -87,10 +89,12 @@ private static function activateMocksIfNeeded(): void uopz_set_return('getdate', self::mock_getdate(), true); uopz_set_return('gettimeofday', self::mock_gettimeofday(), true); uopz_set_return('gmdate', self::mock_gmdate(), true); + uopz_set_return('gmmktime', self::mock_gmmktime(), true); uopz_set_return('gmstrftime', self::mock_gmstrftime(), true); uopz_set_return('idate', self::mock_idate(), true); uopz_set_return('localtime', self::mock_localtime(), true); uopz_set_return('microtime', self::mock_microtime(), true); + uopz_set_return('mktime', self::mock_mktime(), true); uopz_set_return('strftime', self::mock_strftime(), true); uopz_set_return('strtotime', self::mock_strtotime(), true); uopz_set_return('time', self::mock_time(), true); @@ -190,6 +194,26 @@ private static function mock_gmstrftime(): callable return fn (string $format, ?int $timestamp = null) => $gmstrftime_mock($format, $timestamp); } + /** + * @see https://www.php.net/manual/en/function.gmmktime.php + */ + private static function mock_gmmktime(): callable + { + $gmmktime_mock = function (int $hour, ?int $minute, ?int $second, ?int $month, ?int $day, ?int $year) { + /** @var \DateTime $gmtDateTime */ + $gmtDateTime = self::mock_date_create()(self::mock_gmdate()('Y-m-d H:i:s.u')); + + return self::mock_mktime()($hour + self::$frozenDateTime->getOffset() / 3600, + $minute ?? (int) $gmtDateTime->format('i'), + $second ?? (int) $gmtDateTime->format('s'), + $month ?? (int) $gmtDateTime->format('m'), + $day ?? (int) $gmtDateTime->format('j'), + $year ?? (int) $gmtDateTime->format('Y')); + }; + + return fn (int $hour, ?int $minute = null, ?int $second = null, ?int $month = null, ?int $day = null, ?int $year = null) => $gmmktime_mock($hour, $minute, $second, $month, $day, $year); + } + /** * @see https://www.php.net/manual/en/function.idate.php */ @@ -242,6 +266,23 @@ private static function mock_strftime(): callable return fn (string $format, ?int $timestamp = null) => $strftime_mock($format, $timestamp); } + /** + * @see https://www.php.net/manual/en/function.mktime.php + */ + private static function mock_mktime(): callable + { + $mktime_mock = function (int $hour, ?int $minute, ?int $second, ?int $month, ?int $day, ?int $year) { + return mktime($hour, + $minute ?? (int) self::$frozenDateTime->format('i'), + $second ?? (int) self::$frozenDateTime->format('s'), + $month ?? (int) self::$frozenDateTime->format('m'), + $day ?? (int) self::$frozenDateTime->format('j'), + $year ?? (int) self::$frozenDateTime->format('Y')); + }; + + return fn (int $hour, ?int $minute = null, ?int $second = null, ?int $month = null, ?int $day = null, ?int $year = null) => $mktime_mock($hour, $minute, $second, $month, $day, $year); + } + /** * @see https://www.php.net/manual/en/function.strtotime.php */ diff --git a/tests/ClockMockTest.php b/tests/ClockMockTest.php index fb046d6..53b363b 100644 --- a/tests/ClockMockTest.php +++ b/tests/ClockMockTest.php @@ -182,6 +182,60 @@ public function test_gmstrftime() $this->assertEquals('2022-04-04 11:26:29', gmstrftime('%F %T')); } + public function dateProvider_gmmktime(): array + { + // NOTE: for all datasets, hour in freezeDateTime is completely irrelevant because always overridden by $hour + // parameter provided to gmmktime. Also, in expectedDateTime hour is always "13" because hour 10 in GMT + // corresponds to hour 13 when we are in +03:00 offset. + return [ + [ + '2022-04-04T05:26:29+03:00', + [10], + '2022-04-04T13:26:29+00:00' + ], + [ + '2022-04-04T05:26:29+03:00', + [10, 10], + '2022-04-04T13:10:29+00:00' + ], + [ + '2022-04-04T05:26:29+03:00', + [10, null, 10], + '2022-04-04T13:26:10+00:00' + ], + [ + '2022-04-04T05:26:29+03:00', + [10, null, null, 10], + '2022-10-04T13:26:29+00:00' + ], + [ + '2022-04-04T05:26:29+03:00', + [10, null, null, null, 10], + '2022-04-10T13:26:29+00:00' + ], + [ + '2022-04-04T05:26:29+03:00', + [10, null, null, null, null, 10], + '2010-04-04T13:26:29+00:00' + ], + [ + '2022-04-04T05:26:29+03:00', + [10, 10, 10, 10, 10, 10], + '2010-10-10T13:10:10+00:00' + ], + ]; + } + + /** + * @dataProvider dateProvider_gmmktime + */ + public function test_gmmktime(string $freezeDateTime, array $mktimeArgs, string $expectedDateTime) + { + ClockMock::freeze(new \DateTime($freezeDateTime)); + + $this->assertEquals($expectedDateTime, date(DATE_ATOM, gmmktime(...$mktimeArgs))); + } + public function test_idate() { ClockMock::freeze(new \DateTime('1986-06-05')); @@ -225,6 +279,57 @@ public function test_strftime() $this->assertEquals('2022-04-04 14:26:29', strftime('%F %T')); } + public function dateProvider_mktime(): array + { + return [ + [ + '2022-04-04T14:26:29+00:00', + [10], + '2022-04-04T10:26:29+00:00' + ], + [ + '2022-04-04T14:26:29+00:00', + [10, 10], + '2022-04-04T10:10:29+00:00' + ], + [ + '2022-04-04T14:26:29+00:00', + [10, null, 10], + '2022-04-04T10:26:10+00:00' + ], + [ + '2022-04-04T14:26:29+00:00', + [10, null, null, 10], + '2022-10-04T10:26:29+00:00' + ], + [ + '2022-04-04T14:26:29+00:00', + [10, null, null, null, 10], + '2022-04-10T10:26:29+00:00' + ], + [ + '2022-04-04T14:26:29+00:00', + [10, null, null, null, null, 10], + '2010-04-04T10:26:29+00:00' + ], + [ + '2022-04-04T14:26:29+00:00', + [10, 10, 10, 10, 10, 10], + '2010-10-10T10:10:10+00:00' + ], + ]; + } + + /** + * @dataProvider dateProvider_mktime + */ + public function test_mktime(string $freezeDateTime, array $mktimeArgs, string $expectedDateTime) + { + ClockMock::freeze(new \DateTime($freezeDateTime)); + + $this->assertEquals($expectedDateTime, date(DATE_ATOM, mktime(...$mktimeArgs))); + } + public function test_strtotime() { ClockMock::freeze($fakeNow = new \DateTimeImmutable('1986-06-05'));