2022-06-14 17:17:25
Работа со временем, часть 2/3
Вся информация об исторических переменах собирается в tz database. Это такой public domain файлик, где для каждого города написано, какой у него UTC offset, как и когда он переходит на летнее время и как это менялось с 1970-го года. Он используется для всех преобразований между wall clock и unix time.
Написано в нем примерно следущее:
# From Paul Eggert (2016-03-18):
# Asia/Novosibirsk covers:
# 54 RU-NVS Novosibirsk Oblast
# From Stepan Golosunov (2016-05-30):
# http://asozd2.duma.gov.ru/main.nsf/(Spravka)?OpenAgent&RN=1085784-6
# moves Novosibirsk oblast from UTC+6 to UTC+7.
# From Stepan Golosunov (2016-07-04):
# The law was signed yesterday and published today on
# http://publication.pravo.gov.ru/Document/View/0001201607040064
Zone Asia/Novosibirsk 5:31:40 - LMT 1919 Dec 14 6:00
6:00 - +06 1930 Jun 21
7:00 Russia +07/+08 1991 Mar 31 2:00s
6:00 Russia +06/+07 1992 Jan 19 2:00s
7:00 Russia +07/+08 1993 May 23 # say Shanks & P.
6:00 Russia +06/+07 2011 Mar 27 2:00s
7:00 - +07 2014 Oct 26 2:00s
6:00 - +06 2016 Jul 24 2:00s
7:00 - +07
TZ database изначально собирается волонтерами (да, блин!), затем компилируется и поставляется операционными системами и некоторыми платформами (в JDK, например, есть копия). Помню, как несколько лет страдал со своим Андроидом, на который не выходили обновления, а Новосибирск поменял часовой пояс и Asia/Novosibirsk показывало неправильное местное время.
Теперь про сложности. Главная сложность заключается в том, что время идет по Unix time и работать с ним легче тоже в Unix time, но люди хотят иметь дело с Wall clock time. И вот тут, ну, нужно быть внимательным, и все будет хорошо.
Пример — скольчо часов в сутках? 24, правильно? Кроме дней перевода часов, тогда там будет или 23, или 25, потому что для человека сутки — это интервал между 9 утра на часах сегодня и 9 утра на часах завтра, а сколько на самом деле времени прошло — не так уж важно. Важно, во сколько вставать на работу.
Или другая ситуация — я поставил будильник на завтра на 9 утра. И потом перелетел из Берлина в Москву. Во сколько должен зазвонить будильник? В 9 утра, но уже по Москве, да? То есть Unix timestamp будильника должен поменяться в момент смены часового пояса.
А вот для календаря это уже неверно — событие на 9 утра по Берлину должно превратиться в 10 утра по Москве, где бы я ни находился.
Из-за всего этого возникает концепция «местного», или «символического» времени. Скажем, вам надо посчитать, какое число будет через пять дней после 5 июня. Можно взять 5 июня, какой-то часовой пояс (например, текущий), перевести в Unix timestamp, прибавить 5 * 24 * 3600 * 1000, и перевести обратно в wall clock той же таймзоной и посмотреть на дату.
Но это бред — как мы видели, не в каждых сутках 24 часа, таймзону приходится брать с потолка, и вообще вопрос не об этом был. Как люди мы понимаем, что через пять дней после 5 июня будет 10 июня, где бы мы ни находились и сколько бы между ними реально часов не прошло. Поэтому такие вычисления лучше делать без Unix time вообще, а чисто на символическом календаре, в котором 5 и 10 июня не соответствуют какому-то конкретному моменту времени.
Но на этом сложности более-менее заканчиваются. Если хорошо понимать, о чем каждый раз идет речь — о конкретном _физическом_ моменте времени (unix time), о времени на часах в комнате (wall clock) или о символических вычислениях (даты, обычно, но и время тоже) — то почти всегда достаточно легко сделать то что нужно и получить правильный ответ. Главное не спутать одно с другим, потому что на словах все это — время, часы, а смысл сильно разный.
4.3K viewsNikita Prokopov, 14:17