Anleitung zu java.util.GregorianCalendar

1. Einleitung

In diesem Tutorial werfen wir einen kurzen Blick auf die GregorianCalendar- Klasse.

2. Gregorianischer Kalender

GregorianCalendar ist eine konkrete Implementierung der abstrakten Klasse java.util.Calendar . Es überrascht nicht, dass der Gregorianische Kalender der am häufigsten verwendete Zivilkalender der Welt ist.

2.1. Eine Instanz bekommen

Es gibt zwei Optionen, um eine Instanz von GregorianCalendar abzurufen: Calendar.getInstance () und die Verwendung eines der Konstruktoren.

Die Verwendung der statischen Factory-Methode Calendar.getInstance () wird nicht empfohlen, da eine Instanz subjektiv zum Standardgebietsschema zurückgegeben wird.

Möglicherweise wird ein buddhistischer Kalender für Thai oder ein japanischer Kaiserlicher Kalender für Japan zurückgegeben. Wenn Sie den Typ der zurückgegebenen Instanz nicht kennen, kann dies zu einer ClassCastException führen :

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

Mit einem der sieben überladenen Konstruktoren können wir das Kalenderobjekt entweder mit dem Standarddatum und der Standardzeit initialisieren, abhängig vom Gebietsschema unseres Betriebssystems, oder wir können eine Kombination aus Datum, Uhrzeit, Gebietsschema und Zeitzone angeben.

Lassen Sie uns die verschiedenen Konstruktoren verstehen, mit denen ein GregorianCalendar- Objekt instanziiert werden kann.

Der Standardkonstruktor initialisiert den Kalender mit dem aktuellen Datum und der aktuellen Uhrzeit in der Zeitzone und dem Gebietsschema des Betriebssystems:

new GregorianCalendar();

Wir können das Jahr, den Monat, den Tag des Monats, die Stunde des Tages, die Minute und die Sekunde für die Standardzeitzone mit dem Standardgebietsschema angeben:

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

Beachten Sie, dass wir nicht HourOfDay, Minute und Sekunde angeben müssen, da es andere Konstruktoren ohne diese Parameter gibt.

Wir können die Zeitzone als Parameter übergeben, um einen Kalender in dieser Zeitzone mit dem Standardgebietsschema zu erstellen:

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

Wir können das Gebietsschema als Parameter übergeben, um einen Kalender in diesem Gebietsschema mit der Standardzeitzone zu erstellen:

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

Schließlich können wir sowohl die Zeitzone als auch das Gebietsschema als Parameter übergeben:

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

2.2. Neue Methoden mit Java 8

Mit Java 8 wurden neue Methoden in GregorianCalendar eingeführt.

Die from () -Methode ruft eine Instanz von GregorianCalendar mit dem Standardgebietsschema von einem ZonedDateTime-Objekt ab.

Mit getCalendarType () können wir den Typ der Kalenderinstanz ermitteln. Die verfügbaren Kalendertypen sind "Gregory", "Buddhist" und "Japanisch".

Wir können dies beispielsweise verwenden, um sicherzustellen, dass wir einen Kalender eines bestimmten Typs haben, bevor wir mit unserer Anwendungslogik fortfahren:

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

Durch Aufrufen von toZonedDateTime () können wir das Kalenderobjekt in ein ZonedDateTime- Objekt konvertieren , das denselben Punkt auf der Zeitachse wie dieser Gregorianische Kalender darstellt .

2.3. Termine ändern

Die Kalenderfelder können mit den Methoden add () , roll () und set () geändert werden .

Mit der Methode add () können wir dem Kalender in einer bestimmten Einheit basierend auf dem internen Regelsatz des Kalenders Zeit hinzufügen:

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

Wir können auch die add () -Methode verwenden, um die Zeit vom Kalenderobjekt zu subtrahieren:

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

Die Ausführung der Methode add () erzwingt eine sofortige Neuberechnung der Millisekunden des Kalenders und aller Felder.

Beachten Sie, dass die Verwendung von add () auch die höheren Kalenderfelder ändern kann (in diesem Fall MONTH).

Die roll () -Methode fügt dem angegebenen Kalenderfeld einen signierten Betrag hinzu, ohne die größeren Felder zu ändern. Ein größeres Feld repräsentiert eine größere Zeiteinheit. Beispielsweise ist DAY_OF_MONTH größer als HOUR.

Schauen wir uns ein Beispiel an, wie man Monate aufrollt.

In diesem Fall wird YEAR als größeres Feld nicht erhöht:

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

Ebenso können wir Monate verkürzen:

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

Mit der set () -Methode können wir ein Kalenderfeld direkt auf einen bestimmten Wert setzen . Der Zeitwert des Kalenders in Millisekunden wird erst neu berechnet, wenn der nächste Aufruf von get () , getTime () , add () oder roll () erfolgt.

Thus, multiple calls to set() don't trigger unnecessary computations.

Let's see an example which will set the month field to 3 (i.e. 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. Working With XMLGregorianCalendar

JAXB allows mapping Java classes to XML representations. The javax.xml.datatype.XMLGregorianCalendar type can help in mapping the basic XSD schema types such as xsd:date, xsd:time and xsd:dateTime.

Let's have a look at an example to convert from GregorianCalendar type into the XMLGregorianCalendar type:

@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

In diesem Artikel haben wir bestimmte Aspekte des Gregorianischen Kalenders untersucht .

Wie immer ist der Beispielcode über GitHub verfügbar.