Как я могу правильно обрабатывать дополнительную секунду в моем приложении
Я создаю приложения, и я хотел бы знать, как я должен / могу справиться с секундой. Я постараюсь описать проблему с помощью (надеюсь) простого примера ситуации. В этой простой ситуации вы можете легко утверждать, что дополнительная секунда времени ожидания каждые +- 1,5 года может быть неактуальной, но я все равно буду спать лучше, зная, что это работает правильно / так, как я хочу, чтобы это тоже происходило во всех ситуациях:)
ситуация
(Мы не учитываем никаких задержек, поэтому, когда пользователь нажимает кнопку, это "происходит" немедленно)
У вас есть игра, в которой вы создаете солдат.
- Каждый солдат тратит 110 секунд на создание.
- Пользователи нажимают кнопку, чтобы создать 1 солдат в
day 1 - 23:58:30
- Затем пользователь ожидает, что солдаты будут созданы
110s
потом. Через обычноевычисление DateTime ваше приложение получитday 2 - 00:00:20
,
Теперь между прыжком day 1
а также day 2
-> 23:59:60
, Следуя этому методу, пользователь на самом деле ждал 111s
для своего солдата.
Я бы предпочел использовать время Unix. Таким образом, вам нужно только добавить 110s
к текущему времени в секундах. Но, насколько я знаю, это не учитывает и дополнительных секунд. Вы все равно будете ждать 111s
в реальном времени.
Вопрос
Что я должен сделать, чтобы убедиться, что пользователь или программа ожидает только того времени, которое должно ждать?
Существует ли часто используемая метка времени, которая учитывает дополнительные секунды?
Должен ли я всегда проверять, происходит ли високосная секунда? (может вызвать много "талии" мощности процессора?)
РЕДАКТИРОВАТЬ: я в основном работаю в Javascript (Node.js), но пример на C, php или Python тоже будет работать хорошо!
4 ответа
Время UTC отличается от атомного времени точными секундами. Без ссылки на атомное время вы не сможете определить только по UTC, когда была добавлена дополнительная секунда. Это делает время в UTC "почти" непрерывным из-за этих небольших скачков более 0,5 с и менее 1,0 с, которые мешают времени, когда они происходят. UTC определяется как таковое, чтобы сохранить календарное время и сопоставить его с движением Земли, но, несмотря на это, его можно считать непрерывным, просто игнорируя эти високосные секунды.
Когда добавляется високосная секунда, вы просто ничего не замечаете в своих часах, так как была исправлена только разница между атомными часами и часами. Только в том случае, если вы рассчитываете орбиты планет или спутников, вам нужно скорректировать атомные часы, или вы будете вставлять в свои расчеты целую скачку секунды (и заставлять свои орбиты меняться). Фактический эффект заключается в продвижении UTC на одну секунду. фантомом. Это влияет только на нумерацию секунд, которые теряют еще одну разницу между атомным временем и временем UTC. Но вы замечаете, что ничего не происходит в вашей машине. Разница в реальном времени для временных меток, которые оказываются перекрытыми с появлением високосной секунды, не затрагивается, поскольку вставка високосной секунды влияет только на разницу в нумерации атомных секунд и utc секунд.
В случае, если вы должны учитывать время, которое перекрывает високосную секунду (например, в исчислении орбитальных параметров какого-то инопланетного корабля), то вам нужно взять эту дополнительную секунду (это не учитывалось в атомных часах и да в UTC время) и добавьте его к интервалу, иначе ваше исчисление будет неверным. Но астрофизики всегда делают свои расчеты, используя правильную временную шкалу, так что не стесняйтесь, что космический мусор падает на вашу голову по ошибке.
Если вы используете программы синхронизации часов (например, ntpd), то добавление дополнительной секунды может происходить несколькими способами:
Вторая вставляется путем добавления одного к системным часам точно в момент вставки високосных часов. Это заставляет происходить странные вещи, поскольку задержка тайм-аута в это время сильно зависит от настройки часов, которая была выполнена.
Часы настраиваются быстро за некоторое время до високосной секунды (скажем, за два часа до) и снова настраиваются нормально через некоторое время после високосной секунды. У вас будет непрерывная шкала времени с секундами длительностью, немного меньшей стандартного атомного времени, для регулировки времени.
Пусть часы бегут. Цикл синхронизации неожиданно "видит" смещение в одну секунду между эталоном ("новая" шкала utc) и его внутренними часами, поэтому он начинает корректировать его обычным образом (настраивая тактовую частоту). Это то же самое, что и предыдущий, но приводит к большему количеству смещений (одна целая секунда против половины предыдущей точки)
В данный момент я не знаю, следует ли вашему приложению синхронизации часов первый или второй подход. По крайней мере, в Linux я думаю, что используется второй или третий, и обычно вы этого не замечаете.
НОТА
В случае, если вы положите в качестве примера, и предположим, что наихудший случай (время синхронизируется путем настройки шага по часам), вы получите солдата, созданного за 111 секунд вместо 110, но об этом не стоит беспокоиться, так как все в этом упущении произошло в 111s вместо 110. Вы получите 1.0%
больше времени, чтобы получить вашего солдата, но все произошло 1.0%
медленнее в тот же период, и ваш солдат не имеет фактических штрафов от других солдат, которые были зачаты до или после високосной секунды.
И, наконец, если вы не используете программы синхронизации времени, ваши часы будут страдать больше от их фактического смещения (разности времени ваших часов и фактического времени), чем от дрейфа внесения в него пошаговых настроек.
Вы действительно должны использовать метку времени здесь.
Временные метки - это просто количество секунд (все секунды, не имеет значения скачок или нет), которые проходят от предварительно определенной даты (называемой "эпохой"). Это просто счетчик.
Он невосприимчив к високосным секундам, смене часового пояса летом / зимой и даже безумному правительству, которое каждый год меняет границу часовых поясов.
С помощью метки времени вы всегда можете рассчитать, сколько сейчас времени в UTC, GMT и Европе / Москве (с високосными секундами и без них, это зависит от вашей конфигурации tz_data). Обратную операцию иногда невозможно сделать.
Вы не можете сделать это в JavaScript. Там нет високосных секунд в JavaScript. ECMAScript 5, раздел 15.9.1.1 говорит:
Время измеряется в ECMAScript в миллисекундах с 1 января 1970 года по Гринвичу. В значениях времени високосные секунды игнорируются. Предполагается, что ровно 86 400 000 миллисекунд в день
Не гарантируется, что значения времени будут монотонными, и когда произойдет високосная секунда, они, скорее всего, не будут. В POSIX вы можете использовать clock_gettime
с clk_id
из CLOCK_MONOTONIC
(если _POSIX_MONOTONIC_CLOCK
определено).
Некоторые RTL поддерживают високосные секунды. Например, в Ada 2005 Ada.Calendar.Time поддерживает високосные секунды, хотя и не очевидные, наблюдаемые только через дочерние пакеты Ada.Calendar.Formatting и Ada.Calendar.Arithmetic. Кроме того, Ada.Calendar.Formatting.Image записывает ":59" для дополнительных секунд, а Ada.Calendar.Formatting.Value не принимает ":60".
В целях GNAT, не имеющих встроенной поддержки високосных секунд, для ее включения требуется ключ -y "-y". С этим ключом мне удалось работать с високосными секундами даже на Windows. Я сделал крошечную библиотеку для преобразования из UNIX time_t с или без високосных секунд, а также функций форматирования / анализа, поддерживающих високосные секунды, чтобы полностью раскрыть эту функцию стандарта Ada. Конечно, в Windows несоответствие во время второго этапа неизбежно, но различие между моментами может быть правильно рассчитано, и могут быть выполнены операции со значениями, полученными из других источников.
Монотонное время следует использовать, чтобы избежать шоков во время процесса. В любом случае его следует использовать, поскольку пользователь может изменять время на часах или время можно настроить с помощью синхронизации, что происходит гораздо чаще и гораздо менее предсказуемо, чем високосные секунды.
Если вам это действительно нужно, вы можете использовать монотонное время для экстраполяции гражданского времени:
with Ada.Calendar;
with Ada.Real_Time;
-- ...
------------------------
-- Extrapolated_Clock --
------------------------
type Extrapolated_Clock is tagged record
C_Clock : Ada.Calendar.Time := Ada.Calendar.Clock;
RT_Clock : Ada.Real_Time.Time := Ada.Real_Time.Clock;
end record;
use all type Ada.Calendar.Time;
use all type Ada.Real_Time.Time;
use all type Ada.Real_Time.Time_Span;
procedure Synchronize (Object : in out Extrapolated_Clock);
function Extrapolate (Object : Extrapolated_Clock) return Ada.Calendar.Time is
(Object.C_Clock + To_Duration (Ada.Real_Time.Clock - Object.RT_Clock));
-- ...
------------------------------------
-- Extrapolated_Clock.Synchronize --
------------------------------------
procedure Synchronize (Object : in out Extrapolated_Clock) is
begin
Object.C_Clock := Ada.Calendar.Clock;
Object.RT_Clock := Ada.Real_Time.Clock;
end Synchronize;
Вам также может понадобиться убедиться, что захваченный момент времени не может быть високосной (секунда после захваченного не является скачком).