Кто-нибудь знает PHP-код для исправления конфликтного изменения времени в стране?

Например, когда страна меняет время, есть 2 возможности:

1.- Если время меняется на более раннее, например, в 3 часа ночи в Центральной Европе, последнее воскресенье октября в 3 часа ночи становится 2 часами ночи, поэтому, если есть дата в 02:30, 2 Даты и Возможны часы: один до Изменения, и один после Изменения.

2.- В Центральной Европе последнее воскресенье марта в 2 часа ночи становится 3 часами ночи, поэтому, если кто-то установит дату/время следующим образом: 31.03.2024 в 02:30, это МЕСТНОЕ время. Это теоретически невозможно, поскольку между 2 и 3 нет возможности местного времени.

Есть ли какой-нибудь код, предупреждающий об этом?

Например, у меня есть этот код на PHP, я передаю ему часовой пояс, и он не предупреждает меня, что это время, 02:30:00, официально невозможно, и я хотел бы, чтобы он предупреждал меня об этих конфликтующих часах. :

(В коде JulianDay есть ошибка, ниже делаю комментарий с исправлением, это небольшая ошибка, ссылка уже исправлена)

https://timezonespro.com/php/test4.php?tzname=Europe/Madrid

<?php
$timezoneStr = $_GET["tzname"];
echo "TimeZone = " . $timezoneStr;


$datetime = "2024-03-31 02:30:00";
print '<br>';
echo "Local = " . $datetime;
$given = new DateTime($datetime, new DateTimeZone($timezoneStr));
$given->setTimezone(new DateTimeZone("UTC"));
$output = $given->format("Y-m-d H:i:s"); 
print '<br>';
echo "UTC = " . $output;

$ano = substr($output, 0, 4);
$mes = substr($output, 5, 2);
$dia = substr($output, 8, 2);
$hor = substr($output, 11, 2);
$min = substr($output, 14, 2);
$sec = substr($output, 17, 2);
print '<br>';
echo "Year = " . $ano;
print '<br>';
echo "Month = " . $mes;
print '<br>';
echo "Day = " . $dia;
print '<br>';
echo "Hours = " . $hor;
print '<br>';
echo "Minutes = " . $min;
print '<br>';
echo "Seconds = " . $sec;

$meses = ["Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"];
$mesStr = $meses[intval($mes) - 1];

print '<br>';
echo $dia . "-" . $mesStr . "-" . $ano . " a las " . $hor . ":" . $min . ":" . $sec;

$secondsInTime = intval($hor * 3600) + intval($min * 60) + intval($sec);
$secondsInTimeDec = $secondsInTime / 86400;

$jd = GregorianToJD($mes, $dia, $ano);
$jdDec = intval($jd) + $secondsInTimeDec;
print '<br>';
echo "JulianDay = " . $jdDec;
?>

Кодекс, предупреждающий о противоречивых временах во времени, меняется в стране.

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
4
0
95
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Ответ принят как подходящий

DateTime уже занимается такими случаями:

$dt = new DateTime('2024-03-31 02:30:00', new DateTimeZone('Europe/Madrid'));
echo $dt->format('Y-m-d H:i:s'); // prints: 2024-03-31 03:30:00

Обратите внимание, как «невозможные» 02:30 автоматически стали 03:30.

Предупреждения нет, но вы всегда можете сравнить отформатированные Y-m-d H:i:s строки даты с информацией о часовом поясе и без нее, если вам нужно проверить, произошло ли это.

Небольшая ошибка в моем коде в JulianDay, исправление:

    <?php
$timezoneStr = $_GET["tzname"];
echo "TimeZone = " . $timezoneStr;


$datetime = "2024-03-31 02:30:00";
print '<br>';
echo "Local = " . $datetime;
//$given = new DateTime($datetime, new DateTimeZone("Europe/Madrid"));
$given = new DateTime($datetime, new DateTimeZone($timezoneStr));
$given->setTimezone(new DateTimeZone("UTC"));
$output = $given->format("Y-m-d H:i:s"); 
print '<br>';
echo "UTC = " . $output;

$ano = substr($output, 0, 4);
$mes = substr($output, 5, 2);
$dia = substr($output, 8, 2);
$hor = substr($output, 11, 2);
$min = substr($output, 14, 2);
$sec = substr($output, 17, 2);
print '<br>';
echo "Year = " . $ano;
print '<br>';
echo "Month = " . $mes;
print '<br>';
echo "Day = " . $dia;
print '<br>';
echo "Hours = " . $hor;
print '<br>';
echo "Minutes = " . $min;
print '<br>';
echo "Seconds = " . $sec;

$meses = ["Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"];
$mesStr = $meses[intval($mes) - 1];

print '<br>';
echo $dia . "-" . $mesStr . "-" . $ano . " a las " . $hor . ":" . $min . ":" . $sec;

$secondsInTime = intval($hor * 3600) - intval(12 * 3600) + intval($min * 60) + intval($sec);
$secondsInTimeDec = $secondsInTime / 86400;

$jd = GregorianToJD($mes, $dia, $ano);
$jdDec = intval($jd) + $secondsInTimeDec;
print '<br>';
echo "JulianDay = " . $jdDec;
?>

Исправление в этой части:

$secondsInTime = intval($hor * 3600) - intval(12 * 3600) + intval($min * 60) + intval($sec);

Поскольку инициализация JulianDay в 12 часов дня, для этого необходимо добавить "- intval(12 * 3600)"

И что ж, можно перечислить все изменения времени и найти даты, в которых возникают эти проблемы, но я искал, есть ли кто-нибудь, кто уже это сделал.

Например, с помощью этого кода вы можете перечислить все изменения в часовом поясе «Европа/Мадрид», а затем проверить, является ли дата и время частью проблем с изменениями времени:

https://timezonespro.com/php/get_from_tz_allchanges_b.php?tzname=Europe/Madrid

Код:

<?php
$timezoneStr = $_GET["tzname"];
print_r('timezone = ' . $timezoneStr . '@');
print '<br>';
$timezone_identifiers = DateTimeZone::listIdentifiers();
for ($i=0; $i < 1005; $i++)
    {
    if ($timezone_identifiers[$i] == "")
        break;
    else if ($timezone_identifiers[$i] == $timezoneStr)
        {
        $timezone = new DateTimeZone($timezone_identifiers[$i]);
        $transitions = $timezone->getTransitions();
        for ($k=0; $k<500; $k++)
            {
            if ($transitions[$k] == "")
                break;
            $UnixTimeStamp = $transitions[$k][ts];
            $julianDay = ($UnixTimeStamp / 86400) + 2440587.5;
            print_r('UnixTimeStamp = ' . $UnixTimeStamp . ' | ');
            print_r('JulianDay = ' . $julianDay . ' | ');
            print_r('DateTime (Time) = ' . $transitions[$k][time] . ' | ');
            print_r('Seconds Difference to GMT (Offset) = ' . $transitions[$k][offset] . ' | ');
            print_r('Is Dst (IsDst) = ' . $transitions[$k][isdst] . ' | ');
            print_r('TimeZone Abreviation (Abbr) = ' . $transitions[$k][abbr] . '@');
            Print '<br>';
            }
        return;
        }
    }
return;

?>

Я ищу, был ли уже кто-то, кто это сделал. Ну, это должно быть что-то, что делалось уже давно, подобные проблемы с изменением времени возникают всегда.

И я думаю, что в php это уже должно быть исправлено, и когда есть официально невозможные часы, оповещать, а когда возможны двойные часы, тоже оповещать.

Необходимо принять во внимание, что когда Страна меняет и задерживает время, всегда будет и было 2 возможных часа, пример, который я привел, 27 октября 2024 года в Центральной Европе в 03:00:00 утра, становится 02: 00:00, поэтому есть 2 возможных часа:

Например: 27 октября 2024 в 02:30:00

Это может быть 02:30:00 до внесения изменения или 02:30:00 после внесения изменения, и я видел, что на многих сайтах это не исправляют - php тоже не выдает предупреждения - , и поэтому, например, для данных JulianDay, используемых в астрономии, это проблема, поскольку существует 2 возможных юлианских дня, и это сильно меняется на астрономическом уровне.

И то же самое при изменении наоборот, если 2 часа ночи становятся 3 часами ночи, как официальные часы, потому что официально между 02:00:00 и 02:59:59 промежуточных часов нет. И в вопросах совершенствования, и особенно в Астрономии, важно иметь это в виду.

Как отметил lafor, PHP DateTime сделает это за вас.

Добавьте эти строки после создания объекта DateTime:

if ($given->format('Y-m-d H:i:s') != $datetime) {
    echo "WARNING: $datetime is impossible in $timezoneStr. Automatically adjusted to account for daylight savings time.";
}
<?php
$timezoneStr = $_GET["tzname"];
echo "TimeZone = " . $timezoneStr;


$datetime = "2024-03-31 02:30:00";
print '<br>';
echo "Local = " . $datetime;
$given = new DateTime($datetime, new DateTimeZone($timezoneStr));

// check if $given was adjusted for daylight savings in locale
if ($given->format('Y-m-d H:i:s') != $datetime) {
    echo "WARNING: $datetime is impossible in $timezoneStr. Automatically adjusted to account for daylight savings time.";
}


$given->setTimezone(new DateTimeZone("UTC"));
$output = $given->format("Y-m-d H:i:s"); 
print '<br>';
echo "UTC = " . $output;

$ano = substr($output, 0, 4);
$mes = substr($output, 5, 2);
$dia = substr($output, 8, 2);
$hor = substr($output, 11, 2);
$min = substr($output, 14, 2);
$sec = substr($output, 17, 2);
print '<br>';
echo "Year = " . $ano;
print '<br>';
echo "Month = " . $mes;
print '<br>';
echo "Day = " . $dia;
print '<br>';
echo "Hours = " . $hor;
print '<br>';
echo "Minutes = " . $min;
print '<br>';
echo "Seconds = " . $sec;

$meses = ["Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"];
$mesStr = $meses[intval($mes) - 1];

print '<br>';
echo $dia . "-" . $mesStr . "-" . $ano . " a las " . $hor . ":" . $min . ":" . $sec;

$secondsInTime = intval($hor * 3600) + intval($min * 60) + intval($sec);
$secondsInTimeDec = $secondsInTime / 86400;

$jd = GregorianToJD($mes, $dia, $ano);
$jdDec = intval($jd) + $secondsInTimeDec;
print '<br>';
echo "JulianDay = " . $jdDec;
?>

Кстати, возможно, вы захотите попробовать Carbon. Я не имею никакого отношения к его разработке, но я использовал его всякий раз, когда это было возможно, с тех пор, как обнаружил несколько лет назад. Это избавило меня от бесчисленных головных болей.

Большое спасибо, хороший код, тестирую!!! Спасибо, Райли...

Jaime Reynolds 19.06.2024 17:09

Огромное спасибо Райли!!! В одном вопрос, можно ли, а в другом поменять? Есть ли небольшой код PHP - как вы пишете, простой и небольшой полезный код - который предупреждает, что есть 2 возможных часа? Например, 27 октября 2024 года время в Центральной Европе изменится, в 03:00:00 оно станет 02:00:00, и между 02:00:00 и 02 будет 2 возможных часа: 59:59... Например, в 02:30:00 до Изменения будет 02:30:00, а после Изменения — 02:30:00. Есть ли что-то в PHP, которое предупреждает, что будет 2 возможных часа? Заранее спасибо.

Jaime Reynolds 19.06.2024 17:28

Рад, что это сработало. Не забудьте проголосовать за и отметить ответ как принятый. Мадрид теряет час 27 октября 2024 г., и в этом случае перед изменением будет 02:30, затем после 02:59 часы вернутся к 02:00, и вы снова увидите 02:30. Однако PHP не может узнать, о каком 02:30 вы говорите, когда вы создаете DateTime с «2024-10-27 02:30:00». Однако, если вы используете Carbon со строкой «2024-10-27 01:30:00» и добавляете два часа, он правильно скажет, что время по-прежнему 02:30. Carbon::parse("2024-10-27 01:30:00", "Europe/Madrid")->addHours(2)

rileys 20.06.2024 15:16

Моя проблема состоит в том, чтобы тратить время на знание того, как работает Carbon, и я думаю, что это можно сделать с помощью функций PHP, я что-то сделал, и это работает хорошо, но не идеально, мне нужно посмотреть, как поступить, когда изменения задерживают время с помощью getTransitions(); Это должно быть возможно сделать, я проверяю... Но очень благодарен за ваше время, Райли...

Jaime Reynolds 21.06.2024 01:39

ЭТОТ КОД РАБОТАЕТ!!!

Его нужно немного доработать под нужды каждого человека, но он работает хорошо - я думаю, хотя мне еще придется сверяться с другими часовыми поясами, но я думаю, что он работает хорошо -.

Но он УЖЕ УВЕДОМЛЯЕТ, если дата/время для часового пояса невозможны - в случае, если место меняет официальное время путем добавления, то есть, например, в 02:00:00 оно становится 03:00:00. и установите дату и время, например 02:30:00, время, которое официально невозможно.

И он УЖЕ УВЕДОМЛЯЕТ, если дата/время для часового пояса имеет 2 возможных часа, один до изменения, а другой после изменения - в случае, если место меняет официальное время с вычитанием, то есть, например, в 03:00:00. Время утра становится 02:00:00, а час устанавливается как 02:30:00, время, которое может быть до изменения или после него.

https://timezonespro.com/php/test8b.php?tzname=Europe/Madrid

Код здесь: https://timezonespro.com/php/test8b.txt

Исправление JulianDay, которое я прокомментировал в сообщении ниже, уже заложено в коде и всё проверено.

Привет... Спасибо, Райли!!!

Другие вопросы по теме