Rationale for Ada 2005: Predefined library
RUSTOPBACKNEXT
ENG |
3. Times and dates
@ The first change to note is that the subtype Year_Number in the package Ada.Calendar in Ada 2005 is
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Rationale for Ada 2005: Predefined library
@ENGRUSTOPBACKNEXT3. Дата и время
@ Первое изменение в этой области в Аде 2005, которое следует упомянуть это подтип Year_Number в пакете Ada.Calendar.
|
@ В Аде 95 (и в Аде 83) этот диапазон - 1901.. 2099. Это нововведение позволяет избежать проблем с высокосным годом в соответствии с 400-летним правилом за счет использования дат в далеком будущем. Но, конец 21-ого столетия, возможно, не такое уж далёкое будущее и, таким образом, проблема 2100 года должна быть решена уже теперь, а не когда-нибудь потом. Однако, было решено не изменять нижнюю границу, потому что некоторые системы, как известно, использовали её как базовую точку отсчёта времени. Верхняя граница была выбрана чтобы избежать трудностей при реализаций. Например, с одной наносекундой для Duration'Small, тип Time может уместиться в 64 бита.
@ Взявшись должным образом за проблему високосных годов Ада 2005 имеет дело с скачками секунд, часовыми поясами и другими такими делами.
@ Есть три новых дочерних пакета Calendar.Time_Zones, Calendar.Arithmetic и Calendar.Formatting.
@ Спецификация первого
|
@ Часовые пояса отсчитываются в минутах относительно UTC (Координированное Среднее Время); это почти тоже самое что и GMT (Среднее время по Гринвичу) и оно так же не страдает от перевода часов весной и осенью. Возможно, казалось более естественным мерять часовые пояса в часах, но у некоторых мест (например в Индии) есть часовые пояса, которые не являются целым числом часов относительно UTC.
@ Время - необычайно сложный предмет. Различие между GMT и UTC не больше секунды, а в настоящий момент она составляет приблизительно 0.577 секунды. BBC передаёт проверки точного времени основанные на UTC, но называет их GMT, и с цифровой передачей они поднимаются поздно так или иначе. Хронофилы могут зайти на вебсайт www.merlyn.demon.co.uk/misctime.htm # GMT для интереса.
@ Таким образом, функция UTC_Time_Offset, примененная в Ада - программе в Париже к значению типа Time летом должна возвратить смещение времени 120 минут (один час в средне-европейского времени плюс один час поправки для летнего времени). Напомним что тип Calendar.Time включает и дату. Чтобы теперь найти смещение (то есть, во время вызова функции) мы просто пишем:
|
@ и тогда часы вызываются по умолчанию.
@ Чтобы найти смещение которое было на Рождество 2000 мы пишем:
|
@ и это должно возвратить 60 в Париже. Таким образом, плохая функция должна помнить целую хронологию изменений местного времени с 1901 и предсказывать их плодь до 2399 года - эти системы Ады довольно умны! В действительности намерение состоит в том, чтобы использовать возможности операционной системы. Если информация не известна тогда, она может возбудить исключение Unknown_Zone_Error.
@ Отметим, что мы предполагаем, что пакет Calendar установлен на местное время (или настенные часы). Это вполне ожидаемая нормальная ситуация. Конечно, вполне возможно чтобы для работающей Ада-системы в Калифорнии установить Календарь на местное время Новой Зеландии, но согласитесь, это была бы далеко необычная ситуация. Естественно, Календарь не должен корректироваться с переходом на летнее и зимнее время, как мы и ожидали. (Неудивительно что Ада.Real_Time был введен для жизненных миссий, таких как кипячение яйца). Полезный факт состоит в том, что Clock - Duration (UTC_Time_Offset*60) дает UTC время - вне зависимости от перехода на зимнее и летнее время, иначе бы запрос Clock и UTC_Time_Offset не были бы совместимыми.
@ Более широко тип Time_Offset может использоваться, чтобы представить различие между двумя часовыми поясами. Если мы хотим работать с различием между Нью-Йорком и Парижем тогда, мы могли бы написать:
|
@ Смещение времени между двумя различными местами может быть больше 24 часов в двух случаях. Во-первых, когда Демаркационная линия времени несколько раз переплетается, и во-вторых, в случае перехода на летнее время. Различия в 26 и даже в 27 часов могут легко произойти.
@ Соответственно диапазон типа Time_Offset щедро определён аж до 28 часов.
@ Пакет Calendar.Arithmetic обеспечивает некоторые неуклюжие арифметические операции и также покрывает скачки секунд. Его спецификация:
|
@ Диапазон для Leap_Seconds_Count щедр. Он обеспечивает скачки секунд по крайней мере до четырёх раз в год для обозримого будущего - несколько произвольно выбранный диапазон кодируется 12 битами. Также предел 366 для Day_Count также немного щедр - но истинное выражение было бы очень неприятно.
@ Одна из проблем с нашей планетой состоит в том, что она замедляется, и день который определяется вращением Земли теперь немного больше 86400 секунд. Достаточно естественно мы должны сохранить униформу секунд и так, чтобы сохранить мирские часы синхронизированными с естественным днем, нечетный секундный скачёк должен время от времени добавляться. Он всегда добавляется в полночь UTC (что означает то что он может призойти в середине дня в других часовых поясах). Существование скачков секунд делает вычисление времени довольно хитрым занятием.
@ Основная неприятность состоит в том, что мы хотим одновременно и иметь наш пирог и съесть его. Мы хотим иметь инвариант, что у дня есть 86400 секунд, но к сожалению это - не всегда возможно.
@ Процедура Difference принимает два параметра типа Time и выдает результат в виде трех значений, числа дней (целое число), числа секунд как Duration и числа скачков секунд (целое число). Если Left раньше чем Right тогда, все три числа будут неотрицательными; если посже, то неположительными.
@ Напомним, что Difference как все эти другие операции всегда воздействует на местное время как определено часами в Calendar (если не заявлено иначе).
@ Предположим, что мы хотим найти различие между полуднем 1-ого июня 1982 и 2pm 1-ого июля 1985 согласно системному набору к UTC. Мы могли бы написать:
|
@ Результат должен быть такой:
|
@ Т.е. имеются скачки секунд 30 июня 1983 и 30 июня 1985.
@ Функции "+" и "-" применимы к значениям типа Time и Day_Count (тогда как в родительском пакете Calendar применяются только к Time и Duration, и таким образом, работают только на интервалах приблизительно одного дня). Отметим, что функция "-" между двумя значениями типа Time в этом дочернем пакете производит то же самое значение для числа дней как и соответствующий вызов функции Difference - скачки секунд полностью игнорируются. Скачки секунд фактически игнорируются и во всех операциях "+" и "-" в дочернем пакете.
@ Однако, надо отметить что Calendar."-" считает истинные секунды и так выражение:
|
@ имеет значение Duration 7201.0 а не 7200.0 из-за скачка секунды в полночь той ночью. (Мы предполагаем, что наша Ада-система работает в UTC). То же самое вычисление в Нью-Йорке выдаст 7200.0, потому что скачок секунды не происходит до 4:00 в EST (летнего времени).
@ Отметим также что:
|
@ в Париже, где скачок секунды происходит в 10:00 результат будет 86401.0, тогда как то же самое вычисление в Нью-Йорке выдаст 86400.0.
@ Третий дочерний пакет Calendar.Formatting имеет множество функций. Его спецификация:
|
@ Функция Day_Of_Week будет очень цениться. Ибо это весьма противное вычисление.
@ Имеются функции Year, Month, Day, Hour, Minute, Second и Sub_Second, которые выдают соответствующие части Time, принимающего во внимание часовой пояс, данный по мере необходимости. Очень жаль, что функции выдающие части времени (в противоположность частям даты) не были предоставлены в пакете Calendar первоначально. Всё что обеспечивает Calendar это функция Seconds которая выдает число секунд после полуночи предоставляя пользователям самим нарубить время на часы. Отметим что Calendar.Second возвращает Duration, тогда как функция Seconds в дочернем пакете возвращает Integer. Доли секунды выдаёт функция Sub_Second.
@ У большинства этих функций есть дополнительный параметр, который является смещением часового пояса. В любом месте мира где бы мы ни работали, если мы хотим знать час согласно UTC мы пишем:
|
@ Если же мы находимся в Нью-Йорке и хотим знать час в Париже тогда, мы пишем:
|
@ так как разница с Нью-Йорком и Парижем составляет 6 часов (360 минут).
@ Отметим, что у Second и у Sub_Second нет дополнительного параметра Time_Offset, потому что смещения - целое число минут и, таким образом, число секунд не зависит от часового пояса.
@ Пакет также великодушно предоставляет четыре процедуры Split и две процедуры Time_Of. Они имеют то же самое предназначение что и в пакете Calendar. Имеется также функция Seconds_Of. Мы рассмотрим их в порядке объявления в спецификации пакета выше.
@ Функция Seconds_Of создаёт значение типа Duration из компонентов Hour, Minute, Second и Sub_Second. Отметим, что мы можем использовать её вместе с Calendar.Time_Of для создания значения типа Time. Например:
|
@ делает время момента, когда я (первоначально) напечатал ту последнюю точку с запятой.
@ Первая процедура Split является обратной Seconds_Of. Она разбирает значение типа Duration на Hour, Minute, Second и Sub_Second. Её совместное использование с функцией Calendar.Split весьма полезно:
|
@ Следующая процедура Split (номер 2) берёт Time и Time_Offset (опционально) и разбивает время на семь компонентов. Отметим, что дополнительный параметр является последним для удобства. Нормальное правило для параметров предопределенных процедур состоит в том, что параметры режима in являются первыми, и параметры режима out являются последними. Но это - неприятность, если у параметров режима in есть значения по умолчанию, так как это требует именнованного назначения остальных параметров, если значение по умолчанию используется.
@ Ещё имеются две функции Time_Of, которые составляют Time из его различных непосредственных составляющих и Time_Offset (опционально). Каждая берет семь компонентов (с индивидуальным Hour, Minute и т.д) тогда как другие берут только четыре компонента (с Seconds в целый день). Интересная особенность этих двух функций состоит в том, что у них также есть параметр Leap_Second Boolean, который по умолчанию является False.
@ Назначение этого параметра должна быть ясно понято. В большинстве случаев при получении времени этот параметр будет False. Но предположим, что мы должны составить время на полпути в течение скачка секунды, который произошоёл 30 июня 1985 и назначать его переменной Magic_Moment:
|
@ В некотором смысле были два момента 19:59:59 в тот день в Нью-Йорке. Надлежащий и затем после скачка секунды; параметр различает их. Таким образом, моментом одной секундой ранее является:
|
@ Мы могли бы руководствоатся правилами ISO и использовать 23:59:60 UTC и иметь подтип Second_Number с Natural range 0.. 60; но это произвело бы к несовместимости с Адой 95.
@ Отметим, что, если параметр Leap_Second - True а другие параметры не идентифицируют время скачка секунды тогда возбуждается исключение Time_Error.
@ Также имеются две соответствующие процедуры Split (номер 3 и 4) с выходным параметром Leap_Second. Первая производит семь компонентов, а другая четыре. Различие между процедурой Split с семью компонентами (номер 3) и более ранней Split (номер 2) состоит в том, что она имеет параметр Leap_Second. Написав:
|
@ результат в Leap будет True, тогда как:
|
@ результат в Leap будет False, но все Остальные параметры (Y..., SS) будут такими же.
@ С другой стороны вызывая версию Split (номер 2) без параметра Leap_Second таким образом
|
@ приводит точно к тем же самым результатам.
@ Читатель мог бы задаться вопросом, почему есть два Разбиения (Splits) времени (Time) с Leap_Second, но только однин без.
@ Дело в том, что у родительского пакета Calendar уже есть такая функция (хотя без параметра часового пояса). Другой момент состоит в том, что в случае Time_Of, мы можем иметь значение по умолчанию для параметра Leap, т.к. он передаётся в режиме in, но в случае Split параметр имеет режим out и не может быть опущен. Это была бы плохая практика поощрять использование фиктивного параметра, который игнорируется и следовательно должны быть дополнительные версии Split.
@ Наконец, есть две пары функций Image и Value. Первая пара работает со значениями типа Time. Вызов Image возвращает значение даты и времени в формате стандарта ISO 8601. Таким образом, беря Normal_Moment выше
|
@ мы получаем следующую строку "1985-06-30 19:59:59" - в Нью-Йорке, Если мы устанавливаем опциональный параметр Include_Time_Fraction в True то
|
@ получаем "1985-06-30 19:59:59.50". Имеется также обычный опциональный параметр Time_Zone, и таким образом, мы можем получить время в Париже (в программе работающей в Нью-Йорке) таким образом:
|
@ В результате получим "1985-07-01 02:59:59.50" -- в Париже. Соответственно функция Value работает в обратном направлении как ожидается.
@ Мы ожидали бы получать точно такие же результаты с Magic_Moment. Однако, так как некоторые реализации могут иметь в наличии ISO функцию в их операционной системе, которая также позволяет произвести "1985-06-30 19:59:60" -- в Нью-Йорке. Другая пара Image и Value работают над значениями типа Duration таким образом:
|
@ с опциональным параметром Include_Time_Fraction как и прежде. Снова соответствующая функция Value работает в обратном направлении.
2010-10-24 00:26:57
. .