Проблема високосного года
Проблема високосного года (известная также как баг високосного года или баг високосного дня) — это проблема как для цифровой (связанной с компьютерами), так и нецифровой документации и систем хранения данных, которая обусловлена ошибками в расчёте, какие годы являются високосными, или манипуляциями с датами без учёта разницы между високосными и обычными годами.
Категории
Ошибки, связанные с високосным годом, обычно делятся на две категории в зависимости от степени их влияния на реальное использование[1]:
- Те, которые приводят к условиям ошибок, таким как исключения, коды возврата ошибок, неинициализированные переменные или бесконечные циклы
- Те, которые приводят к некорректным данным, таким как проблемы с «единицей смещения» в запросах диапазона или агрегации
Примеры
Python
Приведённый ниже код на Python является примером ошибки категории 1.
Код будет работать корректно, пока переменная today (текущее время високосного года) не достигнет 29 февраля. Тогда, программа попытается создать дату 29 февраля следующего года, которой не существует. Конструктор date даст ошибку ValueError с сообщением «день выходит за пределы допустимого для месяца»[2].
from datetime import date
today = date.today()
later = today.replace(year = today.year + 1)
Windows C++
Приведённый ниже код на C++ для Windows является примером ошибки категории 1. Код будет работать корректно, пока текущая дата не станет 29 февраля високосного года. Затем код изменит st для представления 29 февраля невисокосного года, а такой даты не существует. Передавая st в любую функцию, принимающую структуру SYSTEMTIME в качестве параметра, скорее всего, приведёт к сбою.
Например, вызов SystemTimeToFileTime, показанный здесь, возвратит код ошибки. Поскольку этот код возврата не проверяется (что встречается крайне часто), это приведёт к тому, что структура ft останется неинициализированной[3].
SYSTEMTIME st;
FILETIME ft;
GetSystemTime(&st);
st.wYear++;
SystemTimeToFileTime(&st, &ft);
Microsoft C#
Следующий код на .NET C# является примером ошибки категории 1. Код будет работать корректно, пока dt (текущая дата) не станет 29 февраля високосного года. Тогда код попытается создать дату 29 февраля следующего года, которой не существует. Конструктор DateTime вызовет исключение ArgumentOutOfRangeException[4].
DateTime dt = DateTime.Now;
DateTime result = new DateTime(dt.Year + 1, dt.Month, dt.Day);
JavaScript
Следующий код на JavaScript является примером ошибки категории 2. Код будет работать корректно, пока dt (текущая дата) не станет 29 февраля високосного года, например, 2020-02-29. Тогда код попытается установить год в 2021. Поскольку дата 2021-02-29 не существует, объект Date перенесётся на следующую корректную дату, которой будет 2021-03-01[5].
var dt = new Date();
dt.setFullYear(dt.getFullYear() + 1);
Неверный алгоритм високосных лет (многие языки)
Следующий код является примером ошибки, который был замечен во множестве языков. Код приводит к ошибке категории 1 или 2, в зависимости от того, для чего используется результат. Алгоритм ошибочно предполагает, что високосный год случается каждый четвёртый год [6].
bool isLeapYear = year % 4 == 0;
Верный алгоритм проверки високосного года объясняется здесь: Григорианский календарь.
Происшествия
- Microsoft Excel, начиная с самых ранних версий, ошибочно считал 1900 год високосным, а потому 29 февраля появлялось между 28 февраля и 1 марта в этом году. Ошибка была унаследована от Lotus 1-2-3 и была намеренно имплементирована в Excel с целью обратной совместимости. Microsoft опубликовал статью, объясняющую причины такого подхода к 1900 году как високосному[7]. Впоследствии эта ошибка была закреплена как требование в спецификации Ecma Office Open XML (OOXML)[8][9].
- 31 декабря 1996 года на двух алюминиевых заводах в Тивай-Пойнт (Новая Зеландия) и Бэлл-Бэй (Тасмания, Австралия) в полночь отключились все 660 компьютеров, контролирующих линиями выплавки, поскольку компьютеры не были рассчитаны на обработку 366-го дня (1996 год был високосным и содержал дату 29 февраля). Стоимость ремонта была оценена более чем в миллион новозеландских долларов[10].
- 31 декабря 2000 года в Норвегии национальная железнодорожная компания Vy обнаружила, что все 29 её новых поездов Signatur не смогли отправиться в путь, поскольку их бортовые компьютеры не распознали 366-й день года. В качестве временной меры инженеры перезапустили поезда, сбросив их часы на месяц назад[11][12][13].
- В полночь 31 декабря 2008 года многие[14] плееры первого поколения Zune 30 перестали работать[15][16]. Microsoft объяснила, что причиной стала ошибка во внутреннем драйвере, написанном компанией Freescale и в том, как устройство обрабатывает високосный год. Проблема устранилась сама собой через 24 часа, но для тех, кто не хотел ждать, временным решением было полностью разрядить аккумулятор устройства, а затем зарядить его после полудня по всемирному координированному времени 1 января 2009 года[17][18].
- PlayStation 3 от Sony ошибочно трактовала 2010 год как високосный год, так что несуществующая дата 29 февраля 2010 года отображалась как 1 марта 2010 года и вызывала программную ошибку (см.: Баг високосного года)[19].
- В 2012 году навигационные устройства TomTom дали сбой из-за ошибки, связанной с високосным годом, которая впервые проявилась 31 марта[20].
- В 2012 году в истории чатов Gmail для всех сообщений, сохранённых 29 февраля, отображалась дата 31 декабря 1969 года.
- В 2012 году Microsoft Azure был недоступен из-за ошибки, связанной с високосным годом, которая произошла 28 февраля. Ошибка приводила к падениям виртуальных машин при запуске. В 17:45 по тихоокеанскому времени команда Windows Azure узнала о проблеме, которая в итоге оказалась вызвана операцией «через год», включавшей изменение года без изменения дня[21].
- В 2016 году ошибка, связанная с високосным годом, в системе конвейерной ленты для багажа в дюссельдорфском аэропорту 29 февраля привела к тому, что более 1200 единиц багажа не попали на свои рейсы[22].
- В 2024 году ошибка, связанная с високосным годом, в автоматах самообслуживания привела к тому, что заправочные станции с оплатой на колонке в Новой Зеландии были отключены более чем на 10 часов[23].
Более подробные списки ошибок, связанных с високосным годом, за 2016[24], 2020[25] и 2024[26] годы можно найти на сайте Code of Matt.
См. также
Примечания
- ↑ Johnson-Pint, Matt. What are some examples of leap year bugs? Stack Overflow. Дата обращения: 5 февраля 2020.
- ↑ Johnson-Pint, Matt. Python - Replacing the year. Stack Overflow. Дата обращения: 29 февраля 2020.
- ↑ Johnson-Pint, Matt. Win32 / C++ SYSTEMTIME struct manipulation. Stack Overflow. Дата обращения: 5 февраля 2020.
- ↑ Johnson-Pint, Matt. .NET / C# - Construction from date parts. Stack Overflow. Дата обращения: 5 февраля 2020.
- ↑ Johnson-Pint, Matt. JavaScript - Adding Year(s). Stack Overflow. Дата обращения: 5 февраля 2020.
- ↑ Johnson-Pint, Matt. Determining if a Year is a Leap Year. Stack Overflow. Дата обращения: 5 февраля 2020.
- ↑ Excel incorrectly assumes that the year 1900 is a leap year. Retrieved 2019-05-01.
- ↑ Standard ECMA-376 / Open Office XML File Formats. Retrieved 2016-09-10.
- ↑ ISO/IEC 29500 / Open Office XML File Formats. Retrieved 2016-09-10.
- ↑ Jim Towler. Leap-Year software bug gives "Million-dollar glitch" // The RISKS Digest. — ACM Committee on Computers and Public Policy, 1997. — Январь (т. 18, вып. 74).
- ↑ The last bite of the bug. BBC News (5 января 2001).
- ↑ 7-Eleven Systems Hit by Y2k-like Glitch. Дата обращения: 10 апреля 2023.
- ↑ Y2K Bug Hits Norway's Railroad At End Of Year (англ.). 1 января 2001. Дата обращения: 10 апреля 2023.
- ↑ Home - Microsoft Answers. Forums.zune.net. Дата обращения: 27 июля 2011. Архивировано из оригинала 30 августа 2009 года.
- ↑ John Herrman. 30GB Zunes Failing Everywhere, All At Once. Gizmodo.com (31 декабря 2008). Дата обращения: 27 июля 2011. Архивировано из оригинала 12 августа 2011 года.
- ↑ Geere, Duncan. BREAKING: Zunes worldwide hit by mystery crash : Tech Digest. Techdigest.tv (31 декабря 2008). Дата обращения: 27 июля 2011.
- ↑ Zune 30 FAQ. Microsoft (31 декабря 2008). Дата обращения: 1 января 2009. Архивировано из оригинала 2 января 2009 года.
- ↑ Zadegan, Bryant. A lesson on infinite loops. AeroXperience (3 января 2009). Дата обращения: 5 января 2009.
- ↑ Sony fixes PS3 leap year bug. Metro (англ.). 2 марта 2010. Дата обращения: 10 октября 2019.
- ↑ TomTom sat-nav devices hit by GPS 'leap year bug'. BBC News. 3 апреля 2012. Дата обращения: 5 февраля 2020.
- ↑ Summary of Windows Azure Service Disruption on Feb 29th, 2012. azure.microsoft.com (9 марта 2012). Дата обращения: 23 января 2025.
- ↑ Airport hiccup leaves 100s of passengers pantless. The Local (de) (март 2016). Дата обращения: 5 февраля 2020.
- ↑ Petrol pumps back online after day-long outage blamed on leap year glitch (новозел. англ.). The New Zealand Herald (1 марта 2024). Дата обращения: 29 февраля 2024.
- ↑ Johnson-Pint, Matt. List of 2016 Leap Day Bugs. Code of Matt (29 февраля 2016). Дата обращения: 5 февраля 2020.
- ↑ Johnson-Pint, Matt. List of 2020 Leap Day Bugs. Code of Matt (29 февраля 2020). Дата обращения: 9 апреля 2020.
- ↑ List of 2024 Leap Day Bugs (англ.). Code of Matt (29 февраля 2024). Дата обращения: 29 февраля 2024.