From 87af1e34a68eb52157b0703a91d86dbcdfa0b3cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Vo=C5=99=C3=AD=C5=A1ek?= Date: Sat, 5 Apr 2025 18:59:41 +0200 Subject: [PATCH] Fix DateTime::format('u') return type --- src/Type/Php/DateFunctionReturnTypeHelper.php | 6 +++++- tests/PHPStan/Analyser/nsrt/bug-10893.php | 20 +++++++++++++------ tests/PHPStan/Analyser/nsrt/bug-6613.php | 8 ++++++-- 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/Type/Php/DateFunctionReturnTypeHelper.php b/src/Type/Php/DateFunctionReturnTypeHelper.php index 5e15482336..7723ee2151 100644 --- a/src/Type/Php/DateFunctionReturnTypeHelper.php +++ b/src/Type/Php/DateFunctionReturnTypeHelper.php @@ -76,8 +76,12 @@ public function buildReturnTypeFromFormat(string $formatString, bool $useMicrose return $this->buildNumericRangeType(0, 1, false); case 'u': return $useMicrosec - ? new IntersectionType([new StringType(), new AccessoryNonFalsyStringType()]) + ? new IntersectionType([new StringType(), new AccessoryNonFalsyStringType(), new AccessoryNumericStringType()]) : new ConstantStringType('000000'); + case 'v': + return $useMicrosec + ? new IntersectionType([new StringType(), new AccessoryNonFalsyStringType(), new AccessoryNumericStringType()]) + : new ConstantStringType('000'); } $date = date($formatString); diff --git a/tests/PHPStan/Analyser/nsrt/bug-10893.php b/tests/PHPStan/Analyser/nsrt/bug-10893.php index 469c8956bd..0878d2f302 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-10893.php +++ b/tests/PHPStan/Analyser/nsrt/bug-10893.php @@ -5,16 +5,24 @@ use function PHPStan\Testing\assertType; /** - * @param non-falsy-string $nonfalsy + * @param non-falsy-string&numeric-string $str */ -function hasMicroseconds(\DateTimeInterface $value, string $nonfalsy): bool +function hasMicroseconds(\DateTimeInterface $value, string $str): bool { - assertType('non-falsy-string', $value->format('u')); + assertType('non-falsy-string&numeric-string', $str); + assertType('int', (int)$str); + assertType('bool', (int)$str !== 0); + + assertType('non-falsy-string&numeric-string', $value->format('u')); assertType('int', (int)$value->format('u')); assertType('bool', (int)$value->format('u') !== 0); - assertType('non-falsy-string', $nonfalsy); - assertType('int', (int)$nonfalsy); - assertType('bool', (int)$nonfalsy !== 0); + + assertType('non-falsy-string&numeric-string', $value->format('v')); + assertType('int', (int)$value->format('v')); + assertType('bool', (int)$value->format('v') !== 0); + + assertType('float', $value->format('u') * 1e-6); + assertType('float', $value->format('v') * 1e-3); return (int) $value->format('u') !== 0; } diff --git a/tests/PHPStan/Analyser/nsrt/bug-6613.php b/tests/PHPStan/Analyser/nsrt/bug-6613.php index 29898f7532..20abbe4b24 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-6613.php +++ b/tests/PHPStan/Analyser/nsrt/bug-6613.php @@ -6,6 +6,10 @@ function (\DateTime $dt) { assertType("'000000'", date('u')); - assertType('non-falsy-string', date_format($dt, 'u')); - assertType('non-falsy-string', $dt->format('u')); + assertType('non-falsy-string&numeric-string', date_format($dt, 'u')); + assertType('non-falsy-string&numeric-string', $dt->format('u')); + + assertType("'000'", date('v')); + assertType('non-falsy-string&numeric-string', date_format($dt, 'v')); + assertType('non-falsy-string&numeric-string', $dt->format('v')); };