Calendar.getInstance с TimeZone против новой даты () - PullRequest
0 голосов
/ 07 октября 2018

У меня есть утилита, написанная в моем приложении, которая берет часовой пояс и возвращает мне дату (java.util.Date) следующим образом -

// Inside MyDateHelper.java
public static java.util.Date getTimeForTimeZone(String timeZoneId)
{
    final Date currentDate = Calendar.getInstance(TimeZone.getTimeZone(timeZoneId)).getTime();
    return currentDate;
}

Я исследовал Интернет, чтобы найти, что Date делаетне имеет никакой информации о часовом поясе в нем.Скорее, это обертка вокруг длинного значения, начиная с эпохи 1970 года. Итак, мой вопрос заключается в том, должен ли я получить текущую дату-время, когда произошла транзакция, для хранения в поле даты (типа java.util.Date), Эта утилита для какого-либо использования?

Для всех практических целей две строки кода достигают того же самого?

transactionEntry.setTime(MyDateHelper.getTimeForTimeZone("UTC+7:00"));

ИЛИ

transactionEntry.setTime(new Date());

Я такжепроверил новый Java 8 Time API, но для моей цели я думаю, что это тоже излишнее и ничего больше не дает new Date() -

Date date4 = new Date();
LocalDateTime localDate = date4.toInstant().atZone(ZoneId.of("UTC+07:00")).toLocalDateTime();
final ZonedDateTime dateWithZone = localDate.atZone(ZoneId.of("UTC+07:00"));
Date dateOutput = Date.from(dateWithZone.toInstant());
transactionEntry.setTime(dateOutput);

Вся цель состоит в том, чтобы зафиксировать время, когда транзакция произошла счасовой пояс, но я могу хранить время только как java.util.Date.Независимо от того, в каком часовом поясе произошла транзакция, Дата сможет правильно зафиксировать момент времени, верно?Может ли кто-нибудь подтвердить, что это понимание верно?

Ответы [ 3 ]

0 голосов
/ 07 октября 2018

Первое предложение:

    Instant transactionTime = Instant.now();

Вы правы, что нет смысла проходить время в вашем часовом поясе, ни в ZonedDateTime, ни в Calendar, когда вам нужноэто метка времени, момент времени.java.time.Instant - это именно тот момент времени без часового пояса (и, следовательно, самая прямая замена для Date).Возможно, вам следует по возможности использовать java.time, современный Java-интерфейс даты и времени.Date, Calendar и TimeZone не только давно устарели, но и имеют ряд проблем с дизайном.С современными классами работать намного удобнее.

Если ваш класс записи транзакции внутренне использует java.util.Date и вы не хотите обновлять его внутреннюю логику прямо сейчас, вы все равно можете добавить перегруженный setTimeметод, который принимает Instant.

public void setTime(Instant time) {
    // Delegate to the old method that accepts a java.util.Date
    setTime(Date.from(time));
}

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

Второе предложение, если вы настаиваете на Date Я бы все же предпочел:

    Date transactionTime = Date.from(Instant.now());

Он делает то же самое, что и new Date(), но гораздо более прямо говорит читателю, что вы получаете текущий момент.Я не понимаю, как это не может быть преимуществом.

В качестве отступления, если вы хотите использовать свой часовой пояс, вам следует использовать правильный идентификатор часового пояса, например Antarctica/Davis, а не смещение.Опять же, он сообщает вашему читателю больше о ваших намерениях и ориентирован на будущее, если летнее время (DST) будет введено какое-то время или смещение изменится по другим причинам.

0 голосов
/ 07 октября 2018

Ответ Ole VV Правильно.Я добавлю немного обсуждения.

Существует только одна временная шкала, переживаемая всеми на Земле одновременно (игнорируя Эйнштейна и др.).По договоренности мы отслеживаем это время в UTC.

Научитесь думать о UTC как Единственное истинное время .Все другие смещения и зоны являются всего лишь вариацией UTC.Когда вы работаете программистом или системным администратором, забудьте о своем собственном приходском часовом поясе.Держите второй клик на вашем столе или время отслеживания стены в UTC.Делайте все ваши записи, отслеживание, хранение данных и обмен данными в UTC.

Базовый класс для отслеживания момента в UTC - java.time.Instant.Объекты этого класса всегда находятся в UTC по определению.Этот класс заменяет java.util.Date, который также представляет момент в UTC, но имеет много недостатков дизайна и никогда не должен использоваться.Instant имеет разрешение наносекунд, меньше, чем миллисекунды Date.

Для большей гибкости используйте класс OffsetDateTime.

OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;

И снова.

Instant instant = odt.toInstant() ;

Смещение от UTC - это просто количество часов, минут и секунд.Часовой пояс гораздо больше.Часовой пояс - это история прошлых, настоящих и будущих изменений в смещении, используемом людьми определенного региона.

Чтобы использовать часовой пояс, примените ZoneId, чтобы получить ZonedDateTime.Этот класс вытесняет ужасные классы Calendar и GregorianCalendar.

ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = instant.atZoneId( z ) ;

Возвращаясь снова.

Instant instant = zdt.toInstant() ;

Это zdt, odt и instant все представляют тот же самый одновременный момент , ту же точку на временной шкале.

Наконец, прекратите использовать Date и Calendar.Sun, Oracle и сообщество JCP отказались от этих классов, когда приняли JSR 310, и вы тоже должны это делать.Эти классы наследства действительно ужасны.

0 голосов
/ 07 октября 2018

но я могу сохранить время только как java.util.Date.

Тогда часовой пояс не имеет значения,

Calendar calendar = Calendar.getInstance();

calendar.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles"));
Date america = calendar.getTime();

calendar.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
Date shanghai = calendar.getTime();

System.out.println(america.equals(shanghai)); // true

Вы можете простоиспользуйте:

transactionEntry.setTime(new Date());

Эта страница поможет вам понизить Instant/Date, LocalDateTime, ZonedDateTime.

Я думаю, вы могли быпродумать дизайн.Почему допускается только java.util.Date?

Из описания кажется, что вам небезразличен часовой пояс, в котором происходит транзакция.Пока java.util.Date просто не поддерживают его.Это означает, что вы можете сохранить точное значение (в миллисекундах с эпохи) до java.util.Date, но это значение не может быть представлено точным датой и временем, поскольку часовой пояс был потерян.

Возможно, вам понадобится использовать java.time.ZonedDateTime чтобы достичь этого.

...