Старый
java.util.Date
Класс java.util.Date
является частью старых классов даты и времени, которые оказались плохо спроектированными, запутанными и неприятными. Цель состоит в том, чтобы представить момент ( дата и время дня ) на временной шкале.
Класс, кажется, представляет момент в UTC, за исключением того, что его метод toString
молча применяет текущий часовой пояс JVM по умолчанию при генерации String, что создает иллюзию, что java.util.Date имеет часовой пояс, но на самом деле не. Ну, на самом деле у есть часовой пояс, назначенный глубоко в его исходном коде, который используется для чего-то внутри, но не очевиден и не может быть установлен или получен. Запутанный беспорядок.
java.sql.Date
java.sql.Date
усугубляет плохую ситуацию, представляя значение только для даты (что подразумевается под «DATE» в мире баз данных SQL ) но сделал это как хак, расширив java.util.Date
. Но вы должны притворяться, что это , а не подкласс, как указано в классе документа. Кроме того, у него есть время суток, но он делает вид, что не настраивается на первый момент дня в UTC . Запутанный беспорядок.
И еще одна вещь ... класс java.sql.Date
добавляет доли секунды с разрешением наносекунд . Это выходит за рамки разрешения миллисекунд , используемого java.util.Date. Многие базы данных поддерживают более точное разрешение, например микросекунда или наносекунда.
Таким образом, в этих старых классах даты и времени невозможно по-настоящему представить значение только для даты без времени суток и часового пояса.
Новый
На помощь приходит фреймворк java.time . Вдохновлен успешным проектом Joda-Time . Встроенный в Java 8 и позже. Back-портирован на Java 6 & 7 , а далее адаптирован под Android . См. Oracle Tutorial .
Instant
Класс Instant
представляет момент на временной шкале в UTC с разрешением наносекунд. Ясно и просто.
Instant instant = Instant.now();
instant.toString () → 2016-06-19T02: 34: 55,564Z
Если для использования со старым кодом требуется java.util.Date
, вы можете выполнить конвертацию. Смотрите новые методы, добавленные к старому классу: java.util.Date :: toInstant () и java.util.Date.from (Instant) .
Зонная
Чтобы настроить время настенных часов в некоторых населенных пунктах , примените offset-from-UTC (ZoneOffset
), чтобы получить OffsetDateTime
объект. Еще лучше, если вы знаете правильное название часового пояса, примените ZoneId
, чтобы получить ZonedDateTime
.
Например, America/Montreal
на четыре часа меньше UTC летом под Летнее время (DST) , поэтому мы видим 22:00 (22:00) ) в предыдущую дату в коде ниже, а не в 2 часа ночи в примере выше. Возвращение на четыре часа перешло через полночь в предыдущую дату. Но и объект instant
, показанный выше, и объект zdt
, увиденный следующим , представляют один и тот же одновременный момент на временной шкале. Тот же момент в истории, но «завтра» в Париже, Калькутте и Окленде, а «вчера» в Монреале, Мехико и Гонолулу.
ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );
zdt.toString () → 2016-06-18T22: 34: 55.564-04: 00 [Америка / Монреаль]
LocalDate
Для значения только на дату используйте класс LocalDate
. Ни время суток, ни часовой пояс не сохраняются.
LocalDate localDate = zdt.toLocalDate();
Но учтите, что часовой пояс имеет решающее значение при определении даты , поскольку в любой данный момент дата может меняться по всему земному шару в зависимости от часового пояса. Таким образом, обсуждение выше об указании часового пояса. Например, посмотрите далее, как мы получаем 18 июня, а не 19th .
localDate.toString () → 2016-06-18
Если это различиемежду датами по часовому поясу имеет значение для вашего бизнеса, вы должны использовать значение даты и времени, хранящееся в столбце базы данных типа TIMESTAMP WITH TIME ZONE
, а не DATE
.
Переполнение стека поиска для получения дополнительной информации и множества примеров java.time (тег: java-time
).
База данных
Для сохранения в базе данных используйте JDBC драйвер , соответствующий JDBC 4.2 spec (см. Guide * 1159) *). Вызовите setObject
и getObject
для PreparedStatement
, чтобы напрямую использовать объекты java.time.
Если ваш драйвер JDBC еще не поддерживает такое прямое использование типов java.time, используйте новые методы , добавленные к старым классам , чтобы упростить преобразование. Но сведите к минимуму использование старых классов; немедленно преобразуйте в java.time и используйте только объекты java.time в своей бизнес-логике.
java.sql.Date mySqlDate = java.sql.Date.valueOf( localDate );
И другое направление.
LocalDate localDate = mySqlDate.toLocalDate();