ทำไมเดือนมกราคม 0 ในปฏิทิน Java


300

ในjava.util.Calendarเดือนมกราคมหมายถึงเดือนที่ 0 ไม่ใช่เดือนที่ 1 มีเหตุผลเฉพาะเจาะจงหรือไม่

ฉันเห็นหลายคนสับสนเกี่ยวกับเรื่องนี้ ...


4
รายละเอียดการดำเนินการนั้นไม่ได้เป็นเช่นนี้เนื่องจากค่าคงที่มกราคม, กุมภาพันธ์ ฯลฯ อยู่? คลาสวันที่มาก่อนรองรับจาวา enum ที่เหมาะสม
gnud

6
น่ารำคาญยิ่งขึ้น - ทำไมถึงมีวันเพ็ญเดือนกันยายน?
matt b

40
@gnud: ไม่มันไม่ใช่รายละเอียดการใช้งาน มันทำให้เกิดความเจ็บปวดเมื่อคุณได้รับจำนวนเต็มในฐาน "ธรรมชาติ" (เช่น Jan = 1) และคุณจำเป็นต้องใช้กับ API ปฏิทิน
Jon Skeet

1
@matt b: สำหรับปฏิทินที่ไม่ใช่คริสต์ศักราช (ปฏิทินจันทรคติ ฯลฯ ) ที่มีสิบสามเดือน นั่นเป็นเหตุผลที่ดีที่สุดที่จะไม่คิดในแง่ของตัวเลข แต่ให้ปฏิทินทำการแปลเป็นภาษาท้องถิ่น
erickson

7
การโต้แย้ง 13 เดือนไม่สมเหตุสมผล ถ้าเป็นเช่นนั้นทำไมไม่มีเดือนพิเศษเป็น 0 หรือ 13
Quinn Taylor

คำตอบ:


323

มันเป็นเพียงส่วนหนึ่งของระเบียบที่น่ากลัวซึ่งเป็น API วันที่ / เวลาของ Java การระบุสิ่งผิดปกติใช้เวลานานมาก (และฉันแน่ใจว่าฉันไม่ทราบปัญหาครึ่งหนึ่ง) การทำงานกับวันและเวลาที่เป็นที่ยอมรับนั้นเป็นเรื่องยุ่งยาก

ตัวเองไม่ชอบและใช้Joda เวลาแทนหรืออาจจะเป็นJSR-310

แก้ไข: สำหรับเหตุผลที่ - ตามที่ระบุไว้ในคำตอบอื่น ๆ อาจเป็นเพราะ C APIs เก่าหรือเพียงแค่ความรู้สึกทั่วไปของการเริ่มต้นทุกอย่างตั้งแต่ 0 ... ยกเว้นว่าวันนั้นเริ่มต้นด้วย 1 แน่นอน ฉันสงสัยว่าใครก็ตามที่อยู่นอกทีมเริ่มต้นใช้งานจริงสามารถระบุเหตุผลได้ - แต่อีกครั้งฉันขอให้ผู้อ่านไม่ต้องกังวลมากนักเกี่ยวกับสาเหตุของการตัดสินใจที่ไม่java.util.Calendarดี

จุดหนึ่งซึ่งเป็นในความโปรดปรานของการใช้ 0 ตามดัชนีก็คือว่ามันทำให้สิ่งที่ชอบ "อาร์เรย์ของชื่อ" ง่ายขึ้น:

// I "know" there are 12 months
String[] monthNames = new String[12]; // and populate...
String name = monthNames[calendar.get(Calendar.MONTH)];

แน่นอนว่าสิ่งนี้จะล้มเหลวทันทีที่คุณได้รับปฏิทินที่มี 13 เดือน ... แต่อย่างน้อยขนาดที่ระบุคือจำนวนเดือนที่คุณคาดหวัง

นี่ไม่ใช่เหตุผลที่ดีแต่เป็นเหตุผล ...

แก้ไข: ในฐานะที่เป็นประเภทความคิดเห็นขอความคิดบางอย่างเกี่ยวกับสิ่งที่ฉันคิดว่าผิดกับวันที่ / ปฏิทิน:

  • ฐานที่น่าแปลกใจ (ปี 1900 เป็นปีฐานในวันที่ยอมรับสำหรับผู้รับเหมาที่เลิกใช้แล้ว 0 เป็นฐานรายเดือนทั้งคู่)
  • ความไม่แน่นอน - การใช้รูปแบบที่ไม่เปลี่ยนรูปแบบทำให้การทำงานกับสิ่งที่มีคุณค่ามีประสิทธิภาพทำได้ง่ายกว่ามาก
  • ชุดประเภทไม่เพียงพอ: ยินดีที่ได้รับDateและCalendarเป็นสิ่งที่แตกต่างกัน แต่การแยกค่า "ท้องถิ่น" vs "ส่วน" หายไปเช่นเดียวกับวันที่ / เวลาเทียบกับวันที่เวลา
  • API ที่นำไปสู่โค้ดที่น่าเกลียดซึ่งมีค่าคงที่เวทย์มนตร์แทนวิธีการตั้งชื่ออย่างชัดเจน
  • API ซึ่งเป็นเรื่องยากมากที่จะให้เหตุผลเกี่ยวกับ - ธุรกิจทั้งหมดเกี่ยวกับเมื่อมีการคำนวณสิ่งใหม่และอื่น ๆ
  • การใช้ตัวสร้างแบบไม่มีพารามิเตอร์เป็นค่าเริ่มต้นเป็น "ตอนนี้" ซึ่งนำไปสู่รหัสที่ยากต่อการทดสอบ
  • Date.toString()การดำเนินงานซึ่งมักจะใช้เขตเวลาท้องถิ่นระบบ (ว่าสับสนผู้ใช้กองมากเกินจำนวนมากก่อนหน้านี้)

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

3
@Brian: ฉันรู้สึกเจ็บปวดของคุณ อีกครั้ง Joda Time ก็เรียบง่าย :) (ปัจจัยที่ไม่สามารถเปลี่ยนแปลงได้ทำให้สิ่งต่าง ๆ น่าพึงพอใจในการทำงานด้วยเช่นกัน)
Jon Skeet

8
คุณไม่ได้ตอบคำถาม
Zeemee

2
@ user443854: ฉันได้ระบุบางจุดไว้ในการแก้ไข - ดูว่าช่วยได้ไหม
Jon Skeet

2
หากคุณใช้ Java 8 คุณสามารถทิ้งคลาส Calendar และเปลี่ยนเป็นDateTime APIใหม่และทันสมัย API ใหม่ยังรวมถึงDateTimeFormatterที่ไม่เปลี่ยนรูปแบบ / ซึ่งเป็นการปรับปรุงครั้งใหญ่กว่า SimpleDateFormat ที่มีปัญหาและมีราคาแพง
ccpizza

43

เพราะการทำคณิตศาสตร์กับเดือนนั้นง่ายกว่ามาก

1 เดือนหลังจากเดือนธันวาคมคือเดือนมกราคม แต่หากต้องการคิดออกตามปกติคุณจะต้องใช้หมายเลขเดือนและทำคณิตศาสตร์

12 + 1 = 13 // What month is 13?

ฉันรู้ว่า! ฉันสามารถแก้ไขได้อย่างรวดเร็วโดยใช้โมดูลัส 12

(12 + 1) % 12 = 1

ใช้งานได้ดี 11 เดือนจนถึงพฤศจิกายน ...

(11 + 1) % 12 = 0 // What month is 0?

คุณสามารถทำให้งานทั้งหมดนี้อีกครั้งโดยการลบ 1 ก่อนที่จะเพิ่มเดือนจากนั้นทำโมดูลัสของคุณและในที่สุดก็เพิ่ม 1 กลับมาอีกครั้ง ... aka การแก้ไขปัญหาพื้นฐาน

((11 - 1 + 1) % 12) + 1 = 12 // Lots of magical numbers!

ทีนี้ลองคิดถึงปัญหาของเดือนที่ 0 - 11

(0 + 1) % 12 = 1 // February
(1 + 1) % 12 = 2 // March
(2 + 1) % 12 = 3 // April
(3 + 1) % 12 = 4 // May
(4 + 1) % 12 = 5 // June
(5 + 1) % 12 = 6 // July
(6 + 1) % 12 = 7 // August
(7 + 1) % 12 = 8 // September
(8 + 1) % 12 = 9 // October
(9 + 1) % 12 = 10 // November
(10 + 1) % 12 = 11 // December
(11 + 1) % 12 = 0 // January

ทุกเดือนทำงานเหมือนเดิมและไม่จำเป็นต้องแก้ไขอีกต่อไป


5
นี่คือความพึงพอใจ อย่างน้อยก็มีค่าต่อความบ้าคลั่งนี้!
moljac024

"ตัวเลขเวทย์มนตร์มากมาย" - ไม่มันเป็นเพียงตัวเลขเดียวที่ปรากฏขึ้นสองครั้ง
user123444555621

การย้อนกลับไปหนึ่งเดือนยังคงเป็นเรื่องลำบาก แต่ต้องขอบคุณผู้ใช้งานที่เหลืออยู่ของ "C" แทน "โมดูลัส" ฉันก็ไม่แน่ใจเหมือนกันว่าบ่อยครั้งที่คนต้องการชนเดือนโดยไม่ต้องปรับปีและการมีเดือนไป 1-12 ไม่สร้างปัญหากับ `ในขณะที่ (เดือน> 12) {month- = 12; ปี ++;}
supercat

2
เนื่องจากฟังก์ชั่นที่มีสติเช่น DateTime.AddMonths นั้นยากเกินกว่าที่จะนำไปใช้อย่างถูกต้องใน lib เราจึงต้องทำคณิตศาสตร์ที่คุณอธิบายด้วยตัวเอง ... Mmmmmkay
nsimeonov

8
ฉันไม่เข้าใจ upvotes เหล่านี้ - ((11 - 1 + 1) % 12) + 1 = 12เป็น(11 % 12) + 1เช่นสำหรับเดือน 1..12 คุณเพียงแค่ต้องเพิ่ม 1 หลังจากทำ modulo ไม่ต้องใช้เวทมนต์
mfitzp

35

ภาษาที่ใช้ภาษา C คัดลอก C ในระดับหนึ่ง tmโครงสร้าง (ที่กำหนดไว้ในtime.h) มีข้อมูลจำนวนเต็มtm_monกับ (ความเห็น) ช่วง 0-11

ภาษาที่ใช้ภาษา C เริ่มต้นอาร์เรย์ที่ดัชนี 0 ดังนั้นสิ่งนี้จึงสะดวกสำหรับการแสดงผลสตริงในอาร์เรย์ของชื่อเดือนพร้อมกับtm_monดัชนี


22

มีคำตอบมากมายเกี่ยวกับเรื่องนี้ แต่ฉันจะให้ความเห็นเกี่ยวกับเรื่องนี้ต่อไป เหตุผลที่อยู่เบื้องหลังพฤติกรรมแปลก ๆ ดังที่ระบุไว้ก่อนหน้านี้มาจาก POSIX C time.hซึ่งเดือนที่จัดเก็บใน int ด้วยช่วง 0-11 เพื่ออธิบายว่าทำไมดูที่นี่ ปีและวันถือเป็นตัวเลขในภาษาพูด แต่เดือนมีชื่อของตัวเอง ดังนั้นเนื่องจากมกราคมเป็นเดือนแรกมันจะถูกเก็บเป็นออฟเซ็ต 0 องค์ประกอบอาร์เรย์แรก จะเป็นmonthname[JANUARY] "January"เดือนแรกในปีคือองค์ประกอบอาร์เรย์เดือนแรก

ตัวเลขในทางกลับกันเนื่องจากพวกเขาไม่มีชื่อเก็บไว้ใน int อย่างที่ 0-30 จะทำให้สับสนเพิ่มday+1คำแนะนำจำนวนมากสำหรับการแสดงผลและแน่นอนมีแนวโน้มที่จะมีข้อบกพร่องมากมาย

ที่ถูกกล่าวว่าไม่สอดคล้องกันมีความสับสนโดยเฉพาะอย่างยิ่งในจาวาสคริปต์ (ซึ่งยังได้รับมรดก "คุณสมบัติ") นี้เป็นภาษาสคริปต์ที่สิ่งนี้ควรจะใจลอยห่างจาก langague

TL; DR : เนื่องจากเดือนมีชื่อและวันในเดือนนั้นไม่


1
"เดือนมีชื่อและวันไม่ได้" เคยได้ยินคำว่า 'วันศุกร์' หรือไม่ ;) ตกลงฉันคาดเดาว่าคุณหมายถึง '.. วันของเดือนไม่' - อาจจ่ายเพื่อแก้ไขคำตอบของคุณ :-)
Andrew Thompson

0/0/0000 แสดงผลดีกว่าเป็น "00-Jan-0000" หรือเป็น "00-XXX-0000" หรือไม่ IMHO รหัสจำนวนมากน่าจะสะอาดกว่าถ้ามี "เดือน" สิบสามเดือน แต่เดือนที่ 0 ได้รับชื่อดัมมี่
supercat

1
นั่นเป็นสิ่งที่น่าสนใจ แต่ 0/0/0000 ไม่ใช่วันที่ที่ถูกต้อง คุณจะเรนเดอร์ 40/40/0000 อย่างไร
piksel bitworks

12

ใน Java 8 มีวันที่ / เวลา API JSR 310 ใหม่ที่มีสติมากกว่า ข้อมูลจำเพาะนั้นเหมือนกับผู้เขียนหลักของ JodaTime และพวกเขาแบ่งปันแนวคิดและรูปแบบที่คล้ายคลึงกันจำนวนมาก


2
API วันที่เวลาใหม่ตอนนี้เป็นส่วนหนึ่งของ Java 8
mschenk74

9

ฉันจะบอกว่าขี้เกียจ อาร์เรย์เริ่มต้นที่ 0 (ทุกคนรู้ว่า) เดือนของปีเป็นอาร์เรย์ซึ่งทำให้ฉันเชื่อว่าวิศวกรบางคนของ Sun ไม่ได้สนใจที่จะใส่รหัสนี้ลงในโค้ด Java


9
ไม่ฉันไม่ต้องการ การเพิ่มประสิทธิภาพของลูกค้าเป็นสิ่งสำคัญกว่าการเขียนโปรแกรม เนื่องจากลูกค้ารายนี้ใช้เวลาที่นี่ถามพวกเขาจึงล้มเหลว
TheSmurf

2
มันไม่เกี่ยวกับประสิทธิภาพอย่างสิ้นเชิง - ไม่ใช่ว่าเก็บเดือนไว้ในอาร์เรย์และคุณต้องใช้ 13 ถึง 12 เดือน เป็นเรื่องของการไม่ทำให้ API ใช้งานง่ายอย่างที่ควรจะเป็นในตอนแรก Josh Bloch rags ตามวันที่และปฏิทินใน "Effective Java" API น้อยมากที่สมบูรณ์แบบและ API ของวันที่ / เวลาใน Java มีบทบาทที่น่าเสียดายที่เป็น API ที่ถูกทำผิด นั่นคือชีวิต แต่อย่าทำท่าว่ามีอะไรเกี่ยวข้องกับประสิทธิภาพ
Quinn Taylor

1
ทำไมไม่นับจำนวนวันตั้งแต่ 0 ถึง 30? มันไม่สอดคล้องและเลอะเทอะ
Juangui Jordán


8

เนื่องจากโปรแกรมเมอร์กำลังหมกมุ่นอยู่กับดัชนี 0-based ตกลงมันซับซ้อนกว่านั้นเล็กน้อย: มันสมเหตุสมผลกว่าเมื่อคุณทำงานกับตรรกะระดับล่างเพื่อใช้การจัดทำดัชนีแบบ 0 แต่โดยมากฉันจะยังคงยึดติดกับประโยคแรกของฉัน


1
นี้เป็นอีกหนึ่งสำนวนเหล่านั้น / นิสัยที่ไปทางกลับไปประกอบหรือภาษาเครื่องที่ทุกอย่างจะทำในแง่ของการชดเชยที่ไม่ได้จัดทำดัชนี สัญกรณ์อาร์เรย์กลายเป็นทางลัดสำหรับการเข้าถึงบล็อกที่ต่อเนื่องกันเริ่มต้นที่ offset 0
Ken Gentle

4

โดยส่วนตัวแล้วฉันใช้ความแปลกประหลาดของ API ปฏิทิน Java เป็นตัวบ่งชี้ว่าฉันต้องการหย่าตัวเองจากความคิดที่เป็นศูนย์กลางแบบคริสต์ศักราชและพยายามที่จะเขียนโปรแกรม agnostically ให้มากขึ้น โดยเฉพาะฉันเรียนรู้อีกครั้งเพื่อหลีกเลี่ยงค่าคงที่ฮาร์ดโค้ดสำหรับสิ่งต่าง ๆ เช่นเดือน

ข้อใดต่อไปนี้มีแนวโน้มที่จะถูกต้องมากขึ้น

if (date.getMonth() == 3) out.print("March");

if (date.getMonth() == Calendar.MARCH) out.print("March");

สิ่งนี้แสดงให้เห็นสิ่งหนึ่งที่ทำให้ฉันรู้สึกแย่เกี่ยวกับ Joda Time - มันอาจกระตุ้นให้โปรแกรมเมอร์คิดในแง่ของค่าคงที่ฮาร์ดโค้ด (มีเพียงเล็กน้อยเท่านั้นไม่ใช่ว่า Joda บังคับให้โปรแกรมเมอร์เขียนโปรแกรมไม่ดี)


1
แต่รูปแบบใดที่มีแนวโน้มที่จะทำให้คุณปวดหัวเมื่อคุณไม่มีรหัสคงที่ - คุณมีค่าซึ่งเป็นผลมาจากการโทรเข้าเว็บหรืออะไรก็ตาม
Jon Skeet

แน่นอนว่าการให้บริการผ่านเว็บนั้นควรใช้ค่าคงที่แน่นอน :-) เหมือนกันไปสำหรับผู้โทรภายนอกใด ๆ เมื่อเราได้พิสูจน์แล้วว่ามีหลายมาตรฐานความต้องการในการบังคับใช้จะกลายเป็นชัดเจน (ฉันหวังว่าฉันเข้าใจความคิดเห็นของคุณ ... )
Paul Brinkley

3
ใช่เราควรบังคับใช้มาตรฐานที่เกือบทุกอย่างอื่นในโลกใช้เมื่อแสดงเดือน - มาตรฐานที่ใช้ 1
Jon Skeet

คำสำคัญที่นี่คือ "เกือบ" เห็นได้ชัดว่า Jan = 1 และอื่น ๆ รู้สึกเป็นธรรมชาติในระบบวันที่ที่มีการใช้งานที่กว้างขวางมาก แต่ทำไมตัวเราถึงทำให้เป็นข้อยกเว้นในการหลีกเลี่ยงค่าคงที่ฮาร์ดโค้ดในกรณีนี้?
Paul Brinkley

3
เพราะมันทำให้ชีวิตง่ายขึ้น มันแค่ทำ ฉันไม่เคยพบปัญหาแบบออฟไลน์กับระบบแบบ 1 เดือน ฉันเห็นข้อบกพร่องมากมายเช่นนี้กับ Java API ไม่สนใจสิ่งที่คนอื่น ๆ ในโลกไม่เข้าใจ
Jon Skeet

4

สำหรับฉันไม่มีใครอธิบายได้ดีไปกว่าmindpro.com :

gotchas

java.util.GregorianCalendarมีข้อบกพร่องและ gotchas น้อยกว่ามากใน old java.util.Dateชั้นเรียน แต่ก็ยังไม่มีการปิกนิก

หากมีผู้เขียนโปรแกรมเมื่อเสนอการปรับเวลาตามฤดูกาลครั้งแรกพวกเขาจะคัดค้านว่าเป็นคนบ้า ด้วยการปรับเวลาตามฤดูกาลมีความกำกวมพื้นฐาน ในฤดูใบไม้ร่วงเมื่อคุณตั้งค่านาฬิกาของคุณกลับหนึ่งชั่วโมงเวลา 02.00 น. มีเวลาที่แตกต่างกันสองแบบในเวลาทั้งสองเรียกว่าเวลาท้องถิ่น 1:30 น. คุณสามารถแยกแยะความแตกต่างได้เฉพาะเมื่อคุณบันทึกว่าคุณต้องการให้ปรับเวลาตามฤดูกาลหรือเวลามาตรฐานด้วยการอ่าน

น่าเสียดายที่ไม่มีวิธีที่จะบอกGregorianCalendarว่าคุณตั้งใจไว้ คุณต้องหันไปบอกเวลาท้องถิ่นกับเขตเวลา UTC จำลองเพื่อหลีกเลี่ยงความคลุมเครือ โปรแกรมเมอร์มักจะหลับตากับปัญหานี้และหวังว่าจะไม่มีใครทำอะไรเลยในช่วงเวลานี้

บั๊กสหัสวรรษ ข้อบกพร่องยังคงไม่ได้อยู่ในคลาสปฏิทิน แม้แต่ใน JDK (Java Development Kit) 1.3 ยังมีข้อบกพร่องในปี 2001 พิจารณารหัสต่อไปนี้:

GregorianCalendar gc = new GregorianCalendar();
gc.setLenient( false );
/* Bug only manifests if lenient set false */
gc.set( 2001, 1, 1, 1, 0, 0 );
int year = gc.get ( Calendar.YEAR );
/* throws exception */

ข้อผิดพลาดจะหายไปเวลา 7:00 น. ในวันที่ 2001/01/01 สำหรับ MST

GregorianCalendarถูกควบคุมโดยกองยักษ์แห่งค่าคงที่เวทมนต์ int ที่ยังไม่ได้พิมพ์ เทคนิคนี้ทำลายความหวังทั้งหมดของการตรวจสอบข้อผิดพลาดเวลาคอมไพล์ ตัวอย่างเช่นเพื่อให้ได้เดือนที่คุณใช้ GregorianCalendar. get(Calendar.MONTH));

GregorianCalendarมีการประหยัดแบบดิบ GregorianCalendar.get(Calendar.ZONE_OFFSET)และเวลากลางวัน GregorianCalendar. get( Calendar. DST_OFFSET)แต่ไม่มีวิธีการชดเชยเวลาตามจริงที่ใช้ คุณต้องแยกสองอย่างนี้ออกจากกันและเพิ่มเข้าด้วยกัน

GregorianCalendar.set( year, month, day, hour, minute) ไม่ตั้งค่าวินาทีเป็น 0

DateFormatและGregorianCalendarไม่ได้ตาข่ายอย่างถูกต้อง คุณต้องระบุปฏิทินสองครั้งครั้งเดียวโดยอ้อมเป็นวันที่

หากผู้ใช้ไม่ได้กำหนดค่าเขตเวลาของเขาอย่างถูกต้องผู้ใช้จะเริ่มต้นอย่างเงียบ ๆ กับ PST หรือ GMT

ใน GregorianCalendar เดือนจะมีหมายเลขเริ่มต้นที่มกราคม = 0 แทนที่จะเป็น 1 เหมือนกับคนอื่น ๆ บนโลก ยังวันเริ่มต้นที่ 1 เช่นเดียวกับวันของสัปดาห์กับวันอาทิตย์ = 1, วันจันทร์ = 2, …วันเสาร์ = 7 ยัง DateFormat แยกวิเคราะห์พฤติกรรมในแบบดั้งเดิมกับมกราคม = 1


4

java.util.Month

Java เป็นอีกวิธีหนึ่งในการใช้ดัชนีตามดัชนี 1 เดือน ใช้java.time.Monthenum วัตถุหนึ่งถูกกำหนดไว้ล่วงหน้าสำหรับแต่ละสิบสองเดือน พวกเขามีหมายเลขที่กำหนดให้แต่ละ 1-12 สำหรับเดือนมกราคมถึงธันวาคม โทรgetValueหาหมายเลข

ใช้ประโยชน์จากMonth.JULY(ให้คุณ 7) แทนCalendar.JULY(ให้คุณ 6)

(import java.time.*;)

3

TL; DR

Month.FEBRUARY.getValue()  // February → 2.

2

รายละเอียด

คำตอบโดยจอนสกีตที่ถูกต้อง

ตอนนี้เรามีการแทนที่ที่ทันสมัยสำหรับคลาสวัน - เวลาเก่าที่ยุ่งยากเหล่านั้น: คลาสjava.time

java.time.Month

ในบรรดาผู้เรียนเป็นenum Enum ดำเนินการหนึ่งหรือมากกว่าวัตถุที่กำหนดไว้ล่วงหน้าวัตถุที่มีอินสแตนซ์โดยอัตโนมัติเมื่อชั้นโหลด ในวันที่เรามีโหลวัตถุดังกล่าวแต่ละที่กำหนดชื่อ: , , และอื่น ๆ แต่ละคนเป็นค่าคงที่ระดับ คุณสามารถใช้และส่งผ่านวัตถุเหล่านี้ได้ทุกที่ในรหัสของคุณ ตัวอย่าง:Month MonthJANUARYFEBRUARYMARCHstatic final publicsomeMethod( Month.AUGUST )

โชคดีที่พวกเขามีเลขมีสติ 1-12 โดยที่ 1 คือมกราคมและ 12 คือธันวาคม

รับMonthวัตถุสำหรับหมายเลขเดือนหนึ่ง ๆ (1-12)

Month month = Month.of( 2 );  // 2 → February.

ไปอีกทางหนึ่งถามMonthวัตถุสำหรับหมายเลขเดือน

int monthNumber = Month.FEBRUARY.getValue();  // February → 2.

หลายวิธีที่มีประโยชน์อื่น ๆ ในชั้นนี้เช่นรู้จำนวนวันในแต่ละเดือน ชั้นสามารถสร้างชื่อเฉพาะของเดือน

คุณสามารถรับชื่อที่แปลเป็นภาษาท้องถิ่นของเดือนความยาวหรือตัวย่อต่างๆ

String output = 
    Month.FEBRUARY.getDisplayName( 
        TextStyle.FULL , 
        Locale.CANADA_FRENCH 
    );

กุมภาพันธ์

นอกจากนี้คุณควรผ่านวัตถุของ enum นี้รอบ ๆ ฐานรหัสของคุณแทนที่จะเป็นตัวเลขจำนวนเต็มเท่านั้น การทำเช่นนี้ให้ความปลอดภัยประเภทมั่นใจช่วงที่ถูกต้องของค่าและทำให้รหัสของคุณเอกสารด้วยตนเอง ดูบทช่วยสอนของ Oracleหากไม่คุ้นเคยกับสิ่งอำนวยความสะดวกด้าน enum ที่ทรงพลังในจาวา

คุณอาจพบว่ามีประโยชน์YearและYearMonthคลาส


เกี่ยวกับ java.time

java.timeกรอบถูกสร้างขึ้นใน Java 8 และต่อมา ชั้นเรียนเหล่านี้แย่งลำบากเก่ามรดกเรียนวันที่เวลาเช่นjava.util.Date, และ.Calendarjava.text.SimpleDateFormat

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

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

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

  • Java SE 8และ SE 9และใหม่กว่า
    • Built-in
    • เป็นส่วนหนึ่งของ Java API มาตรฐานที่มีการใช้งานแบบรวม
    • Java 9 เพิ่มคุณสมบัติและการแก้ไขเล็กน้อย
  • Java SE 6และ SE 7
    • มากของการทำงาน java.time จะกลับรังเพลิง Java 6 และ 7 ในThreeTen-ย้ายกลับ
  • Android
    • ThreeTenABPโครงการปรับThreeTen-ย้ายกลับ (ดังกล่าวข้างต้น) สำหรับ Android โดยเฉพาะ
    • ดูวิธีใช้… .

โครงการThreeTen-Extraขยาย java.time ด้วยคลาสเพิ่มเติม โครงการนี้เป็นพื้นฐานที่พิสูจน์ได้สำหรับการเพิ่มเติมในอนาคตไปยัง java.time คุณอาจพบว่าการเรียนที่มีประโยชน์บางอย่างที่นี่เช่นInterval, YearWeek, YearQuarterและอื่น ๆ อีกมากมาย


0

มันไม่ได้กำหนดว่าเป็นศูนย์ต่อ se มันถูกกำหนดให้เป็นปฏิทินมกราคม มันเป็นปัญหาของการใช้ ints เป็นค่าคงที่แทนที่จะเป็น enums ปฏิทิน. มกราคม == 0


1
ค่าเป็นหนึ่งและเหมือนกัน API อาจส่งคืน 0 ซึ่งเป็นค่าคงที่ ปฏิทิน. มกราคมอาจถูกกำหนดเป็น 1 - นั่นคือทั้งหมด Enum จะเป็นทางออกที่ดี แต่ไม่ได้เพิ่ม enums จริงในภาษาจนกว่า Java 5 และ Date จะเริ่มต้นตั้งแต่เริ่มต้น เป็นเรื่องที่โชคร้าย แต่คุณไม่สามารถ "แก้ไข" เช่น API พื้นฐานเมื่อรหัสของบุคคลที่สามใช้งานได้ สิ่งที่ดีที่สุดที่สามารถทำได้คือการให้ API ใหม่และคัดค้าน API เก่าเพื่อสนับสนุนให้คนเดินหน้าต่อไป ขอบคุณ Java 7 ...
Quinn Taylor

0

เพราะการเขียนภาษานั้นยากกว่าที่คิดและการจัดการเวลาโดยเฉพาะนั้นยากกว่าที่คนทั่วไปคิด สำหรับส่วนเล็ก ๆ ของปัญหา (ในความเป็นจริงไม่ Java) ดูวิดีโอ YouTube "ปัญหาที่มีเวลาและเขต - Computerphile" ที่https://www.youtube.com/watch?v=-5wpm-gesOY อย่าแปลกใจถ้าหัวของคุณหล่นจากการหัวเราะด้วยความสับสน


-1

นอกจากนี้ในการตอบ DannySmurf Calendar.JANUARYของความเกียจคร้านฉันจะเพิ่มว่ามันเป็นขอแนะนำให้คุณใช้ค่าคงที่เช่น


5
ทั้งหมดนี้เป็นเรื่องที่ดีมากเมื่อคุณเขียนรหัสอย่างชัดเจนสำหรับเดือนใดเดือนหนึ่ง แต่มันเป็นความเจ็บปวดเมื่อคุณได้รับเดือนในรูปแบบ "ปกติ" จากแหล่งอื่น
Jon Skeet

1
นอกจากนี้ยังเป็นความเจ็บปวดเมื่อคุณพยายามพิมพ์ค่าเดือนนั้นด้วยวิธีเฉพาะ - คุณเพิ่ม 1 ลงไปเสมอ
Brian Warshaw

-2

เพราะทุกอย่างเริ่มต้นด้วย 0 นี่คือข้อเท็จจริงพื้นฐานของการเขียนโปรแกรมใน Java หากมีสิ่งใดที่เบี่ยงเบนไปจากสิ่งนั้นสิ่งนั้นก็จะนำไปสู่ความสับสนอย่างสิ้นเชิง อย่าเถียงการก่อตัวของพวกเขาและรหัสกับพวกเขา


2
ไม่สิ่งต่าง ๆ ในโลกแห่งความเป็นจริงเริ่มต้นด้วย 1 ออฟเซ็ตเริ่มต้นด้วย 0 และเดือนของปีไม่ได้ชดเชยมันเป็นหนึ่งในสิบสองเหมือนวันที่ของเดือนเป็นหนึ่งใน 31 หรือ 30 หรือ 29 หรือ 28. การปฏิบัติต่อเดือนในฐานะผู้ชดเชยนั้นเป็นเพียงการ จำกัด โดยเฉพาะอย่างยิ่งหากในเวลาเดียวกันเราจะไม่ปฏิบัติต่อวันดังกล่าวในลักษณะเดียวกัน อะไรคือเหตุผลของความแตกต่างนี้
SantiBailors

ในโลกแห่งความเป็นจริงเริ่มต้นด้วย 1 ในโลก Java เริ่มต้นด้วย 0 แต่ ... ฉันคิดว่าเป็นเพราะ: - ในการคำนวณวันของสัปดาห์มันไม่สามารถชดเชยการคำนวณที่เป็นคู่ได้โดยไม่ต้องเพิ่มอีกสองสามก้าวในการ มัน ... - นอกจากนี้ยังแสดงวันที่สมบูรณ์ในเดือนถ้าจำเป็น (โดยไม่สับสนหรือจำเป็นต้องตรวจสอบ ก.พ. ) - สำหรับเดือนนั้นบังคับให้คุณแสดงผลในรูปแบบวันที่ซึ่งควรใช้ทั้งสองวิธี นอกจากนี้เนื่องจากจำนวนเดือนในหนึ่งปีเป็นปกติและวันในหนึ่งเดือนนั้นไม่เหมาะสมถ้าคุณต้องการประกาศอาร์เรย์และใช้ออฟเซ็ตเพื่อให้เหมาะสมกับอาร์เรย์มากขึ้น
Syrrus
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.