2015-05-22 4 views
1

У меня есть код, приведенный ниже, чтобы добавить время к экземпляру DateTime:Как добавить время в DateTime, когда изменяется часовой пояс?

 DateTime d1 = new DateTime(); 
     d1 = d1.withZone(DateTimeZone.forID("Europe/London")); 
     ArrayList<String> timeList = new ArrayList<String>(); 

     for(int x = 1; x <= 10; x++) { 
     //Adds six hours to the DateTime instance. 
       d1 = d1.plusHours(6); 
       d1 = d1.plusMinutes(0); 
       d1 = d1.plusSeconds(0); 
       timeList.add(d1.toString()); 
     } 

Это создаст набор из 10 раз, чтобы добавить к ArrayList. Однако скажите, что было внесено изменение летнего времени, когда было добавлено 6 часов. Как я могу сгенерировать правильное время, когда дополнительный час добавляется/удаляется из-за изменения часового пояса? На данный момент он не удаляет/не добавляет дополнительный час, используя этот метод.

Например, я ожидал бы, что ниже будут генерироваться следующие моменты, если я начну использовать код 24 октября 2015 года в 10:00. Обратите внимание, что часовой пояс изменяется в 02:00 25/10/2015.

24/10/2015 10:00:00 BST 
24/10/2015 16:00:00 BST 
24/10/2015 22:00:00 BST 
25/10/2015 05:00:00 GMT 
25/10/2015 11:00:00 GMT 
25/10/2015 17:00:00 GMT 
25/10/2015 23:00:00 GMT 
26/10/2015 05:00:00 GMT 
26/10/2015 11:00:00 GMT 
26/10/2015 17:00:00 GMT 
+1

Что вы подразумеваете под "пристройкой"? Было бы очень полезно, если бы вы показали короткую, но полную программу, демонстрирующую проблему, включая фактический вывод и ожидаемый результат. –

+0

Добавил больше информации в сообщение. – MisterIbbs

+1

Вы не добавили короткий, но полный пример, хотя это то, что я действительно хотел бы увидеть ... –

ответ

2

Обычно я бы оставил правильный ответ Джон Скит (его последний комментарий является более или менее ответ на мой взгляд), но теперь есть два других недопустимые ответы, которые пропускают критическую точку.

Ваша "проблема" может быть сужен до этих строк и (неправильно) ожидания:

24/10/2015 22:00:00 BST

25/10/2015 05 : 00: 00 GMT

Вы правильно пишете, что переход от летнего времени к зимнему периоду происходит в Великобритании в 2015-10-25 в 2:00 утра. Это означает, что час с надписью «01» происходит дважды (ситуация перекрытия), потому что часы установлены назад и повторяются в этот час. Поэтому номинальное количество часов в качестве позиций часов должно быть увеличено на один час, чтобы получить реальную физическую продолжительность в часах. Математически:

nominal duration + one hour = real duration (= 6 real hours) 
=> nominal duration = (6 - 1) hours = 5 virtual hours 

Имейте в виду, что временные метки, как "24/10/2015 22:00:00 BST" (в ISO-офсетной нотации: "2015-10-24T22: 00: 00 + 01") стенд для глобальных физических моментов, поэтому временная дельта между такими моментами выражает физическую продолжительность. Добавление продолжительности в шесть часов к первоначальному моменту содержит дополнительный час, тем не менее, так что вам нужно удалить один час с настоящих часов, чтобы получить номинальную продолжительность (измеряется в положениях часов - см. Вторую часть данного уравнения выше). Поэтому в мгновенной записи:

[2015-10-24T22:00+01] + 6 physical hours = 
    [2015-10-25T04:00+01] = [2015-10-25T03:00+00] = [2015-10-25T03:00Z] 

И в номинальной локальной метке времени записи (только наблюдая позицию часов):

[2015-10-24T22:00] + 5 virtual hours (clock positions) = [2015-10-25T03:00] 

Так повторение позиции часов снижает номинальную продолжительность и не увеличивает его.

И это то, что Joda времени правильно делает:

DateTime d1 = new DateTime(2015, 10, 24, 10, 0, 0, 0, DateTimeZone.forID("Europe/London")); 

for (int x = 1; x <= 10; x++) { 
    d1 = d1.plusHours(6); 
    System.out.println("> " + d1.toString()); 
} 

> 2015-10-24T16:00:00.000+01:00 
> 2015-10-24T22:00:00.000+01:00 
> 2015-10-25T03:00:00.000Z 
> 2015-10-25T09:00:00.000Z 
> 2015-10-25T15:00:00.000Z 
> 2015-10-25T21:00:00.000Z 
> 2015-10-26T03:00:00.000Z 
> 2015-10-26T09:00:00.000Z 
> 2015-10-26T15:00:00.000Z 
> 2015-10-26T21:00:00.000Z 
+0

О, бог * facepalm * Я просто предположил, что ОП был прав и не смотрел на дату. –

+0

Исправление ... Что касается утверждения: «час, обозначенный как« 02 », случается дважды», я считаю, что на самом деле это повторение «01». Из того, что я прочитал, в США, Канаде и ЕС, в 1:59 или в такт 2 часа, часы возвращаются к «01: 00», чтобы повторить 1 час AM. –

+0

@BasilBourque Исправил опечатку. Я был в заблуждении, потому что в Центральной Европе часы отскакивают через час по местному времени в 3 часа ночи (в Германии: часы 2 повторяются). –

0

Не волнуйтесь, использование java.time

  • Видимо вы используете библиотеку Joda-Time. Вместо этого используйте java.time.
  • Java.классы времени автоматически обрабатывают переходы на летнее время (DST).
  • Вам не нужно ничего делать, кроме как поддерживать JVM в актуальном состоянии с изменениями tzdata time zone database, которые могут повлиять на ваши часовые пояса. См. Обновления Oracle’s provided tool for tzdata.

java.time

Давайте посмотрим на результаты добавления шести часов с помощью классов java.time.

Определите дату и время суток.

LocalDate ld = LocalDate.of (2015, Month.OCTOBER, 24); // 24th Oct 2015 at 10:00am per the Question. 
LocalTime lt = LocalTime.of (10, 0); 

Определение часового пояса, а ZoneId объект, для Europe/London.

ZoneId z = ZoneId.of ("Europe/London"); 

Комбинировать, чтобы создать объект ZonedDateTime.

ZonedDateTime zdtStart = ZonedDateTime.of (ld, lt, z); 

Извлечение Instant из ZonedDateTime. Класс Instant представляет собой момент на временной шкале в UTC с разрешением nanoseconds (до девяти (9) цифр десятичной дроби).

Instant instantStart = zdtStart.toInstant (); 

Определить наш промежуток времени, шесть часов, как Duration. Классы java.time могут выполнять математику с датой и временем, добавляя объект Duration.

A Duration не привязан к временной шкале и фактически хранит несколько секунд и несколько наносекунд. Таким образом, в этом классе нет никаких умений «шесть часов», часов и летнего времени и т. Д. Когда мы запрашиваем Duration из шести часов, этот класс немедленно вычисляет (6 часов * 60 минут в час * 60 секунд в минуту) = 21 600 секунд в общей сложности.

Duration sixHours = Duration.ofHours (6); // 21,600 seconds = (6 hours * 60 minutes per hour * 60 seconds per minute). 

Петля десять раз. Первый цикл, добавив Duration к ZonedDateTime и преобразуйте результат в Instant.

// Increment the `ZonedDateTime`. 
ZonedDateTime zdt = zdtStart; 
for (int i = 1 ; i <= 10 ; i++) { 
    System.out.println (">zdt.toString() " + zdt + " | zdt.toInstant().toString(): " + zdt.toInstant () + "\n"); 
    // Set up next loop. 
    zdt = zdt.plus (sixHours); 
} 

При запуске. Обратите внимание на скачок во времени дня в Лондонское время. Это осень Daylight Saving Time (DST) осенью, когда осенью осень возвращается к стандартному времени, начиная со смещения от UTC +01:00 до смещения Zulu +00:00, где в 2 часа ночи часы возвращаются, чтобы повторить 1 AM час. Поэтому, когда мы ожидали бы 22:00 плюс шесть часов, чтобы выйти в 4 часа ночи, вместо этого мы увидим 3 часа ночи. В значении Instant вы можете увидеть, что действительно прошло шесть часов. Хитрость заключалась в том, что лондонцы ранили назад свои часы в течение часа.

См. history of DST cutovers за Europe/London.

zdt.toString() 2015-10-24T10: 00 + 01: 00 [Европа/Лондон] | zdt.toInstant(). toString(): 2015-10-24T09: 00: 00Z

zdt.toString() 2015-10-24T16: 00 + 01: 00 [Европа/Лондон] | zdt.toInstant(). toString(): 2015-10-24T15: 00: 00Z

zdt.toString() 2015-10-24T22: 00 + 01: 00 [Европа/Лондон] | zdt.toInstant().toString(): 2015-10-24T21: 00: 00Z

zdt.toString() 2015-10-25T03: 00Z [Европа/Лондон] | zdt.toInstant(). toString(): 2015-10-25T03: 00: 00Z

zdt.toString() 2015-10-25T09: 00Z [Европа/Лондон] | zdt.toInstant(). toString(): 2015-10-25T09: 00: 00Z

zdt.toString() 2015-10-25T15: 00Z [Европа/Лондон] | zdt.toInstant(). toString(): 2015-10-25T15: 00: 00Z

zdt.toString() 2015-10-25T21: 00Z [Европа/Лондон] | zdt.toInstant(). toString(): 2015-10-25T21: 00: 00Z

zdt.toString() 2015-10-26T03: 00Z [Европа/Лондон] | zdt.toInstant(). toString(): 2015-10-26T03: 00: 00Z

zdt.toString() 2015-10-26T09: 00Z [Европа/Лондон] | zdt.toInstant(). toString(): 2015-10-26T09: 00: 00Z

zdt.toString() 2015-10-26T15: 00Z [Европа/Лондон] | . Zdt.toInstant() ToString(): 2015-10-26T15: 00: 00Z

Для удовольствия мы подкачки, добавив шесть часов подряд, чтобы Instant и конвертировать результат в лондонскому времени.

// Increment the `Instant`. 
Instant instant = instantStart; 
for (int i = 1 ; i <= 10 ; i++) { 
    System.out.println (">instant.toString() " + instant + " | instant.atZone(z).toString(): " + instant.atZone (z) + "\n"); 
    // Set up next loop. 
    instant = instant.plus (sixHours); 
} 

При запуске мы видим одинаковые значения.

instant.toString() 2015-10-24T09: 00: 00Z | instant.atZone (z) .toString(): 2015-10-24T10: 00 + 01: 00 [Европа/Лондон]

instant.toString() 2015-10-24T15: 00: 00Z | instant.atZone (z) .toString(): 2015-10-24T16: 00 + 01: 00 [Европа/Лондон]

instant.toString() 2015-10-24T21: 00: 00Z | instant.atZone (z) .toString(): 2015-10-24T22: 00 + 01: 00 [Европа/Лондон]

instant.toString() 2015-10-25T03: 00: 00Z | instant.atZone (z) .toString(): 2015-10-25T03: 00Z [Европа/Лондон]

instant.toString() 2015-10-25T09: 00: 00Z | instant.atZone (z) .toString(): 2015-10-25T09: 00Z [Европа/Лондон]

instant.toString() 2015-10-25T15: 00: 00Z | instant.atZone (z) .toString(): 2015-10-25T15: 00Z [Европа/Лондон]

instant.toString() 2015-10-25T21: 00: 00Z | instant.atZone (z) .toString(): 2015-10-25T21: 00Z [Европа/Лондон]

instant.toString() 2015-10-26T03: 00: 00Z | instant.atZone (z) .toString(): 2015-10-26T03: 00Z [Европа/Лондон]

instant.toString() 2015-10-26T09: 00: 00Z | instant.atZone (z) .toString(): 2015-10-26T09: 00Z [Европа/Лондон]

instant.toString() 2015-10-26T15: 00: 00Z | instant.atZone (г) .ToString(): 2015-10-26T15: 00Z [Europe/London]

Смотрите эту code run live at IdeOne.com.


О java.время

Рамка java.time встроена в Java 8 и более поздних версий. Эти классы вытесняют неприятные старые legacy классы времени, такие как java.util.Date, Calendar, & SimpleDateFormat.

Проект Joda-Time, в настоящее время в maintenance mode, советует перейти на классы java.time.

Чтобы узнать больше, см. Oracle Tutorial. И поиск Stack Overflow для многих примеров и объяснений. Спецификация: JSR 310.

Где получить классы java.time?

  • Java SE 8 и SE 9, а затем
    • Встроенный.
    • Часть стандартного Java API с объединенной реализацией.
    • Java 9 добавляет некоторые незначительные функции и исправления.
  • Java SE 6 и SE 7
    • Большая часть функциональности java.time будет обратно портирован на Java 6 & 7 в ThreeTen-Backport.
  • Android

ThreeTen-Extra Проект расширяет java.time с дополнительными классами. Этот проект является доказательством возможных будущих дополнений к java.time. Здесь вы можете найти полезные классы, такие как Interval, YearWeek, YearQuarter и more.

Смежные вопросы