Казалось бы, простая задача: посчитать, сколько времени прошло между двумя датами. Оказывается, сложность этой задачи в некоторых случаях может зашкаливать. Вот небольшой рассказ об этом. Эта статья — не про само программирование, а про сложности, с которыми иногда сталкиваются разработчики при написании программ. Если нужно именно программирование, почитайте статью про гороскоп на питоне.
🤔 На эту статью нас вдохновило видео Тома Скотта из канала Computerphile. Если вы знаете английский, посмотрите оригинальный ролик, там много английского юмора:
Вводные
Допустим, мы пишем программу, которая посчитает, сколько секунд, минут или дней прошло с какого-либо солнечного затмения, наблюдаемого из разных точек Земли за её историю. У нас есть перечень наблюдений: «Такого-то числа в такое-то время в таком-то городе такой-то страны было замечено солнечное затмение» — и этот перечень пополняется с каждым затмением.
Кажется, что это простая программа, которая берёт текущую дату, вычитает из неё дату предыдущего затмения и получает ответ.
Но не всё так просто.

Нестандартные часовые пояса
Из школьного курса географии мы знаем, что:
- земной шар делится на часовые пояса;
- в каждом часовом поясе — своё время;
- для единой точки отсчёта используют нулевой меридиан в Гринвиче (его называют UTC);
- есть единый список часовых поясов, которым пользуются все желающие.
Сложность в том, что не во всех странах время совпадает с тем, которое должно быть в этом часовом поясе. Например, у Австралии своё время — UTC+9:30. Это значит, что там на 9 с половиной часов больше, чем на нулевом меридиане. Такое дробное значение часового пояса вносит хаос в наши таблицы, но пока можно справляться.
Кроме Австралии есть ещё несколько стран со своим временем, например Непал (UTC+5:45), Индия (UTC+5:30) или Канада (UTC−3:30). Чтобы перейти на своё время, стране не нужно это ни с кем согласовывать — она просто решает это внутри себя, а потом объявляет всем остальным.
Значит, нам в программе нужно учесть полный список стран, каждую со своим поясом, а ещё предусмотреть автоматическое обновление списка — вдруг какая страна решит перейти на своё отдельное время. А также иметь всю историю принадлежности территорий к часовым поясам: вдруг двести лет назад какая-то страна меняла часовой пояс?

Летнее и зимнее время
Когда мы разобрались с часовыми поясами, появляется новая сложность — переход с летнего на зимнее время и обратно. Каждый такой переход прибавляет час к текущему времени весной и отнимает его осенью.
Каждая страна решает сама, переходить ей на зимнее время или не переходить. На этот раз программисты уже знают, что делать — берут список стран и видят, кто переходят и какого числа они это делают. Естественно, в программе это тоже нужно учесть при расчётах. Кажется, что проблема решена.
Отдельно нужно помнить, что летнее и зимнее время в разных полушариях меняется местами. Когда в северном полушарии страны переходят на зимнее время, в южном наступает летнее время, и наоборот. И это тоже нужно учесть при разработке софта :-)
Но бывает так, что страна решает отказаться от перехода на зимнее или на летнее время — как Россия в 2011 году. Это значит, что все программы, которые работают со временем, должны заранее обновиться, чтобы всё дальше считалось точно.
Если это заранее не сделать и всех не предупредить, часть данных окажется неверной и её придётся перепроверять вручную. Так произошло в 2013 году в Ливии, когда за два дня до перевода часов правительство решило ничего не переводить. Естественно, никто в мире к этому не был готов, и все ливийские компьютеры, сайты и софт несколько месяцев отставали от всего мира на один час.

Внезапная смена даты
Иногда бывает так, что страны, которые расположены возле линии перемены дат, могут пропустить день. Например, Самоа однажды объявила всем, что у них после 29 декабря 2011 года будет сразу 31 декабря — так им проще торговать с Австралией.
Поэтому нам нужно постоянно отслеживать страны возле линии перемены дат, не собираются ли они сделать что-то подобное снова. Если собираются — вносим это изменение в код программы, чтобы она продолжила считать всё правильно.

Политическая обстановка
На работу со временем могут влиять даже отношения между странами. Самый популярный пример: Израиль, Западный берег Иордана и отношения с палестинцами. Смысл такой: Палестина живёт по своему времени, Израиль — по своему, а на Западном берегу реки Иордан всё сложно: часть служб, фирм живут по палестинскому времени, а другая часть — по израильскому.
Запрограммировать на уровне скрипта это невозможно — нам нужно будет при первом запуске вручную уточнить у пользователя, по какому времени вести отсчёт.

Исторические календари
Постепенно подбираемся к сложным вопросам — а как считать время, которое было раньше, в старых календарях? Тогда ведь тоже фиксировали затмения, там есть много ценных данных. Все тонкости переходов нужно тоже учесть.
Например, в одной стране при переходе от юлианского к григорианскому календарю просто прибавили три недели к дате с какого-то момента в 18-м веке. В другой сделали то же самое, но не в 18-м веке, а лет 40 назад. Сюда же добавляется русский календарь со старым и новым стилем — и это тоже нужно учитывать в программе, если мы хотим, чтобы она находила правильное расстояние между событиями.
Решение — добавить в программу все старые календари и правила перехода между датами для каждой страны.
Отдельно нужно ещё учитывать разность в календарях — откуда начинался отсчёт нового года в каждой стране в разное время. Например, до 17-го века в Англии год начинался 25 марта. Это значит, что даты шли так:23 марта 1509 → 24 марта 1509 → 25 марта 1510 → 26 марта 1510 → … → 31 декабря 1510 → 1 января 1510 →…

Продвинутый уровень — високосная секунда
До этого момента мы говорили только про дни и часы, но что, если у нас стоит задача посчитать прошедшее время с точностью до секунды? И здесь тоже всё сложно: из-за неравномерного вращения Земли у нас время от времени появляются високосные секунды.
Чтобы наша программа точно учитывала время, она должна получить сигнал от приборов или от сервера астрофизиков, что в мире прошла високосная секунда. И в этот момент внутренние часы после, например, 23:59:59 показывают 23:59:60!
Ещё есть астрономическое время, которое не учитывает високосные секунды, и с каждым годом расхождение астрономического и земного времени увеличивается. Так происходит потому, что остальным планетам, звёздам и кометам всё равно, по какому календарю живёт сейчас какая страна.

Что дальше
В следующей части расскажем о том, как программисты всего мира синхронизируют время между собой — через специальные серверы и протоколы. Подпишитесь, чтобы не пропустить продолжение.