Search code examples
phptimeinternationalizationcakephp-3.0dst

Cake\I18n\Time object echoes wrong hour plus daylight saving time


I have a CakePHP 3 project with those configurations:

app.php:

    'defaultLocale' => env('APP_DEFAULT_LOCALE', 'pt_BR'),
    'defaultTimezone' => env('APP_DEFAULT_TIMEZONE', 'America/Sao_Paulo'),

bootstrap.php

date_default_timezone_set('America/Sao_Paulo');

When i

echo date("Y-m-d H:i:s"); it shows right date and time;

But when i

$data = Time::now();

and

echo $data;

It is shown with +1 hour because we used to add one hour for dst but this year it was canceled.

The strange part is when i debug $data it shows right, without +1 hour:

\src\Controller\TesteController.php (line 104)
object(Cake\I18n\Time) {

    'time' => '2019-10-24T15:15:07-03:00',
    'timezone' => 'America/Sao_Paulo',
    'fixedNowTime' => false

}

echo data:24/10/2019 16:15:07`

I've tried to add Time Zone with

$dateTimeZoneBrasil = new \DateTimeZone("America/Sao_Paulo");

and

$data = Time::now($dateTimeZoneBrasil);

But still shows with +1 hour.

UPDATE

Here are the tests to reproduce the problem:

ini_set('intl.default_locale', 'pt_BR');
I18n::locale('pt_BR');
date_default_timezone_set('America/Sao_Paulo');
Time::setToStringFormat([\IntlDateFormatter::SHORT, \IntlDateFormatter::SHORT]);
$time = Time::now();
debug($time);
debug((string)$time);
debug($time->i18nFormat());
debug($time->i18nFormat('yyyy-MM-dd HH:mm:ss'));
debug($time->format('Y-m-d H:i:s'));
debug($time->getTimezone()->getTransitions(strtotime('2019-01-01'), strtotime('2020-01-01')));
phpinfo(INFO_MODULES);

And my results:

\src\Controller\TesteController.php (line 79)
object(Cake\I18n\Time) {

    'time' => '2019-10-25T09:34:37-03:00',
    'timezone' => 'America/Sao_Paulo',
    'fixedNowTime' => false

}
\src\Controller\TesteController.php (line 80)
'25/10/19 10:34'
\src\Controller\TesteController.php (line 81)
'25/10/19 10:34'
\src\Controller\TesteController.php (line 82)
'2019-10-25 10:34:37'
\src\Controller\TesteController.php (line 83)
'2019-10-25 09:34:37'
\src\Controller\TesteController.php (line 84)
[
    (int) 0 => [
        'ts' => (int) 1546308000,
        'time' => '2019-01-01T02:00:00+0000',
        'offset' => (int) -7200,
        'isdst' => true,
        'abbr' => '-02'
    ],
    (int) 1 => [
        'ts' => (int) 1550368800,
        'time' => '2019-02-17T02:00:00+0000',
        'offset' => (int) -10800,
        'isdst' => false,
        'abbr' => '-03'
    ],
    (int) 2 => [
        'ts' => (int) 1572750000,
        'time' => '2019-11-03T03:00:00+0000',
        'offset' => (int) -7200,
        'isdst' => true,
        'abbr' => '-02'
    ]
]

Modules:

date
date/time support   enabled
"Olson" Timezone Database Version   2018.7
Timezone Database   external
Default timezone    America/Sao_Paulo
Directive   Local Value Master Value
date.default_latitude   31.7667 31.7667
date.default_longitude  35.2333 35.2333
date.sunrise_zenith 90.583333   90.583333
date.sunset_zenith  90.583333   90.583333
date.timezone   America/Sao_Paulo   America/Sao_Paulo

Solution

  • The problem is in the operating system where the application is running. The time zone rules to DST are out of date. Brazil has changed its daylight saving time rules recently. But other governments can do this at any time as well.

    The IANA organization maintains an up-to-date bank with time zones and other characteristics. The latest version is 2019c, published at 2019-09-11 [1].

    The CAKEPHP Framework uses the PHP INTL library. The PHP INTL library uses ICU library which is part of the Linux distribution packages [2]. And ICU library uses the IANA data.

    So, an outdated version of ICU will affect how PHP handles dates.

    You can check the ICU version on phpinfo() or using the command:

    php -i | grep ICU
    

    The latest version of the ICU library is 65.1 and was published on 2019-10-03 [3] and doesn't include IANA version 2019c. However, you can see that in the ICU repository they have already updated the zoneinfo64.txt file for future releases [4].

    The latest version of ICU on CentOS 8 is 60.5 [5]. If you are in the Amazon AMI distribution (EC2, EBS, RDS) it will be even worse as the latest version (2018-05-14) of ICU for their distribution is 50.1.2 [6]. The latter has a release date at 2012-12-17 [7]

    If you are an expert in download and compile Linux services, you can compile the ICU package using the latest source code.

    If you can accept an outline solution, you can lie temporarily using the America/Fortaleza time zone instead of America/Sao_Paulo. Fortaleza zone hasn't belonged to daylight saving time since 2012.