CodeGym /จาวาบล็อก /สุ่ม /วิธีที่จะไม่หลงทาง: วันที่และเวลาและปฏิทิน
John Squirrels
ระดับ
San Francisco

วิธีที่จะไม่หลงทาง: วันที่และเวลาและปฏิทิน

เผยแพร่ในกลุ่ม
สวัสดี! วันนี้เราจะเริ่มทำงานกับประเภทข้อมูลใหม่ที่เรายังไม่เคยพบมาก่อน ซึ่งก็คือวันที่ วิธีที่จะไม่หลงทางในเวลา: วันที่และเวลาและปฏิทิน - 1ฉันไม่คิดว่าฉันต้องอธิบายว่าวันที่คืออะไร :) โดยหลักการแล้ว เราสามารถเก็บวันที่และเวลาปัจจุบันไว้ใน Java String ธรรมดาได้

public class Main {
   public static void main(String[] args) {

       String date = "June 11, 2018";
       System.out.println(date);
   }
}
แต่แนวทางนี้มีข้อเสียมากมาย ชั้นStringเรียนได้รับการออกแบบให้ทำงานกับข้อความ และวิธีการของชั้นเรียนนั้นเหมาะสมสำหรับงานนี้ หากเราจำเป็นต้องปรับเปลี่ยนวันที่ในทางใดทางหนึ่ง (เช่น เพิ่ม 2 ชั่วโมง) Stringก็ไม่ได้ผลดีนัก หรือถ้าเราต้องการแสดงวันที่และเวลาปัจจุบันเมื่อโปรแกรมคอมไพล์ Stringไม่ได้ช่วยที่นี่เช่นกัน: ตามเวลาที่คุณเขียนโค้ดและเรียกใช้ เวลาจะเปลี่ยนไปและคอนโซลจะแสดงข้อมูลที่ไม่ถูกต้อง นั่นเป็นเหตุผลที่ผู้สร้างของ Java จัดเตรียมหลายคลาสสำหรับการทำงานกับวันที่และเวลา ประการแรกคือjava.util.Date

คลาสวันที่

เราระบุชื่อเต็มเนื่องจากแพ็คเกจ Java อื่นมีjava.sql.Dateคลาส อย่าผสมพวกเขา! สิ่งแรกที่คุณต้องรู้เกี่ยวกับมันก็คือ มันเก็บวันที่เป็นจำนวนมิลลิวินาทีที่ผ่านไปตั้งแต่วันที่ 1 มกราคม 1970 ระบบเวลานี้มีชื่อของตัวเองว่า " Unix-time " แนวทางที่น่าสนใจทีเดียว คุณเห็นด้วยไหม :) สิ่งที่สองที่ควรจดจำคือ: หากคุณสร้างวัตถุDateโดยใช้ตัวสร้างเริ่มต้น ผลลัพธ์จะแสดง วันที่และเวลาปัจจุบัน ณ เวลา ที่วัตถุถูกสร้างขึ้น จำได้ไหมว่าเราบอกว่าวันที่เป็นตัวแทนStringจะต้องต่อสู้กับงานดังกล่าว? ชั้นDateจัดการกับมันได้อย่างง่ายดาย

public class Main {
   public static void main(String[] args) {

       Date date = new Date();
       System.out.println(date);
   }
}
เรียกใช้รหัสนี้หลายๆ ครั้ง แล้วคุณจะเห็นการเปลี่ยนแปลงเวลาซ้ำๆ :) สิ่งนี้เกิดขึ้นได้เนื่องจากเวลาถูกจัดเก็บเป็นมิลลิวินาที ซึ่งเป็นหน่วยเวลาที่เล็กมาก ดังนั้นผลลัพธ์จึงมีความแม่นยำสูง ตัวสร้าง คลาสDateอื่น: คุณสามารถส่งจำนวนมิลลิวินาทีที่แน่นอนตั้งแต่ 00:00 น. ของวันที่ 1 มกราคม 1970 ไปยังวันที่ที่ต้องการ และวัตถุวันที่ที่สอดคล้องกันจะถูกสร้างขึ้น:

public class Main {
   public static void main(String[] args) {

       Date date = new Date(1212121212121L);
       System.out.println(date);
   }
}
เอาต์พุตของคอนโซล: วันศุกร์ที่ 30 พฤษภาคม 04:20:12 GMT 2008 เราได้วันที่ 30 พฤษภาคม 2008 "วันศุกร์" หมายถึงวันในสัปดาห์ (วันศุกร์ duh) และ GMT เป็นโซนเวลา (เวลามาตรฐานกรีนิช) มิลลิวินาทีจะถูกส่งผ่านเป็นlongs เนื่องจากจำนวนมิลลิวินาทีมักไม่พอดีintกับ ดังนั้น การดำเนินการใดที่มีวันที่ที่เราอาจต้องดำเนินการ แน่นอนว่าสิ่งที่ชัดเจนที่สุดคือการเปรียบเทียบ เพื่อกำหนดว่าวันที่หนึ่งมาก่อนหรือหลังอีกวัน สามารถทำได้หลายวิธี ตัวอย่างเช่น คุณสามารถเรียกใช้Date.getTime()เมธอดซึ่งส่งคืนจำนวนมิลลิวินาทีที่ผ่านไปตั้งแต่เที่ยงคืนของวันที่ 1 มกราคม 1970 เพียงเรียกเมธอดบนออบเจกต์ Date สองตัวแล้วเปรียบเทียบผลลัพธ์:

public class Main {
   public static void main(String[] args) {

       Date date1 = new Date();

       Date date2 = new Date();

       System.out.println((date1.getTime() > date2.getTime())?
               "date1 is later than date2" : "date1 is earlier than date2");
   }
}
ผลลัพธ์: date1 เร็วกว่า date2 แต่ก็ยังมีวิธีที่สะดวกกว่า เช่น โดยใช้วิธีพิเศษที่มีให้โดยคลาส Date : before(), after()และ equals()ทั้งหมดส่งคืนค่าบูลีน เมธอดbefore()ตรวจสอบว่าวันที่ของเราอยู่ก่อนวันที่ผ่านเป็นอาร์กิวเมนต์หรือไม่:

public class Main {
   public static void main(String[] args) throws InterruptedException {

       Date date1 = new Date();

       Thread.sleep(2000);// Suspend the program for 2 seconds
       Date date2 = new Date();

       System.out.println(date1.before(date2));
   }
}
เอาต์พุตคอนโซล: จริง ในทำนองเดียวกันafter()วิธีการตรวจสอบเพื่อดูว่าวันที่ของเราอยู่หลังวันที่ที่ส่งผ่านเป็นอาร์กิวเมนต์หรือไม่:

public class Main {
   public static void main(String[] args) throws InterruptedException {

       Date date1 = new Date();

       Thread.sleep(2000);// Suspend the program for 2 seconds
       Date date2 = new Date();

       System.out.println(date1.after(date2));
   }
}
เอาต์พุตของคอนโซล: เท็จ ในตัวอย่างของเรา เรา "ทำให้โปรแกรมเข้าสู่โหมดสลีป" เป็นเวลา 2 วินาที เพื่อรับประกันวันที่ทั้งสองจะแตกต่างกัน บนคอมพิวเตอร์ที่เร็ว เวลาระหว่างการสร้างdate1และdate2อาจน้อยกว่าหนึ่งมิลลิวินาที ทำให้ทั้งbefore()และafter()ส่งคืนค่าเท็จ แต่ในกรณีนี้equals()เมธอดจะคืนค่าจริง! หลังจากนั้นจะเปรียบเทียบจำนวนมิลลิวินาทีตั้งแต่ 00:00 น. ของวันที่ 1 มกราคม 1970 ในแต่ละวัน วัตถุจะถือว่าเท่ากันก็ต่อเมื่อตรงกับมิลลิวินาที :

public static void main(String[] args) {

   Date date1 = new Date();
   Date date2 = new Date();

   System.out.println(date1.getTime());
   System.out.println(date2.getTime());

   System.out.println(date1.equals(date2));
}
นี่เป็นอีกสิ่งที่คุณต้องใส่ใจ หากคุณเปิดเอกสารประกอบสำหรับDateคลาสบน เว็บไซต์ Oracleคุณจะเห็นว่าเมธอดและคอนสตรัคเตอร์หลายตัวถูกทำเครื่องหมายว่าเลิกใช้แล้ว (เช่น ไม่แนะนำให้ใช้) นี่คือสิ่งที่ผู้สร้างของ Java พูดเกี่ยวกับส่วนของคลาสที่เลิกใช้แล้ว:
"องค์ประกอบของโปรแกรมที่มีคำอธิบายประกอบ @Deprecated เป็นสิ่งที่โปรแกรมเมอร์ไม่แนะนำให้ใช้ มักจะเป็นเพราะมันอันตราย หรือเพราะมีทางเลือกอื่นที่ดีกว่า"
ไม่ได้หมายความว่าจะใช้วิธีเหล่านี้ไม่ได้เลย หากคุณพยายามรันโค้ดโดยใช้เมธอดที่เลิกใช้แล้วใน IDE โค้ดนั้นมักจะใช้งานได้ ตัวอย่างเช่น พิจารณาเมธอดที่เลิกใช้แล้วDate.getHours()ซึ่งจะส่งคืนจำนวนชั่วโมงที่เกี่ยวข้องกับDateอ็อบเจกต์

public static void main(String[] args) {

   Date date1 = new Date();

   System.out.println(date1.getHours());
}
หากคุณเริ่มโค้ดเวลา 14:21 น. (14:21 น.) รหัสจะแสดงหมายเลข 14 อย่างที่คุณเห็น วิธีการที่เลิกใช้แล้วจะถูกขีดฆ่า แต่ก็ยังใช้งานได้ เมธอดเหล่านี้ไม่ได้ถูกลบออกเพื่อไม่ให้โค้ดขนาดใหญ่ที่มีอยู่ที่ใช้เมธอดเสียหาย กล่าวอีกนัยหนึ่ง วิธีการเหล่านี้ไม่ได้ "เสีย" หรือ "ถูกลบ" ไม่แนะนำให้ใช้เพราะมีทางเลือกอื่นที่สะดวกกว่า อนึ่ง เอกสารกล่าวถึงทางเลือกนี้โดยเฉพาะ:
วิธีที่จะไม่หลงทางในเวลา: วันที่และเวลาและปฏิทิน - 2
เมธอดของคลาส ส่วนใหญ่Dateถูกย้ายไปยังCalendarคลาส ที่ปรับปรุงและขยายแล้ว ต่อไปเราจะมาทำความรู้จักกับคลาสนั้นกัน :)

คลาสปฏิทิน

JDK 1.1 แนะนำคลาสใหม่: Calendar. ทำให้การทำงานกับวันที่ใน Java ง่ายขึ้นกว่าเดิม การใช้งานคลาสเดียวCalendarที่เราจะทำงานด้วยคือGregorianCalendarคลาส มันใช้ปฏิทินเกรกอเรียนซึ่งประเทศส่วนใหญ่ทั่วโลกสังเกต ข้อได้เปรียบหลักคือสามารถทำงานกับวันที่ในรูปแบบที่สะดวกกว่า ตัวอย่างเช่น สามารถ:
  • เพิ่มเดือนหรือวันในวันที่ปัจจุบัน
  • ตรวจสอบว่าปีนั้นเป็นปีอธิกสุรทินหรือไม่
  • ส่งกลับส่วนประกอบของวันที่แต่ละรายการ (เช่น แยกหมายเลขเดือนออกจากวันที่ทั้งหมด)
  • นอกจากนี้ยังมีระบบค่าคงที่ที่สะดวกมาก (ซึ่งเราจะดูด้านล่าง)
การปรับปรุงที่สำคัญอีกอย่างของCalendarคลาสคือค่าคงที่ของปฏิทิน ERA : คุณสามารถระบุวันที่ก่อนยุคทั่วไป (ก่อนคริสต์ศักราช - ก่อนคริสต์ศักราช) หรือในยุคทั่วไป (AD - Anno Domini) ลองดูทั้งหมดนี้ด้วยตัวอย่าง มาสร้างcalendarวัตถุด้วยวันที่ 25 มกราคม 2017:

public static void main(String[] args) {

  Calendar calendar = new GregorianCalendar(2017, 0 , 25);
}
ในCalendarคลาส (เช่นเดียวกับDateคลาสสำหรับเรื่องนั้น) เดือนจะเริ่มต้นจากศูนย์ดังนั้นเราจึงส่งเลข 0 เป็นอาร์กิวเมนต์ที่สอง เมื่อทำงานกับCalendarชั้นเรียน สิ่งสำคัญคือต้องเข้าใจว่านี่เป็นเพียงปฏิทินไม่ใช่วันที่เดี่ยวๆ วิธีที่จะไม่หลงทางในเวลา: DateTime and Calendar - 3 วันที่เป็นเพียงตัวเลขไม่กี่ตัวที่ระบุช่วงเวลาหนึ่งๆ ปฏิทินคือระบบทั้งหมดที่ให้คุณทำสิ่งต่างๆ ได้มากมายด้วยวันที่ :) สิ่งนี้ชัดเจนมากหากคุณพยายามแสดงวัตถุCalendar: java.util.GregorianCalendar[เวลา=?,areFieldsSet=false,areAllFieldsSet=false,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Europe/London",offset=0,dstSavings=0,useDaylight= เท็จ,การเปลี่ยนผ่าน=79,lastRule=null],วันแรกของสัปดาห์=2,วันที่น้อยที่สุดในสัปดาห์แรก=1,ศก=?,ปี=2017,เดือน=0,WEEK_OF_YEAR=?,WEEK_OF_MONTH=?,DAY_OF_MONTH=25,DAY_OF_YEAR=?,DAY_OF_WEEK=? ,DAY_OF_WEEK_IN_MONTH=?,AM_PM=0,HOUR=0,HOUR_OF_DAY=0,MINUTE=0,SECOND=0,MILLISECOND=?,ZONE_OFFSET=?,DST_OFFSET=?] ดูข้อมูลที่คุณได้รับ ! ปฏิทินมีคุณสมบัติหลายอย่างที่วันที่ปกติไม่มี และคุณสมบัติทั้งหมดจะแสดง (นี่คือวิธีtoString()การทำงานของเมธอดในCalendarคลาส) หากคุณต้องการเพียงแค่ได้รับวันที่อย่างง่ายจากปฏิทิน เช่นDateวัตถุ ให้ใช้Calendar.getTime()วิธีการ (ชื่อไม่สมเหตุสมผลที่สุด แต่คุณจะทำอะไรได้บ้าง):

public static void main(String[] args) {

   Calendar calendar = new GregorianCalendar(2017, 0 , 25);
   Date date = calendar.getTime();
   System.out.println(date);
}
ผลลัพธ์: วันพุธที่ 25 มกราคม 00:00:00 น. GMT 2017 ตอนนี้เราได้ใช้ปฏิทินและ "ลดขนาด" เป็นวันที่ปกติ ไปต่อกันเถอะ นอกจากการกำหนดเดือนด้วยตัวเลขแล้ว คุณยังสามารถใช้ค่าฟิลด์ค่าคงที่Calendarของคลาสได้ ค่าคงที่เหล่านี้เป็นฟิลด์สแตติกของคลาสที่มีค่าที่ตั้งไว้ล่วงหน้าซึ่งไม่สามารถเปลี่ยนแปลงได้ นี่เป็นตัวเลือกที่ดีกว่าจริง ๆ เพราะการใช้สิ่งเหล่านี้ช่วยเพิ่มความสามารถในการอ่านรหัสของคุณ Calendar

public static void main(String[] args) {
   GregorianCalendar calendar = new GregorianCalendar(2017, Calendar.JANUARY , 25);
}
Calendar.JANUARYเป็นหนึ่งในค่าคงที่ที่แสดงถึงเดือนต่างๆ ของปี เมื่อใช้ค่าคงที่ที่มีชื่อเหล่านี้จะไม่มีใครลืม เช่น เลข 3 หมายถึงเดือนเมษายน ไม่ใช่เดือนที่ 3 ซึ่งเราชอบเรียกว่ามีนาคม แค่เขียน Calendar.APRILเท่านี้ก็เสร็จแล้ว :) สามารถระบุฟิลด์ปฏิทินทั้งหมด (ตัวเลข, เดือน, นาที, วินาที, ฯลฯ.) แยกกันได้โดยใช้set()เมธอด วิธีนี้สะดวกมาก เนื่องจากCalendarคลาสมีค่าคงที่สำหรับแต่ละฟิลด์ และโค้ดที่เป็นผลลัพธ์นั้นอ่านง่ายมาก ในตัวอย่างที่แล้ว เราสร้างวันที่ แต่ไม่ได้ตั้งเวลาไว้ ตั้งเวลา 19:42:12 กันเถอะ

public static void main(String[] args) {
   Calendar calendar = new GregorianCalendar();
   calendar.set(Calendar.YEAR, 2017);
   calendar.set(Calendar.MONTH, 0);
   calendar.set(Calendar.DAY_OF_MONTH, 25);
   calendar.set(Calendar.HOUR_OF_DAY, 19);
   calendar.set(Calendar.MINUTE, 42);
   calendar.set(Calendar.SECOND, 12);

   System.out.println(calendar.getTime());
}
ผลลัพธ์: วันพุธที่ 25 มกราคม 19:42:12 GMT 2017 เราเรียกset()เมธอด โดยส่งผ่านค่าคงที่ (ขึ้นอยู่กับฟิลด์ที่เราต้องการเปลี่ยน) และค่าใหม่สำหรับฟิลด์ ปรากฎว่าset()วิธีนี้เป็น "ตัวตั้งค่าขั้นสูง" ที่รู้วิธีตั้งค่าไม่เพียงสำหรับฟิลด์เดียว แต่สำหรับหลาย ๆ ฟิลด์ :) Calendarคลาสใช้add()วิธีการบวกและลบค่า คุณผ่านฟิลด์ที่คุณต้องการเปลี่ยนและตัวเลข (จำนวนที่คุณต้องการเพิ่ม/ลบออกจากค่าปัจจุบัน) ตัวอย่างเช่น มากำหนดวันที่ล่วงหน้า 2 เดือนก่อนวันที่ที่เราสร้างขึ้น:

public static void main(String[] args) {
   Calendar calendar = new GregorianCalendar(2017, Calendar.JANUARY , 25);
   calendar.set(Calendar.HOUR, 19);
   calendar.set(Calendar.MINUTE, 42);
   calendar.set(Calendar.SECOND, 12);

   calendar.add(Calendar.MONTH, -2); // To subtract, pass a negative number
   System.out.println(calendar.getTime());
}
เอาท์พุต: ศุกร์ 25 พฤศจิกายน 19:42:12 GMT 2016 ดีมาก! เราได้วันที่เมื่อ 2 เดือนที่แล้ว สิ่งนี้ไม่เพียงทำให้เดือนเปลี่ยนไปเท่านั้น แต่ปียังเปลี่ยนจากปี 2017 เป็น 2016 ด้วย แน่นอนว่าเมื่อแปลงวันที่ ปีปัจจุบันจะถูกคำนวณโดยอัตโนมัติโดยที่คุณไม่ต้องติดตามด้วยตนเอง แต่ถ้าคุณต้องการปิดการทำงานนี้ด้วยเหตุผลบางประการ คุณสามารถทำได้ วิธีการ นี้roll()สามารถเพิ่มและลบค่าได้โดยไม่กระทบกับค่าที่เหลือ ตัวอย่างเช่น:

public static void main(String[] args) {
   Calendar calendar = new GregorianCalendar(2017, Calendar.JANUARY , 25);
   calendar.set(Calendar.HOUR, 10);
   calendar.set(Calendar.MINUTE, 42);
   calendar.set(Calendar.SECOND, 12);

   calendar.roll(Calendar.MONTH, -2);
   System.out.println(calendar.getTime());
}
เราทำเช่นเดียวกันกับตัวอย่างที่แล้ว: เราใช้เวลา 2 เดือนนับจากวันที่ปัจจุบัน แต่ตอนนี้รหัสทำอย่างอื่น: เดือนเปลี่ยนจากมกราคมเป็นพฤศจิกายน แต่ปียังคงไม่เปลี่ยนแปลง - 2017! เอาท์พุต: Sat Nov 25 10:42:12 GMT 2017 เดินหน้าต่อไป ดังที่เราได้กล่าวไว้ข้างต้น เราสามารถแยกCalendarฟิลด์ทั้งหมดออกจากกันได้ เราทำเช่นนี้ด้วยget()วิธี:

public static void main(String[] args) {
   GregorianCalendar calendar = new GregorianCalendar(2017, Calendar.JANUARY , 25);
   calendar.set(Calendar.HOUR, 10);
   calendar.set(Calendar.MINUTE, 42);
   calendar.set(Calendar.SECOND, 12);

   System.out.println("Year: " + calendar.get(Calendar.YEAR));
   System.out.println("Month: " + calendar.get(Calendar.MONTH));
   System.out.println("Week in the month: " + calendar.get(Calendar.WEEK_OF_MONTH));// Week in this month?

   System.out.println("Day: " + calendar.get(Calendar.DAY_OF_MONTH));

   System.out.println("Hours: " + calendar.get(Calendar.HOUR));
   System.out.println("Minutes: " + calendar.get(Calendar.MINUTE));
   System.out.println("Seconds: " + calendar.get(Calendar.SECOND));
   System.out.println("Milliseconds: " + calendar.get(Calendar.MILLISECOND));

}
เอาท์พุต: ปี: 2017 เดือน: 0 สัปดาห์ในเดือน: 5 วัน: 25 ชั่วโมง: 10 นาที: 42 วินาที: 12 มิลลิวินาที: 0 ดังนั้น นอกจากคลาส "super-setter" แล้ว ยังมี " super Calendar-getter ". :) แน่นอน อีกแง่มุมที่น่าสนใจของคลาสนี้คือการทำงานกับยุคสมัยต่างๆ หากต้องการสร้างวันที่ "BC" คุณจะต้องใช้ ฟิลด์ Calendar.ERAตัวอย่างเช่น สร้างวันที่สำหรับ Battle of Cannae ที่ Hannibal เอาชนะกองทัพโรมัน สิ่งนี้เกิดขึ้นเมื่อวันที่ 2 สิงหาคม 216 ปีก่อนคริสตกาล:

public static void main(String[] args) {
   GregorianCalendar cannae = new GregorianCalendar(216, Calendar.AUGUST, 2);
   cannae.set(Calendar.ERA, GregorianCalendar.BC);

   DateFormat df = new SimpleDateFormat("MMM dd, yyy GG");
   System.out.println(df.format(cannae.getTime()));
}
ที่นี่เราใช้SimpleDateFormatชั้นเรียนเพื่อพิมพ์วันที่ในรูปแบบที่เราเข้าใจได้ง่ายขึ้น (ตัวอักษร "GG" ระบุว่าเราต้องการให้แสดงศักราช) ออก: 02 ส.ค. 216 ปีก่อนคริสตกาล คลาสCalendarมีเมธอดและค่าคงที่อีกมากมาย คุณสามารถอ่านเกี่ยวกับสิ่งเหล่านี้ได้ในเอกสารประกอบ . หากไม่ชอบรูปแบบวันที่นี้ Sat Nov 25 10:42:12 GMT 2017 คุณสามารถใช้SimpleDateFormatเพื่อทำให้เป็นอย่างที่คุณต้องการได้อย่างง่ายดาย

public static void main(String[] args) {

   SimpleDateFormat dateFormat = new SimpleDateFormat("EEEE, MMMM d, yyyy");
   Calendar calendar = new GregorianCalendar(2017, Calendar.JANUARY , 25);
   calendar.set(Calendar.HOUR, 10);
   calendar.set(Calendar.MINUTE, 42);
   calendar.set(Calendar.SECOND, 12);

   calendar.roll(Calendar.MONTH, -2);
   System.out.println(dateFormat.format(calendar.getTime()));
}
ผลลัพธ์: วันเสาร์ที่ 25 พฤศจิกายน 2017 ดีกว่ามากใช่ไหม :)
ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION