cakephp / chronos

A standalone DateTime library originally based off of Carbon

Home Page:http://book.cakephp.org/chronos

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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.