Cake\Chronos\Date::parse("YYYYMMDD") throws unexpected TypeError
Tietew opened this issue · comments
I encountered this issue when trying to parse Ymd-style date string such as "20200522".
Chronos version: 2.0.4
PHP version: 7.4.6
How to reproduce
$ php -r 'require "vendor/autoload.php"; var_dump(Cake\Chronos\Date::parse("20200522"));'
PHP Fatal error: Uncaught TypeError: gmdate() expects parameter 2 to be int, string given in .../vendor/cakephp/chronos/src/Traits/FrozenTimeTrait.php:42
Stack trace:
#0 .../vendor/cakephp/chronos/src/Traits/FrozenTimeTrait.php(42): gmdate()
#1 .../vendor/cakephp/chronos/src/Date.php(100): Cake\Chronos\Date->stripTime()
#2 .../vendor/cakephp/chronos/src/Traits/FactoryTrait.php(61): Cake\Chronos\Date->__construct()
#3 Command line code(1): Cake\Chronos\Date::parse()
#4 {main}
thrown in .../vendor/cakephp/chronos/src/Traits/FrozenTimeTrait.php on line 42
This caused by missing cast in FrozenTimeTrait->stripTime()
.
Suggestions
I have some suggestions. Which is best?
1. Remove ctype_digit
check
I need this behavior.
Because PHP's native DateTime
, strtotime
, and Chronos's Cake\Chronos\Chronos::parse
return 2020/05/22 00:00:00 from "20200522"
.
--- FrozenTimeTrait.php.orig 2020-05-22 11:24:37.230724313 +0900
+++ FrozenTimeTrait.php 2020-05-22 11:24:46.542865555 +0900
@@ -38,7 +38,7 @@
protected function stripTime($time, $tz): string
{
- if (is_int($time) || ctype_digit($time)) {
+ if (is_int($time)) {
return gmdate('Y-m-d 00:00:00', $time);
}
Pros: Ymd-style date string can be parsed.
Cons: Backward incompatibility.
2. Adding cast
--- FrozenTimeTrait.php.orig 2020-05-22 11:24:37.230724313 +0900
+++ FrozenTimeTrait.php 2020-05-22 11:27:36.325440736 +0900
@@ -40,5 +40,5 @@
{
if (is_int($time) || ctype_digit($time)) {
- return gmdate('Y-m-d 00:00:00', $time);
+ return gmdate('Y-m-d 00:00:00', (int)$time);
}
Pros: Backward compaitibility.
Cons: Ymd-style date string cannot be parsed.
3. Special Case for /^\d{8}$/
--- FrozenTimeTrait.php.orig 2020-05-22 11:24:37.230724313 +0900
+++ FrozenTimeTrait.php 2020-05-22 11:31:31.585005122 +0900
@@ -39,5 +39,5 @@
protected function stripTime($time, $tz): string
{
- if (is_int($time) || ctype_digit($time)) {
+ if (is_int($time) || (ctype_digit($time) && strlen($time) !== 8)) {
return gmdate('Y-m-d 00:00:00', $time);
}
Pros: Backward compaitibility (except for 8-digit epoch!). Ymd-style date string can be parsed.
Cons: Complex behavior.
Option 3 seems like the best option to me. What is the 8 digit epoch format you mentioned?
We could look at requiring users to cast timestamps to integer.
The 8-digit timestamps cover a 3 year range from about 1970 to 1973.