ТЛ; Др
myPreparedStatement.setObject( // Pass java.time objects directly to database with JDBC 4.2 or later.
… ,
LocalDate.now() // Get current date today. Better to pass optional `ZoneId` time zone object explicitly than rely implicitly on JVM’s current default.
)
Java. время
В Java 8 an d позже новая структура java.time теперь встроена. Этот преемник Joda-Time определяется JSR 310 и расширен проектом ThreeTen-Extra.
Надеюсь, мы в конечном итоге увидим, что драйверы JDBC обновлены, чтобы напрямую обрабатывать новые типы java.time. Но до тех пор нам по-прежнему нужны типы java.sql. *. К счастью, новые методы были добавлены для удобного преобразования между типами.
Для даты, без времени суток и без часового пояса, тип Java - LocalDate
(весьма похож на Joda-Time).
Что касается вашей обеспокоенности по поводу часового пояса, связанного с LocalDate
, это имеет значение, когда вы переводите дату только к дате-времени, к моменту времени. Только для даты - это просто неопределенная идея, без реального смысла, пока вы не переведете ее на временной промежуток времени на шкале времени (от полуночи до полуночи в какой-то часовой пояс). Например, для определения «сегодня» требуется часовой пояс. В java.time мы используем класс ZoneId
.
LocalDate today = LocalDate.now(ZoneId.of("America/Montreal"));
Если вы не указали, то для определения даты используется текущий часовой пояс вашего JVM. Другими словами, следующие две строки эквивалентны.
LocalDate today = LocalDate.now();
LocalDate today = LocalDate.now(ZoneId.systemDefault());
Я считаю, что первый вариант, now()
, чтобы быть плохим выбором дизайна API. Это неявное применение текущего часового пояса JVM не приводит к путанице, ошибкам и страданиям среди наивных разработчиков. Во-первых, текущее значение JVM зависит от машины, настроек хост-системы и системных администраторов. Хуже того, текущий по умолчанию JVM может изменить в любой момент, во время выполнения, любым кодом в любом потоке любого приложения в пределах этой JVM. Поэтому наилучшей практикой является всегда указывать желаемый/ожидаемый часовой пояс.
Теперь, когда у нас есть объект java.time для «today», как его получить в базе данных?
С помощью JDBC 4.2 или более поздней версии обменивайтесь java.time
объектами с вашей базе данных.
myPreparedStatement.setObject(… , today) ;
Чтобы получить:
LocalDate ld = myResultSet.getObject(… , LocalDate.class) ;
Если вы пока не можете обновить до JDBC 4.2 или более поздней версии: Используйте java.sql.Date
объект. В Java 8 этот старый класс получил новые методы, toLocalDate
и valueOf
. Последний является нашим мостом от типа java.time до типа java.sql.
java.sql.Date sqlToday = java.sql.Date.valueOf(today);
Оттуда осуществляется обычная обработка PreparedStatement
.
myPreparedStatement.setDate(1 , sqlToday);
Дата только против Даты времени
Возможно, у вас есть опасения по поводу такой даты только фитинг ваших потребностей бизнеса.
Если вам необходимо знать, например, если контракт был заключен к концу дня по юридическим причинам, то дата-только является неправильным типом данных, если это означает определенный момент, такой как удар в полночь в Монреаль. Новый день наступает раньше в Париже, чем в Монреале, поэтому «сегодня» в Париже «вчера» в Монреале. Если конечный срок вашего контракта определяется юридически в конце дня в Монреале, вы должны применить часовой пояс. Чтобы применить часовой пояс, вы должны иметь дату-время, а не только дату. Вы можете сделать прыжок с LocalDate
в ZonedDateTime
, но я считаю, что слишком сложный. Ваша база данных должна была использовать тип даты с начала.
В Postgres тип даты - тип TIMESTAMP WITH TIME ZONE
. Это имя является неправильным, поскольку часовой пояс фактически не хранится. Подумайте об этом как «отметка времени с уважением для часового пояса». Postgres использует любое смещение-from-UTC или информацию о часовом поясе, сопровождающую входящие данные, для настройки на UTC, и эта информация о смещении/зоне затем отбрасывается. Другой тип, TIMESTAMP WITHOUT TIME ZONE
, полностью игнорирует информацию о смещении/зоне, и это неправильное поведение для большинства бизнес-приложений.
Я подозреваю, что многие разработчики или администраторы баз данных могут сделать наивную ошибку в мышлении по интуиции, что только с датой имеет очевидный смысл. Но на самом деле, если у вас есть конкретные или строгие ориентированные на мгновение потребности, такие как законности в отношении таких событий, как «подписанный контракт», «полученная фактура» или «нанятый сотрудник компании», тогда следует использовать значение даты-времени, а не дату -только.
Другими словами, в отношении автора на вопрос в комментарии:
и я ожидал, там должен быть способ работы с датами, не прибегая к экземплярам времени.
Нет, я бы сказал, что просит неприятностей. Если момент имеет значение, используйте дату-время, а не дату-только.
О java.time
java.time каркас встроен в Java 8 и более поздних версий. Эти классы вытесняют неприятные старые legacy классы времени, такие как java.util.Date
, Calendar
, & SimpleDateFormat
.
Проект Joda-Time, в настоящее время в maintenance mode, советует перейти на классы java.time.
Чтобы узнать больше, см. Oracle Tutorial. И поиск Stack Overflow для многих примеров и объяснений. Спецификация: JSR 310.
Где получить классы java.time?
- Java SE 8, Java SE 9, а затем
- Встроенный.
- Часть стандартного Java API с объединенной реализацией.
- Java 9 добавляет некоторые незначительные функции и исправления.
- Java SE 6 и Java SE 7
- Большая часть функциональности java.time будет обратно портирован на Java 6 & 7 в ThreeTen-Backport.
- Android
- Более поздние версии Android реализаций пачке классов java.time.
- Для более ранних Android, проект ThreeTenABP адаптируется ThreeTen-Backport (упомянутый выше). См. How to use ThreeTenABP….
ThreeTen-Extra Проект расширяет java.time с дополнительными классами. Этот проект является доказательством возможных будущих дополнений к java.time. Здесь вы можете найти полезные классы, такие как Interval
, YearWeek
, YearQuarter
и more.
И какова семантика на стороне db? Если это * мгновенно *, а не * дата *, вы все равно жареные. –
@MarkoTopolnik Как я получаю от [table] (http://www.postgresql.org/docs/9.1/static/datatype-datetime.html), это просто дата с интервалом времени (так как это занимает 4 байта, а не 8 байты как типы DateTime). – ovgolovin
Должно быть безопасно использовать вашу технику, потому что все проблемы с часовым поясом должны быть приняты во внимание с помощью «LocalDate # toDate». –