Изменить часовой пояс объекта Date без изменения даты

Могу ли я изменить часовой пояс объекта Date в моем Java-коде без изменения даты? Когда я пишу Date date = new Date(longValue);, я получаю эту дату в моем местном часовом поясе. Я хочу получить эту дату, но мой часовой пояс должен присутствовать в БД (не локальный) для моего идентификатора пользователя (например, «Америка/Чикаго»).

Заранее спасибо за помощь.


person user3334226    schedule 06.12.2016    source источник
comment
Всегда сохраняйте дату в БД, используя время UTC, и при необходимости вы можете получить дату любого часового пояса.   -  person Tony Dong    schedule 07.12.2016


Ответы (3)


tl;dr

ZonedDateTime zdtMontreal = 
    ZonedDateTime.now( ZoneId.of( "America/Montreal" ) );

ZonedDateTime zdtAuckland = 
    zdtMontreal.withZoneSameLocal( ZoneId.of( "Pacific/Auckland" ) );  

Не момент. Момент zdtAuckland произошел несколько часов назад.

Будьте уверены, что это действительно ваше намерение. У меня смутное ощущение, что вы делаете что-то не так, смущенный тем, как работает обработка даты и времени. Работа с датой и временем сбивает с толку. Обязательно поищите и изучите Stack Overflow.

Java.время

Проект Joda-Time, теперь в режим обслуживания, советует перейти на java.time.

Классы Local… намеренно не имеют информации о часовом поясе или смещении от UTC.

LocalDate ld = LocalDate.of( 2016 , Month.January , 23 ); // 2016-01-23
LocalTime lt = LocalTime.of( 12 , 34 , 56 );  // 12:34:56

Эти значения не еще не представляют точку на временной шкале. Будет ли это полдень в Окленде, Новой Зеландии, Париже, Франции или Монреале, Калифорния? Мы должны применить часовой пояс, чтобы определить фактический момент. Мы применяем ZoneId, чтобы получить ZonedDateTime.

Укажите правильное название часового пояса в формате continent/region, например America/Montreal, Africa/Casablanca или Pacific/Auckland. Никогда не используйте аббревиатуру из 3-4 букв, например EST, IST или CST, поскольку они не соответствуют часовым поясам, не стандартизированы и даже не уникальны(!).

ZoneId zMontreal = ZoneId.of( "America/Montreal" );
ZonedDateTime zdtMontreal = ZonedDateTime.of( ld , lt , zMontreal );

Чтобы увидеть строку, представляющую это значение в стандартном формате ISO 8601, вызовите toString. На самом деле класс ZonedDateTime расширяет стандартный формат, разумно добавляя название часового пояса в квадратных скобках.

String outputMontreal = zdtMontreal.toString();

2016-01-23T12:34:56-05:00[Америка/Монреаль]

Чтобы получить ту же дату и время суток в другом часовом поясе, повторите процесс.

ZoneId zParis = ZoneId.of( "Europe/Paris" );
ZonedDateTime zdtParis = ZonedDateTime.of( ld , lt , zParis );

ZoneId zAuckland = ZoneId.of( "Pacific/Auckland" );
ZonedDateTime zdtAuckland = ZonedDateTime.of( ld , lt , zAuckland );

Но знайте, что вы попадаете в другой момент времени. Полдень в Окленде наступает на несколько часов раньше, чем в Париже, а полдень в Монреале наступает еще позже, потому что три разных момента времени совпадают по совпадению с одним и тем же время настенных часов.

2016-01-23T12:34:56-05:00[Америка/Монреаль]

2016-01-23T12:34:56+01:00[Европа/Париж]

2016-01-23T12:34:56+13:00[Тихий океан/Окленд]

введите описание изображения здесь

Текущий момент

Чтобы узнать текущий момент, позвоните по номеру Instant.now. Класс Instant представляет момент на временной шкале. в UTC с разрешением наносекунды (до девяти (9) цифр десятичной дроби).

Instant instance = Instance.now();

Примените ZoneId для настройки часового пояса.

ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instance.atZone( z );

Повторите процесс для других желаемых часовых поясов, аналогично тому, что мы сделали выше.

В качестве ярлыка вы можете получить ZonedDateTime напрямую.

ZonedDateTime zdtMontreal = ZonedDateTime.now( ZoneId.of( "America/Montreal" ) );

И в качестве еще одного ярлыка вы можете применить другой часовой пояс, сохранив ту же дату и то же время суток (то же самое время настенных часов). Вызовите ZonedDateTime::withZoneSameLocal.

ZonedDateTime zdtAuckland = zdtMontreal.withZoneSameLocal( ZoneId.of( "Pacific/Auckland" ) );

Повторяю: это результаты в различных точках на временной шкале. zdtAuckland происходит за несколько часов до zdtMontreal.

Чтобы сохранить тот же момент, вместо этого вызовите ZonedDateTime::withZoneSameInstant.

База данных

Обычно лучше всего хранить значения даты и времени в базе данных в формате UTC. Уже широко обсуждалось на Stack Overflow. Найдите дополнительную информацию.


О java.time

Построена структура java.time. в Java 8 и выше. Эти классы заменяют проблемные старые устаревшие классы даты и времени, такие как java.util.Date, Calendar и SimpleDateFormat.

Проект Joda-Time, теперь в режим обслуживания, советует перейти на java.time.

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

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

  • Java SE 8 and SE 9 and later
    • Built-in.
    • Часть стандартного Java API со встроенной реализацией.
    • Java 9 добавляет некоторые незначительные функции и исправления.
  • Java SE 6 and SE 7
    • Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
  • Android

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

person Basil Bourque    schedule 06.12.2016

Вы можете найти ZonedDateTime весьма полезным:

Java 8 Преобразование заданного времени и часового пояса в UTC время

В качестве альтернативы вы можете создать еще один объект Date и применить к нему некоторое смещение вручную.

person Coderslang Master    schedule 06.12.2016
comment
Я уже пробовал, но это не решило мою проблему. Я только хочу изменить свой часовой пояс, а не дату. Например, я хочу, чтобы эта дата 23.11.2016, 16:16 EST была изменена на 23.11.2016, 16:16 CST. Это возможно? - person user3334226; 07.12.2016

Пример того, как это сделать с помощью класса Java8 ZonedDateTime:

Date date = new Date(longValue);
ZoneId = ZoneId.of("America/Chicago");
ZonedDateTime dt = ZonedDateTime.ofInstant(date.toInstant(), zoneId);

Вы пометили вопрос с помощью Joda, но на самом деле с Java8 он вам больше не нужен.

person Magd Kudama    schedule 06.12.2016
comment
Я уже пробовал, но это не решило мою проблему. Я только хочу изменить свой часовой пояс, а не дату. Например, я хочу, чтобы эта дата 23.11.2016, 16:16 EST была изменена на 23.11.2016, 16:16 CST. Ваш пример также меняет дату. - person user3334226; 07.12.2016