PHP и MySQL:Ошибка 2038 года:Что это такое?Как это решить?

StackOverflow https://stackoverflow.com/questions/2012589

  •  19-09-2019
  •  | 
  •  

Вопрос

Я подумывал об использовании метки времени для хранения даты + времени, но я прочитал, что на нее наложено ограничение 2038 годом.Вместо того чтобы задавать свой вопрос в целом, я предпочел разбить его на небольшие части, чтобы начинающим пользователям было легко его понять.Итак, мой вопрос (ы):

  1. В чем именно заключается проблема 2038 года?
  2. Почему это происходит и что происходит, когда это происходит?
  3. Как мы можем это решить?
  4. Существуют ли какие-либо возможные альтернативы его использованию, которые не создают подобной проблемы?
  5. Что мы можем сделать с существующими приложениями, использующими временную метку, чтобы избежать так называемой проблемы, когда она действительно возникает?

Заранее благодарю.

Это было полезно?

Решение

Я пометил это как вики-страницу сообщества, так что не стесняйтесь редактировать на досуге.

В чем именно заключается проблема 2038 года?

"Проблема 2038 года (также известная как ошибка тысячелетия Unix, Y2K38 по аналогии с проблемой Y2K) может привести к сбою некоторых компьютерных программ до или в 2038 году.Проблема затрагивает все программное обеспечение и системы, которые хранят системное время в виде 32-разрядного целого числа со знаком и интерпретируют это число как количество секунд, прошедших с 00:00:00 UTC 1 января 1970 года ".


Почему это происходит и что происходит, когда это происходит?

Времена за пределами 03:14:07 UTC во вторник, 19 января 2038 года будет "обернуто" и сохранено внутри в виде отрицательного числа, которое эти системы будут интерпретировать как время 13 декабря 1901 года, а не в 2038 году.Это связано с тем фактом, что количество секунд, прошедших с эпохи UNIX (1 января 1970 года 00:00:00 GMT), превысит максимальное значение компьютера для 32-разрядного целого числа со знаком.


Как мы можем это решить?

  • Используйте длинные типы данных (достаточно 64 бит).
  • Для MySQL (или MariaDB), если вам не нужна информация о времени, рассмотрите возможность использования DATE тип столбца.Если вам нужна более высокая точность, используйте DATETIME вместо того , чтобы TIMESTAMP.Остерегайтесь этого DATETIME столбцы не хранят информацию о часовом поясе, поэтому вашему приложению необходимо будет знать, какой часовой пояс был использован.
  • Другие возможные решения, описанные в Википедии
  • Подождите, пока разработчики MySQL исправят этот баг сообщалось более десяти лет назад.

Существуют ли какие-либо возможные альтернативы его использованию, которые не создают подобной проблемы?

Старайтесь везде, где это возможно, использовать большие типы для хранения дат в базах данных:достаточно 64 бит - длинный тип long в GNU C и POSIX / SuS, или sprintf('%u'...) в PHP или расширении BCMath.


Каковы некоторые потенциально опасные варианты использования, хотя мы еще не в 2038 году?

Итак, MySQL ДАТА - ВРЕМЯ имеет диапазон 1000-9999, но ВРЕМЕННАЯ МЕТКА имеет только диапазон 1970-2038.Если ваша система хранит даты рождения, будущие даты (напримерипотека на 30 лет) или аналогичная, вы уже столкнетесь с этой ошибкой.Опять же, не используйте ВРЕМЕННУЮ метку, если это может стать проблемой.


Что мы можем сделать с существующими приложениями, использующими временную метку, чтобы избежать так называемой проблемы, когда она действительно возникает?

В 2038 году все еще будет существовать несколько приложений PHP, хотя это трудно предвидеть, поскольку веб пока едва ли является устаревшей платформой.

Ниже приведен процесс изменения столбца таблицы базы данных для преобразования TIMESTAMP Для DATETIME.Все начинается с создания временного столбца:

# rename the old TIMESTAMP field
ALTER TABLE `myTable` CHANGE `myTimestamp` `temp_myTimestamp` int(11) NOT NULL;

# create a new DATETIME column of the same name as your old column
ALTER TABLE `myTable` ADD `myTimestamp` DATETIME NOT NULL;

# update all rows by populating your new DATETIME field
UPDATE `myTable` SET `myTimestamp` = FROM_UNIXTIME(temp_myTimestamp);

# remove the temporary column
ALTER TABLE `myTable` DROP `temp_myTimestamp`

Ресурсы

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

При использовании временных меток UNIX для хранения дат вы фактически используете 32-битные целые числа, которые ведут отсчет количества секунд с 1970-01-01 ;видишь Время Unix

Это 32-битное число переполнится в 2038 году.Это проблема 2038 года.


Чтобы решить эту проблему, вы не должны использовать 32-битную временную метку UNIX для хранения ваших дат - это означает, что при использовании MySQL вы не должны использовать TIMESTAMP, но DATETIME (см. 10.3.1.Типы DATETIME, ДАТА и ВРЕМЕННАЯ МЕТКА) :

В DATETIME тип используется, когда вам нужны значения, содержащие как дату, так и информацию о времени.Поддерживаемый диапазон составляет '1000-01-01 00:00:00' Для '9999-12-31 23:59:59'.

В TIMESTAMP тип данных имеет диапазон из '1970-01-01 00:00:01' UTC до '2038-01-19 03:14:07' UTC.


В (вероятно) лучшее, что вы можете сделать для своего приложения, чтобы избежать / устранить эту проблему, - это не использовать TIMESTAMP, но DATETIME для столбцов, которые должны содержать даты, не относящиеся к периоду с 1970 по 2038 год.

Однако одно маленькое замечание :существует очень высокая вероятность (с точки зрения статистики) что ваше приложение будет переписано довольно много раз до 2038 года ^^ Так что, возможно, если вам не придется иметь дело с датами в будущем, вам не придется решать эту проблему с текущей версией вашего приложения...

Быстрый поиск в Google сделает свое дело: Проблема 2038 года

  1. Проблема 2038 года (также известная как ошибка тысячелетия Unix, Y2K38 по аналогии с проблемой Y2K) может привести к сбою некоторых компьютерных программ до или в 2038 году
  2. Проблема затрагивает все программное обеспечение и системы, которые хранят системное время в виде 32-разрядного целого числа со знаком и интерпретируют это число как количество секунд, прошедших с 00:00:00 UTC 1 января 1970 года.Последнее время, которое можно представить таким образом, - 03:14:07 UTC во вторник, 19 января 2038 года.Время после этого момента будет "обернуто" и сохранено внутри в виде отрицательного числа, которое эти системы будут интерпретировать как дату в 1901, а не в 2038 году
  3. Для существующих комбинаций CPU / OS, существующих файловых систем или существующих форматов двоичных данных нет простого решения этой проблемы

http://en.wikipedia.org/wiki/Year_2038_problem содержит большинство деталей

В заключение:

1) + 2) Проблема в том, что многие системы хранят информацию о дате в виде 32-разрядного int со знаком, равного количеству секунд, прошедших с 1/1/1970.Последняя дата, которая может быть сохранена таким образом, - 03:14:07 UTC во вторник, 19 января 2038 года.Когда это произойдет, значение int "обернется" и будет сохранено как отрицательное число, которое будет интерпретировано как дата в 1901 году.Что именно произойдет тогда, зависит от системы к системе, но достаточно сказать, что это, вероятно, не принесет пользы ни одной из них!

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

3) Используйте один из доступных альтернативных форматов даты или перейдите на 64-разрядную систему и используйте 64-разрядные целые числа.Или для баз данных используйте альтернативный формат временной метки (например, для MySQL используйте DATETIME)

4) Смотри 3!

5) Смотри 4!!!;)

Братаны, если вам нужно использовать PHP для отображения временных меток, это ЛУЧШЕЕ PHP-решение без перехода от формата UNIX_TIMESTAMP.

Используйте функцию custom_date().Внутри него используйте DateTime. Вот решение для даты и времени.

До тех пор, пока у вас есть НЕПОДПИСАННЫЙ BIGINT(8) в качестве временных меток в базе данных.До тех пор, пока у вас есть PHP 5.2.0 ++

Поскольку я не хотел ничего обновлять, я попросил свой серверный сервер (MSSQL) выполнить эту работу вместо PHP!

$qry = "select DATEADD(month, 1, :date) next_date ";
$rs_tmp = $pdo->prepare($qry);
$rs_tmp->bindValue(":date", '2038/01/15');
$rs_tmp->execute();
$row_tmp = $rs_tmp->fetch(PDO::FETCH_ASSOC);

echo $row_tmp['next_date'];

Возможно, это неэффективный способ, но он работает.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top