Если я запускаю следующую программу, которая анализирует две строки даты, ссылаясь на раз в 1 секунду, и сравнивает их:
public static void main(String[] args) throws ParseException {
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String str3 = "1927-12-31 23:54:07";
String str4 = "1927-12-31 23:54:08";
Date sDt3 = sf.parse(str3);
Date sDt4 = sf.parse(str4);
long ld3 = sDt3.getTime() /1000;
long ld4 = sDt4.getTime() /1000;
System.out.println(ld4-ld3);
}
Выход:
353
Почему ld4-ld3
нет 1
(как и следовало ожидать от разницы во времени в одну секунду), но 353
?
Если я изменю даты на время 1 секунду позже:
String str3 = "1927-12-31 23:54:08";
String str4 = "1927-12-31 23:54:09";
Тогда ld4-ld3
будет 1
.
Версия Java:
java version "1.6.0_22"
Java(TM) SE Runtime Environment (build 1.6.0_22-b04)
Dynamic Code Evolution Client VM (build 0.2-b02-internal, 19.0-b04-internal, mixed mode)
Timezone(`TimeZone.getDefault()`):
sun.util.calendar.ZoneInfo[id="Asia/Shanghai",
offset=28800000,dstSavings=0,
useDaylight=false,
transitions=19,
lastRule=null]
Locale(Locale.getDefault()): zh_CN
Ответы:
Это изменение часового пояса 31 декабря в Шанхае.
Смотрите эту страницу для деталей 1927 года в Шанхае. В основном в полночь в конце 1927 года часы вернулись на 5 минут и 52 секунды. Таким образом, «1927-12-31 23:54:08» фактически происходило дважды, и похоже, что Java анализирует его как более поздний возможный момент для этой локальной даты / времени - отсюда и разница.
Просто еще один эпизод в часто странном и чудесном мире часовых поясов.
РЕДАКТИРОВАТЬ: Стоп пресс! История меняется ...
Исходный вопрос больше не будет демонстрировать совершенно такое же поведение, если его перестроить с версией TZDB 2013a . В 2013a результат будет 358 секунд с временем перехода 23:54:03 вместо 23:54:08.
Я заметил это только потому, что собираю подобные вопросы в Noda Time в форме модульных тестов ... Теперь тест изменился, но он показывает, что даже исторические данные не являются безопасными.
РЕДАКТИРОВАТЬ: История снова изменилась ...
В TZDB 2014f время изменения сместилось на 1900-12-31, и теперь это всего лишь 343 секунды (так что время между
t
иt+1
составляет 344 секунды, если вы понимаете, что я имею в виду).РЕДАКТИРОВАТЬ: Чтобы ответить на вопрос о переходе в 1900 году ... похоже, что реализация часового пояса Java обрабатывает все часовые пояса как просто в их стандартное время в любой момент до начала 1900 UTC:
Приведенный выше код не производит вывод на мой компьютер с Windows. Таким образом, любой часовой пояс с любым смещением, отличным от стандартного в начале 1900 года, будет считаться переходным. Сам TZDB имеет некоторые данные, возвращающиеся раньше, и не полагается ни на какое представление о «фиксированном» стандартном времени (что является
getRawOffset
допустимым понятием), поэтому другие библиотеки не должны вводить этот искусственный переход.источник
Вы столкнулись с разрывом местного времени :
Это не особенно странно и происходило практически везде когда-то, поскольку часовые пояса менялись или менялись из-за политических или административных действий.
источник
Мораль этой странности такова:
источник
При увеличении времени вы должны преобразовать обратно в UTC, а затем добавить или вычесть. Используйте местное время только для отображения.
Таким образом, вы сможете пройти любые периоды, когда часы или минуты встречаются дважды.
Если вы конвертировали в UTC, добавляйте каждую секунду и переводите в местное время для отображения. Вы должны пройти до 23:54:08 вечера LMT - 11:59:59 вечера LMT, а затем 11:54:08 вечера CST - 11:59:59 вечера CST.
источник
Вместо преобразования каждой даты вы можете использовать следующий код:
И тогда увидите, что результат:
источник
1
, потому что у нас разные локали.Мне жаль говорить, но разрыв во времени немного сдвинулся
JDK 6 два года назад, а в JDK 7 совсем недавно в обновлении 25 .
Урок, который нужно выучить: избегайте времени, отличного от UTC, любой ценой, за исключением, возможно, демонстрации.
источник
Как объясняют другие, там есть временной разрыв. Существует два возможных смещения часового пояса для
1927-12-31 23:54:08
atAsia/Shanghai
, но только одно смещение для1927-12-31 23:54:07
. Таким образом, в зависимости от того, какое смещение используется, разница составляет либо одну секунду, либо разницу в 5 минут и 53 секунды.Это небольшое смещение смещений вместо привычного для нас перехода на летнее время в течение одного часа (летнее время), к которому мы привыкли, немного затеняет проблему.
Обратите внимание, что обновление 2013a базы данных часовых поясов переместило этот разрыв на несколько секунд раньше, но эффект все еще будет заметен.
Новый
java.time
пакет на Java 8 позволяет использовать это более ясно и предоставляет инструменты для его обработки. Данный:Тогда
durationAtEarlierOffset
будет одна секунда, аdurationAtLaterOffset
будет пять минут 53 секунды.Кроме того, эти два смещения одинаковы:
Но эти два разные:
Вы можете увидеть ту же проблему по сравнению
1927-12-31 23:59:59
с тем1928-01-01 00:00:00
, что в этом случае более раннее смещение вызывает более раннее смещение, а более ранняя дата имеет два возможных смещения.Другой способ подойти к этому - проверить, происходит ли переход. Мы можем сделать это так:
Вы можете проверить, является ли переход перекрытием, когда существует более одного действительного смещения для этой даты / времени, или промежуток, когда эта дата / время недопустима для этого идентификатора зоны - с помощью методов
isOverlap()
и .isGap()
zot4
Я надеюсь, что это поможет людям справиться с такой проблемой, как только Java 8 станет широко доступной, или тем, кто использует Java 7, которые используют JSR 310 backport.
источник
1900-12-31 23:54:16
и есть1900-12-31 23:54:17
, но это не работает на сайте, которым вы делитесь, поэтому они используют версию Java, отличную отИМХО, повсеместная, неявная локализация в Java - это ее самый большой недостаток дизайна. Это может быть предназначено для пользовательских интерфейсов, но, честно говоря, кто действительно использует Java для пользовательских интерфейсов сегодня, за исключением некоторых IDE, где вы можете в основном игнорировать локализацию, потому что программисты не являются целевой аудиторией для нее. Вы можете исправить это (особенно на серверах Linux):
К процессу Java Community членов Я рекомендую:
Я имею в виду, да ладно, разве глобальные статические переменные не являются шаблоном анти-OO? Ничто иное не является теми распространенными значениями по умолчанию, заданными некоторыми элементарными переменными среды .......
источник
Как говорили другие, это изменение времени в 1927 году в Шанхае.
Когда это было
23:54:07
в Шанхае, по местному стандартному времени, но через 5 минут и 52 секунды оно перешло на следующий день в00:00:00
, а затем местное стандартное время изменилось на23:54:08
. Вот почему разница между двумя значениями составляет 343 секунды, а не 1 секунда, как вы и ожидали.Время также может испортить в других местах, таких как США. В США есть летнее время. Когда начинается летнее время, время идет вперед на 1 час. Но через некоторое время летнее время заканчивается, и оно возвращается назад на 1 час назад к стандартному часовому поясу. Так что иногда при сравнении времени в США разница составляет около
3600
секунды, а не 1 секунды.Но есть что-то другое в этих двух временных изменениях. Последнее постоянно меняется, а первое было просто изменением. Это не изменилось назад или изменилось снова на ту же сумму.
Лучше использовать UTC, где время не меняется, если только не нужно использовать время не UTC, как на дисплее.
источник