ฉันจะสร้าง Java 8 LocalDate จากเวลาที่ยาวนานเป็นมิลลิวินาทีได้อย่างไร


218

ฉันมี API ภายนอกที่ให้วันที่ฉันเป็นlongs แสดงเป็นมิลลิวินาทีนับตั้งแต่เริ่มยุค

ด้วย Java API แบบเก่าฉันก็แค่สร้างDateจากมันด้วย

Date myDate = new Date(startDateLong)

อะไรคือสิ่งที่เทียบเท่าใน Java 8's LocalDate/ LocalDateTimeคลาส?

ฉันสนใจที่จะแปลงเวลาlongให้เป็น a LocalDateในเขตเวลาปัจจุบันของฉัน


6
คุณต้องเริ่มต้นด้วยการจัดการกับโซนเวลาที่คุณสนใจ ค่า "มิลลิวินาทีนับตั้งแต่ยุค" ให้เวลาคุณทันที ... ที่สามารถอ้างถึงวันที่ที่แตกต่างกันในเขตเวลาที่แตกต่างกัน โปรดจำไว้ว่าjava.util.Dateไม่เคยออกเดทในแบบที่LocalDateเป็นจริง - มันเป็นเวลาทันทีเช่นกัน
Jon Skeet

2
ตรวจสอบคำถามนี้: stackoverflow.com/questions/21242110/…ซึ่งครอบคลุมการแปลงjava.util.Dateเป็นLocalDate
hotzst

3
หมายเหตุ: Q & A ยังเป็นที่มีคุณค่าสำหรับผู้ที่พยายามแปลงFile.lastModified()(ยุคมิลลิวินาที) LocalDate(Time)เพื่อ
kevinarpe

คำตอบ:


403

หากคุณมีมิลลิวินาทีนับตั้งแต่ Epoch และต้องการแปลงให้เป็นวันที่ท้องถิ่นโดยใช้เขตเวลาท้องถิ่นปัจจุบันคุณสามารถใช้

LocalDate date =
    Instant.ofEpochMilli(longValue).atZone(ZoneId.systemDefault()).toLocalDate();

แต่โปรดทราบว่าแม้กระทั่งเขตเวลาเริ่มต้นของระบบอาจเปลี่ยนแปลงดังนั้นlongค่าเดียวกันอาจให้ผลลัพธ์ที่แตกต่างในการเรียกใช้ครั้งต่อไปแม้ในเครื่องเดียวกัน

นอกจากนี้โปรดจำไว้ว่าLocalDateไม่เหมือนjava.util.Dateวันที่และวันเวลาจริงๆ

มิฉะนั้นคุณอาจใช้LocalDateTime:

LocalDateTime date =
    LocalDateTime.ofInstant(Instant.ofEpochMilli(longValue), ZoneId.systemDefault());

2
+1 จากฉันสำหรับคำอธิบายเพิ่มเติม โดยวิธีการแม้โซนที่ไม่ใช่ระบบสามารถเปลี่ยน (โดย tzupdater-tool หรือโดย jdk-change) และดังนั้นจึงให้ผลลัพธ์ที่แตกต่างก่อนและหลัง
Meno Hochschild

2
@Meno Hochschild: ฉันไม่ได้มุ่งเน้นไปที่เขตเวลา hardcoded แต่เปรียบเทียบกับเขตเวลาที่ระบุโดยผู้ใช้อ่านจากไฟล์การกำหนดค่าหรือตัวแปรสภาพแวดล้อมที่โปรแกรมเมอร์สันนิษฐานว่าอาจมีการเปลี่ยนแปลง เขตเวลาของ Hardcoded นั้นเหมือนกับค่าเริ่มต้นของระบบ โปรแกรมเมอร์ถูกล่อลวงให้คิดว่าพวกเขาไม่เคยเปลี่ยน ...
โฮล

2
@Demigod LocalDateTime.ofEpochSecond(…)ต้องเกิดขึ้นจริงZoneOffsetแต่ ผลตอบแทนZoneId.systemDefault() สามารถแผนที่เพื่อชดเชยที่แตกต่างกันขึ้นอยู่กับจุดของเวลาที่คุณกำลังหมายถึง นั่นคือสิ่งที่ทำให้คุณแปลงที่ระบุตามที่ให้ไว้ ZoneIdZoneIdLocalDateTime.ofInstantZoneIdInstant
Holger

2
Epoch ถูกกำหนดให้เป็น UTC และควรเป็นเขตเวลาอิสระดังนั้น ZoneId ควรเป็น UTC
PlexQ

2
@PlexQ โซนเวลาที่ระบุไม่เกี่ยวข้องกับยุคซึ่งแน่นอนเป็นเขตอิสระ แต่สำหรับความหมายของผลหรือLocalDate LocalDateTimeคุณสามารถระบุเขตเวลาใดก็ได้ที่คุณต้องการตราบใดที่มันสอดคล้องกับการใช้วัตถุผลลัพธ์เหล่านี้ในภายหลัง นึกถึงสิ่งที่เกิดขึ้นเมื่อคุณจัดการกับวัตถุหลายชิ้นที่สร้างขึ้นโดยวิธีการต่าง ๆ กรณีการใช้งานทั่วไปสำหรับวันที่ท้องถิ่นหรือชุดข้อมูลรวมเขตเวลาเริ่มต้นของระบบเช่นLocalDateTime.now()LocalDateTime.ofInstant(Instant.ofEpochMilli(System.currentTimeMillis()), ZoneId.systemDefault())
Holger

37

คุณสามารถเริ่มต้นด้วยInstant.ofEpochMilli (ยาว) :

LocalDate date =
  Instant.ofEpochMilli(startDateLong)
  .atZone(ZoneId.systemDefault())
  .toLocalDate();

5
+1 ที่ชัดเจนเกี่ยวกับเขตเวลา หากไม่ระบุเขตเวลาเริ่มต้นปัจจุบันของ JVM จะถูกนำไปใช้โดยนัยในการกำหนดวันที่ สำหรับช่วงเวลาที่กำหนดวันที่จะแตกต่างกันไปทั่วโลกตามโซนเวลาเป็นวันใหม่รุ่งอรุณก่อนหน้านี้ในภาคตะวันออก
Basil Bourque

12

ฉันคิดว่าฉันมีคำตอบที่ดีกว่า

new Timestamp(longEpochTime).toLocalDateTime();

ใหม่ Timestamp (ts) .toLocalDateTime (). toLocalDate ()
Stepan Yakovenko

5
ฉันหมายถึง - ถ้าคุณไม่รังเกียจที่จะนำเข้า javal.sql.Timestamp ซึ่งเนื่องจากลักษณะเสาหินของ Java ที่ฉันคิดว่าใช้ได้เพราะมันเป็นเพียงส่วนหนึ่งของ JVM ... แต่รู้สึกเหม็น แต่ฉันก็ยังชอบดีกว่า มันได้รับการยอมรับว่าเป็นยุคพื้นฐานใน UTC
PlexQ

1
Timestampชั้นถูกออกแบบมาไม่ดีและล้าสมัยยาว รหัสของคุณจะใช้การตั้งค่าเขตเวลาของ JVM แต่เนื่องจากการตั้งค่านี้สามารถเปลี่ยนแปลงได้โดยส่วนอื่นของโปรแกรมของคุณหรือโปรแกรมอื่นที่ทำงานใน JVM เดียวกันเราจึงไม่แน่ใจว่ามันคืออะไร
Ole VV

1
เป็นการดีกว่าเสมอที่จะระบุให้ชัดเจนว่าจะใช้เขตเวลาใด การใช้ java.sql.Timestamp เก่ามีข้อเสียเปรียบในการใช้เขตเวลาของระบบโดยปริยายซึ่งมักทำให้เกิดความสับสนในหมู่นักพัฒนา
Ruslan

3

เขตเวลาและสิ่งต่าง ๆ เป็นทางเลือกที่ง่ายมากที่new Date(startDateLong)จะเป็นLocalDate.ofEpochDay(startDateLong / 86400000L)


6
ฉันคิดว่าอย่างน้อยคุณควรอธิบายว่าอะไรคือ 86400000L
BAERUS

3
ฉันคิดว่ามันง่ายมากที่จะสังเกตเห็นว่ามันเป็นจำนวนมิลลิวินาทีในหนึ่งวัน
Michael Piefel

7
สำหรับบางคนแล้วและฉันคิดว่ามีเพียงสิ่งที่จะสมเหตุสมผล แต่หากไม่มีการคำนวณใหม่ว่ามีกี่มิลลิวินาทีต่อวันจริง ๆ ฉันไม่แน่ใจ เพียงแค่พูดกับตัวเองฉันไม่ทราบหมายเลขนี้ดีจนฉันรู้ว่ามันหมายถึงอะไรโดยอัตโนมัติ
BAERUS

โปรดทราบด้วยว่าคำตอบที่ได้รับการยอมรับนั้นเป็นคำตอบที่ดีที่สุด แฮ็คเรียบง่ายของฉันแค่พอในหลายกรณี มันน่าเสียดายที่java.timeไม่รวมถึงDateTimeConstantsJoda
Michael Piefel

2
java.util.concurrent.TimeUnit.MILLISECONDS.toDays(startDateLong)
Vadzim

1

แทนที่ now.getTime () ด้วยค่ายาวของคุณ

//GET UTC time for current date
        Date now= new Date();
        //LocalDateTime utcDateTimeForCurrentDateTime = Instant.ofEpochMilli(now.getTime()).atZone(ZoneId.of("UTC")).toLocalDateTime();
        LocalDate localDate = Instant.ofEpochMilli(now.getTime()).atZone(ZoneId.of("UTC")).toLocalDate();
        DateTimeFormatter dTF2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
        System.out.println(" formats as " + dTF2.format(utcDateTimeForCurrentDateTime));

-6

ในกรณีเฉพาะที่เวลา epoch วินาทีของคุณมาจาก SQL หรือเกี่ยวข้องกับ SQL อย่างใดคุณสามารถขอรับดังนี้:

long startDateLong = <...>

LocalDate theDate = new java.sql.Date(startDateLong).toLocalDate();

2
สิ่งนี้ไม่ได้เกี่ยวข้องกับคำถามที่ถามมากนัก
Ketan R

@ KetanR ฉันไม่เห็นด้วย คำถามคือ "วิธีการรับLocalDateจากepoch-millis" และฉันแสดงวิธีการใช้java.sql.Dateชวเลข วิธีนี้มีความหมายในรหัสที่จัดการกับ JDBC แล้วในความสามารถบางอย่างและใช้งานได้ดี หากคุณยังไม่มั่นใจให้อธิบายว่ามันไม่เกี่ยวข้องกับคำถามเริ่มต้นอย่างไร
M. Prokhorov

2
หากคุณอ่านคำถามจะมีข้อความระบุว่า "API ภายนอกที่ส่งคืนวันที่ของฉันเป็นระยะเวลานาน" และคุณกำลังอธิบายวิธีการแปลงนี้สามารถทำได้หากคุณได้รับวันที่ยาวนานจาก SQL คำตอบของคุณจะอธิบายกรณีที่เฉพาะเจาะจงมากของการแปลงวันที่ แต่ไม่เกี่ยวข้องกับคำถามที่ถูกถาม ed คำอธิบายของคุณอาจเป็นคำตอบที่ถูกต้องสำหรับคำถามที่เกี่ยวข้องอื่น ๆ
Ketan R

@ KetanR หากมีใครได้รับ SQL มานานฉันแนะนำให้เปลี่ยน schema ของเขาเพื่อที่เขาจะไม่ได้รับวันที่ในรูปแบบดังกล่าวอีกต่อไป อย่างไรก็ตามหากมีวันที่เป็นมิลลิวินาทีจากที่อื่น (API ภายนอก) และใช้วันที่เหล่านี้ทันทีในการทำแบบสอบถาม JDBC java.sql.Dateวิธีการนั้นเป็นวิธีที่สั้นที่สุดใช้รหัสได้และฉันก็บอกว่ามันไม่ได้มีประโยชน์อะไรเลย ที่จะไปแม้ว่าInstantกับวัตถุชั่วคราวกลางทั้งหมดเมื่อผลลัพธ์ที่ได้คือเหมือนกัน
M. Prokhorov

2
ดังที่ฉันได้กล่าวไปแล้วและเห็นได้ชัดจากคำอธิบายล่าสุดของคุณคำตอบของคุณนั้นถูกต้อง แต่ไม่ใช่สำหรับคำถามที่อยู่ในมือคำถามพูดว่า: "ฉันสนใจที่จะเปลี่ยนเวลาให้เป็น LocalDate ในเขตเวลาปัจจุบันของฉัน "คำตอบของคุณบอกว่า:" รับวันที่เป็นมิลลิวินาทีและใช้วันที่เหล่านี้ทันทีเพื่อทำการค้นหา JDBC " ฉันไม่เข้าใจสิ่งที่ไม่ชัดเจนที่นี่
Ketan R
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.