Например, когда страна меняет время, есть 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;
?>
Кодекс, предупреждающий о противоречивых временах во времени, меняется в стране.






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. Я не имею никакого отношения к его разработке, но я использовал его всякий раз, когда это было возможно, с тех пор, как обнаружил несколько лет назад. Это избавило меня от бесчисленных головных болей.
Огромное спасибо Райли!!! В одном вопрос, можно ли, а в другом поменять? Есть ли небольшой код 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 возможных часа? Заранее спасибо.
Рад, что это сработало. Не забудьте проголосовать за и отметить ответ как принятый. Мадрид теряет час 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)
Моя проблема состоит в том, чтобы тратить время на знание того, как работает Carbon, и я думаю, что это можно сделать с помощью функций PHP, я что-то сделал, и это работает хорошо, но не идеально, мне нужно посмотреть, как поступить, когда изменения задерживают время с помощью getTransitions(); Это должно быть возможно сделать, я проверяю... Но очень благодарен за ваше время, Райли...
ЭТОТ КОД РАБОТАЕТ!!!
Его нужно немного доработать под нужды каждого человека, но он работает хорошо - я думаю, хотя мне еще придется сверяться с другими часовыми поясами, но я думаю, что он работает хорошо -.
Но он УЖЕ УВЕДОМЛЯЕТ, если дата/время для часового пояса невозможны - в случае, если место меняет официальное время путем добавления, то есть, например, в 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, которое я прокомментировал в сообщении ниже, уже заложено в коде и всё проверено.
Привет... Спасибо, Райли!!!
Большое спасибо, хороший код, тестирую!!! Спасибо, Райли...