PHP и MySQL: 2038 год. Ошибка: что это? Как это решить? - PullRequest
93 голосов
/ 06 января 2010

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

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

Заранее спасибо.

Ответы [ 6 ]

123 голосов
/ 06 января 2010

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

Что именно является проблемой 2038 года?

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


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

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


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

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

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

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


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

Таким образом, MySQL DATETIME имеет диапазон 1000-9999, а TIMESTAMP имеет диапазон только 1970-2038. Если ваша система хранит даты рождения, будущие форвардные даты (например, 30-летние ипотеки) или аналогичные, вы уже столкнетесь с этой ошибкой. Опять же, не используйте TIMESTAMP, если это будет проблемой.


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

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

Вот процесс изменения столбца таблицы базы данных для преобразования 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`

Ресурсы

12 голосов
/ 06 января 2010

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

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


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

Тип 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 года ^^ Так что, возможно, если вы не В будущем вам не придется разбираться с датами, вам не придется решать эту проблему с текущей версией вашего приложения ...

7 голосов
/ 06 января 2010

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

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

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

В итоге:

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

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

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

4) См. 3!

5) См. 4 !!!;)

1 голос
/ 13 октября 2010

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

Используйте функцию custom_date (). Внутри используйте DateTime. Вот решение DateTime .

Пока у вас есть UNSIGNED BIGINT (8) в качестве ваших меток времени в базе данных. Пока у вас есть PHP 5.2.0 ++

0 голосов
/ 15 июля 2016

Поскольку я не хотел ничего обновлять, я попросил свой бэкэнд (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'];

Может не быть эффективным способом, но он работает.

...