นับตั้งแต่การเปิดตัว Java 8 ในปี 2014 Java.util.date โบราณของเราในที่สุดก็ไม่ได้เป็นทางเลือกเดียวสำหรับวันที่ดำเนินการและเวลาใน Java
ในความเป็นจริง APIs ที่เกี่ยวข้องของวันที่และเวลาใน Java ได้รับการวิพากษ์วิจารณ์จากโลกเสมอ ไม่เพียง แต่ไม่เพียงเพราะแผนกการออกแบบนั้นไม่ชัดเจน แต่มักจะสามารถจัดการทั้งวันและเวลาซึ่งทำให้สับสนมาก นอกจากนี้ยังมีการแมปตัวเลขในบางปีเดือนและวันที่ถูกเก็บไว้กับมนุษย์เช่น: 0 สอดคล้องกับเดือนมกราคม 11 สอดคล้องกับเดือนธันวาคม, 118 สอดคล้องกับปี 2018 (1900 + 118) ฯลฯ
บ่อยครั้งเมื่อเราได้รับมูลค่าปีและเดือนเราจำเป็นต้องดำเนินการที่สอดคล้องกันเพื่อให้ได้ข้อมูลปีเดือนและวันที่ที่ถูกต้อง จนกระทั่ง Java 8 ของเราเรายืมการออกแบบที่ยอดเยี่ยมของห้องสมุดโอเพ่นซอร์สของบุคคลที่สาม Joda-time และออกแบบวันที่และเวลา API เมื่อเทียบกับอันที่ก่อนหน้านี้อาจกล่าวได้ว่าใช้งานง่ายกว่าร้อยเท่า อินเทอร์เฟซ API ที่เกี่ยวข้องทั้งหมดอยู่ในแพ็คเกจ java.time
อินเทอร์เฟซวันที่และเวลาโบราณ
วันที่แทนข้อมูลเวลา
คอมพิวเตอร์ทุกเครื่องในโลกใช้จำนวนเต็มยาวประเภทและค่าของจำนวนเต็มนี้คือจำนวนมิลลิวินาทีที่สัมพันธ์กับ GMT ในสหราชอาณาจักร (0: 0: 00, 1 มกราคม 1970) ตัวอย่างเช่น:
โมฆะคงที่สาธารณะหลัก (สตริง [] args) {// 1 มกราคม 1970 00:00:00 GMT วันที่วันที่ = วันที่ใหม่ (1,000); System.out.println (วันที่);}ผลลัพธ์ผลลัพธ์:
// 1970-1-1 8: 00: 01thu ม.ค. 01 08:00:01 CST 1970
หลายคนอาจสงสัยว่า 1,000 หมายถึง 1 วินาทีก่อนเวลามาตรฐานดังนั้นทำไมเวลาผ่านไปแปดชั่วโมง?
สิ่งนี้มีส่วนเกี่ยวข้องกับ "เขตเวลา" หากคุณอยู่ในกรีนนิชผลลัพธ์จะเป็นไปตามที่คาดไว้ แต่เราตั้งอยู่ในเขตแปดตะวันออกของจีนและเวลาคือแปดชั่วโมงก่อนหน้านี้ดังนั้นค่าพื้นฐานที่อยู่บนโซนเวลาที่แตกต่างกันจึงแตกต่างกัน
คลาสวันที่เคยมีบทบาทหลายอย่างมาก่อน จะเห็นได้จากซอร์สโค้ดว่ามีวิธีการที่สามารถใช้งานเวลาวิธีการที่สามารถใช้งานปีเดือนและวันและแม้แต่จัดการโซนเวลา อาจกล่าวได้ว่ามันเพียงพอที่จะมีในวันที่และเวลาที่เกี่ยวข้องกับการดำเนินงานเพียงอย่างเดียว
แต่นี่คือโลก หากคุณสนใจมากเกินไปคุณจะไม่สามารถครอบคลุมทุกอย่างได้โดยธรรมชาติ การออกแบบวิธีการหลายวิธีในปัจจุบันไม่สมเหตุสมผลมากนัก เราเคยพูดมาก่อนและมันก็เป็นต่อต้านมนุษย์เล็กน้อย ดังนั้นเกือบ 80% ของวิธีการในคลาสวันที่ปัจจุบันจึงถูกยกเลิกและถูกทำเครื่องหมาย @deprecated
การวางตำแหน่งปัจจุบันของ บริษัท ซันสำหรับวันที่คือการเป็นตัวแทนเพียงช่วงเวลาเดียวดังนั้นตำแหน่งภายในควรหมุนรอบมิลลิวินาทีของจำนวนเต็มนั้นและไม่มุ่งเน้นไปที่เขตเวลาปฏิทินประจำปีและข้อมูลอื่น ๆ อีกต่อไป
วันที่อนุญาตให้วัตถุได้รับการสร้างอินสแตนซ์ผ่านตัวสร้างสองตัว:
Private Transient Long Fasttime; วันที่สาธารณะ () {this (system.currentTimeMillis ());} วันที่สาธารณะ (วันที่ยาว) {fasttime = วันที่;}แอตทริบิวต์ FastTime ที่นี่เก็บจำนวนมิลลิวินาทีที่สอดคล้องกับเวลา ตัวสร้างทั้งสองยังคงง่ายมาก หากมีการเรียกตัวสร้างพารามิเตอร์เครื่องเสมือนจริงจะกำหนด FastTime กับค่าเวลาปัจจุบันของระบบ
มีวิธีอื่นอีกสองสามอย่างที่ยังไม่ได้ทิ้ง:
มีอีกสองวิธีที่เพิ่มใหม่ใน JDK1.8 หลังจากนั้นและใช้เพื่อแปลงอินเทอร์เฟซใหม่เป็น Java 8 ซึ่งจะมีการแนะนำในภายหลัง
ปฏิทินอธิบาย Almanac
ปฏิทินใช้เพื่อแสดงข้อมูลวันที่เช่นปีเดือนวัน ฯลฯ มันเป็นคลาสนามธรรมดังนั้นวัตถุอินสแตนซ์ของมันจะได้รับโดยทั่วไปผ่านวิธีการโรงงานสี่วิธีต่อไปนี้
ปฏิทินสาธารณะคงที่ GetInstance () ปฏิทินคงที่สาธารณะ Getinstance (เขตเขตเวลา) ปฏิทินคงที่สาธารณะ Getinstance (สถานที่ตั้ง Alocale) ปฏิทินคงที่สาธารณะ Getinstance (เขตเวลาเขต, Locale Alocale)
ในความเป็นจริงวิธีการภายในเดียวกันจะถูกเรียกในที่สุด:
CreateCalendar ปฏิทินส่วนตัว (เขตเขตเวลา, locale alocale)
วิธีนี้ต้องใช้พารามิเตอร์สองพารามิเตอร์หนึ่งคือโซนเวลาและอีกวิธีหนึ่งคือประเทศและภาษา กล่าวคือการสร้างอินสแตนซ์ปฏิทินต้องใช้ข้อมูลพารามิเตอร์ทั้งสองอย่างน้อยไม่เช่นนั้นจะใช้โซนเวลาเริ่มต้นหรือข้อมูลภาษาเริ่มต้นของระบบ
เนื่องจากโซนเวลาที่แตกต่างกันและภาษาประจำชาติส่งออกแตกต่างกันสำหรับข้อมูลเวลาและปีเดือนและวันนี่เป็นเหตุผลว่าทำไมอินสแตนซ์ปฏิทินจะต้องผ่านข้อมูลเขตเวลาและประเทศ ดูตัวอย่าง:
โมฆะคงที่สาธารณะหลัก (สตริง [] args) {ปฏิทินปฏิทิน = ปฏิทิน. getInstance (); System.out.println (Calendar.getTime ()); ปฏิทินปฏิทิน 1 = Calendar.getInstance (Timezone.getTimeZone ("GMT"), locale.english); System.out.println (Calendar1.get (Calendar.year) + ":" + Calendar1.get (calendar.hour) + ":" + ปฏิทิน 12.get (calendar.minute)); -ผลลัพธ์ผลลัพธ์:
วันเสาร์ที่ 21 10:32:20 CST 20182018: 2: 32
อย่างที่คุณเห็นเอาท์พุทแรกคือเวลาปัจจุบันของเขตเวลาเริ่มต้นของระบบและประเทศและอินสแตนซ์ปฏิทินที่สองที่เราระบุว่ามันตั้งอยู่ในเขตเวลากรีนนิช (เขตเวลา 0) และผลลัพธ์ก็ชัดเจนด้วยความแตกต่างแปดชั่วโมงเพราะเราอยู่ใน East Eighth แปดชั่วโมง
บางคนอาจสงสัยว่าทำไมเอาท์พุทของอินสแตนซ์ปฏิทินที่สองจึงซับซ้อนมากในการประกบกันแทนที่จะเรียกวิธี getTime ที่กระชับโดยตรงเช่นอินสแตนซ์ปฏิทินแรก?
สิ่งนี้เกี่ยวข้องกับการดำเนินการภายในของปฏิทินลองมาดูกัน:
ได้รับการป้องกันเป็นเวลานานวันสุดท้ายของสาธารณะ getTime () {ส่งคืนวันที่ใหม่ (getTimeInmillis ());}เช่นวันที่ปฏิทินเก็บข้อมูลเวลาไว้ภายในและวิธีการรับเวลาจริงสร้างวัตถุวันที่ตามเวลานี้และส่งคืน
โดยทั่วไปเมื่อเราสร้างอินสแตนซ์ปฏิทินเราจะไม่ผ่านข้อมูลเวลาดังนั้นเมื่ออินสแตนซ์เริ่มต้นโปรแกรมจะคำนวณหมายเลขมิลลิวินาทีตามเขตเวลาเริ่มต้นของระบบและเวลาปัจจุบันและกำหนดให้เป็นเวลา
ดังนั้นภายในอินสแตนซ์ปฏิทินทั้งหมดที่มีค่าแอตทริบิวต์เวลาไม่ได้รับการแก้ไขด้วยตนเองค่าเวลาคือค่าเวลาของเขตเวลาเริ่มต้นในเวลานั้น กล่าวอีกนัยหนึ่งผลลัพธ์ผลลัพธ์ของ GetTime จะละเว้นข้อมูลโซนเวลาที่สอดคล้องกับอินสแตนซ์ปัจจุบัน นี่เป็นข้อบกพร่องในการออกแบบปฏิทินเพราะสิ่งนี้จะทำให้ค่าเอาท์พุท getTime ของอินสแตนซ์ปฏิทินทั้งสองขึ้นอยู่กับเวลาทำงานของระบบเมื่ออินสแตนซ์เริ่มต้น
ปฏิทินยังกำหนดค่าคงที่จำนวนมากและอาร์เรย์แอตทริบิวต์:
Public Final Static Int ERA = 0; INT สุดท้ายของสาธารณะสุดท้าย = 1; เดือนสุดท้ายของสาธารณะคงที่เดือน = 2; สาธารณะสุดท้ายคงที่ int Week_of_year = 3; สาธารณะสุดท้ายคงที่ int int Week_of_month = 4; วันที่ int สุดท้ายของสาธารณะ = 5;
ข้อมูลที่เกี่ยวข้องทั้งหมดเกี่ยวกับวันที่จะถูกเก็บไว้ในอาร์เรย์แอตทริบิวต์และค่าของค่าคงที่คงที่เหล่านี้มักจะเป็นตัวแทนของค่าดัชนี ด้วยวิธี GET เราผ่านดัชนีแอตทริบิวต์และส่งคืนค่าของแอตทริบิวต์ ตัวอย่างเช่น:
ปฏิทิน myCalendar = calendar.getInstance (); int year = mycalendar.get (calendar.year);
วิธีการรับที่นี่จริง ๆ แล้วจะใช้ฟิลด์โดยตรง [1] เป็นค่าส่งคืน อาร์เรย์แอตทริบิวต์ฟิลด์คำนวณและกำหนดโดยระบบตามเขตเวลาและภาษาเมื่ออินสแตนซ์ปฏิทินเริ่มต้น โปรดทราบว่ามันจะถูกคำนวณตามเขตเวลาที่คุณระบุซึ่งแตกต่างจากเวลาซึ่งจะขึ้นอยู่กับเขตเวลาเริ่มต้นของระบบเสมอ
โดยส่วนตัวแล้วฉันคิดว่าการออกแบบของปฏิทินมีแง่มุมที่สง่างามและไม่มีเหตุผล ท้ายที่สุดมันเป็น "โบราณ" และในที่สุดจะถูกแทนที่
การแปลงรูปแบบ dateFormat
อย่างที่เราเห็นได้จากหนึ่งในตัวอย่างก่อนหน้าของเรามันเป็นปัญหามากในการส่งออกข้อมูลวันที่ส่งออกในรูปแบบที่คาดหวังสำหรับปฏิทินและจำเป็นต้องมีการประกบด้วยตนเอง DateFormat ของเราใช้เพื่อจัดการการแปลงระหว่างสตริงที่จัดรูปแบบและสายข้อมูล
เช่นเดียวกับปฏิทิน DateFormat ยังเป็นคลาสนามธรรม เราจำเป็นต้องสร้างวัตถุอินสแตนซ์ผ่านวิธีการโรงงาน ส่วนใหญ่มีวิธีการโรงงานต่อไปนี้:
// เฉพาะกระบวนการแปลงเวลาสาธารณะสุดท้ายคงที่วันที่คงที่ getTimeInstance () // เฉพาะวันที่กระบวนการแปลงสาธารณะสุดท้ายคงที่วันที่คงที่ getDateInstance () // คุณสามารถจัดการทั้งเวลาและวันที่สาธารณะสุดท้ายวันที่คงที่ getDateTimeInstance ()
แน่นอนว่าพวกเขาแต่ละคนมีวิธีการเกินพิกัดของตัวเองและเราจะเห็นรายละเอียดในภายหลัง
มีสองประเภทของวิธีการสำหรับวันที่รูปแบบและการแยกวิเคราะห์
รูปแบบสตริงสุดท้ายสาธารณะ (วันที่) วันที่สาธารณะแยกวิเคราะห์ (แหล่งที่มาของสตริง)
วิธีการฟอร์แมตใช้ในการจัดรูปแบบวัตถุวันที่เป็นสตริงและวิธีการแยกวิเคราะห์ใช้เพื่อแทนที่สตริงที่จัดรูปแบบด้วยวัตถุวันที่ ตัวอย่างเช่น:
โมฆะคงที่สาธารณะหลัก (สตริง [] args) {ปฏิทินปฏิทิน = ปฏิทิน. getInstance (); DateFormat DateFormat = DateFormat.getDateTimeInstance (); System.out.println (dateformat.format (calendar.getTime ()));}ผลลัพธ์ผลลัพธ์:
2018-4-21 16:58:09
เห็นได้ชัดว่าอินสแตนซ์ DateFormat ที่สร้างจากโรงงานไม่สามารถปรับแต่งเนื้อหาการจัดรูปแบบเอาต์พุตได้นั่นคือรูปแบบสตริงเอาต์พุตได้รับการแก้ไขและไม่สามารถตอบสนองความต้องการพิเศษในบางกรณี โดยทั่วไปเราจะใช้หนึ่งในคลาสการใช้งาน SimpledateFormat โดยตรง
SimpledateFormat ช่วยให้คุณผ่านพารามิเตอร์รูปแบบเมื่อสร้างอินสแตนซ์เพื่อปรับแต่งรูปแบบเอาต์พุตของอักขระวันที่ ตัวอย่างเช่น:
โมฆะคงที่สาธารณะหลัก (สตริง [] args) {วันที่ dateformat = new SimpledateFormat ("Yyyyy Year mm เดือน DD Day"); System.out.println (dateformat.format (วันที่ใหม่ ()));}ผลลัพธ์ผลลัพธ์:
21 เมษายน 2018
ใน,
แน่นอนว่ามันสะดวกมากในการแปลงวันที่สตริง โหมดที่กำหนดเองได้รับอนุญาต แต่คุณต้องปฏิบัติตามรูปแบบที่คุณกำหนดด้วยตัวเองมิฉะนั้นโปรแกรมจะไม่สามารถแยกวิเคราะห์ได้สำเร็จ ตัวอย่างเช่น:
โมฆะคงที่สาธารณะหลัก (สตริง [] args) {string str = "วันเสาร์ที่ 21 เมษายน 2018"; dateformat sdateformat = new SimpledateFormat ("Yyyy Year M เดือน Dd Day Hh Point MM Point E"); sdateformat.parse (str); System.out.println (sdateformat.getCalendar (). getTime ());}ผลลัพธ์ผลลัพธ์:
Sat 21 เม.ย. 17:17:00 CST 2018
เห็นได้ชัดว่าโปรแกรมนั้นแยกวิเคราะห์สตริงของเราอย่างถูกต้องและแปลงเป็นวัตถุปฏิทินที่เก็บไว้ใน DateFormat
โดยทั่วไปวันที่ปฏิทินและวันที่สามารถจัดการปัญหาเวลาและวันที่ทั่วไปได้ แต่อย่างหลีกเลี่ยงไม่ได้พวกเขายังคงยุ่งยากและใช้งานยาก
เนื่องจากข้อ จำกัด ด้านพื้นที่เราจะเปรียบเทียบวันที่และเวลาใหม่ของ Java 8 ในบทความถัดไปและคุณจะพบว่ามันมีการออกแบบที่สง่างามและการทำงานที่เรียบง่ายมากขึ้น