Преобразование LocalDate в LocalDateTime или java.sql.Timestamp

126

Я использую JodaTime 1.6.2.

У меня есть LocalDateфайл LocalDateTime, который мне нужно преобразовать либо в (Joda) , либо в или java.sqlTimestampдля отображения.

Причина этого в том, что я понял, как конвертировать между a LocalDateTimeи a java.sql.Timestamp:

LocalDateTime ldt = new LocalDateTime();
DateTimeFormatter dtf = DateTimeFormatter.forPattern("yyyy-MM-dd HH:mm:ss");
Timestamp ts = Timestamp.valueOf(ldt.toString(dtf));

Итак, если я могу просто преобразовать между LocalDateи LocalDateTime, тогда я могу продолжить преобразование в java.sql.Timestamp. Спасибо за любые толчки в правильном направлении!

IAmYourFaja
источник
К вашему сведению, проект Joda-Time сейчас находится в режиме обслуживания , и команда советует перейти на классы java.time . См. Учебник Oracle . Кроме того, этот java.sql.Timestampкласс теперь унаследован, заменен классами java.time , в частности, классом Instant.
Basil Bourque

Ответы:

270

JodaTime

Чтобы преобразовать JodaTime org.joda.time.LocalDateв java.sql.Timestamp, просто выполните

Timestamp timestamp = new Timestamp(localDate.toDateTimeAtStartOfDay().getMillis());

Чтобы преобразовать JodaTime org.joda.time.LocalDateTimeв java.sql.Timestamp, просто выполните

Timestamp timestamp = new Timestamp(localDateTime.toDateTime().getMillis());

JavaTime

Чтобы преобразовать Java8 java.time.LocalDateв java.sql.Timestamp, просто выполните

Timestamp timestamp = Timestamp.valueOf(localDate.atStartOfDay());

Чтобы преобразовать Java8 java.time.LocalDateTimeв java.sql.Timestamp, просто выполните

Timestamp timestamp = Timestamp.valueOf(localDateTime);
BalusC
источник
Будьте осторожны при преобразовании LocalDateTimeв, так DateTimeкак не все LocalDateTimes действительны DateTime. Источник: joda-time.sourceforge.net/faq.html#illegalinstant и просто столкнулся с этим.
Christophe De Troyer
Получена ошибка компиляции аргумента, поскольку valueOf () принимает строку.
Patriotic
@Patriotic: это произойдет, только если вы на самом деле не используете Java SE 1.8 или новее. Как указано в ответе и в предоставленных ссылках на Javadoc (синие тексты в приведенном выше ответе на самом деле являются ссылками, вы можете щелкнуть их, чтобы перейти к Javadoc), Timestamp#valueOf()метод принимает, поскольку Java SE 1.8 также LocalDateTime.
BalusC
60

Лучший способ использовать Java 8 time API:

  LocalDateTime ldt = timeStamp.toLocalDateTime();
  Timestamp ts = Timestamp.valueOf(ldt);

Для использования с JPA, вставленным в вашу модель ( https://weblogs.java.net/blog/montanajava/archive/2014/06/17/using-java-8-datetime-classes-jpa ):

@Converter(autoApply = true)
public class LocalDateTimeConverter implements AttributeConverter<LocalDateTime, Timestamp> {
    @Override
    public Timestamp convertToDatabaseColumn(LocalDateTime ldt) {
        return Timestamp.valueOf(ldt);
    }

    @Override
    public LocalDateTime convertToEntityAttribute(Timestamp ts) {
        return ts.toLocalDateTime();
    }
}

Итак, теперь это относительное время, независимое от часового пояса. Дополнительно легко сделать:

  LocalDate ld = ldt.toLocalDate();
  LocalTime lt = ldt.toLocalTime();

Форматирование:

 DateTimeFormatter DATE_TME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")
 String str = ldt.format(DATE_TME_FORMATTER);
 ldt = LocalDateTime.parse(str, DATE_TME_FORMATTER);

ОБНОВЛЕНИЕ: postgres 9.4.1208, HSQLDB 2.4.0 и т. Д. Понимают Java 8 Time API без каких-либо разговоров!

Григорий Кислин
источник
17

ТЛ; др

Проект Joda-Time находится в режиме обслуживания и заменен классами java.time .

  • Просто используйте java.time.Instant класс.
  • Нет необходимости в:
    • LocalDateTime
    • java.sql.Timestamp
    • Струны

Захватите текущий момент в формате UTC.

Instant.now()  

Чтобы сохранить этот момент в базе данных:

myPreparedStatement.setObject(  , Instant.now() )  // Writes an `Instant` to database.

Чтобы получить этот момент из базы данных:

myResultSet.getObject(  , Instant.class )  // Instantiates a `Instant`

Чтобы настроить время настенных часов в соответствии с определенным часовым поясом.

instant.atZone( z )  // Instantiates a `ZonedDateTime`

LocalDateTime не тот класс

Другие ответы верны, но они не указывают на то, что LocalDateTime это не тот класс для вашей цели.

В обоих java.time и Joda-Time , LocalDateTimeнамеренно отсутствует какая - либо концепция временной зоны или офсетные из-UTC. Таким образом, он не представляет момент и не является точкой на шкале времени. A LocalDateTimeпредставляет собой приблизительное представление о потенциале моментах в диапазоне примерно 26-27 часов.

Используйте a, LocalDateTimeкогда зона / смещение неизвестны (не очень хорошая ситуация), или когда смещение зоны не определено. Например, «Рождество начинается в первый момент 25 декабря 2018 г.» будет представлено какLocalDateTime .

Используйте ZonedDateTimeдля обозначения момента в определенном часовом поясе. Например, Рождество начинается в какой-либо конкретной зоне, например, Pacific/Aucklandили America/Montrealможет быть представлено ZonedDateTimeобъектом.

На мгновение всегда в формате UTC используйте Instant.

Instant instant = Instant.now() ;  // Capture the current moment in UTC.

Применить часовой пояс. Тот же момент, та же точка на временной шкале, но просмотр с другим временем настенных часов.

ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;  // Same moment, different wall-clock time.

Итак, если я могу просто конвертировать между LocalDate и LocalDateTime,

Нет, неправильная стратегия. Если у вас есть значение только для даты и вам нужно значение даты и времени, вы должны указать время дня. Это время дня может быть недействительным в этот день для определенной зоны - в этом случае ZonedDateTimeкласс автоматически корректирует время дня по мере необходимости.

LocalDate ld = LocalDate.of( 2018 , Month.JANUARY , 23 ) ;
LocalTime lt = LocalTime.of( 14 , 0 ) ;  // 14:00 = 2 PM.
ZonedDateTime zdt = ZonedDateTime.of( ld , lt , z ) ;

Если вы хотите, чтобы в качестве времени суток был выбран первый момент дня, пусть java.time определит этот момент. Не думайте, что день начинается в 00:00:00. Аномалии, такие как переход на летнее время (DST), означают, что день может начинаться в другое время, например 01:00:00.

ZonedDateTime zdt = ld.atStartOfDay( z ) ;

java.sql.Timestamp не тот класс

Это java.sql.Timestampчасть проблемных старых классов даты и времени, которые теперь унаследованы и полностью вытеснены классами java.time . Этот класс использовался для представления момента в формате UTC с разрешением наносекунды . Этой цели теперь служат java.time.Instant.

JDBC 4.2 с getObject/setObject

Начиная с JDBC 4.2 и новее, ваш драйвер JDBC может напрямую обмениваться объектами java.time с базой данных, вызывая:

Например:

myPreparedStatement.setObject(  , instant ) ;

… и …

Instant instant = myResultSet.getObject(  , Instant.class ) ;

Преобразование наследия в современное

Если вам необходимо взаимодействовать со старым кодом, который еще не обновлен до java.time , конвертируйте туда и обратно, используя новые методы, добавленные к старым классам.

Instant instant = myJavaSqlTimestamp.toInstant() ;  // Going from legacy class to modern class.

…и…

java.sql.Timestamp myJavaSqlTimestamp = java.sql.Timestamp.from( instant ) ;  // Going from modern class to legacy class.

О java.time

Java.time каркас встроен в Java 8 и более поздних версий. Эти классы вытеснять неприятные старые устаревшие классы даты и времени , такие как java.util.Date, Calendar, и SimpleDateFormat.

Проект Joda-Time , находящийся сейчас в режиме обслуживания , рекомендует перейти на классы java.time .

Чтобы узнать больше, см. Oracle Tutorial . И поищите в Stack Overflow множество примеров и объяснений. Спецификация - JSR 310 .

Вы можете обмениваться объектами java.time напрямую с вашей базой данных. Используйте драйвер JDBC, совместимый с JDBC 4.2 или новее. Нет необходимости в строках, нет необходимости в java.sql.*занятиях.

Где взять классы 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 (<26) проект ThreeTenABP адаптирует ThreeTen-Backport (упомянутый выше). См. Как использовать ThreeTenABP… .

Проект ThreeTen-Extra расширяет java.time дополнительными классами. Этот проект является испытательной площадкой для возможных будущих дополнений к java.time. Вы можете найти некоторые полезные классы здесь , такие как Interval, YearWeek, YearQuarter, и более .

Василий Бурк
источник
5

В зависимости от вашего часового пояса вы можете потерять несколько минут (1650-01-01 00:00:00 становится 1649-12-31 23:52:58)

Используйте следующий код, чтобы избежать этого

new Timestamp(localDateTime.getYear() - 1900, localDateTime.getMonthOfYear() - 1, localDateTime.getDayOfMonth(), localDateTime.getHourOfDay(), localDateTime.getMinuteOfHour(), localDateTime.getSecondOfMinute(), fractional);
user1302021
источник
3

Поскольку Joda становится блеклой, кто-то может захотеть преобразовать LocaltDateее LocalDateTimeв Java 8. В Java 8 LocalDateTimeэто даст возможность создать LocalDateTimeэкземпляр с помощью LocalDateи LocalTime. Проверить здесь.

общедоступный статический LocalDateTime из (Дата LocalDate, время LocalTime)

Образец будет,

    // just to create a sample LocalDate
    DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMdd");
    LocalDate ld = LocalDate.parse("20180306", dtf);

    // convert ld into a LocalDateTime
    // We need to specify the LocalTime component here as well, it can be any accepted value
    LocalDateTime ldt = LocalDateTime.of(ld, LocalTime.of(0,0)); // 2018-03-06T00:00

Просто для справки, для получения секунд ниже можно использовать эпоху,

    ZoneId zoneId = ZoneId.systemDefault();
    long epoch = ldt.atZone(zoneId).toEpochSecond(); 

    // If you only care about UTC
    long epochUTC = ldt.toEpochSecond(ZoneOffset.UTC);
простое число
источник
LocalDateTimeЗдесь вообще не нужно использовать . В этом классе намеренно отсутствует понятие часового пояса или смещения от UTC. Так что здесь это бесполезно. Вместо этого: LocalDate.parse( “20180306” , DateTimeFormatter.BASIC_ISO_DATE ).atStartOfDay( ZoneId.of( “Africa/Tunis” ).toEpochSecond()не предполагайте, что день начинается в 00:00, это не всегда так.
Basil Bourque
Что вы имеете в виду, говоря не предполагать, что день начинается в 00:00
премьер
1
Аномалии, такие как переход на летнее время (DST), означают, что в некоторые даты в некоторых местах день может начинаться в другое время, например 01:00:00. Итак, вместо того, чтобы предполагать, позвольте java.time определить первый момент, вызвав java.time.LocalDate.atStartOfDayдля получения ZonedDateTime. См. Примеры в моем ответе . Как я уже сказал, LocalDateTimeзанятия во всем этом бесполезны и контрпродуктивны.
Basil Bourque
Итак, LocalDateTimeмы должны использовать ZoneId?
премьер
Я думаю, вы упустили все мои моменты. Перечитайте мой ответ на этой странице. Найдите Stack Overflow, чтобы узнать больше из множества других примеров и обсуждений. Но я скажу в последний раз здесь: LocalDateTimeэто не ассигновать на проблему под рукой здесь. LocalDateTimeВовсе не представляет собой момент. A не LocalDateTimeимеет ничего общего с какой-либо конкретной местностью или часовым поясом, хотя на первый взгляд название может означать иное - узнайте больше о назначении и деталях этого класса. LocalDateTimeКласс действительно служит цели, но не цель видели в этом вопросе.
Basil Bourque
2

Вызов функции asStartOfDay()на java.time.LocalDateобъекте возвращает java.time.LocalDateTimeобъект

Ахмад Сибай
источник
0

Java8 +

import java.time.Instant;
Instant.now().getEpochSecond(); //timestamp in seconds format (int)
Instant.now().toEpochMilli(); // timestamp in milliseconds format (long)
Mohamed.Abdo
источник
Полезно, но, похоже, не совсем ответ на вопрос.
Ole VV
Спасибо за код, но это не имеет отношения к вопросу.
refaelio