Frontier who watches the watchmen?

Заблуждения программистов о времени

Последние пару лет я потратил немало времени на отладку тестового кода других инженеров. Это было интересно, иногда обескураживающе, но всегда поучительно. Кто-то может не сразу подумать, что в тестах будут ошибки, но, конечно, во всём коде есть ошибки — и тесты не исключение.

Я раз за разом был удивлен тем, как много ошибках и в тестах, и в коде приложения происходят от непонимания и ложных представлений о времени. Я имею в виду и интересный способ обработки времени в компьютерах и фундаментальные подводные камни, заложеные в том, как мы, люди, сконструировали наш календарь — переход на летнее время лишь верхушка айсберга.

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

Все эти предположения ложны

  • В сутках всегда 24 часа.
  • В месяце либо 30, либо 31 день.
  • В году 365 дней.
  • Февраль всегда состоит из 28 дней.
  • Любой 24-часовой период всегда начинается и заканчивается в одном дне (или неделе, или месяце)
  • Неделя всегда начинается и заканчивается в том же самом месяце.
  • Недельный период (или месячный) всегда начинается и заканчивается в одном и том же году.
  • На машинах с программой всегда будет Гринвичское время.
  • Ну ладно, это не так. Но хотя бы часовой пояс не будет меняться.
  • Хорошо, ну уж точно никогда не будет изменений в часовом поясе, в котором программа работает в продакшене.
  • Системные часы всегда будут выставлены на правильное местное время.
  • Системные часы всегда будут выставлены на время, которое не сильно отличается от правильного местного времени.
  • Если системные часы выставлены неправильно, то, как минимум, они всегда будут отличаться от правильных на постоянное количество секунд.
  • Серверные и клиентские часы всегда будут выставлены на одно и то же время.
  • Серверные и клиентские часы всегда будут выставлены на примерно одно и то же время.
  • Хорошо, но время на серверных и клиентских часах никогда не будет отличаться на десятилетия.
  • Если серверные часы и клиентские часы не синхронизированы, то они, всё-таки, всегда будут рассинхронизированы на постоянное количество секунд.
  • Серверные часы и клиентские часы будут использовать один и тот же часовой пояс.
  • Системные часы никогда не будут выставлены на время, которое в далеком прошлом или далеком будущем.
  • У времени нет начала и конца.
  • Одна минута на системных часах длится ровно столько же, как и минута на любых других часах.
  • Хорошо, но продолжительность одной минуты будет довольно близкой к продолжительности одной минуты на большинстве других часов.
  • Ладно, но продолжительность одной минуты на системных часах никогда не превысит один час.
  • Ты же не всерьёз, да?
  • Самая малая единица времени — одна секунда.
  • Окей, одна миллисекунда.
  • Никогда не понадобится устанавливать системное время на любое значение, отличное от правильного местного времени.
  • Хорошо, тестирование может потребовать установку системного времени на значение, отличное от правильного местного времени, но это никогда не придётся делать в продакшене.
  • Таймстампы всегда будут указаны во всеми понимаемом формате вроде 1339972628 или 133997262837.
  • Таймстампы всегда будут указаны в одном и том же формате.
  • Таймстампы всегда будут иметь один и тот же уровень точности.
  • Таймстамп с достаточным уровнем точности можно безопасно считать уникальным.
  • Человекочитабельные даты можно указать во всеми понимаемых форматах, например 05/07/11.

Эта штука про минуту дольше часа — это шутка, правда?

Нет.

Был потрясающий баг в старых версиях KVM на CentOS.
А именно, виртуальная машина KVM не имела представления, что она работает не на реальном железе. Это значит, что если хостовая OS переводила VM в спящий режим, виртуализированные системные часы сохраняли время, в которое систему перевели в спящий режим. Например, если VM остановили в 13:00, а затем запустили опять через два часа (в 15:00), то системные часы VM всё ещё будут показывать местное время 13:00. В результате, каждый раз, когда машина KVM ничего не делала, внешняя ОС переводила её в спящий режим и часы VM всё дальше уходили от реальности, иногда на огромные промежутки, в зависимости от того, как долго VM оставалась в этом состоянии.

Был cron job, который можно было установить для того, чтобы поддерживать состояние часов VM, близкое к железным часам хостовой ОС. Но про него легко забыть, создавая новую VM, и это постоянно приводило к забавным ситуациям. Позже баг пофиксили.

Уведомление

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