LocalDate и LocalDateTime на сервере, который работает в EST против UTC - PullRequest
1 голос
/ 06 апреля 2020

Я пытаюсь понять LocalDate и LocalDateTime. Поскольку они не несут информацию о зоне, как она работает сейчас () в двух разных часовых поясах.

Пример:

Сервер 1 (часовой пояс EST):

LocalDateTime.now () -> 2020-04-06T23: 00: 00.040 LocalDate.now (). -> 2020-04-06

Сервер 2 (UT C часовой пояс):

LocalDateTime.now () -> Каким будет значение? LocalDate.now (). -> Какова будет ценность? (Обратите внимание, что в EST время выполнения было 11 вечера)

Кроме того, если я преобразую строку даты ниже в LocalDateTime, а затем в LocalDate, каков будет результат?

2020-04-06T23: 00: 00,000

Ответы [ 2 ]

4 голосов
/ 06 апреля 2020

Чтобы избежать путаницы, передайте явный часовой пояс на now() и убедитесь сами:

    ZoneId easternTime = ZoneId.of("America/Montreal");
    System.out.println(LocalDateTime.now(easternTime));
    System.out.println(LocalDateTime.now(ZoneOffset.UTC));
    System.out.println(LocalDate.now(easternTime));
    System.out.println(LocalDate.now(ZoneOffset.UTC));

Вывод, когда я бегал только сейчас:

2020-04-06T09:56:17.381558
2020-04-06T13:56:17.385215
2020-04-06
2020-04-06

Хотя вы правы, что LocalDateTime и LocalDate не содержат никакой информации о часовом поясе, их методы now используют часовые пояса. Либо тот, который был передан им, либо, если вы используете вариант без аргументов, часовой пояс JVM по умолчанию.

Вы также спросили:

Кроме того, если я преобразую ниже строка даты для LocalDateTime, а затем toLocalDate, каков будет результат?

2020-04-06T23: 00: 00.000

Почему бы не попробовать это тоже?

    LocalDateTime ldt = LocalDateTime.parse("2020-04-06T23:00:00.000");
    System.out.println(ldt);
    LocalDate ld = ldt.toLocalDate();
    System.out.println(ld);
2020-04-06T23:00
2020-04-06

Преобразование из LocalDateTime в LocalDate не требует никакого часового пояса (или смещения UT C). Часть времени просто отбрасывается, а часть даты остается неизменной.

4 голосов
/ 06 апреля 2020

Смещения меняются со временем

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

Возможно, вы думаете о 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. Таким образом, даже во время выполнения вашего приложения значение по умолчанию можно изменить в любой момент.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...