แปลง LocalDate เป็น LocalDateTime หรือ java.sql.Timestamp


126

ฉันใช้ JodaTime 1.6.2

ฉันมี LocalDateที่ต้องแปลงเป็น (Joda) LocalDateTimeหรือjava.sqlTimestampสำหรับ ormapping

เหตุผลนี้คือฉันได้หาวิธีการแปลงระหว่างไฟล์ 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 ดูการสอนโดยออราเคิล นอกจากนี้java.sql.Timestampระดับคือตอนนี้มรดกแทนที่ด้วยjava.timeInstantเรียนโดยเฉพาะ
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);

ระวังเมื่อมีการแปลงLocalDateTimeไปDateTimeเป็นไม่ได้ทั้งหมดLocalDateTimeที่ถูกต้องDateTimes ที่มา: joda-time.sourceforge.net/faq.html#illegalinstantและเพิ่งพบสิ่งนี้
Christophe De Troyer

มีข้อผิดพลาดในการคอมไพล์ในอาร์กิวเมนต์เนื่องจาก valueOf () ยอมรับสตริง
รักชาติ

@ Patriotic: จะเกิดขึ้นก็ต่อเมื่อคุณไม่ได้ใช้ Java SE 1.8 หรือใหม่กว่า ตามที่ระบุไว้ในคำตอบและในลิงก์ที่ให้ไปยัง Javadoc (ข้อความสีน้ำเงินในคำตอบด้านบนเป็นลิงก์จริงๆคุณสามารถคลิกเพื่อดูรายละเอียดใน Javadoc) Timestamp#valueOf()วิธีนี้ยอมรับตั้งแต่ Java SE 1.8 และ a 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);

UPDATE: postgres 9.4.1208, HSQLDB 2.4.0 และอื่น ๆ เข้าใจ Java 8 Time API โดยไม่ต้องสนทนาใด ๆ !


17

TL; DR

โครงการ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เจตนาที่จะขาดแนวคิดเรื่องเขตเวลาหรือ offset-from-UTC ด้วยเหตุนี้จึงไม่ได้แสดงถึงช่วงเวลาหนึ่งและไม่ใช่จุดบนไทม์ไลน์ A LocalDateTimeแสดงถึงแนวคิดคร่าวๆเกี่ยวกับศักยภาพช่วงเวลาที่ในช่วงประมาณ 26-27 ชั่วโมง

ใช้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, และCalendarSimpleDateFormat

โครงการJoda-Timeขณะนี้อยู่ในโหมดการบำรุงรักษาแนะนำการโยกย้ายไปยังคลาสjava.time

ต้องการเรียนรู้เพิ่มเติมโปรดดูที่ออราเคิลกวดวิชา และค้นหา Stack Overflow สำหรับตัวอย่างและคำอธิบายมากมาย สเปกJSR 310

คุณสามารถแลกเปลี่ยนวัตถุjava.timeโดยตรงกับฐานข้อมูลของคุณ ใช้ไดรเวอร์ JDBC ที่สอดคล้องกับJDBC 4.2หรือใหม่กว่า ไม่ต้องใช้สายไม่จำเป็นต้องมีjava.sql.*คลาส

จะหาคลาส java.time ได้ที่ไหน?

  • Java SE 8 , Java SE 9และใหม่กว่า
    • Built-in
    • ส่วนหนึ่งของ Java API มาตรฐานพร้อมการใช้งานแบบรวม
    • Java 9 เพิ่มคุณสมบัติและการแก้ไขเล็กน้อย
  • Java SE 6และ Java SE 7
    • มากของการทำงาน java.time จะกลับรังเพลิง Java 6 และ 7 ในThreeTen-ย้ายกลับ
  • Android
    • การใช้งานกลุ่ม Android เวอร์ชันที่ใหม่กว่าของคลาส java.time
    • สำหรับก่อนหน้านี้ Android (<26) ที่ThreeTenABPโครงการปรับThreeTen-ย้ายกลับ (ดังกล่าวข้างต้น) ดูวิธีใช้ 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อินสแตนซ์โดยใช้ a 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เลยที่นี่ ชั้นเรียนนั้นไม่มีแนวคิดเรื่องเขตเวลาหรือ offset-from-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เราต้องใช้ a ZoneId?
นายก

ฉันคิดว่าคุณพลาดทุกคะแนนของฉันแล้ว อ่านคำตอบของฉันอีกครั้งในหน้านี้ ค้นหา Stack Overflow เพื่อเรียนรู้เพิ่มเติมจากตัวอย่างและการอภิปรายอื่น ๆ อีกมากมาย แต่ผมจะบอกว่าครั้งสุดท้ายที่นี่: LocalDateTimeจะไม่เหมาะสมในการแก้ไขปัญหาที่อยู่ในมือที่นี่ A LocalDateTimeไม่ได้แสดงถึงช่วงเวลา มีอะไรจะทำอย่างไรกับเฉพาะท้องที่ใดหรือเขตเวลาแม้ว่าชื่ออาจบ่งบอกถึงการเป็นอย่างอื่นได้อย่างรวดเร็วก่อน - เรียนรู้เพิ่มเติมเกี่ยวกับความตั้งใจและรายละเอียดของชั้นนี้ ระดับไม่ตอบสนองวัตถุประสงค์ แต่ไม่ได้มีวัตถุประสงค์ที่เห็นในคำถามนี้ LocalDateTimeLocalDateTime
Basil Bourque


0

Java8 +

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

มีประโยชน์ แต่ดูเหมือนจะไม่ตอบคำถามจริงๆ
Ole VV

ขอบคุณสำหรับรหัส แต่ไม่มีส่วนเกี่ยวข้องกับคำถาม
refaelio
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.