Panduan untuk java.util.GregorianCalendar

1. Perkenalan

Dalam tutorial ini, kita akan melihat sekilas kelas GregorianCalendar .

2. GregorianCalendar

GregorianCalendar adalah implementasi konkret dari kelas abstrak java.util.Calendar . Tak heran, Kalender Gregorian merupakan kalender sipil yang paling banyak digunakan di dunia.

2.1. Mendapatkan sebuah Instance

Ada dua opsi yang tersedia untuk mendapatkan instance GregorianCalendar: Calendar.getInstance () dan menggunakan salah satu konstruktor.

Menggunakan metode pabrik statis Calendar.getInstance () bukanlah pendekatan yang disarankan karena akan mengembalikan instance yang subjektif ke lokal default.

Mungkin mengembalikan Kalender Buddha untuk Thailand atau Kalender Kekaisaran Jepang untuk Jepang. Tidak mengetahui jenis instance yang dikembalikan dapat 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 dari tujuh konstruktor kelebihan beban, kita dapat menginisialisasi objek Kalender baik dengan tanggal dan waktu default bergantung pada lokal sistem operasi kita atau kita dapat menentukan kombinasi tanggal, waktu, lokal dan zona waktu.

Mari kita pahami berbagai konstruktor yang dapat digunakan untuk membuat objek GregorianCalendar .

Konstruktor default akan menginisialisasi kalender dengan tanggal dan waktu saat ini di zona waktu dan lokal sistem operasi:

new GregorianCalendar();

Kita dapat menentukan tahun, bulan, dayOfMonth, hourOfDay, menit , dan detik untuk zona waktu default dengan lokal default:

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

Perhatikan bahwa kita tidak perlu menentukan hourOfDay, minute dan second karena ada konstruktor lain tanpa parameter ini.

Kita dapat melewatkan zona waktu sebagai parameter untuk membuat kalender di zona waktu ini dengan lokal default:

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

Kita bisa melewatkan lokal sebagai parameter untuk membuat kalender di lokal ini dengan zona waktu default:

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

Terakhir, kita dapat melewatkan zona waktu dan lokal sebagai parameter:

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

2.2. Metode Baru Dengan Java 8

Dengan Java 8, metode baru telah diperkenalkan ke GregorianCalendar.

Metode from () mendapatkan instance GregorianCalendar dengan lokal default dari objek ZonedDateTime.

Menggunakan getCalendarType () kita bisa mendapatkan jenis contoh kalender. Jenis kalender yang tersedia adalah 'gregory', 'buddhist' dan 'japanese'.

Kita dapat menggunakan ini, misalnya, untuk memastikan kita memiliki jenis kalender tertentu sebelum melanjutkan dengan logika aplikasi kita:

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

Memanggil toZonedDateTime () kita dapat mengonversi objek kalender menjadi objek ZonedDateTime yang mewakili titik yang sama di garis waktu dengan GregorianCalendar ini .

2.3. Mengubah Tanggal

Bidang kalender dapat dimodifikasi menggunakan metode add () , roll () dan set () .

Metode add () memungkinkan kita menambahkan waktu ke kalender dalam unit tertentu berdasarkan kumpulan aturan internal kalender:

@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 bisa menggunakan metode add () untuk mengurangi waktu dari objek kalender:

@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); }

Eksekusi metode add () memaksa penghitungan ulang langsung dari milidetik kalender dan semua bidang.

Perhatikan bahwa menggunakan add () juga dapat mengubah bidang kalender yang lebih tinggi (MONTH dalam hal ini).

Metode roll () menambahkan jumlah yang ditandatangani ke bidang kalender tertentu tanpa mengubah bidang yang lebih besar. Bidang yang lebih besar menunjukkan satuan waktu yang lebih besar. Misalnya, DAY_OF_MONTH lebih besar dari HOUR.

Mari kita lihat contoh bagaimana menggulung bulan.

Dalam kasus ini, YEAR sebagai 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); }

Demikian pula, kami 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 bisa langsung menyetel bidang kalender ke nilai yang ditentukan menggunakan metode set () . Nilai waktu kalender dalam milidetik tidak akan dihitung sampai panggilan berikutnya untuk get () , getTime () , add () atau roll () dilakukan.

Dengan demikian, beberapa panggilan ke set () tidak memicu komputasi yang tidak perlu.

Mari kita lihat contoh yang akan menyetel field bulan ke 3 (yaitu 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 XMLGregorianCalendar

JAXB memungkinkan pemetaan kelas Java ke representasi XML. The javax.xml.datatype.XMLGregorianCalendar jenis dapat membantu dalam memetakan jenis XSD skema dasar seperti xsd: tanggal , xsd: waktu dan xsd: datetime .

Mari kita lihat contoh untuk mengonversi dari jenis GregorianCalendar menjadi 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 menjelajahi aspek-aspek tertentu dari GregorianCalendar .

Seperti biasa, kode sampel tersedia di GitHub.