Проблемы с датировкой PHP при переходе на летнее время
Вопрос
У меня возникла очень странная ошибка в каком-то имеющемся у меня PHP-коде.Страница предназначена для управления зачислением студентов на курсы.На странице представлена таблица курсов студента, и в каждой строке указано количество дат:когда они поступили, когда они закончили, когда они прошли оценку и когда они получили свой сертификат.
Данные таблицы генерируются PHP (извлекая данные из базы данных), а Javascript фактически визуализирует таблицу.Результатом работы PHP является JS-код, который выглядит примерно так:
var e = new Enrolment();
e.contactId = 5801;
e.enrolId = 14834;
e.courseId = 3;
e.dateEnrolled = new Date(1219672800000);
e.dateCompleted = new Date(-1000); // magic value meaning they haven't completed.
e.resultDate = new Date(1223647200000);
e.certDate = new Date(1223560800000);
e.result = 95;
e.passed = true;
enrolments[14834] = e;
В базе данных все поля даты хранятся в виде DATE
(не DATETIME
) поля.
Ошибка заключается в том, что даты отображаются как один выходной.Я бы заподозрил, что это во многом связано с тем, что сервер находится в районе, где действует летнее время, тогда как здесь его нет (это означает, что серверное время отключено на один час).Это многое объясняет, особенно то, как подготовка данных и рендеринг выполняются в двух разных часовых поясах.Это:сервер сообщает клиенту, что пользователь завершил работу в полночь 15 августа, а клиент интерпретирует это как 11 вечера 14-го и, следовательно, отображает 14 августа.
Но вот что сбивает с толку:это делается только для полей resultDate и certDate!Я скопировал данные на свой локальный сервер и обнаружил, что рабочий сервер фактически отправляет другую временную метку (ту, которая отключена на 1 час) только для этих двух полей, тогда как поле dateEnrolled остается тем же самым.
Вот результат, использующий точно такой же код и данные из базы данных:
// local server (timezone GMT+1000)
e.dateEnrolled = new Date(1219672800000); // 26 Aug 2008 00:00 +10:00
e.dateCompleted = new Date(-1000);
e.resultDate = new Date(1223647200000); // 11 Oct 2008 00:00 +10:00
e.certDate = new Date(1223560800000); // 10 Oct 2008 00:00 +10:00
// production server (timezone GMT+1100)
e.dateEnrolled = new Date(1219672800000); // 26 Aug 2008 00:00 +10:00
e.dateCompleted = new Date(-1000);
e.resultDate = new Date(1223643600000); // 10 Oct 2008 23:00 +10:00 **
e.certDate = new Date(1223557200000); // 09 Oct 2008 23:00 +10:00 **
Я могу понять, была ли это проблема из-за того, что переход на летнее время не учитывался, но обратите внимание, что введенная дата одинакова?
PHP- код, который преобразует дату MySQL в временную метку unix, выглядит следующим образом:
list ($year, $month, $day) = explode ('-', $mysqlDT);
$timestamp = mktime (0,0,0, $month, $day, $year);
Есть какие-нибудь идеи о том, как это исправить?
Решение
Это потому, что вы используете mktime, который зависит от конкретной локали.То есть он преобразует его в количество секунд с 00:00: 00 1970-1-1 по Гринвичу, и это смещается на 1 час с одним часовым поясом.
Вы также должны помнить, что javascript использует тот же часовой пояс, что и браузер, а не веб-страница.
e.resultDate = new Date(year, month - 1, day);
Это гарантирует, что дата будет одинаковой для каждого зрителя из каждого часового пояса.
Или вы можете использовать gmmktime и использовать методы UTC в Date.
Другие советы
Хорошо, я только что понял, почему это портит одно свидание, но не другое.В августе переход на летнее время не действовал. мазок для лица
- всегда храните даты / datetimes в GMT / UTC
- внимательно посмотрите на запрос, который извлекает эти значения, есть что-нибудь отличающееся от тех, которые корректируются?
- если нет, то все ли они являются меткой времени, датой или datetime?
Скорее всего, это будет проблема экономии дневного света.Причина, по которой это делается только для resultDate и certDate, заключается в том, что dateEnrolled приходится на август, переход на летнее время обычно начинается / заканчивается в конце сентября или начале октября.
Установите параметр date.timezone ini в качестве часового пояса вашего приложения, используя apache.conf, .htaccess или ini_set().