วิธีแปลง java.sql.timestamp เป็น LocalDate (java8) java.time


127

ใน Java 8 ฉันจะแปลง a Timestamp(in java.sql) เป็น a LocalDate(in java.time) ได้อย่างไร?


1
ผมมีปัญหาที่คล้ายกันบ้างที่นี่: stackoverflow.com/a/23197731/1856960 ตอบสั้น ๆ ไม่ได้จริงๆ แต่นั่นไม่จำเป็นต้องเป็นเรื่องเลวร้าย
jacobhyphenated

คำตอบ:


196

คุณทำได้:

timeStamp.toLocalDateTime().toLocalDate();

โปรดทราบว่าtimestamp.toLocalDateTime() จะใช้Clock.systemDefaultZone()เขตเวลาในการแปลง สิ่งนี้อาจใช่หรือไม่ใช่สิ่งที่คุณต้องการ


1
มันถูกเพิ่มใน Java 8
assylias

54
โปรดทราบว่าtimestamp.toLocalDateTime()เมธอดจะใช้โซนเวลา systemDefault เพื่อทำการแปลง สิ่งนี้อาจใช่หรือไม่ใช่สิ่งที่คุณต้องการ
jacobhyphenated

1
@jacobhyphenated โปรดโพสต์คำตอบโดยใช้เขตเวลาที่ชัดเจน ขอบคุณ!
user482745

ความคิดเห็นของ @ jacobhyphenated มีความสำคัญอย่างยิ่งที่นี่ดังนั้นจำนวนการโหวตเพิ่มขึ้น ดูคำตอบของฉันสำหรับรายละเอียดstackoverflow.com/a/57101544/2032701
Ruslan

@jacobhyphenated LocalDateTimeใช้เขตเวลาเริ่มต้นของระบบเสมอ นั่นคือความหมายของ "Local" ในชื่อ
M. Prokhorov

21

คำตอบที่ยอมรับนั้นไม่เหมาะอย่างยิ่งดังนั้นฉันจึงตัดสินใจเพิ่ม 2 เซ็นต์

timeStamp.toLocalDateTime().toLocalDate();

เป็นวิธีแก้ปัญหาที่ไม่ดีโดยทั่วไปฉันไม่แน่ใจด้วยซ้ำว่าทำไมพวกเขาถึงเพิ่มวิธีนี้ใน JDK เพราะมันทำให้สิ่งต่าง ๆ สับสนจริงๆโดยทำการแปลงโดยปริยายโดยใช้เขตเวลาของระบบ โดยปกติเมื่อใช้เฉพาะคลาสวันที่ java8 โปรแกรมเมอร์จะถูกบังคับให้ระบุเขตเวลาซึ่งเป็นสิ่งที่ดี

ทางออกที่ดีคือ

timestamp.toInstant().atZone(zoneId).toLocalDate()

โดยzoneIdคือเขตเวลาที่คุณต้องการใช้ซึ่งโดยทั่วไปจะเป็นZoneId.systemDefault ()หากคุณต้องการใช้เขตเวลาระบบของคุณหรือเขตเวลาที่เข้ารหัสเช่นZoneOffset.UTC

แนวทางทั่วไปควรเป็น

  1. แยกอิสระไปยังคลาสวันที่ java8 ใหม่โดยใช้คลาสที่เกี่ยวข้องโดยตรงเช่นในกรณีของเราjava.time.instant เกี่ยวข้องโดยตรงกับ java.sql.Timestampกล่าวคือไม่จำเป็นต้องมีการแปลงเขตเวลาระหว่างกัน
  2. ใช้วิธีการที่ออกแบบมาอย่างดีในคลาส java8 นี้เพื่อทำสิ่งที่ถูกต้อง ในกรณีของเราatZone (zoneId)ทำให้ชัดเจนว่าเรากำลังทำการแปลงและใช้เขตเวลาเฉพาะสำหรับมัน

1
ฉันไม่เห็นด้วย. การประทับเวลา (และวันที่) ไม่มีข้อมูลโซนใด ๆ LocalDate ไม่มีข้อมูลโซนใด ๆ ดังนั้นทั้งสองจะเท่ากัน การแปลงระหว่างกันสามารถทำได้โดยไม่ขึ้นกับโซนใดโซนหนึ่ง การแปลงเป็น ZonedDateTime ก่อนที่จะแปลงเป็น LocalDate จะเพิ่มในเขตเวลาแล้วนำออกไปอีกครั้ง - คุณมีแนวโน้มที่จะได้รับสิ่งที่น่ารังเกียจมากขึ้น - หายาก - เกิดข้อผิดพลาดในการทำเช่นนั้น
AutomatedMike

5
@AutomatedMike Timestamp (และวันที่) แทนจุดในเวลาใน UTC LocalDate ไม่ได้แสดงถึงจุดในเวลา แต่เป็นเวลาตามที่เห็นบนนาฬิกาแขวน โปรดอ่าน Javadocs ของพวกเขา "การแปลงระหว่างกันสามารถทำได้โดยไม่ขึ้นกับโซนใดโซนหนึ่ง" - ไม่เป็นความจริงการประทับเวลาใหม่ (0L) .toLocalDateTime () ส่งคืน "1970-01-01T03: 00" สำหรับเขตเวลามอสโกวของฉัน ผลลัพธ์อาจแตกต่างกันไปตามเขตเวลาของคุณ
Ruslan

1
@AutomatedMike แม้ว่าคุณจะตัดเวลาโดยทำ toLocalDate () มันง่ายมากที่จะพิสูจน์ว่าวันนั้นอาจผิดได้หาก Timestamp มีเวลาประมาณเที่ยงคืนตัวอย่างเช่น Timestamp ใหม่ (1000 * 60 * 60 * 23) .toLocalDateTime () toLocalDate () ส่งคืน "1970-01-02" สำหรับเขตเวลามอสโกวของฉันเมื่อเป็น "1970-01-01" ใน UTC
Ruslan

1
@AutomatedMike "เพิ่มในเขตเวลาแล้วปิดอีกครั้ง" - ประเด็นนี้ไม่ได้อยู่ที่การเพิ่มและลบเขตเวลา แต่เป็นการแปลงระหว่างแนวคิดที่แตกต่างกันโดยใช้เขตเวลาที่ชัดเจน นี้เป็นในทางตรงกันข้ามกับตัวอย่างของก่อนหน้านี้สองความคิดเห็นของฉันที่เขตเวลาที่ถูกนำไปใช้โดยปริยาย
Ruslan

7

ฉันจะขยายคำตอบของ @assylias เล็กน้อยเพื่อพิจารณาเขตเวลา มีอย่างน้อยสองวิธีในการรับ LocalDateTime สำหรับเขตเวลาเฉพาะ

คุณสามารถใช้โซนเวลา setDefault สำหรับแอปพลิเคชันทั้งหมด ควรเรียกก่อนการประทับเวลาใด ๆ -> การแปลง java.time:

public static void main(String... args) {
    TimeZone utcTimeZone = TimeZone.getTimeZone("UTC");
    TimeZone.setDefault(utcTimeZone);
    ...
    timestamp.toLocalDateTime().toLocalDate();
}

หรือคุณสามารถใช้ toInstant.atZone chain:

timestamp.toInstant()
        .atZone(ZoneId.of("UTC"))
        .toLocalDate();
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.