Перетворити LocalDate в LocalDateTime або java.sql.Timestamp


126

Я використовую JodaTime 1.6.2.

У мене є LocalDateте, що мені потрібно конвертувати або в (Joda) LocalDateTime, або в java.sqlTimestampormapping.

Причиною цього є те, що я з’ясував, як конвертувати між 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. Дякуємо за будь-які натискання в правильному напрямку!


FYI, проект Joda-Time зараз перебуває в режимі обслуговування , команда радить перейти до класів java.time . Дивіться Підручник від Oracle . Також java.sql.Timestampклас тепер застарілий, витіснений класами java.time , зокрема користувачем Instant.
Василь Бурк

Відповіді:


269

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);

Слідкуйте за переходом LocalDateTimeдо того DateTime, що не всі LocalDateTimes є дійсними DateTimes. Джерело: joda-time.sourceforge.net/faq.html#illegalinstant і просто впадає в це.
Крістоф Де Троєр

отримана помилка компіляції аргументу, оскільки valueOf () приймає рядок.
Вітчизняна

@Patriotic: Це станеться лише в тому випадку, якщо ви фактично не використовуєте Java SE 1.8 або новішу версію. Як зазначено у відповіді і в умови посилання на Javadoc (сині тексти у відповіді вище, на самому ділі посилання, ви можете натиснути їх , щоб розгорнути в Javadoc), то Timestamp#valueOf()метод приймає , так як Java SE 1.8 також LocalDateTime.
BalusC

60

Найкращий спосіб використання Java 8-часового 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. Як такий, він не представляє моменту і не є точкою на часовій шкалі. А LocalDateTimeпредставляє приблизне уявлення про потенційні моменти протягом приблизно 26-27 годин.

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

Використовуйте a, 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.

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 . І шукайте переповнення стека за багатьма прикладами та поясненнями. Специфікація - 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);

3

Оскільки Joda зникає, хтось може захотіти перетворитись LocaltDateна LocalDateTimeJava 8. У Java 8 LocalDateTimeце дасть змогу створити LocalDateTimeекземпляр за допомогою а LocalDateта LocalTime. Перевірте тут.

загальнодоступний статичний LocalDateTime (LocalDate дата, LocalTime time)

Зразок був би,

    // 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, не завжди так.
Василь Бурк

Чого ви маєте на увазі, не вважайте, що день починається о 00.00
прем'єр

1
Такі аномалії, як літній час (DST) означають, що в деякі дати в деяких місцях день може починатися в інший час, наприклад, 01:00:00. Отже, замість того, щоб припустити, нехай java.time визначить перший момент, зателефонувавши java.time.LocalDate.atStartOfDayотримати ZonedDateTime. Дивіться приклади в моїй відповіді . Як я коментував, LocalDateTimeклас у всьому цьому марний і контрпродуктивний.
Василь Бурк

Так що з LocalDateTimeнами треба використовувати ZoneId?
прем'єр

Я думаю, ти пропустив усі мої моменти. Перечитайте мою відповідь на цій сторінці. Шукайте переповнення стека, щоб дізнатися більше від багатьох інших прикладів та дискусій. Але я скажу в останній раз тут: LocalDateTimeце НЕ асигнувати на проблему під рукою тут. LocalDateTimeЗовсім НЕ є момент. A не LocalDateTimeмає нічого спільного з якоюсь конкретною місцевістю чи часовим поясом, хоча назва може означати інакше на перший погляд - дізнайтеся більше про наміри та деталі цього класу. LocalDateTimeКлас дійсно має на меті, але не мета бачили в цьому питанні.
Василь Бурк


0

Java8 +

import java.time.Instant;
Instant.now().getEpochSecond(); //timestamp in seconds format (int)
Instant.now().toEpochMilli(); // timestamp in milliseconds format (long)

Корисно, але, здається, не відповідають на питання.
Оле ВВ

Дякуємо за код, але це не має нічого спільного з питанням.
refaelio
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.