Ubah LocalDate ke LocalDateTime atau java.sql.Timestamp


126

Saya menggunakan JodaTime 1.6.2.

Saya memiliki LocalDateyang perlu saya ubah menjadi (Joda) LocalDateTime, atau java.sqlTimestampuntuk ormapping.

Alasannya adalah saya telah menemukan cara mengonversi antara a LocalDateTimedan 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));

Jadi, jika saya dapat mengonversi antara LocalDatedan LocalDateTime, maka saya dapat membuat konversi lanjutan ke java.sql.Timestamp. Terima kasih atas dorongan ke arah yang benar!


FYI, proyek Joda-Time sekarang dalam mode pemeliharaan , dengan tim menyarankan migrasi ke kelas java.time . Lihat Tutorial oleh Oracle . Selain itu, java.sql.Timestampkelas tersebut sekarang sudah lama, digantikan oleh kelas java.time , khususnya oleh Instant.
Basil Bourque

Jawaban:


269

JodaTime

Untuk mengonversi JodaTime org.joda.time.LocalDatemenjadi java.sql.Timestamp, lakukan saja

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

Untuk mengonversi JodaTime org.joda.time.LocalDateTimemenjadi java.sql.Timestamp, lakukan saja

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

JavaTime

Untuk mengonversi Java8 java.time.LocalDatemenjadi java.sql.Timestamp, lakukan saja

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

Untuk mengonversi Java8 java.time.LocalDateTimemenjadi java.sql.Timestamp, lakukan saja

Timestamp timestamp = Timestamp.valueOf(localDateTime);

Hati-hati saat mengonversi LocalDateTimemenjadi DateTimekarena tidak semua LocalDateTimes valid DateTime. Sumber: joda-time.sourceforge.net/faq.html#illegalinstant dan baru saja menemukan ini.
Christophe De Troyer

mendapat kesalahan kompilasi pada argumen karena valueOf () menerima sebuah string.
Patriotik

@ Patriotik: Itu hanya akan terjadi jika Anda sebenarnya tidak menggunakan Java SE 1.8 atau yang lebih baru. Seperti yang ditunjukkan dalam jawaban dan dalam tautan yang disediakan ke Javadoc (teks biru di jawaban di atas sebenarnya adalah tautan, Anda dapat mengkliknya untuk menelusuri ke Javadoc), Timestamp#valueOf()metode ini menerima karena Java SE 1.8 juga a LocalDateTime.
BalusC

60

Cara terbaik menggunakan Java 8 time API:

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

Untuk digunakan dengan JPA yang disertakan dengan model Anda ( 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();
    }
}

Jadi sekarang waktu relatif zona waktu independen. Selain itu mudah dilakukan:

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

Pemformatan:

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

UPDATE: postgres 9.4.1208, HSQLDB 2.4.0 dll memahami Java 8 Time API tanpa percakapan apa pun!


17

tl; dr

Proyek Joda-Time dalam mode pemeliharaan, sekarang digantikan oleh kelas java.time .

  • Gunakan sajajava.time.Instant kelas.
  • Tidak perlu untuk:
    • LocalDateTime
    • java.sql.Timestamp
    • String

Tangkap momen saat ini dalam UTC.

Instant.now()  

Untuk menyimpan momen itu di database:

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

Untuk mengambil momen itu dari database:

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

Untuk menyesuaikan waktu jam dinding dengan zona waktu tertentu.

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

LocalDateTime adalah kelas yang salah

Jawaban Lain benar, tetapi mereka gagal menunjukkan bahwa itu LocalDateTimeadalah kelas yang salah untuk tujuan Anda.

Baik di java.time dan Joda-Time , sebuah LocalDateTimekonsep zona waktu atau offset-from-UTC sengaja tidak ada. Dengan demikian, ini tidak mewakili suatu momen, dan bukan merupakan titik pada garis waktu. A LocalDateTimemewakili gambaran kasar tentang momen potensial dalam rentang sekitar 26-27 jam.

Gunakan a LocalDateTimeuntuk saat zona / offset tidak diketahui (bukan situasi yang baik), atau saat offset zona tidak dapat ditentukan. Misalnya, "Natal dimulai pada saat pertama tanggal 25 Desember 2018" akan direpresentasikan sebagai LocalDateTime.

Gunakan a ZonedDateTimeuntuk mewakili momen di zona waktu tertentu. Misalnya, Natal yang dimulai di zona tertentu seperti Pacific/Aucklandatau America/Montrealakan diwakili dengan sebuah ZonedDateTimeobjek.

Untuk sesaat selalu dalam UTC, gunakan Instant.

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

Terapkan zona waktu. Momen yang sama, titik yang sama di garis waktu, tetapi dilihat dengan waktu jam dinding yang berbeda.

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

Jadi, jika saya bisa mengonversi antara LocalDate dan LocalDateTime,

Tidak, strategi yang salah. Jika Anda memiliki nilai khusus tanggal, dan Anda menginginkan nilai tanggal-waktu, Anda harus menentukan waktu dalam sehari. Waktu hari itu mungkin tidak valid pada tanggal itu untuk zona tertentu - dalam hal ini ZonedDateTimekelas secara otomatis menyesuaikan waktu sesuai kebutuhan.

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

Jika Anda ingin momen pertama hari itu sebagai waktu Anda, biarkan java.time menentukan momen itu. Jangan berasumsi bahwa hari dimulai pada 00:00:00. Anomali seperti Daylight Saving Time (DST) berarti hari dapat dimulai pada waktu lain seperti 01:00:00.

ZonedDateTime zdt = ld.atStartOfDay( z ) ;

java.sql.Timestamp adalah kelas yang salah

Ini java.sql.Timestampadalah bagian dari kelas tanggal-waktu lama bermasalah yang sekarang warisan, digantikan sepenuhnya oleh kelas java.time . Kelas itu digunakan untuk mewakili momen dalam UTC dengan resolusi nanodetik . Tujuan itu sekarang terlayani dengan java.time.Instant.

JDBC 4.2 dengan getObject/setObject

Mulai JDBC 4.2 dan yang lebih baru, driver JDBC Anda bisa langsung bertukar objek java.time dengan database dengan memanggil:

Sebagai contoh:

myPreparedStatement.setObject(  , instant ) ;

… Dan…

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

Ubah warisan ⬌ modern

Jika Anda harus antarmuka dengan kode lama yang belum diperbarui ke java.time , ubah bolak-balik menggunakan metode baru yang ditambahkan ke kelas lama.

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

…dan…

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

Tentang java.time

The java.time kerangka dibangun ke Jawa 8 dan kemudian. Kelas-kelas ini menggantikan tua merepotkan warisan kelas tanggal-waktu seperti java.util.Date, Calendar, & SimpleDateFormat.

Proyek Joda-Time , sekarang dalam mode pemeliharaan , menyarankan migrasi ke kelas java.time .

Untuk mempelajari lebih lanjut, lihat Tutorial Oracle . Dan cari Stack Overflow untuk banyak contoh dan penjelasan. Spesifikasinya adalah JSR 310 .

Anda dapat bertukar objek java.time langsung dengan database Anda. Gunakan driver JDBC yang sesuai dengan JDBC 4.2 atau yang lebih baru. Tidak perlu string, tidak perlu java.sql.*kelas.

Di mana mendapatkan kelas java.time?

Proyek ThreeTen-Extra memperluas java.time dengan kelas tambahan. Proyek ini adalah tempat pembuktian untuk kemungkinan penambahan java.time di masa mendatang. Anda mungkin menemukan beberapa kelas berguna di sini seperti Interval, YearWeek, YearQuarter, dan lebih .


5

Bergantung pada zona waktu Anda, Anda mungkin kehilangan beberapa menit (1650-01-01 00:00:00 menjadi 1649-12-31 23:52:58)

Gunakan kode berikut untuk menghindarinya

new Timestamp(localDateTime.getYear() - 1900, localDateTime.getMonthOfYear() - 1, localDateTime.getDayOfMonth(), localDateTime.getHourOfDay(), localDateTime.getMinuteOfHour(), localDateTime.getSecondOfMinute(), fractional);

3

Karena Joda semakin pudar, seseorang mungkin ingin mengonversi LocaltDateke LocalDateTimedi Java 8. Di Java 8, LocalDateTimeini akan memberikan cara untuk membuat LocalDateTimeinstance menggunakan LocalDatedan LocalTime. Cek di sini.

LocalDateTime statis publik (tanggal LocalDate, waktu LocalTime)

Sampel akan menjadi,

    // 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

Sekadar referensi, Untuk mendapatkan epoch detik di bawah ini bisa digunakan,

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

    // If you only care about UTC
    long epochUTC = ldt.toEpochSecond(ZoneOffset.UTC);

Tidak perlu menggunakan LocalDateTimesama sekali di sini. Kelas itu sengaja tidak memiliki konsep zona waktu atau offset-dari-UTC. Jadi tidak ada gunanya di sini. Sebaliknya: LocalDate.parse( “20180306” , DateTimeFormatter.BASIC_ISO_DATE ).atStartOfDay( ZoneId.of( “Africa/Tunis” ).toEpochSecond()Jangan menganggap hari dimulai pukul 00.00, tidak selalu demikian.
Basil Bourque

Apa yang Anda maksud dengan jangan menganggap hari dimulai pukul 00.00
prime

1
Anomali seperti Daylight Saving Time (DST) berarti bahwa pada beberapa tanggal di beberapa tempat, hari dapat dimulai pada waktu lain, seperti 01:00:00. Jadi, alih-alih berasumsi, biarkan java.time menentukan momen pertama dengan memanggil java.time.LocalDate.atStartOfDayuntuk mendapatkan file ZonedDateTime. Lihat contoh di Jawaban saya . Seperti yang saya komentari, LocalDateTimekelas tidak berguna dan kontra-produktif dalam semua ini.
Basil Bourque

Jadi dengan LocalDateTimekita harus menggunakan a ZoneId?
perdana

Saya pikir Anda telah melewatkan semua poin saya. Baca kembali Jawaban saya di halaman ini. Telusuri Stack Overflow untuk mempelajari lebih lanjut dari lebih banyak contoh dan diskusi. Tapi aku akan mengatakan untuk terakhir kalinya di sini: LocalDateTimeyang tidak yang sesuai untuk masalah yang dihadapi di sini. Sebuah LocalDateTimetidak tidak mewakili sejenak. Sebuah LocalDateTimememiliki apa-apa hubungannya dengan lokalitas tertentu atau zona waktu meskipun nama mungkin menyiratkan sebaliknya pada pandangan pertama - mempelajari lebih lanjut tentang maksud dan rincian dari kelas ini. The LocalDateTimekelas tidak melayani tujuan, tetapi bukan tujuan terlihat dalam pertanyaan ini.
Basil Bourque

2

fungsi panggilan asStartOfDay()pada java.time.LocalDateobjek mengembalikan java.time.LocalDateTimeobjek


0

Java8 +

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

Berguna, tetapi sepertinya tidak menjawab pertanyaan itu.
Ole VV

Terima kasih atas kodenya, tetapi tidak ada hubungannya dengan pertanyaan.
refaelio
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.