В других ответах используются устаревшие классы.
java.time
И Joda-Time, и старые классы java.util.Date/.Calendar были вытеснены фреймворком java.time , встроенным в Java 8 и более поздние версии. Определяется JSR 310 . Продлен проектом ThreeTen-Extra . Обратный перенос в Java 6 & 7 с помощью проекта ThreeTen-BackPort , который обернут для Android с помощью проекта ThreeTenABP .
LocalDate
Значение только для даты без времени суток и без часового пояса может быть представлено классом LocalDate
. Такой класс отсутствовал в старых классах даты-времени, связанных с ранними версиями Java. Старый класс java.sql.Date
претендует на то, чтобы иметь только дату, но фактически имеет время суток, унаследованное от java.util.Date
(значение даты-времени).
LocalDate dateOfBirth = LocalDate.new( 1979 , 1 , 10 );
Без времени суток и часового пояса дата рождения по своей сути является неточной для определения возраста. Но почти во всех случаях использования нам все равно; часть дня «давай или возьми» достаточно близка.
ZonedDateTime
Для встречи мы не можем быть такими глупыми. Нам нужна дата, время и часовой пояс. В java.time это означает ZonedDateTime
класс. Часовой пояс является ключевым элементом , отсутствующим в сценарии в Вопросе. Добавьте часовой пояс и все хорошо.
ZoneId zoneIdMontreal = ZoneId.of( "America/Montreal" );
ZonedDateTime zdtMontreal = ZonedDateTime.of( 2010 , 1 , 10 , 20 , 0 , 0 , zoneIdMontreal );
Теперь передайте объекты на другую машину. Оба остаются неизменными: одно и то же значение только для даты рождения (1979-01-10) и одно и то же время для собрания в Монреале.
Настройка часового пояса
Затем вы можете настроить это совещание на другой часовой пояс, ожидаемый человеком, использующим этот другой аппарат.
ZoneId zoneIdParis = ZoneId.of( "Europe/Paris" );
ZonedDateTime zdtParis = zdtMontreal.withZone( zoneIdParis );
У нас есть один и тот же момент на временной шкале, представленной двумя модами, в двух объектах, zdtMontreal & zdtParis.
LocalDateTime
Если ваш nextMeeting
не имеет ни часового пояса, ни информации о смещении от UTC, тогда представляйте как LocalDateTime
объект. В базе данных он будет храниться в виде типа TIMESTAMP WITHOUT TIME ZONE
.
Такие значения не представляют момент на временной шкале. Они представляют только диапазон возможных моментов. Чтобы определить фактический момент, вы должны предоставить контекст определенного часового пояса.
Для хранения будущих значений даты и времени, таких как запланированное собрание, продолжительностью более нескольких недель, может быть целесообразно использовать это без часового пояса. Политики по всему миру склонны часто менять летнее время и пересматривать свои часовые пояса. И они часто делают это с небольшим предупреждением, всего за несколько недель.
Чтобы определить фактический момент, такой как отображение расписания в календаре, примените часовой пояс ZoneId
, чтобы получить ZonedDateTime
.
ISO 8601
Классы java.time по умолчанию используют стандартные форматы ISO 8601 при синтаксическом анализе / генерации текстовых представлений значений даты и времени. Класс ZonedDateTime
идет еще дальше, расширяя стандарт ISO 8601, добавляя название часового пояса в квадратных скобках.
При сериализации значений через текст используйте понятные и однозначные форматы ISO 8601.
Ни один из вопросов, поднятых в Вопросе, не остается. Использование превосходной библиотеки даты и времени и ISO 8601, такого как java.time, решает проблему.
База данных
В вашей базе данных должен использоваться тип только дата для даты рождения и тип отметки времени с часовым поясом для собрания (см. Типы данных SQL в Википедии и в документации вашей базы данных). Ваш драйвер JDBC обеспечивает вас обоими типами.
Со временем драйверы JDBC будут обновлены для непосредственного использования типов java.time. Но до тех пор мы должны конвертировать в java.sql типы, такие как java.sql.Date
и java.sql.Timestamp
. Новые методы были добавлены в старые классы для поддержки этих преобразований.
java.sql.Date sqlDateOfBirth = java.sql.Date.valueOf( dateOfBirth );
java.sql.Timestamp sqlMeeting = java.sql.Timestamp.valueOf( zdtMontreal );
Затем позвоните setDate
и setTimestamp
на ваш PreparedStatement
.
Идя в другом направлении, от базы данных до Java, наберите getDate
и getTimestamp
на вашем ResultSet
. Затем немедленно переводите в типы java.time, избегая использования типов java.sql в вашей бизнес-логике.
Для значения даты и времени мы должны пройти через объект Instant
. Instant
- это момент времени на UTC . Мы применяем часовой пояс, чтобы получить время настенных часов для пользователя.
LocalDate dateOfBirth = mySqlDate.toLocalDate();
Instant instant = mySqlTimestamp.toInstant();
ZonedDateTime zdtMontreal = ZonedDateTime.ofInstant( instant , zoneIdMontreal );