Главная страница Visual 2000 · Общий список статей

Работа с календарем требует особого внимания.
Похоже, в алгоритме Microsoft есть ошибка

Андрей Колесов

© 1999, Андрей Колесов
Авторский вариант. Статья была опубликована c незначительной литературной правкой в в журнале "Наука и жизнь" № 12/99, с. 91-92.

Любопытным результатом итогов обсуждения компьютерной "Проблемы Y2K" явилось то, что широкие массы как пользователей, так и разработчиков ПО узнали, что с детства известный алгоритм определения високосного года — деление на четыре без остатка — не совсем точен. Но потом программисты облегченно вздохнули, узнав, что он вполне подходит еще для ближайших ста лет: 2000 год действительно является високосным как исключение из ряда вековых лет (номера которых оканчиваются на два нуля).

В этой связи сразу появился принципиальный вопрос — как вообще нужно вести календарь? Что касается компьютерных программ, то тут нужно сделать уточнения. Многие современные программы так или иначе связаны с текущим временем (пользователь может об этом и не знать, текущая дата часто используется в программах в служебных целях). Поэтому имеется такое понятие как "время жизни программы". Например, сегодняшний вариант наиболее популярных операционных систем семейства Microsoft Windows рассчитан на работу до 2099 года.

Совсем другой вопрос — с каким диапазоном дат (в качестве обрабатываемых ею данных) может работать прикладная программа. Например, вы сегодня захотите забронировать билет на самолет в 2010 году. Наверняка, программа, которая используется для решения этой задачи, уже "умрет" к тому времени (замена на новую версию), но сделку она должна обработать уже сегодня.

Или имеется программа, которая решает очень простую задачу — по заданной дате определяет день недели. (Например, для историка может быть важным ответ: в какой день недели родился Александр Пушкин?).

Многие современные программы для работы с датами используют механизм, реализованный в средствах программирования корпорации Microsoft. Его идея очень простая.

Дата хранится в виде числа (Чтобы не усложнять пример, будем считать, что в формате целого. На самом деле там используется вещественное число, что позволяет учитывать и время с точностью до секунд). Начальной точкой (нулем) является 30 декабря 1899 года, суббота. Задав номер суток от этой даты, вы получаете текущую дату и день недели. И наоборот. Например, 31 декабря 2099 года будет четвергом, 73500-м днем от 30.12.1899. А минус тысячный день (-1000) от той же точки отсчета — 4 апреля 1897 года, воскресенье. Этот алгоритм обеспечивают поддержку ведение календаря в в диапазоне от 01.01.100 до 31.12.9999.

В общем, все тут кажется достаточно простым и те, кто имеет дело с бизнес-задачами, можете не волноваться — там, вроде бы, все в порядке. Но кто работает с историческими датами, тем следует прочитать эту статью до конца.

Вопрос: какой был день накануне пятницы 15 октября 1582 года? Скорее всего, каждый даст очевидный ответ (а программы Microsoft его дают однозначно): четверг 14 октября 1582 года. И будут неправы. Если считать по григорианскому календарю (новый стиль), то это действительно четверг, но 4 октября. Если же имеется в виду юлианский календарь (старый стиль), то 15 октября был понедельник, а накануне — 14 октября, воскресенье.

Здесь полезно вспомнить об истории календарей. Основа современного календаря была заложена реформой Юлия Цезаря в 46 до н.э. После ряда уточнений спустя 50 лет календарь принял современный вид. За исключением порядка определения високосного года. В юлианском календаре средняя длина года была принята 365,25 суток, поэтому високосным считался каждый четвертый год. Исследования астрономов еще в средние века позволили определить, что в этой величине имеется погрешность (солнечный года меньше на 11 мин 14 сек), из-за чего за каждые 128 лет накапливалась ошибка в 1 сутки.

В результате получилось, что к концу 16-го века дата весеннего равноденствия приходилась не на 21 марта (как это было в 325 году, когда христианская церковь приняла юлианский календарь в качестве официального), а на 11 марта. А день весеннего равноденствия издавна является ключевой точкой для счета времени в истории человечества.

Ошибка в календаре была исправлена папой римским Григорием XIII, который в 1582 год своей буллой передвинул счет дней на 10 дней вперед: день после четверга 4 октября предписывалось считать пятницей, но не 5, а 15 октября. Чтобы избежать накопления новой ошибки в будущем, был также изменен порядок вычисления високосных годов: из их числа исключаются вековые годы (с двумя нулями в конце) кроме тех, число сотен которых делится без остатка на четыре. Такими годами являются 1700, 1800, 1900, 2100 и пр. Но 2000 год — високосный, причем во всех календарях: и юлианском, и григорианском!

Вывод из этого можно сделать следующий: нельзя использовать алгоритм вычисления даты по григорианскому календарю по временной шкале вниз от 15 октября 1582 года. Но именно так делается в алгоритмах Microsoft.

Простой пример — в григорианском календаре просто нет дат с 6 по 14 октября 1582 года, и вся информация об исторических событиях в предыдущий период приводится в старом стиле. С сегодняшней точки зрения разница в несколько дней, казалось бы, является пустяком, но для историка вопрос, предположим, привязки даты к дню недели может уже быть принципиально важной (Куликовская битва — 08.09.1380 — произошла до или после выходного дня?). Не говоря уже о том, что в истории человечества был, например, день 29 февраля 1500 года, который с точки зрения Visual Basic является недопустимой датой.

Но еще более внимательно нужно относиться к работе с датами с конца 16-го до начала 20 веков. Ведь переход разных стран со старого на новый стиль был не одновременным. Например, Франция, Италия и Испания перешли на григорианский календарь в 16-веке, Германия — в 17-м, Англия — в 18-м, Япония — в 19-м, Россия и Китай — в начале 20-го. Все это уже положило появлению огромного числа исторических мифов: о том, что граф Калиостро в один день мог прибывать и в Петербурге, и в Берлине; что парусники с фантастической скоростью переплывали Атлантику и пр.

Вывод из сказанного таков. При работе с историческими датами после 4 октября 1582 года просто необходима возможность работы с датами в новом и старом стиле. Но использование алгоритма григорианского календаря в обратную сторону от даты его введения, скорее всего, является ошибкой. Например, если мы будем использовать алгоритм Microsoft, то получим, что даты Рождества Христова (25 декабря), т.е. собственно момент рождения, совпадают в юлианском и григорианском календарях только в 3-м веке нашей эры, а не в первом, как это вроде бы должно быть.

В реальной жизни данная проблема, вряд ли, затронет кого-либо всерьез. Однако вспомним — знаменитая эпопея с заменой Pentium пять лет назад начиналась также с ошибки, вероятность которой исчислялась миллионным долями. И была она обнаружена при довольно экзотических астрономических расчетах.

В начало статьи