Эти функции преобразуют значения времени (см. Время суток) в метки времени Lisp, или в календарную информацию и обратно.
Многие операционные системы используют 64-разрядные знаковые целые числа для подсчёта секунд и могут представлять время в далёком прошлом или будущем. Однако некоторые имеют более ограниченные возможности. Например, устаревшие операционные системы, использующие 32-разрядные знаковые целые числа, обычно обрабатывают только время с 13.12.1901 20:45:52 по 19.01.2038 03:14:07 по всемирному времени.
Функции календарного преобразования используют григорианский календарь даже для дат до его введения, а также для дат в далёком прошлом или будущем, для которых григорианский календарь крайне неточен и расходится с общепринятой практикой в научных областях, таких как астрономия и палеонтология, где используют длины юлианского года. Номера годов считаются от 1 года до нашей эры и не пропускают ноль, как это делают традиционные григорианские годы; например, номер года −37 соответствует григорианскому году 38 до нашей эры.
Эта функция преобразует значение времени в метку времени Lisp.
Аргумент форма определяет форму возвращаемой метки времени.
Если форма — символ integer, функция возвращает целое число секунд.
Если форма — положительное целое число, оно задаёт частоту тактов, и функция возвращает
метку времени в виде пары целых (тики . форма). Если форма —
t, функция трактует это как положительное целое, подходящее для представления
метки времени; например, оно трактуется как 1000000000, если время равно nil
и платформа имеет наносекундное разрешение. Если форма равна list, функция
возвращает список целых (старший младший микро пико).
Хотя nil в качестве формы в настоящее время действует как list,
планируется изменить это в будущих версиях Emacs, поэтому вызывающие стороны,
которым нужны списковые метки, должны явно передавать list.
Если время не является значением времени, функция сигнализирует об ошибке.
В противном случае, если время не может быть представлено точно, преобразование
округляет его в сторону минус бесконечности. Когда форма равна t,
преобразование всегда точно, округление не происходит, и возвращаемое разрешение часов
не хуже, чем у времени. Для сравнения, хотя float-time также может
преобразовывать любое значение времени без ошибки, результат может быть неточным.
См. Время суток.
Для эффективности эта функция может возвращать значение, eq равное времени,
или иным образом разделяющее структуру с временем.
Хотя (time-convert nil nil) эквивалентно (current-time),
последнее может быть немного быстрее.
(setq a (time-convert nil t)) ⇒ (1564826753904873156 . 1000000000)
(time-convert a 100000) ⇒ (156482675390487 . 100000)
(time-convert a 'integer) ⇒ 1564826753
(time-convert a 'list) ⇒ (23877 23681 904873 156000)
Эта функция преобразует значение времени в календарную информацию. Если вы не указываете время, она декодирует текущее время, аналогично зона по умолчанию равна текущему правилу часового пояса. См. Правила часовых поясов. Операционная система ограничивает диапазон значений времени и зоны.
Аргумент форма управляет формой возвращаемого элемента секунды, как описано ниже. Возвращаемое значение — список из девяти элементов:
(секунды минуты часы день месяц год день_недели летнее_время смещение_utc)
Что означают элементы:
Число секунд от начала минуты, в форме, описанной ниже.
Число минут от начала часа, целое от 0 до 59.
Час дня, целое от 0 до 23.
День месяца, целое от 1 до 31.
Месяц года, целое от 1 до 12.
Год, целое, обычно больше 1900.
День недели, целое от 0 до 6, где 0 соответствует воскресенью.
t, если действует летнее время, nil, если не действует,
и −1, если эта информация недоступна.
Целое, указывающее смещение относительно всемирного времени в секундах, т.е. количество секунд к востоку от Гринвича.
Элемент секунды — это метка времени Lisp, которая неотрицательна и
меньше 61; она меньше 60, за исключением положительных високосных секунд
(при условии, что операционная система поддерживает високосные секунды). Если
необязательный аргумент форма равен t, секунды имеют ту же
точность, что и время; если форма равна integer,
секунды округляются до целого. Например, если время — это
метка (1566009571321 . 1000), представляющая 2019-08-17 02:39:31.321 UTC
в типичных системах без високосных секунд, то (decode-time время t t)
возвращает ((31321 . 1000) 39 2 17 8 2019 6 nil 0), тогда как
(decode-time время t 'integer) возвращает (31 39 2 17 8 2019 6 nil 0).
Если форма опущена или равна nil, в настоящее время по умолчанию
используется integer, но это значение по умолчанию может измениться в будущих
выпусках Emacs, поэтому вызывающим сторонам, которым требуется определённая форма,
следует указывать форма.
Примечание для Common Lisp: В Common Lisp другие значения для
день_недели, летнее_время и смещение_utc, а секунда
там — целое от 0 до 59 включительно.
Для доступа (или изменения) элементов календарной информации можно использовать
аксессоры decoded-time-second, decoded-time-minute,
decoded-time-hour, decoded-time-day,
decoded-time-month, decoded-time-year,
decoded-time-weekday, decoded-time-dst и
decoded-time-zone.
Эта функция преобразует время в метку времени Lisp.
Она может действовать как обратная к decode-time.
Обычно первый аргумент — это список
(секунда минута час день месяц
год игнорируется летнее_время зона), задающий
декодированное время в стиле decode-time. Значения этих элементов
см. в таблице в описании decode-time. В частности,
летнее_время определяет, как интерпретировать метки времени во время
осеннего перевода часов, когда метки времени повторяются. Если
летнее_время равно −1, значение DST угадывается; если оно
равно t или nil, возвращается метка с этим значением DST,
а в случае отсутствия такой метки сигнализируется ошибка.
К сожалению, значение летнее_время, равное t или nil,
не устраняет неоднозначность меток, повторяющихся когда часовой пояс на основе TZDB
смещается дальше к западу от Гринвича, например, устранение неоднозначности двух
меток стандартного времени 2020-12-27 01:30, когда зона равна
‘"Europe/Volgograd"’, где в 02:00 этого дня стандартное время
сместилось с 4 на 3 часа к востоку от Гринвича; если вам нужно обрабатывать
такие ситуации, вы можете использовать числовую зону для устранения
неоднозначности.
Первый аргумент также может быть списком (секунда минута
час день месяц год), который обрабатывается как список
(секунда минута час день
месяц год nil -1 nil).
В качестве устаревшего соглашения вызова эта функция может принимать шесть
или более аргументов. Первые шесть аргументов секунда,
минута, час, день, месяц и год
задают основные компоненты декодированного времени. Если аргументов больше
шести, то последний аргумент используется как зона, а любые
другие дополнительные аргументы игнорируются, так что (apply
#'encode-time (decode-time ...)) работает. В этом устаревшем соглашении
летнее_время равно −1, а зона по умолчанию равна
текущему правилу часового пояса (см. Правила часовых поясов).
При модернизации устаревшего вызова убедитесь, что более современный
эквивалент в виде списка содержит 9 элементов с элементом летнее_время,
равным −1, а не nil.
Номера годов меньше 100 не обрабатываются особым образом. Если вы хотите,
чтобы они обозначали годы после 1900 или после 2000, вы должны изменить их
самостоятельно перед вызовом encode-time.
Операционная система ограничивает диапазон значений времени и зоны.
Однако метки времени от начала эпохи до ближайшего будущего поддерживаются
всегда.
Функция encode-time действует как грубое обратное преобразование к
decode-time. Например, вы можете передать вывод последней
в первую следующим образом:
(encode-time (decode-time …))
Вы можете выполнять простые арифметические операции с датами, используя выходящие за диапазон значения для секунд, минут, часов, дней и месяцев; например, день 0 означает день, предшествующий заданному месяцу. Будьте осторожны при этом, так как часто это может не сработать в некоторых случаях. Например:
;; Попытка вычислить время через месяц от текущего момента.
;; Будьте осторожны; это может не сработать как ожидается.
(let ((time (decode-time)))
(setf (decoded-time-month time)
(+ (decoded-time-month time) 1))
time)
К сожалению, этот код может не сработать как ожидается, если результирующее
время некорректно из-за разницы в длине месяцев,
переходов на летнее время, изменений часовых поясов
или отсутствующих високосных дней или секунд. Например, если выполнить это
30 января, код даст несуществующую дату 30 февраля,
которую encode-time скорректирует до начала марта.
Аналогично, добавление четырёх лет к 29 февраля 2096 года даст
несуществующую дату 29 февраля 2100 года; а добавление одного часа к 01:30
13 марта 2022 года в Нью-Йорке даст метку времени 02:30, которая не существует,
потому что в этот день часы перевели с 02:00 на 03:00.
Чтобы избежать некоторых (но не всех) проблем, вы можете
строить вычисления на основе середины соответствующей единицы, например,
начинать с 15-го числа месяца при добавлении месяцев. Альтернативно, вы можете использовать
библиотеки calendar и time-date.