Panduan untuk Kalendar java.util.Gregorian

1. Pengenalan

Dalam tutorial ini, kita akan melihat sekilas kelas GregorianCalendar .

2. Kalendar Gregorian

GregorianCalendar adalah pelaksanaan konkrit dari kelas abstrak java.util.Calendar . Tidak hairanlah bahawa Kalendar Gregorian adalah kalendar sivil yang paling banyak digunakan di dunia.

2.1. Mendapat Instance

Terdapat dua pilihan yang tersedia untuk mendapatkan contoh GregorianCalendar: Calendar.getInstance () dan menggunakan salah satu pembina.

Menggunakan kaedah kilang statik Calendar.getInstance () bukanlah pendekatan yang disyorkan kerana akan mengembalikan contoh subjektif ke tempat lalai.

Ia mungkin mengembalikan Kalendar Buddha untuk Kalendar Thai atau Jepun untuk Jepun. Tidak mengetahui jenis contoh yang dikembalikan boleh menyebabkan ClassCastException :

@Test(expected = ClassCastException.class) public void test_Class_Cast_Exception() { TimeZone tz = TimeZone.getTimeZone("GMT+9:00"); Locale loc = new Locale("ja", "JP", "JP"); Calendar calendar = Calendar.getInstance(loc); GregorianCalendar gc = (GregorianCalendar) calendar; }

Dengan menggunakan salah satu daripada tujuh konstruktor yang terlalu banyak, kita dapat menginisialisasi objek Kalendar sama ada dengan tarikh dan waktu lalai bergantung pada lokasi sistem operasi kita atau kita dapat menentukan kombinasi tarikh, waktu, tempat dan zon waktu.

Mari kita fahami pelbagai pembina yang boleh dijadikan objek GregorianCalendar .

Pembina lalai akan memulakan kalendar dengan tarikh dan masa semasa di zon waktu dan tempat sistem operasi:

new GregorianCalendar();

Kita dapat menentukan tahun, bulan, dayOfMonth, hourOfDay, minit , dan kedua untuk zon waktu lalai dengan tempat lalai:

new GregorianCalendar(2018, 6, 27, 16, 16, 47);

Perhatikan bahawa kita tidak perlu menentukan jamOfDay, minit dan saat kerana terdapat pembina lain tanpa parameter ini.

Kita boleh melewati zon waktu sebagai parameter untuk membuat kalendar di zon waktu ini dengan lokasi lalai:

new GregorianCalendar(TimeZone.getTimeZone("GMT+5:30"));

Kita dapat meneruskan lokasi sebagai parameter untuk membuat kalendar di tempat ini dengan zon waktu lalai:

new GregorianCalendar(new Locale("en", "IN"));

Akhirnya, kita dapat melewati zon waktu dan lokal sebagai parameter:

new GregorianCalendar(TimeZone.getTimeZone("GMT+5:30"), new Locale("en", "IN"));

2.2. Kaedah Baru Dengan Java 8

Dengan Java 8, kaedah baru telah diperkenalkan ke GregorianCalendar.

Kaedah dari () mendapat contoh GregorianCalendar dengan lokasi lalai dari objek ZonedDateTime.

Dengan menggunakan getCalendarType () kita dapat memperoleh jenis contoh kalendar. Jenis kalendar yang ada adalah 'gregory', 'buddhist' dan 'jepang'.

Kita boleh menggunakannya, sebagai contoh, untuk memastikan kita mempunyai kalendar jenis tertentu sebelum meneruskan logik aplikasi kita:

@Test public void test_Calendar_Return_Type_Valid() { Calendar calendar = Calendar.getInstance(); assert ("gregory".equals(calendar.getCalendarType())); }

Memanggil keZonedDateTime () kita dapat menukar objek kalendar menjadi objek ZonedDateTime yang mewakili titik yang sama pada garis masa dengan GregorianCalendar ini .

2.3. Mengubah Tarikh

Medan kalendar boleh diubahsuai menggunakan kaedah add () , roll () dan set () .

Kaedah add () membolehkan kita menambah masa ke kalendar dalam unit yang ditentukan berdasarkan peraturan dalaman kalendar:

@Test public void test_whenAddOneDay_thenMonthIsChanged() { int finalDay1 = 1; int finalMonthJul = 6; GregorianCalendar calendarExpected = new GregorianCalendar(2018, 5, 30); calendarExpected.add(Calendar.DATE, 1); System.out.println(calendarExpected.getTime()); assertEquals(calendarExpected.get(Calendar.DATE), finalDay1); assertEquals(calendarExpected.get(Calendar.MONTH), finalMonthJul); }

Kita juga boleh menggunakan kaedah add () untuk mengurangkan masa dari objek kalendar:

@Test public void test_whenSubtractOneDay_thenMonthIsChanged() { int finalDay31 = 31; int finalMonthMay = 4; GregorianCalendar calendarExpected = new GregorianCalendar(2018, 5, 1); calendarExpected.add(Calendar.DATE, -1); assertEquals(calendarExpected.get(Calendar.DATE), finalDay31); assertEquals(calendarExpected.get(Calendar.MONTH), finalMonthMay); }

Pelaksanaan kaedah tambah () memaksa pengiraan semula segera milidetik kalendar dan semua bidang.

Perhatikan bahawa menggunakan add () juga boleh mengubah medan kalendar yang lebih tinggi (BULAN dalam kes ini).

Kaedah roll () menambah jumlah yang ditandatangani ke medan kalendar yang ditentukan tanpa menukar medan yang lebih besar. Medan yang lebih besar mewakili satuan masa yang lebih besar. Contohnya, DAY_OF_MONTH lebih besar daripada JAM.

Mari kita lihat contoh cara menggulung bulan.

Dalam kes ini, TAHUN menjadi bidang yang lebih besar tidak akan bertambah:

@Test public void test_whenRollUpOneMonth_thenYearIsUnchanged() { int rolledUpMonthJuly = 7, orginalYear2018 = 2018; GregorianCalendar calendarExpected = new GregorianCalendar(2018, 6, 28); calendarExpected.roll(Calendar.MONTH, 1); assertEquals(calendarExpected.get(Calendar.MONTH), rolledUpMonthJuly); assertEquals(calendarExpected.get(Calendar.YEAR), orginalYear2018); }

Begitu juga, kita dapat menurunkan bulan:

@Test public void test_whenRollDownOneMonth_thenYearIsUnchanged() { int rolledDownMonthJune = 5, orginalYear2018 = 2018; GregorianCalendar calendarExpected = new GregorianCalendar(2018, 6, 28); calendarExpected.roll(Calendar.MONTH, -1); assertEquals(calendarExpected.get(Calendar.MONTH), rolledDownMonthJune); assertEquals(calendarExpected.get(Calendar.YEAR), orginalYear2018); }

Kita secara langsung dapat menetapkan medan kalendar ke nilai yang ditentukan menggunakan kaedah set () . Nilai masa kalendar dalam milisaat tidak akan dikira semula sehingga panggilan seterusnya untuk mendapatkan () , getTime () , menambah () atau menggulung () dibuat.

Oleh itu, beberapa panggilan untuk menetapkan () tidak mencetuskan pengiraan yang tidak perlu.

Mari kita lihat contoh yang akan menetapkan medan bulan menjadi 3 (iaitu April):

@Test public void test_setMonth() { GregorianCalendarExample calendarDemo = new GregorianCalendarExample(); GregorianCalendar calendarActual = new GregorianCalendar(2018, 6, 28); GregorianCalendar calendarExpected = new GregorianCalendar(2018, 6, 28); calendarExpected.set(Calendar.MONTH, 3); Date expectedDate = calendarExpected.getTime(); assertEquals(expectedDate, calendarDemo.setMonth(calendarActual, 3)); }

2.4. Bekerja Dengan Kalendar XMLGregorian

JAXB membenarkan pemetaan kelas Java ke representasi XML. The javax.xml.datatype.XMLGregorianCalendar jenis boleh membantu dalam pemetaan jenis XSD skema asas seperti XSD: tarikh , XSD: masa dan XSD: Masa tarikh .

Mari kita lihat contoh untuk menukar dari jenis GregorianCalendar ke jenis XMLGregorianCalendar :

@Test public void test_toXMLGregorianCalendar() throws Exception { GregorianCalendarExample calendarDemo = new GregorianCalendarExample(); DatatypeFactory datatypeFactory = DatatypeFactory.newInstance(); GregorianCalendar calendarActual = new GregorianCalendar(2018, 6, 28); GregorianCalendar calendarExpected = new GregorianCalendar(2018, 6, 28); XMLGregorianCalendar expectedXMLGregorianCalendar = datatypeFactory .newXMLGregorianCalendar(calendarExpected); assertEquals( expectedXMLGregorianCalendar, alendarDemo.toXMLGregorianCalendar(calendarActual)); }

Once the calendar object has been translated into XML format, it can be used in any use cases that require a date to be serialized, like messaging or web service calls.

Let's see an example on how to convert from XMLGregorianCalendar type back into GregorianCalendar:

@Test public void test_toDate() throws DatatypeConfigurationException { GregorianCalendar calendarActual = new GregorianCalendar(2018, 6, 28); DatatypeFactory datatypeFactory = DatatypeFactory.newInstance(); XMLGregorianCalendar expectedXMLGregorianCalendar = datatypeFactory .newXMLGregorianCalendar(calendarActual); expectedXMLGregorianCalendar.toGregorianCalendar().getTime(); assertEquals( calendarActual.getTime(), expectedXMLGregorianCalendar.toGregorianCalendar().getTime() ); }

2.5. Comparing Dates

We can use the Calendar classes' compareTo() method to compare dates. The result will be positive if the base date is in the future and negative if the base data is in the past of the date we compare it to:

@Test public void test_Compare_Date_FirstDate_Greater_SecondDate() { GregorianCalendar firstDate = new GregorianCalendar(2018, 6, 28); GregorianCalendar secondDate = new GregorianCalendar(2018, 5, 28); assertTrue(1 == firstDate.compareTo(secondDate)); } @Test public void test_Compare_Date_FirstDate_Smaller_SecondDate() { GregorianCalendar firstDate = new GregorianCalendar(2018, 5, 28); GregorianCalendar secondDate = new GregorianCalendar(2018, 6, 28); assertTrue(-1 == firstDate.compareTo(secondDate)); } @Test public void test_Compare_Date_Both_Dates_Equal() { GregorianCalendar firstDate = new GregorianCalendar(2018, 6, 28); GregorianCalendar secondDate = new GregorianCalendar(2018, 6, 28); assertTrue(0 == firstDate.compareTo(secondDate)); }

2.6. Formatting Dates

We can convert GregorianCalendar into a specific format by using a combination of ZonedDateTime and DateTimeFormatter to get the desired output:

@Test public void test_dateFormatdMMMuuuu() { String expectedDate = new GregorianCalendar(2018, 6, 28).toZonedDateTime() .format(DateTimeFormatter.ofPattern("d MMM uuuu")); assertEquals("28 Jul 2018", expectedDate); }

2.7. Getting Information About the Calendar

GregorianCalendar provides several get methods which can be used to fetch different calendar attributes. Let's look at the different options we have:

  • getActualMaximum(int field) returns the maximum value for the specified calendar field taking into consideration the current time values. The following example will return value 30 for the DAY_OF_MONTH field because June has 30 days:
    GregorianCalendar calendar = new GregorianCalendar(2018 , 5, 28); assertTrue(30 == calendar.getActualMaximum(calendar.DAY_OF_MONTH));
  • getActualMinimum(int field) returns the minimum value for the specified calendar field taking into consideration the current time values:
    GregorianCalendar calendar = new GregorianCalendar(2018 , 5, 28); assertTrue(1 == calendar.getActualMinimum(calendar.DAY_OF_MONTH));
  • getGreatestMinimum(int field) returns the highest minimum value for the given calendar field:
    GregorianCalendar calendar = new GregorianCalendar(2018 , 5, 28); assertTrue(1 == calendar.getGreatestMinimum(calendar.DAY_OF_MONTH));
  • getLeastMaximum(int field) Returns the lowest maximum value for the given calendar field. For the DAY_OF_MONTH field this is 28, because February may have only 28 days:
    GregorianCalendar calendar = new GregorianCalendar(2018 , 5, 28); assertTrue(28 == calendar.getLeastMaximum(calendar.DAY_OF_MONTH));
  • getMaximum(int field) returns the maximum value for the given calendar field:
    GregorianCalendar calendar = new GregorianCalendar(2018 , 5, 28); assertTrue(31 == calendar.getMaximum(calendar.DAY_OF_MONTH));
  • getMinimum(int field) returns the minimum value for the given calendar field:
    GregorianCalendar calendar = new GregorianCalendar(2018 , 5, 28); assertTrue(1 == calendar.getMinimum(calendar.DAY_OF_MONTH));
  • getWeekYear() returns the year of the week represented by this GregorianCalendar:
    GregorianCalendar calendar = new GregorianCalendar(2018 , 5, 28); assertTrue(2018 == calendar.getWeekYear());
  • getWeeksInWeekYear() returns the number of weeks in the week year for the calendar year:
    GregorianCalendar calendar = new GregorianCalendar(2018 , 5, 28); assertTrue(52 == calendar.getWeeksInWeekYear());
  • isLeapYear() returns true if the year is a leap year:
    GregorianCalendar calendar = new GregorianCalendar(2018 , 5, 28); assertTrue(false == calendar.isLeapYear(calendar.YEAR));

3. Conclusion

Dalam artikel ini, kami meneroka aspek-aspek tertentu dari GregorianCalendar .

Seperti biasa, contoh kod boleh didapati di GitHub.