Как может 1-летняя (java) библиотека правильно выполнить форматирование времени UTC, учитывая недавно введенную високосную секунду?

Отметка времени, выраженная в миллисекундах с 1.1.1970 UTC, является распространенным способом хранения отметок времени, например, в Java.

например:

long timestampUtc = System.currentTimeMillis();

Такая временная метка может быть отформатирована в формате времени чтения человека, например, с использованием этого кода

    SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US);
    df.setTimeZone(TimeZone.getTimeZone("UTC"));
    String humanTimeUtc = df.format(new Date(timestampUtc));
    System.out.println(humanTimeUtc);

который дает вывод: 2014-02-14 14:58:05

Теперь представьте, что сегодня в полночь администрация времени вводит новую високосную секунду UTC. Если я запусту код выше завтра, JRE JRE в моей системе не сможет узнать, что такое введение в високосную секунду, и неправильно отформатирует время (на одну секунду).

Правильно ли мое предположение?
Как правильно отформатировать время (например, в файле журнала) в системах, которые не всегда могут использовать обновленную JRE?.

Справочная информация:
Это используется во встроенном устройстве, которое синхронизирует свои системные часы через GPS, с числом GPS високосных секунд, смещенным к UTC.

5 ответов

Решение

Java и Unix "эпоха" (количество секунд с 1 января 1970 года 00:00:00 UTC) обе полностью игнорируют високосные секунды. Они оба предполагают, что каждый день (измеренный в UTC) имел ровно 86400 секунд. Простой блок кода для проверки:

    Calendar c = Calendar.getInstance();
    c.setTimeZone(TimeZone.getTimeZone("UTC"));
    c.set(2014, 0, 1, 0, 0, 0);
    c.set(Calendar.MILLISECOND, 0);
    System.out.println(c.getTimeInMillis());

Вы увидите, что количество секунд с 01.01.1970 по 01.01.2014 является точным кратным 86400 (на самом деле это ровно 44 года * 365,25 дней / год * 86400 секунд / день); Так не должно быть, потому что в этот интервал введено 25 високосных секунд.

Если вам нужно принять во внимание дополнительные секунды, вам нужно найти библиотеку, которая сделает это, или придумать свою собственную настройку.

Обработка високосных секунд трудна, и Java не особенно плоха в этом отношении.

NTP Timescale и Leap Seconds объясняют лишь некоторые из странностей:

Вставка високосных секунд в UTC, а затем в NTP и POSIX влияет на системные часы и, следовательно, на преобразование между временем системных часов и обычным гражданским временем в часах, минутах и ​​секундах. Однако, поскольку единственной доступной институциональной памятью для определения преобразования являются национальные службы вещания UTC, преобразование фактически сбрасывается в UTC, когда принимается каждый временной код вещания. Таким образом, когда в UTC, а затем в NTP или POSIX вставляется дополнительная секунда, знание всех предыдущих дополнительных секунд теряется.

Другой способ описать это состоит в том, чтобы сказать, что существует столько временных шкал NTP или POSIX, сколько исторических секунд високосных. По сути, новая шкала времени восстанавливается после каждой новой високосной секунды. Таким образом, все предыдущие високосные секунды, не говоря уже о кажущемся происхождении самой шкалы времени, отклоняются назад на одну секунду, когда устанавливается каждая новая шкала времени. Например, если часы, синхронизированные с UTC в 2005 году, использовались для установления эпохи UTC для события, которое произошло в начале 1972 года без исправления, событие появилось бы на 22 секунды позже. В результате для наиболее точного определения эпохи относительно исторического григорианского календаря и шкалы времени UTC пользователь должен вычесть из кажущейся эпохи NTP или POSIX соответствующее смещение, предоставленное IERS. Это особенность почти всех современных механизмов распределения времени.

Дополнительные секунды практически никогда не актуальны, если вы не делаете астрономические вычисления или что-то еще, что зависит от положения Земли и Солнца.

Обычно люди, которые думают, что им нужны дополнительные секунды, действительно нуждаются в

  1. стабильный (в обозримом будущем) способ преобразования из кортежного представления, такого как (год, месяц, день, ...), в скалярное представление, такое как миллис-с-эпохи или
  2. иметь дело с одним представлением вместо смешивания и сопоставления.

Я предпочитаю (2). Скалярное представление лучше для научных расчетов, а представление кортежей лучше для деловых и случайных приложений.

Ответ dcsohl и Mike Samuel верны.

Другие комментарии о времени обновления базы данных Java неверны. Да, база данных обновляется, но не на високосные секунды. Дополнительные секунды полностью игнорируются Java, Joda-Time и другими Unix-ориентированными системами хронометража.

Ваш вопрос предполагает проблему там, где ее нет.

Часы дрифт

Физические часы почти на всех компьютерах не очень точные. Дрейфует секунда или больше в месяц. Вот почему практически все операционные системы по умолчанию подключаются к серверам времени либо локально, либо через Интернет. Таким образом, на практике ваш компьютер регулярно настраивает свое текущее время. Из-за этого вы можете уже найти аномалии во временных последовательностях, записанных в ваших журналах, если вы внимательно посмотрели.

Вставка високосной секунды имеет тот же эффект, что и неточность ваших часов. Ваш компьютер выключен на секунду, и вскоре будет исправлен с помощью сервера времени.

Игнорирование второго прыжка

Что касается ваших данных, то и класс java.util.Date, и популярная замена Joda-Time игнорируют дополнительную секунду. Так что думайте о високосной секунде как о том, что она просто растягивает эту 59-ю секунду в последний час дня события с високосной секундой. С точки зрения нашего календаря и часов звонков ничего не произошло. Для всех бизнес-приложений и большинства практических целей большинства программ игнорирование високосных секунд не имеет пагубных последствий.

Да, технически говоря, миллисекунды с эпохи, используемые java.util.Date и Joda-Time, неверны. Прямо сейчас сообщается о 1392442622998 с начала 1970 года, хотя фактически с 252 високосных секунд, вставленных с 1972 года, это число "должно" составить 1 392 442 647 998 (еще 25 000). Да, расчет истекшего времени между двумя временными точками по годам будет коротким на несколько секунд. Но для большинства целей, кого это волнует? Мы настроили наши календари так, чтобы не было лишней секунды.

Если вы обладаете умом, ориентированным на точность, как и я, вам понадобится время, чтобы осознать тот факт, что игнорирование високосных секунд не имеет практического эффекта для отслеживания календаря. Основная проблема:

  • Время дня - это способ, которым мы читаем вращение планеты (которое замедляется), а дата / календарь - это то, как мы читаем орбиту планеты вокруг Солнца.
  • Эти два, время дня и дата / календарь, не имеют ничего общего друг с другом. Это независимые реалии. Но мы, люди, смешиваем их вместе, чтобы понять, как мы вместе смешиваем арахисовое масло и банан, чтобы сделать бутерброд. И точно так же, как мы могли бы посыпать мед между свиньями и бананом, чтобы собрать их вместе, високосные секунды объединяют часы + календарь в едином порядке для нашего умственного потребления.

Одна из возможных проблем

Единственная реальная практическая проблема заключается в том, что, как сообщается, некоторые системы генерируют фактическую 60-ую секунду, время 23:59:60. Это время наносит ущерб некоторым программам, написанным, в то же время не зная о високосных секундах. Такое программное обеспечение ошибочно полагает, что значение невозможно, и может выдавать ошибки или иным образом не работать. Правильно информированное программное обеспечение должно знать, что (а) у нас могут быть дополнительные секунды, поэтому 23:59:60 и 23:59:61 являются допустимыми значениями, и (б) скачок может быть отрицательным. (Хотя до сих пор у нас была только одна положительная високосная секунда, я вспоминаю, что читалось, что более одной возможно, но не ожидается. Я не могу найти источник по этому поводу.) Помните, эта проблема возникает, только если ОС или поставщик значений времени на самом деле отслеживает эти события високосных секунд - немногие делают, поэтому они никогда не видят секунду с номером 60.

Больше информации

На странице Википедии есть больше информации о Leap Second.

Моя новая библиотека Time4J способна обрабатывать дополнительные секунды, так что это одна из нескольких уникальных функций этой библиотеки. Я не знаю никакой другой библиотеки, которая могла бы делать форматирование високосных секунд. Конкретно подробно о вашем вопросе:

Ваш пример кода с использованием стандартной Java

SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US);
df.setTimeZone(TimeZone.getTimeZone("UTC"));
String humanTimeUtc = df.format(new Date(timestampUtc));
System.out.println(humanTimeUtc);

выглядит в Time4J как:

ChronoFormatter<Moment> formatter =
  ChronoFormatter.setUp(Moment.class, Locale.US)
                 .addPattern("uuuu-MM-dd HH:mm:ss", PatternType.CLDR)
                 .build();
Moment timestampUTC = SystemClock.INSTANCE.currentTime();
System.out.println(formatter.format(timestampUTC));
// output: 2014-02-20 14:16:25

а) источник времени SystemClock основывается на System.currentTimeMillis(), Этот источник никогда не подсчитывает високосные секунды и также не может давать метку времени високосной секунды - при условии, что основная ОС не знает о високосной секунде. Таким образом, выходные данные в этом примере никогда не будут отображать значение високосной секунды 60.

б) внутренне объект типа Moment оба держат метку времени посикса и бит в секунду. Таким образом, с помощью внешней таблицы високосных секунд (которая на самом деле хранится в небольшом файле в classpath) каждый Moment будет правильно отображать то же самое время, даже если системный администратор позже обновит файл в секунду и вставит новый. Это не влияет на любой Moment вне високосных секунд, следовательно, нет ошибки в одну секунду. => Если вы перезапустите код после вставки новой високосной секунды, тогда отметка времени сохраненного момента останется прежней. Форматированный вывод не меняется, что хорошо.

в) Вы можете построить Moment которые представляют собой високосную секунду либо путем выбора специализированного источника времени (в будущем я поставлю SNTP-клиента, который мог бы отслеживать дополнительную секунду), либо путем применения подходящего количества SI-секунд, добавленных к нормальному Moment, Форматированный вывод для такой временной метки действительно будет отображать второе значение 60, при условии, что таблица високосных секунд актуальна. Если вы перенесете этот момент второй секунды в другую JVM путем сериализации, где таблица leapsecond не обновлена, то она будет обрабатываться там как одна секунда (и если вы сериализуете ее обратно в правильно обновленную JVM или если получатель получит -JVM должным образом обновляется позже, после чего снова будет показана дополнительная секунда).

d) Time4J также поддерживает шкалу времени GPS. Вы можете построить Moment давая истекшие секунды с начала GPS (полночь 1980-01-06 в начале) и указав шкалу времени GPS. Внутренне Moment преобразует данные в состояние UTC, которое не имеет потерь, при условии, что таблица leapsecond обновлена. Конечно, если ваша конфигурация не обновлена, и источник GPS генерирует количество прошедших секунд, представляющих событие в секунду, тогда будет ошибка в одну секунду. Во избежание таких крошечных и редких ошибок из-за неадекватно управляемых таблиц високосных секунд в клиентских JVM может быть хорошей идеей установить другой механизм настройки. Time4J определяет SPI-интерфейс для этой цели.

Мы столкнулись с этим с C# на Windows, а также с использованием.NET DateTime класс: это не учитывает дополнительных секунд, хотя документация MSDN, кажется, подразумевает иначе.

Мы решили продолжить вместе с этим как известную проблему. Однажды, чтобы обойти эту проблему, мы планируем вернуться и добавить что-то вроде таблицы базы данных или файла конфигурации, который можно обновить в июне / июле и декабре / январе, чтобы поддержать и разрешить изменение значения смещения, чтобы Нам известно, что сегодня ровно столько секунд - правильно учтены високосные секунды.

Если у кого-то есть какие-нибудь яркие идеи в C# или Java, мы будем рады их услышать. Благодарю.

Другие вопросы по тегам