Объект Cake\I18n\Time отображает неправильный час плюс летнее время

У меня есть проект CakePHP 3 с такими конфигурациями:

приложение.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');

Когда я

echo date("Y-m-d H:i:s"); показывает правильную дату и время;

Но когда я

$data = Time::now();

а также

echo $data;

Он показан с +1 часом, потому что раньше мы добавляли один час на летнее время, но в этом году его отменили.

Странно то, что когда я отлаживаю $data, он показывает правильно, без +1 часа:

\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`

Я пытался добавить часовой пояс с помощью

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

а также

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

Но все равно показывает с +1 час.

ОБНОВЛЕНИЕ

Вот тесты для воспроизведения проблемы:

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);

И мои результаты:

\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'
    ]
]

Модули:

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

person Gabriel Souto    schedule 24.10.2019    source источник
comment
Вы вряд ли получите какие-либо (хорошие) ответы, если люди не смогут правильно воспроизвести проблему (gist.github.com/ndm2/df004c19e3eebe5002043a4ab385d278). Ныне несуществующее летнее время в Бразилии было бы запланировано на 3 ноября, поэтому, даже если ваша установка PHP не будет знать об этом, в любом случае не должно быть применено никаких изменений летнего времени прямо сейчас.   -  person ndm    schedule 24.10.2019
comment
@ndm спасибо, но я думаю, вы неправильно поняли, несуществующее летнее время в Бразилии началось в этом году, раньше в Бразилии было летнее время. я обновлю свой вопрос тестами, которые вы разместили в gist.   -  person Gabriel Souto    schedule 25.10.2019
comment
Я думаю, что понял, и я думаю, что я прав в своей оценке, начало летнего времени (т.е. -02:00) для Бразилии было первым воскресеньем ноября (по состоянию на 2018 год), а окончание летнего времени (т.е. -03:00) было третьим. Воскресенье февраля. Таким образом, даже если бы летнее время все еще существовало, в настоящее время вы все равно были бы без летнего времени (-03:00). Глядя на информацию о переходе, правильно видно, как выглядели переходы, и он правильно показывает, что в настоящее время он находится в диапазоне, отличном от летнего времени.   -  person ndm    schedule 25.10.2019
comment
Глядя на ваш вывод отладки, обычное форматирование показывает правильный результат, т.е. 09:34:37, форматирование INTL показывает неправильный результат, т.е. 10:34:37. Я предлагаю протестировать его с новым пустым проектом CakePHP (используя самую последнюю версию CakePHP) и убедиться, что ваши библиотеки INTL и ICU обновлены. У меня gist.github.com/ndm2/231a5277a617e5d304987f13bc794947 работает нормально . Обновление базы данных часовых поясов также не повредит, и я не уверен, действительно ли это необходимо, но похоже, что вам не хватает timelib?   -  person ndm    schedule 25.10.2019
comment
Спасибо за ваше терпение и помощь, часть моей проблемы заключается в том, что переход на летнее время в Бразилии начинается в 3-е воскресенье октября, а не в первое воскресенье ноября. Моя среда разработки и производства — это Windows Server с apache и php 7.0, и я уже обновил часовой пояс здесь: pecl.php. net/package/timezonedb с 2018.7, которая была последней версией для php 7.0   -  person Gabriel Souto    schedule 25.10.2019
comment
Дата 3-го воскресенья октября была изменена в 2017 году, а в 2018 году летнее время было запланировано на 1 воскресенье ноября, и это отражено в выходных данных отладки переходов, в которых показано изменение для 2019-11-03T03:00:00+0000. Возможно, вы используете устаревшую библиотеку INTL / ICU, которая не знает об этом изменении, это мое лучшее предположение, но я действительно просто стреляю в темноту.   -  person ndm    schedule 25.10.2019
comment
Еще раз спасибо @ndm, это, вероятно, проблема, потому что в моей среде есть старый php 7.0 и, возможно, в комплекте intl   -  person Gabriel Souto    schedule 29.10.2019


Ответы (1)


Проблема в операционной системе, в которой запущено приложение. Правила часового пояса для перехода на летнее время устарели. Бразилия недавно изменила правила перехода на летнее время. Но и другие правительства могут сделать это в любое время.

Организация IANA поддерживает актуальный банк с часовыми поясами и другими характеристиками. Последняя версия — 2019c, опубликована 11 сентября 2019 г. [1].

CAKEPHP Framework использует библиотеку PHP INTL. Библиотека PHP INTL использует библиотеку ICU, которая является частью пакетов дистрибутива Linux [2< /а>]. И библиотека ICU использует данные IANA.

Таким образом, устаревшая версия ICU повлияет на то, как PHP обрабатывает даты.

Вы можете проверить версию ICU на phpinfo() или с помощью команды:

php -i | grep ICU

Последняя версия библиотеки ICU — 65.1, опубликованная 03.10.2019 [3] и не включает версию IANA 2019c. Однако вы можете видеть, что в репозитории ICU они уже обновили файл zoneinfo64.txt для будущих выпусков data/misc/zoneinfo64.txt" rel="nofollow noreferrer">4].

Последняя версия ICU для CentOS 8 — 60.5 [5]. Если вы находитесь в дистрибутиве Amazon AMI (EC2, EBS, RDS), будет еще хуже, поскольку последняя версия (2018-05-14) ICU для их дистрибутива — 50.1.2 [6]. Последний имеет дату выпуска 2012-12-17 [7]

Если вы являетесь экспертом в загрузке и компиляции служб Linux, вы можете скомпилировать пакет ICU, используя последний исходный код.

Если вы согласны с общим решением, вы можете временно использовать часовой пояс Америка/Форталеза вместо Америка/Сан-Паулу. Зона Форталеза не перешла на летнее время с 2012 года.

person William    schedule 18.11.2019
comment
Привет, Уильям, спасибо, ты прав, и я временно использую Америку/Ресифи. Но, к сожалению, я использую PHP 7.0 на сервере Windows, и я буду ждать обновления php 7.4 позже в этом году. Проблема не в моем SO, это мой intl+icu устарел. - person Gabriel Souto; 19.11.2019
comment
Мужик, ты спас мне жизнь! - person chuckedw; 12.02.2020