PHP & mySQL: Рік 2038 Помилка: що це? Як це вирішити?


116

Я думав використовувати TIMESTAMP для зберігання дати + часу, але прочитав, що на нього існує 2038 рік. Замість того, щоб задавати моє запитання оптом, я вважав за краще розбити його на невеликі частини, щоб початківцям користувачам було зрозуміло також. Тож моє питання:

  1. Що саме є проблемою Рік 2038?
  2. Чому вона виникає і що відбувається, коли вона виникає?
  3. Як ми її вирішуємо?
  4. Чи існують можливі альтернативи його використанню, які не становлять подібної проблеми?
  5. Що ми можемо зробити з існуючими програмами, які використовують TIMESTAMP, щоб уникнути так званої проблеми, коли вона дійсно виникає?

Заздалегідь спасибі.


1
Це ще 28 років. Ви все ще використовуєте будь-яку технологію, пов'язану з комп'ютером, з 1982 року? Навряд чи. Тож не хвилюйтеся, адже до 2038 року це вже не буде проблемою.
Гордон

24
Гордон, я роблю програму, яка робить прогнозування. Я економлю, скільки грошей маю щомісяця, і потім можу оцінити, коли буду мільйонером. У моєму випадку 28 років не так вже й багато, і я впевнений, що я не єдиний, хто зараз має цю проблему (я вирішив її, використовуючи 64-бітні числа для позначення часової позначки).
Еміль Вікстрьом

2
@Emil Використовуючи 64-бітні цілі числа прямо зараз , ви знайшли просте рішення конкретної проблеми. Не застосовується до (або потрібного) всім, але працює для вашої корисної справи. Справа в тому, що якщо в ОП немає конкретної проблеми, як-от прогнозування, то це може бути цікавою темою, але нічого, про що він не повинен хвилюватися, адже вирішення цього питання на загальному рівні не є проблемою PHP (пам'ятай тег). Просто мій 2с.
Гордон

1
До 2038 р. Розбір рядка "РРРР-ММ-ДД HH: MM: SS: мммм ..." стане найдешевшою операцією, про яку можна мріяти. До 2038 року 32 біт буде застарілим. Я сумніваюся в часовій позначці Unix, оскільки ми знаємо, що вона буде існувати тоді, і якщо це станеться, наші 256-бітові системи оброблятимуть дати, що перевищують вік, коли 4096 бітових систем видаються під час їжі.
Супер Кіт

8
Гордон, його 9 років пізніше. TIMESTAMPS все ще використовується. Ми все ще використовуємо технології з 28 років тому. Його називають всесвітньою павутиною.
sfscs

Відповіді:


149

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

Що саме є проблемою Рік 2038?

"Проблема 2038 року (також відома як Bug Unilen Millennium Bug, 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-бітних - довгий довгий тип у GNU C та POSIX / SuS, або sprintf('%u'...)в PHP або розширенні BCmath.


Назвіть кілька можливих випадків використання, хоча ми ще не в 2038 році?

Отже, DATETIME MySQL має діапазон 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`

Ресурси


2
Дивовижно. На мій погляд, ваша відповідь є найповнішою. Велике спасибі
Девнер

7
У MySQL, якщо майбутня версія змінить базовий тип даних TIMESTAMP на 64-бітну, вам не потрібно змінювати код на DATETIME, правда? Я просто не думаю, що відволікати когось від використання TIMESTAMP - це не правильно, оскільки цей тип даних має своє призначення.
pixelfreak

1
Підписане поле MySQL BIGINT здається, що воно буде добре працювати для зберігання часових позначок, і я провів кілька локальних тестувань на MySQL 5.5, які підтверджують, що це працює. Очевидно, що використання підписаних було б краще, ніж без підпису, оскільки ви можете представляти дати і в минулому. Будь-яка причина не використовувати BIGINT для часових позначок?
zuallauz

Варто зазначити, що MySQL має лише автоматичні налаштування на поточну дату / час (CURRENT_TIMESTAMP) для полів часових позначок. Будемо сподіватися, що ця функціональність з часом перейде на всі типи дат.
Рей

5
Абсолютно абсурдно, що MySQL (і MariaDB) не використовують 64-бітні цілі числа для зберігання часових міток у 64-бітових системах. Використання DATETIME не є адекватним рішенням, оскільки ми не маємо уявлення про часовий пояс. Про це повідомлялося ще в 2005 році , але досі жодних виправлень немає.
Майк

14

Використовуючи часові позначки UNIX для зберігання дат, ви фактично використовуєте 32-бітні цілі числа, що зберігає підрахунок кількості секунд з 1970-01-01; див. час Unix

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


1
+1 Для отримання інформації. Спроба тут полягає в адаптації найкращих практик з самого початку, щоб потім не потрібно було хвилюватися з приводу проблеми. Тож хоча 2038 рік може не виглядати як проблема, я просто хочу дотримуватися кращих практик і дотримуватися його для кожного та кожного створеного нами додатку з самого початку. Сподіваюся, що це має сенс.
Девнер

Так, це має сенс, я бачу вашу думку. Але "найкраща практика" також може означати "що відповідає потребі" - Якщо ви знаєте, що часової позначки буде достатньо, немає необхідності використовувати дату (наприклад, для зберігання потрібно більше пам'яті; це може мати значення, якщо у вас мільйони записів) ;; У мене є додатки, в яких я використовую часові позначки для деяких стовпців (наприклад, стовпці, які містять поточну дату), а для деяких інших дати (наприклад, стовпці, які містять минулі / майбутні дати)
Pascal MARTIN

Я бачу, що ваша процедура також має сенс і працює добре, особливо що стосується місця для зберігання. Якщо це добре, я можу запитати вас, яку структуру та довжину ви зазвичай використовуєте для стовпця TIMESTAMP у своїх програмах? Дякую.
Девнер

Що ж, коли я хочу використовувати TIMESTAMP, це для / тому, що мої дані "дата / час" відповідають 1970 - 2038 роках - і, таким чином, я використовую тип даних MySQL TIMESTAMP.
Паскаль МАРТИН

Дякуємо за інформацію. З вашої відповіді я розумію, що досить просто оголосити стовпчик як TIMESTAMP, і нам не потрібно надати жодної довжини (на відміну від int або var, де ми надаємо довжину). Маю рацію?
Девнер

7

Швидкий пошук в Google зробить трюк: проблема 2038 року

  1. Проблема 2038 року (також відома як Bug Unilen Millennium Bug, Y2K38 за аналогією до проблеми Y2K) може призвести до виходу з ладу деяких програмного забезпечення комп'ютера до або в 2038 році
  2. Проблема стосується всіх програмного забезпечення та систем, які зберігають системний час, як підписане 32-бітове ціле число, і інтерпретують це число як кількість секунд з 00:00:00 UTC 1 січня 1970 року. Останній час, який можна представити таким чином є 03:14:07 UTC у вівторок, 19 січня 2038 р. Часи, що перевищують цей момент, "згортаються" і зберігатимуться всередині як від'ємне число, яке ці системи будуть інтерпретувати як дату 1901 року, а не 2038
  3. Не можна легко вирішити цю проблему для існуючих комбінацій процесора / ОС, існуючих файлових систем або існуючих форматів бінарних даних

2

http://en.wikipedia.org/wiki/Year_2038_problem містить більшість деталей

Підсумовуючи:

1) + 2) Проблема полягає в тому, що багато систем зберігають інформацію про дату як 32-розрядний підписаний int, рівний кількості секунд з 1.01.1970. Остання дата, яка може зберігатися таким чином, - 03:14:07 UTC у вівторок, 19 січня 2038 р. Коли це станеться, int "обернеться" і збережеться як негативне число, яке буде інтерпретуватися як дата в 1901 році. Що саме тоді станеться, залежить від системи до системи, але достатньо сказати, що, мабуть, це не буде корисним для жодної з них!

Що стосується систем, які зберігають дати лише в минулому, то, мабуть, вам не потрібно хвилюватися деякий час! Основна проблема полягає в системах, які працюють з датами в майбутньому. Якщо вашій системі в майбутньому потрібно працювати з датами 28 років, то вам слід почати хвилюватися зараз!

3) Використовуйте один із доступних альтернативних форматів дати або перейдіть до 64-бітної системи та використовуйте 64-бітні вставки. Або для баз даних використовуйте альтернативний формат штампів часу (наприклад, для використання MySQL DATETIME)

4) Дивіться 3!

5) Дивіться 4 !!! ;)


Ваші пункти 4 та 5 нагадують мені "Дзвінок по довіднику" Це поклало посмішку на моє обличчя. Дякуємо та +1 за те саме.
Девнер

1

Брати, якщо вам потрібно використовувати PHP для відображення часових позначок, це найкраще рішення PHP без зміни формату UNIX_TIMESTAMP.

Використовуйте функцію custom_date (). Всередині нього використовуйте DateTime. Ось рішення DateTime .

До тих пір, поки у вас немає часових позначок у базі даних НЕВИЗНАЧЕННЯ BIGINT (8). Поки у вас PHP 5.2.0 ++


-1

Оскільки я не хотів нічого оновлювати, я попросив свого бекенда (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'];

Це може бути не ефективним способом, але це працює.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.