Java Date & Time API ผิดอะไร [ปิด]


107

บ่อยครั้งที่ฉันพบข้อเสนอแนะเชิงลบเกี่ยวกับ Java Dateและคลาสอื่น ๆ ที่เกี่ยวข้องกับวันเวลา ในฐานะนักพัฒนา. NET ฉันไม่สามารถเข้าใจได้อย่างเต็มที่ (โดยไม่ได้ใช้) ว่ามีอะไรผิดปกติกับพวกเขา

มีใครให้ความกระจ่างเกี่ยวกับเรื่องนี้ได้บ้าง?


คำตอบ:


143

อ่าDateคลาสJava บางทีอาจเป็นหนึ่งในตัวอย่างที่ดีที่สุดในการไม่ทำบางสิ่งในภาษาใดก็ได้ทุกที่ ฉันจะเริ่มจากตรงไหนดี?

การอ่าน JavaDoc อาจทำให้เราคิดว่านักพัฒนามีความคิดที่ดี มันจะไปเกี่ยวกับความแตกต่างระหว่างเวลา UTCและเวลา GMTที่มีความยาวแม้จะมีความจริงที่ว่าแตกต่างระหว่างสองเป็นพื้นเผ่นวินาที (ซึ่งเกิดขึ้นสวย ไม่ค่อย )

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

  • แม้จะได้รับการออกแบบในทศวรรษที่ผ่านมาของสหัสวรรษ แต่ก็มีอัตราหลายปีเป็นตัวเลขสองหลักนับตั้งแต่ปี 1900 มีวิธีแก้ปัญหาหลายล้านวิธีที่ทำ 1900+ (หรือ 1900-) ในโลก Java อันเป็นผลมาจากการตัดสินใจซ้ำซากนี้
  • เดือนจะถูกจัดทำดัชนีเป็นศูนย์เพื่อรองรับกรณีที่ผิดปกติอย่างน่าทึ่งของการมีอาร์เรย์ของเดือนและไม่ได้อยู่กับอาร์เรย์องค์ประกอบสิบสามรายการซึ่งกลุ่มแรกมี a null. เป็นผลให้เรามี 0..11 (และวันนี้เป็นเดือนที่ 11 ของปี 109) มีจำนวน ++ และ - ใกล้เคียงกันในเดือนเพื่อที่จะแปลงเป็นสตริง
  • พวกเขากำลังไม่แน่นอน ด้วยเหตุนี้เมื่อใดก็ตามที่คุณต้องการให้วันที่ย้อนกลับ (เช่นโครงสร้างอินสแตนซ์) คุณจะต้องส่งคืนโคลนของวันที่นั้นแทนที่จะเป็นวัตถุวันที่ (เนื่องจากไม่เช่นนั้นผู้คนสามารถกลายพันธุ์โครงสร้างของคุณได้)
  • ซึ่งCalendarออกแบบมาเพื่อ 'แก้ไข' สิ่งนี้ทำให้เกิดข้อผิดพลาดเดียวกัน พวกเขายังคงไม่แน่นอน
  • Dateแสดงถึง a DateTimeแต่เพื่อที่จะเลื่อนไปสู่สิ่งที่อยู่ใน SQL land จึงมีคลาสย่อยอื่นjava.sql.Dateซึ่งแสดงถึงวันเดียว (แม้ว่าจะไม่มีเขตเวลาที่เกี่ยวข้องก็ตาม)
  • ไม่มีTimeZones ที่เกี่ยวข้องกับ a Dateดังนั้นช่วง (เช่น 'ทั้งวัน') มักจะแสดงเป็นเที่ยงคืน - เที่ยงคืน (มักจะอยู่ในเขตเวลาที่กำหนดเอง)

สุดท้ายเป็นที่น่าสังเกตว่าโดยทั่วไปแล้วอธิกวินาทีจะแก้ไขตัวเองเทียบกับนาฬิการะบบที่ดีซึ่งอัปเดตด้วย ntp ภายในหนึ่งชั่วโมง (ดูลิงก์ด้านล่าง) โอกาสที่ระบบจะยังคงทำงานอยู่ในการเปิดตัวสองวินาทีอธิกสุรทิน (ทุก ๆ หกเดือนขั้นต่ำทุกๆสองสามปีในทางปฏิบัติ) นั้นไม่น่าเป็นไปได้มากนักโดยเฉพาะอย่างยิ่งเมื่อพิจารณาถึงความจริงที่ว่าคุณต้องปรับใช้รหัสเวอร์ชันใหม่เป็นครั้งคราว . แม้แต่การใช้ภาษาแบบไดนามิกที่สร้างคลาสหรือบางอย่างเช่นเครื่องมือ WAR จะทำให้พื้นที่ของชั้นเรียนเป็นมลพิษและหมดสิทธิ์ในที่สุด


44

JSR 310ซึ่งแทนที่คลาสวันที่และเวลาเก่าด้วยjava.timeใน Java 8 จะระบุตัวเองในJSR ดั้งเดิมดังนี้:

2.5 อะไรคือความต้องการของชุมชน Java ที่จะได้รับการแก้ไขโดยข้อกำหนดที่เสนอ?

ปัจจุบัน Java SE มี API วันที่และเวลาแยกกันสองรายการ - java.util.Date และ java.util.Calendar API ทั้งสองถูกอธิบายอย่างสม่ำเสมอว่านักพัฒนา Java ใช้งานยากบนเว็บบล็อกและฟอรัม โดยเฉพาะอย่างยิ่งทั้งสองใช้ดัชนีศูนย์เป็นเวลาหลายเดือนซึ่งเป็นสาเหตุของข้อบกพร่องมากมาย ปฏิทินยังได้รับความเดือดร้อนจากข้อบกพร่องและปัญหาด้านประสิทธิภาพมากมายในช่วงหลายปีที่ผ่านมาสาเหตุหลักมาจากการจัดเก็บสถานะในสองวิธีที่แตกต่างกันภายใน

ข้อบกพร่องแบบคลาสสิกข้อหนึ่ง (4639407) ป้องกันไม่ให้สร้างวันที่ที่แน่นอนในวัตถุปฏิทิน สามารถเขียนลำดับของรหัสที่สามารถสร้างวันที่ในบางปี แต่ไม่สามารถสร้างวันที่อื่นได้โดยมีผลในการป้องกันไม่ให้ผู้ใช้บางรายป้อนวันเกิดที่ถูกต้อง สิ่งนี้เกิดจากคลาสปฏิทินอนุญาตให้เพิ่มเวลาออมแสงได้เพียงหนึ่งชั่วโมงในฤดูร้อนเมื่อในอดีตเป็นเวลาบวก 2 ชั่วโมงในช่วงสงครามโลกครั้งที่สอง ในขณะนี้ข้อบกพร่องนี้ได้รับการแก้ไขแล้วหากในอนาคตประเทศหนึ่งเลือกที่จะเพิ่มเวลาออมแสงบวกสามชั่วโมงในช่วงฤดูร้อนคลาสปฏิทินจะเสียอีกครั้ง

Java SE API ปัจจุบันยังทนอยู่ในสภาพแวดล้อมแบบมัลติเธรด คลาสที่ไม่เปลี่ยนรูปเป็นที่รู้กันว่าเธรดปลอดภัยโดยเนื้อแท้เนื่องจากสถานะไม่สามารถเปลี่ยนแปลงได้ อย่างไรก็ตามทั้งวันที่และปฏิทินสามารถเปลี่ยนแปลงได้ซึ่งต้องใช้โปรแกรมเมอร์ในการพิจารณาการโคลนนิ่งและเธรดอย่างชัดเจน นอกจากนี้การขาดความปลอดภัยของเธรดใน DateTimeFormat ยังไม่เป็นที่รู้จักอย่างกว้างขวางและเป็นสาเหตุของปัญหาการเธรดที่ยากต่อการติดตาม

เช่นเดียวกับปัญหาเกี่ยวกับคลาสที่ Java SE มีสำหรับวันที่และเวลาก็ไม่มีคลาสสำหรับการสร้างโมเดลแนวคิดอื่น ๆ วันที่หรือเวลาที่ไม่ใช่โซนเวลาระยะเวลาช่วงเวลาและช่วงเวลาไม่มีการแสดงคลาสใน Java SE ด้วยเหตุนี้นักพัฒนาจึงมักใช้ int เพื่อแสดงระยะเวลาโดย javadoc ระบุหน่วย

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

JSR นี้จะแก้ไขปัญหาของรูปแบบวันที่และเวลาที่สมบูรณ์รวมถึงวันที่และเวลา (มีและไม่มีเขตเวลา) ระยะเวลาและช่วงเวลาช่วงเวลาการจัดรูปแบบและการแยกวิเคราะห์


28
  • อินสแตนซ์วันที่ไม่แน่นอนซึ่งมักจะไม่สะดวก
  • พวกเขามีลักษณะสองเท่า ซึ่งแสดงทั้งการประทับเวลาและวันที่ในปฏิทิน ปรากฎว่านี่เป็นปัญหาเมื่อทำการคำนวณวันที่
  • การแสดงตัวเลขของข้อมูลปฏิทินนั้นใช้งานง่ายในหลาย ๆ กรณี ตัวอย่างเช่น: getMonth()is zero-based getYear()คือ 1900-based (กล่าวคือปี 2009 แสดงเป็น 109)
  • พวกเขาไม่มีฟังก์ชันมากมายที่คุณคาดหวังจากDateชั้นเรียน

13

ฉันรู้สึกแทนคุณ ... ในฐานะอดีตโปรแกรมเมอร์. NET ฉันถามคำถามเดียวกันเวลา API ใน. NET (ช่วงเวลา, การโอเวอร์โหลดตัวดำเนินการ) สะดวกมาก

ขั้นแรกในการสร้างวันที่ที่เฉพาะเจาะจงคุณใช้ API ที่เลิกใช้แล้วหรือ:

Calendar c = Calendar.getInstance();
c.set(2000, 31, 12)

เพื่อลบวันที่คุณทำสิ่งชั่วร้ายเช่น

Date firstDate = ...
Calendar c = Calendar.getInstance();
c.setTime(fistDate);
c.add(Calendar.DATE,-1);
Date dayAgo = c.getTime();

หรือแย่กว่านั้น

Date d = new Date();
Date d2 = new Date(d.getTime() - 1000*60*60*24);

หากต้องการทราบระยะเวลาที่ผ่านไประหว่างวันที่สองวัน (เป็นวัน / สัปดาห์ / เดือน) ... มันยิ่งแย่ลงไปอีก

อย่างไรก็ตามDateUtilsจาก apache ( org.apache.commons.lang.time.DateUtils) มีวิธีการที่สะดวกและฉันพบว่าตัวเองใช้เฉพาะเมื่อเร็ว ๆ นี้

ดังที่ Brabster เขียน Joda Time ก็เป็นไลบรารีภายนอกที่ดีเช่นกัน แต่ apache ดูเหมือน "ธรรมดา" มากกว่าสิ่งอื่นใด ...


โปรดแสดงวิธีการให้เราดู ("ดูว่าเวลาผ่านไปเท่าไรระหว่างวันที่สองวัน")!
Anton Gogolev

ฉันหวังว่าฉันจะรู้วิธีง่ายๆ ... รวมถึงปีอธิกสุรทินเดือนที่น่ากลัวและวันระเหย ...
Eran Medan

1
ดูเพิ่มเติมที่ org.apache.commons.lang.time: commons.apache.org/lang//api/org/apache/commons/lang/time/…
trashgod

@AntonGogolev ในjava.timeใช้PeriodและDurationคลาสเพื่อคำนวณและแสดงเวลาที่ผ่านไปในระดับปี - เดือน - วันและชั่วโมง - นาที - วินาทีตามลำดับ
Basil Bourque

4

ฉันพบว่า Date API ของ Java ใช้งานได้จริง ปัญหาส่วนใหญ่ที่ผมเคยเห็นและได้ยินเกี่ยวกับความสัมพันธ์กับฟุ่มเฟื่อยจำเป็นที่จะต้องเกี่ยวข้องกับหลายชั้นเรียนที่จะทำอะไรที่เป็นประโยชน์ ( Calendar, Date, DateFormat/ SimpleDateFormat) และการขาดการ accessors getDayOfWeek()ง่ายเช่น

Joda Timeเป็น API ทางเลือกที่ได้รับการยอมรับอย่างดีใน Java และในส่วน Why Joda Time จะให้ข้อโต้แย้งเพิ่มเติมว่าเหตุใดจึงเป็นทางเลือกที่ทำงานได้ซึ่งอาจเป็นที่สนใจ

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