Как сохранить DateTime как дату с включенным смещением TimeZone?

У меня есть DateTime, включая TimeZone Europe/Vienna (+0200). Получается таким методом:

settlementService.getPendingPeriodStart()

и посмотрите с toString следующим образом:

2012-06-01T00:00:00.000+02:00

Теперь я хочу сохранить эту дату 2012-06-01 как java.util.Date, поэтому я попробовал что-то вроде этого:

transactionDate = settlementService.getPendingPeriodStart().withTime(0, 0, 0, 0).toDate();

Но результат таков:

Чт, 31 мая, 22:00:00 UTC 2012

Каков наилучший способ сохранить результат DateTime как дату, включая смещение часового пояса, поэтому transactionDate должен быть 2012-06-01. Я мог бы повозиться с GregorianCalendar, но это не то, что мне нравится. Это должно быть проще, не так ли?

Кстати (если не понятно). Локальная система работает в формате UTC. Вот почему результат: Чт, 31 мая, 22:00:00 UTC 2012.


person Bevor    schedule 25.06.2012    source источник
comment
Вы уверены, что вам нужно сохранить дату с часовым поясом пользователей, а не сохранить ее в централизованном часовом поясе и преобразовать ее соответствующим образом?   -  person John Kane    schedule 25.06.2012
comment
У Date не может быть часового пояса, поэтому вы действительно требуете невозможного.   -  person Ole V.V.    schedule 21.05.2021


Ответы (3)


К сожалению, принятый ответ вводит в заблуждение. Собственно говоря,

2012-06-01T00:00:00.000+02:00 = 2012-05-31T22:00:00Z

Z справа — это обозначение часового пояса для нулевого смещения часового пояса. Он означает Zulu и указывает часовой пояс Etc/UTC (который имеет смещение часового пояса +00:00 часа).

Запись 2012-06-01T00:00:00.000+02:00 как 2012-06-01, хотя это всего лишь вызов функции, опасна для любой бизнес-логики, которая зависит от часового пояса, поскольку может иметь другую дату в часовом поясе с другим значением смещения, например. как показано выше. 2012-06-01 — это просто LocalDate, который следует использовать для отслеживания событий. как дата рождения, дата свадьбы и т.д.

java.время

Устаревший API даты и времени (java.util типы даты и времени и их тип форматирования, SimpleDateFormat и т. д.) устарел и подвержен ошибкам. Рекомендуется полностью прекратить его использование и переключиться на java.time, современный API даты и времени*.

Кроме того, ниже приводится уведомление на главной странице Joda-Time:

Обратите внимание, что начиная с Java SE 8 пользователям предлагается перейти на java.time (JSR-310) — основную часть JDK, которая заменяет этот проект.

Решение с использованием java.time, современного API:

Как анализировать заданную строку даты и времени:

Данная строка даты и времени имеет смещение часового пояса, поэтому ее следует анализировать как OffsetDateTime. Поскольку современный API даты и времени основан на ISO 8601 и не требует использования объекта DateTimeFormatter явно, если строка даты и времени соответствует стандартам ISO 8601.

OffsetDateTime odt = OffsetDateTime.parse("2012-06-01T00:00:00.000+02:00"); // 2012-06-01T00:00+02:00

Как получить дату и время в формате UTC:

Есть несколько способов. Самый простой способ — преобразовать его в Instant, который представляет мгновенную точку на временной шкале в формате UTC.

Instant instant = odt.toInstant(); // 2012-05-31T22:00:00Z

Альтернативно,

OffsetDateTime odtUtc = odt.withOffsetSameInstant(ZoneOffset.UTC); // 2012-05-31T22:00Z

Как избавиться от java.util.Date:

Если вам вообще нужен экземпляр java.util.Date из экземпляра OffsetDateTime, вы можете использовать Date#from(Instant instant).

Date date = Date.from(instant); // Thu May 31 23:00:00 BST 2012 <--In my timezone

Обратите внимание, что объект java.util.Date не является реальным объектом даты и времени, как современный типы даты и времени; скорее, он представляет количество миллисекунд со стандартного базового времени, известного как эпоха, а именно January 1, 1970, 00:00:00 GMT (или UTC). Когда вы печатаете объект java.util.Date, его метод toString возвращает дату и время в часовом поясе JVM, вычисленные из этого значения в миллисекундах. Если вам нужно напечатать дату-время в другом часовом поясе, вам нужно будет установить часовой пояс на SimpleDateFormat и получить из него отформатированную строку, например.

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX", Locale.ENGLISH);
sdf.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
System.out.println(sdf.format(date)); // 2012-05-31T22:00:00.000Z

Как убрать часть даты:

Как я уже объяснял, это опасно для любой бизнес-логики, зависящей от часового пояса. Однако это всего лишь вопрос простого вызова функции.

LocalDate localDate = odt.toLocalDate(); // 2012-06-01

Узнайте больше о java.time, современном API даты и времени* из Trail: Дата Время.


* По какой-либо причине, если вам нужно придерживаться Java 6 или Java 7, вы можете использовать ThreeTen-Backport, который переносит большую часть функций java.time на Java 6 и 7. Если вы работаете над проектом Android и ваш уровень Android API по-прежнему не соответствует Java-8, проверьте Java 8+ API доступно через дешугаринг и Как использовать ThreeTenABP в Android Project.

person Arvind Kumar Avinash    schedule 21.05.2021

Дата и часовой пояс пользователя - это две разные вещи. Один — дата, другой — предпочтение или параметр представления.

Не пытайтесь хранить их в одном поле.

Учтите, что было бы невозможно даже эффективно хранить их вместе (без потери точности), поскольку дата может быть сохранена в длинном только потому, что указано, что это дата UTC.

Вы можете сохранить часовой пояс в качестве смещения (часто рекомендуется сохранять минуты в этом смещении ([hh]:[mm]) из-за очень маленьких случаев).

person Denys Séguret    schedule 25.06.2012

Я думаю, что нашел решение. (Если вы знаете лучшее решение, просто дайте мне знать)

DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");

DateTime dateTimeWithTimeZone = new DateTime(DateTimeZone.forID("Europe/Vienna")).withDate(2012, 06, 01).withTime(0, 0, 0, 0);      
Date dateWithTimeZoneIncluded = dateTimeWithTimeZone.toLocalDate().toDate();

System.out.println(dateFormat.format(dateWithTimeZoneIncluded));

Результат 2012-06-01 соответствует ожидаемому.

person Bevor    schedule 25.06.2012