Смещения меняются со временем
6 апреля 2020 года большинство часовых поясов на восточном побережье Северной Америки, такие как America/Montreal
и America/New_York
, используют смещение на четыре часа после UT C.
Таким образом, в этих зонах 23:00 2020-04-06 - это одновременно 3:00 7-го в UT C. Добавьте четыре часа к 2020-04-06T23: 00, чтобы получить 2020-04-07T03: 00. Добавление четырех часов приводит нас от времени настенных часов, использованного в America/Port-au-Prince
и America/Nassau
к UT C.
Смещение, использованное вышеупомянутыми часовыми поясами, составляет четыре часа после UT C всего на полгода. Политики в этих местах решили соблюдать летнее время (DST) около полугода. Таким образом, полгода они прыгают на час вперед на час с смещением от UT C, равным -04: 00, а позже в году они отстают на час на смещение от UT C, равное -05. : 00. Например, ранее в 23:00 в America/New_York
было бы 04:00 в UT C, а не в 03:00 в апреле.
Стандартное время в январе пять часов позади UT C. Итак, 23:00 плюс пять часов - это 4:00 следующего дня.
ZoneId z = ZoneId.of( "America/New_York" ) ;
ZonedDateTime zdt = ZonedDateTime.of( 2020 , 1 , 6 , 23 , 0 , 0 , 0 , zNewYork ) ;
Instant instant = zdt.toInstant() ; // 2020-01-07T04:00Z
Летнее время в апреле на четыре часа отстает от UT C. Итак, 23:00 плюс четыре часа - это 3:00 следующего дня.
ZoneId z = ZoneId.of( "America/New_York" ) ;
ZonedDateTime zdt = ZonedDateTime.of( 2020 , 4 , 6 , 23 , 0 , 0 , 0 , zNewYork ) ;
Instant instant = zdt.toInstant() ; // 2020-04-07T03:00Z
Кстати, летнее время является лишь одной из многих причин, по которым у политиков есть смещение, используемое часовыми поясами их юрисдикции. , Политики во всем мире проявляют склонность к неожиданному изменению своих позиций. Ваше программирование всегда должно ожидать, что часовой пояс изменит свое смещение. Только потому, что ваша конкретная проблемная зона в настоящее время не соблюдает DST, не означает, что смещение никогда не изменится.
Что касается анализа 2020-04-06T23:00:00.000
как LocalDateTime
, вы получите 2020-04-06T23:00:00.000
. Игнорирование часовых поясов - это весь смысл LocalDateTime
. Поэтому никаких корректировок не производится.
![Table of date-time types in Java, both modern and legacy](https://i.stack.imgur.com/HNQS7.png)
Возможно, вы думаете о LocalDateTime
как о представлении определенной местности. Но, нет, он представляет любую местность или все населенные пункты. Но никогда не один конкретный населенный пункт. Для конкретной местности используйте ZonedDateTime
.
Псевдо часовые пояса
Другой момент: EST
- это , а не часовой пояс. Такие 2-4-буквенные буквенные коды не являются зонами реального времени, не стандартизированы и даже не являются уникальными. Например, под EST
вы имели в виду восточное стандартное время Австралии или восточное стандартное время Северной Америки ? * CST
Центральное стандартное время или Китайское стандартное время ? Избегайте этих псевдозон при обработке даты и времени.
И вы случайно использовали неправильный псевдокод. 6 апреля 2020 года большинство из этих часовых поясов на восточном побережье отмечают переход на летнее время. Таким образом, они будут считаться в «EDT», а не «EST». Чтобы избежать проблемы, укажите имя зоны реального времени.
Зоны реального времени именуются в формате Continent/Region
. См. Википедия для списка часовых поясов в реальном времени.
Никогда не звоните LocalDateTime.now
Я не могу представить себе случай, когда вызов LocalDateTime.now
будет правильным решением , Для определения текущего момента требуется часовой пояс (или смещение). И LocalDateTime
по определению не имеет часового пояса или смещения. Когда программист пишет LocalDateTime.now
, вы можете поспорить, что он не в полной мере понимает необходимые понятия.
Когда вы вызываете LocalDateTime.now
, текущий часовой пояс JVM по умолчанию неявно используется для захвата текущего времени, видимого люди в регионе этой зоны. И тогда факт того часового пояса удален.
Это:
LocalDateTime.now()
… - то же самое, что и это:
LocalDateDate.now( ZoneId.systemDefault() )
…, что аналогично получению текущего момента, наблюдаемого в определенном часовом поясе. с последующим удалением информации о часовом поясе:
ZonedDateTime.now( ZoneId.systemDefault() ).toLocalDateTime()
Дополнительные примеры кода, демонстрирующие LocalDateTime.now
, см. в правильном Ответе Ole VV
Где использовать LocalDateTime
Если LocalDateTime
не подходит для получения текущего момента и не подходит для отслеживания какого-либо момента, каково подходящее использование для этого класса? Три вещи: представление любого населенного пункта, представление всех населенных пунктов и бронирование будущих встреч.
- Любая местность была бы чем-то вроде заявления, когда начинается Рождество. В этом году Рождество начинается в 2020-12-25T00: 00, где бы вы ни находились. Конечно, это означает, что Рождество начинается сначала в Кирибати после полуночи, позже в Японии после полуночи, даже позже в Тунисе после полуночи, а еще позже в Чиках go после полуночи.
- Все населенные пункты будут выглядеть примерно так: Политика компании, согласно которой обеденные перерывы на всех наших заводах в Дели, Дюссельдорфе и Детройте запланированы на 12:30. Итак, 6 апреля 2020 года перерыв будет в 2020-04-06T12: 30: 00. Этот перерыв произойдет сначала в Дели, несколько часов спустя в Дюссельдорфе, и еще больше часов спустя в Детройте.
- Бронирование будущих встреч, в которых вы намереваетесь сохранить то же время суток независимо от изменений часового пояса. Смещение должно быть записано без смещения. Если ваше следующее посещение стоматолога состоится через шесть месяцев в 3 часа дня, мы хотим записать 3 часа дня без учета компенсации. Если смещение должно было быть изменено политиками, мы все еще хотим, чтобы встреча началась, когда часы пробивают три в эту дату в этой зоне.
Установить встречу.
LocalDateTime appointment = LocalDateTime.of( 2021 , 1 , 23 , 15 , 0 , 0 , 0 ) ;
Определить момент для создания календаря. Каждый раз, когда вы делаете это, вы можете получить другой результат, если политики изменили правила этого часового пояса.
ZoneId z = ZoneId.of ( "America/Panama" ) ;
ZonedDateTime dueToArrive = appointment.atZone( z ) ;
LocalDate
Что касается LocalDate
, мы видели в приведенных выше примерах дата зависит от часового пояса. В любой момент времени дата меняется по всему земному шару в зависимости от часового пояса. Это может быть «завтра» в Токио, Япония, и еще «вчера» в Монреале, Квебе c Канада.
Таким образом, вы должны указать часовой пояс при запросе текущей даты.
LocalDate ld = LocalDate.now( ZoneId.of( "Asia/Kolkata" ) ) ;
Если вы опустите часовой пояс, текущий часовой пояс JVM по умолчанию применяется неявно. Так LocalDate.now()
становится LocalDate.now( ZoneId.systemDefault() )
. Я рекомендую указывать желаемую / ожидаемую зону явно, а не полагаться на неявное значение по умолчанию.
Часовой пояс сервера
Вы сказали:
сервер, который работает в EST против UT C
К вашему сведению, серверы обычно должны быть установлены в UT C. Большая часть вашего мышления, программирования, ведения журналов и т. Д. Должна выполняться в UT C. Научитесь думать о UT C как об едином истинном времени со всеми другими зонами, кроме простых вариаций.
Как программист, вы никогда не должны полагаться на часовой пояс по умолчанию. Это далеко от вашего контроля. Это значение по умолчанию может быть легко изменено пользователем или системным администратором. Кроме того, любой код в любом потоке любого приложения в JVM может мгновенно изменить текущее время по умолчанию JVM с помощью вызова TimeZone.setDefault
. Таким образом, даже во время выполнения вашего приложения значение по умолчанию можно изменить в любой момент.