ทำไมคลาส Java 8 java.time จึงขาดวิธี getMillis ()


64

Java 8 มีไลบรารีใหม่ทั้งหมดสำหรับวันที่และเวลาในแพคเกจ java.time ซึ่งเป็นสิ่งที่น่ายินดีอย่างมากสำหรับทุกคนที่ต้องใช้ JodaTime มาก่อนหรือสร้างความยุ่งยากด้วยการทำให้เป็นวิธีการประมวลผลตัวช่วยนัดเดทเอง ชั้นเรียนจำนวนมากในแพ็คเกจนี้เป็นตัวแทนของการประทับเวลาและมีวิธีการช่วยเหลือที่getHour()จะได้รับชั่วโมงจากการประทับเวลาที่getMinute()จะได้รับนาทีจากการประทับเวลาที่getNano()จะได้รับ nanos จากการประทับเวลา ฯลฯ ...

ฉันสังเกตเห็นว่าพวกเขาไม่มีวิธีที่เรียกว่าgetMillis()รับมิลลิวินาทีของการประทับเวลา แต่จะต้องมีวิธีการโทรget(ChronoField.MILLI_OF_SECOND)แทน สำหรับฉันดูเหมือนว่าไม่สอดคล้องกันในห้องสมุด ไม่มีใครรู้ว่าทำไมวิธีการดังกล่าวหายไปหรือเป็น Java 8 ยังอยู่ในการพัฒนามีความเป็นไปได้ที่จะเพิ่มในภายหลัง?

https://docs.oracle.com/javase/8/docs/api/java/time/package-summary.html

คลาสที่กำหนดไว้ที่นี่แสดงถึงแนวคิดหลักของวันที่และเวลารวมถึงอินสแตนซ์, ระยะเวลา, วันที่, เวลา, เขตเวลาและช่วงเวลา พวกเขาใช้ระบบปฏิทิน ISO ซึ่งเป็นปฏิทินโลกตามความเป็นจริงตามกฎเกรกอเรียน ชั้นเรียนทั้งหมดไม่เปลี่ยนแปลงและปลอดภัยต่อเธรด

แต่ละอินสแตนซ์เวลาของวันที่ประกอบด้วยฟิลด์ที่ APIs ให้บริการ สำหรับการเข้าถึงระดับล่างไปยังฟิลด์อ้างถึงjava.time.temporalแพคเกจ แต่ละชั้นเรียนมีการสนับสนุนสำหรับการพิมพ์และการแยกวิเคราะห์ทุกวันและเวลา อ้างถึงjava.time.formatแพ็คเกจสำหรับตัวเลือกการปรับแต่ง ...

ตัวอย่างของคลาสประเภทนี้:
https://docs.oracle.com/javase/8/docs/api/java/time/LocalDateTime.html

วันที่และเวลาที่ไม่มีเขตเวลาในระบบปฏิทิน ISO-8601 เช่น 2007-12-03T10: 15: 30

LocalDateTimeเป็นออบเจ็กต์วันที่และเวลาที่ไม่เปลี่ยนรูปแบบซึ่งแสดงถึงวันที่และเวลาซึ่งมักถูกมองว่าเป็นปีเดือนเดือนวันชั่วโมงนาทีวินาที ฟิลด์วันที่และเวลาอื่น ๆ เช่นวันของปีวันของสัปดาห์และสัปดาห์ของปีก็สามารถเข้าถึงได้เช่นกัน เวลาแสดงด้วยความแม่นยำระดับนาโนวินาที ตัวอย่างเช่นค่า "2 ตุลาคม 2550 เวลา 13: 45.30.123456789" สามารถเก็บไว้ในLocalDateTime...


ดูเหมือนว่าพวกเขาต้องการใช้ความหลากหลายในการแก้ไขวิธีการทั้งหมดที่เรียกว่าget()แทนที่จะให้พวกเขาแต่ละชื่อเฉพาะ ถ้ามันรบกวนคุณเขียนคลาสที่สืบทอดคลาสดั้งเดิมและวางgetMillis()วิธีการของคุณเองในคลาสใหม่
Robert Harvey

@RobertHarvey คลาสส่วนใหญ่ในแพ็คเกจ java.time ไม่เปลี่ยนรูปและไม่สามารถขยายได้
assylias

2
@ RobertHarvey คำถามสำหรับฉันไม่ใช่ฉันจะแก้ปัญหานี้ได้อย่างไร มันดูเหมือนความไม่ลงรอยกันแปลก ๆ และฉันก็สงสัยว่าจะมีคำอธิบายที่น่าสนใจสำหรับเรื่องนี้หรือไม่
Tarmo

ฉันมีความคิดว่าสถาปัตย์ / OS บางระบบไม่สนับสนุนมิลลิวินาทีอย่างน่าเชื่อถือ กล่าวอีกนัยหนึ่งเวลาของระบบจะไม่สามารถเรียกคืนมาเป็นมิลลิวินาทีได้เพียงแค่เซนติหรือวินาที
Marco

ดูstackoverflow.com/a/23945792/40064ในการทำมันผ่านInstantคลาส
Wim Deblauwe

คำตอบ:


63

JSR-310ขึ้นอยู่กับนาโนวินาทีไม่ใช่มิลลิวินาที ดังนั้นวิธีการที่เหมาะสมในการใช้งานขั้นต่ำนั้นขึ้นอยู่กับชั่วโมงนาทีวินาทีและนาโนวินาที การตัดสินใจที่จะมีฐานนาโนวินาทีเป็นหนึ่งในการตัดสินใจเดิมของโครงการและเป็นสิ่งที่ฉันเชื่อมั่นว่าถูกต้อง

การเพิ่มวิธีการสำหรับมิลลิวินาทีจะทับซ้อนกันของนาโนวินาทีเป็นวิธีที่ไม่ชัดเจน ผู้ใช้จะต้องคิดว่าสนามนาโนเป็นแบบนาโนวินาทีหรือนาโนมิลลิวินาที การเพิ่มเมธอดเพิ่มเติมที่สับสนนั้นไม่เป็นที่ต้องการดังนั้นเมธอดจึงถูกละเว้น ตามที่ระบุไว้ทางเลือกget(MILLI_OF_SECOND)สามารถใช้ได้

FWIW ฉันจะคัดค้านการเพิ่มgetMillis()วิธีการในอนาคต


1
ฉันได้รับคำตอบที่ดีมากสำหรับคำถามนี้ แต่คำตอบของคุณคือคำตอบที่ฉันชอบเพราะสั้นและยังคงเป็นจุดที่ดีมากและทำให้ฉันเชื่อมั่นในความจำเป็นของวิธีการนี้ ขอขอบคุณ.
Tarmo

12
@ s3ib หากคุณตรวจสอบโปรไฟล์ของผู้ตอบคุณจะสังเกตเห็นว่าเขาเป็นผู้นำในการกำหนดข้อมูลสำหรับ API ที่คุณกำลังถาม นี้จะทำให้คำตอบที่เป็นเผด็จการตามที่ได้รับไม่ได้ :)
ริ้น

ดังนั้นสิ่งที่ต้องทำinstant.getEpochSecond * 1000 + instant.getNano / 1000000ก็คือต้นแบบสำเร็จรูปที่เหมาะสมที่จะสามารถสื่อสารกับมรดก (ณ จุดนี้ทั้งหมด) Java APIs, Javascript และอื่น ๆ ?
nilskp

10
ไม่ในกรณีนั้นคุณสามารถใช้ instant.toEpochMilli () download.java.net/jdk8/docs/api/java/time/?hl=th
JodaStephen

20

ก่อนที่จะเป็นส่วนหนึ่งของ openJDK Threeten อยู่บน github และก่อนหน้านั้นมันอยู่บน sourceforge กลับมาแล้วสตีเฟ่น Colebourne ซึ่งเป็นนำข้อกำหนดเกี่ยวกับ JSR-310 ทำสำรวจ tha คุณยังสามารถหาในเว็บไซต์ SourceForge

The fourth question on the survey covered the method names for LocalTime:
1) getHourOfDay(), getMinuteOfHour(), getSecondOfMinute(), getNanoOfSecond()
2) getHour(), getMinute(), getSecond(), getNanoOfSecond()
3) getHour(), getMinute(), getSecond(), getNano()
4) another idea

มีเพียง 6.23% เท่านั้นที่เลือกคำตอบ # 4 และในหมู่พวกเขาประมาณ 15% ที่ขอให้getMillis()นั่นคือน้อยกว่า 1% ของคะแนนโหวตทั้งหมด

นั่นอาจเป็นสาเหตุที่ไม่มีgetMillisในตอนแรกและฉันไม่สามารถหาอะไรที่เกี่ยวข้องในรายชื่อผู้รับจดหมาย openjdk ดังนั้นเรื่องก็ไม่ได้กล่าวถึงในภายหลัง


3
ฉันคิดว่าการให้คนหลาย ๆ ทางเลือกทำให้มีโอกาสมากขึ้นที่พวกเขาจะเลือกหนึ่งในตัวเลือกเหล่านั้นแม้ว่าตัวเลือกในอุดมคติของพวกเขาจะอยู่ภายใต้ "อื่น ๆ " ฉันอาจจะผิด แต่
Allon Guralnek

2
@AllonGuralnek ใช่แน่นอน - แต่องค์ประกอบมิลลิวินาทีมีความสำคัญใน Date API เพราะทุกอย่างขึ้นอยู่กับจำนวนมิลลิวินาทีนับตั้งแต่ยุค ใน API ใหม่มันเป็น IMO ที่เกี่ยวข้องน้อยกว่า ในกรณีส่วนใหญ่คุณต้องใช้ความแม่นยำที่สองหรือความแม่นยำที่ดีที่สุดที่มีอยู่ (nanos) ฉันอาจจะผิด
assylias

1
ดูเหมือนว่าจะถามเกี่ยวกับการตั้งชื่อของวิธีการไม่ใช่วิธีการที่ควรมีอยู่
svick

1
ใช่ขอโทษฉันยังไม่ชัดเจน: ฉันหมายถึงคำถามจากการสำรวจว่ามันไม่ได้เกี่ยวข้องโดยตรงกับคำถามนี้
svick

15

คลาสที่แสดงเวลา UTC ที่ชัดเจน (นั่นคือ Instant, OffsetDateTime, ZonedDateTime) มีวิธีการช่วยเหลือสองวิธีสำหรับการเข้าถึงออฟเซ็ตสัมบูรณ์จาก Java epoch นั่นคือสิ่งที่คุณเรียกว่า 'เวลามิลลิวินาที' ใน java.util.Date ซึ่งคุณสามารถใช้ เพื่อให้ได้เป็นมิลลิวินาที

long getEpochSecond()
int getNano()

1000L*getEpochSecond() + getNano() / 1000000L;

เหตุผลบางอย่างว่าทำไมสิ่งนี้จึงถูกเลือกแทนที่จะlong getEpochMillis()ถูกกล่าวถึงในรายชื่อผู้รับจดหมาย jsr 310ซึ่งบางส่วนได้แยกออกมาเพื่อความสะดวก:

ดูเหมือนว่ามีเหตุผลที่จะสมมติว่าความแม่นยำเป็นมิลลิวินาทีไม่เพียงพอ อย่างไรก็ตามสิ่งที่มากกว่าความแม่นยำระดับนาโนวินาทีดูเหมือนจะมากเกินไป

...

เพื่อที่จะใช้สิ่งนี้ตัวเลือกที่ฉันต้องการจะเป็น 64 บิตยาววินาที (ลงนาม) + 32 บิต int nanoseconds (ไม่ได้ลงนาม)

...

ฉันชอบแบ่งเป็นระดับที่สองเนื่องจากเป็นหน่วย SI ของเวลาอย่างเป็นทางการในวิทยาศาสตร์และมาตรฐานที่ตกลงกันมากที่สุด

การแยกที่ระดับวันเป็นปัญหาสำหรับ instants เนื่องจากไม่ได้จัดการกับ leap วินาที การแยกที่ระดับมิลลิวินาทีในขณะที่การบูรณาการที่ดีขึ้นเล็กน้อยกับส่วนที่เหลือของ Java ดูเหมือนว่าค่อนข้างแปลก รวมทั้งจะสูญเสียในช่วงที่รองรับ

การแยกที่สองตามที่เสนอจะให้ช่วงของนาโนวินาทีมากกว่า 290 พันล้านปี ในขณะที่ไม่มีใครควรใช้ความแม่นยำนั้นในช่วงของช่วงเวลานั้นฉันขอแนะนำให้ง่ายกว่าที่จะสนับสนุนมันกว่าจะบล็อกมันการแยกที่ระดับวันนั้นเป็นปัญหาสำหรับผู้ใช้งานเพราะมันไม่ได้จัดการกับเผ่นวินาที

ฉันมีความรู้สึกว่าอีกเหตุผลหนึ่งที่ทำให้การแปลงจาก java.util.Date เป็นคลาส JSR310 เป็นไปอย่างยากลำบากโดยหวังว่าผู้พัฒนาจะพยายามเข้าใจความแตกต่างระหว่างตัวเลือกต่าง ๆ และไม่ใช่แค่สุ่มสี่สุ่มห้า (mis) ใช้คลาสใหม่

สาเหตุที่LocalDateTimeชั้นเรียนไม่มีวิธีการเหล่านั้น - พวกเขาไม่สามารถอยู่ที่นั่นได้เพราะLocalDateTimeไม่ได้เชื่อมโยงกับเส้นเวลา UTC จนกว่าคุณจะตัดสินใจว่าคุณอยู่ในโซนใดหรือ UTC ออฟเซ็ตของคุณอยู่ที่จุดใดOffsetDateTimeหรือZonedDateTime(ซึ่งทั้งสองอย่างมีวิธีที่จำเป็น)

หรือคุณสามารถกำหนดว่าคุณเป็นเจ้าของLOCAL_EPOCHค่าคงที่1970-01-01T00:00:00แล้วทำ a MILLIS.between(LOCAL_EPOCH, localTime)เพื่อให้ได้ระยะเวลาเป็นมิลลิวินาที อย่างไรก็ตามค่านี้จะไม่สามารถใช้งานร่วมกับค่าใด ๆ ที่ส่งคืนโดยSystem.currentTimeMilliseconds()หรือjava.util.Date.getTime()ยกเว้นว่าคุณกำหนดเวลาท้องถิ่นของคุณเป็นเวลา UTC แต่ในกรณีนี้คุณอาจใช้ Instant โดยตรงหรือ OffsetDateTime กับ ZoneOffset.UTC


4
" พวกเขาไม่สามารถอยู่ที่นั่นได้เพราะ LocalDateTime ไม่ได้เชื่อมโยงกับเส้นเวลา UTC " => LocalDateTime อาจมีgetMillisวิธีที่จะกลับมาโดยทั่วไปgetNanos()/1e6- ความจริงที่ว่าไม่ใช่เวลาในทันทีไม่ได้ป้องกันไม่ให้มิลลิวินาที ส่วนประกอบ
assylias

2
" ฉันมีความรู้สึกว่าอีกเหตุผลหนึ่งคือทำให้ยากที่จะแปลงจาก java.util.Date เป็นคลาส JSR310 " น่าจะเป็นจริง แต่น่าเสียดาย " มิลลิวินาทีนับตั้งแต่ยุค" กลายเป็นตัวแทนของเวลาเกือบสากลดังนั้นสำหรับทุกสิ่งที่ต้องการ เพื่อสื่อสารกับ Java APIs ที่เก่ากว่า Javascript สิ่งอื่นใดการละเลยนี้เป็นเรื่องยุ่งยาก
nilskp

ข้อมูลโค้ดของคุณที่ด้านบนไม่ถูกต้อง - คุณต้องคูณ getEpochSecond 1,000 ด้วย
Tin Man

@ นิลก์พวกเขามีสองสิ่งที่แตกต่างกัน คำถามถามเกี่ยวกับgetMillis()ใน getMillis-of-second; คุณกำลังพูดถึง "มิลลิวินาทีนับตั้งแต่ยุค" อดีตไม่มีอยู่ตามที่อธิบายไว้ในคำตอบที่ยอมรับ Instant.toEpochMillis()หลังมีอยู่แล้วเป็น ดังนั้นสำหรับLocalDateTimeคุณจะไปที่:ldt.toInstant(offset).toEpochMillis()
SusanW
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.