Guide de java.util.GregorianCalendar

1. Introduction

Dans ce didacticiel, nous allons jeter un coup d'œil rapide à la classe GregorianCalendar .

2. GrégorienCalendrier

GregorianCalendar est une implémentation concrète de la classe abstraite java.util.Calendar . Sans surprise, le calendrier grégorien est le calendrier civil le plus utilisé dans le monde.

2.1. Obtenir une instance

Il existe deux options disponibles pour obtenir une instance de GregorianCalendar: Calendar.getInstance () et en utilisant l'un des constructeurs.

L'utilisation de la méthode de fabrique statique Calendar.getInstance () n'est pas une approche recommandée car elle renverra une instance subjective aux paramètres régionaux par défaut.

Il peut renvoyer un BuddhistCalendar pour le thaï ou un JapaneseImperialCalendar pour le Japon. Ne pas connaître le type de l'instance renvoyée peut conduire à une exception 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; }

En utilisant l'un des sept constructeurs surchargés, nous pouvons initialiser l' objet Calendar soit avec la date et l'heure par défaut en fonction des paramètres régionaux de notre système d'exploitation, soit nous pouvons spécifier une combinaison de date, d'heure, de paramètres régionaux et de fuseau horaire.

Comprenons les différents constructeurs par lesquels un objet GregorianCalendar peut être instancié.

Le constructeur par défaut initialisera le calendrier avec la date et l'heure actuelles dans le fuseau horaire et les paramètres régionaux du système d'exploitation:

new GregorianCalendar();

Nous pouvons spécifier l' année, le mois, le dayOfMonth, hourOfDay, la minute et la seconde pour le fuseau horaire par défaut avec les paramètres régionaux par défaut:

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

Notez que nous n'avons pas à spécifier hourOfDay, minute et seconde car il existe d'autres constructeurs sans ces paramètres.

Nous pouvons passer le fuseau horaire comme paramètre pour créer un calendrier dans ce fuseau horaire avec les paramètres régionaux par défaut:

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

Nous pouvons passer la locale comme paramètre pour créer un calendrier dans cette locale avec le fuseau horaire par défaut:

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

Enfin, nous pouvons passer à la fois le fuseau horaire et les paramètres régionaux:

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

2.2. Nouvelles méthodes avec Java 8

Avec Java 8, de nouvelles méthodes ont été introduites dans GregorianCalendar.

La méthode from () obtient une instance de GregorianCalendar avec les paramètres régionaux par défaut à partir d'un objet ZonedDateTime.

En utilisant getCalendarType (), nous pouvons obtenir le type de l'instance de calendrier. Les types de calendrier disponibles sont «grégoire», «bouddhiste» et «japonais».

Nous pouvons utiliser ceci, par exemple, pour nous assurer que nous avons un calendrier d'un certain type avant de passer à notre logique d'application:

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

En appelant toZonedDateTime (), nous pouvons convertir l'objet de calendrier en un objet ZonedDateTime qui représente le même point sur la chronologie que ce GregorianCalendar.

2.3. Modifier les dates

Les champs du calendrier peuvent être modifiés à l'aide des méthodes add () , roll () et set () .

La méthode add () nous permet d'ajouter du temps au calendrier dans une unité spécifiée en fonction du jeu de règles interne du calendrier:

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

Nous pouvons également utiliser la méthode add () pour soustraire le temps de l'objet calendrier:

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

L'exécution de la méthode add () force un recalcul immédiat des millisecondes du calendrier et de tous les champs.

Notez que l'utilisation de add () peut également modifier les champs de calendrier supérieurs (MONTH dans ce cas).

La méthode roll () ajoute un montant signé au champ de calendrier spécifié sans modifier les plus grands champs. Un champ plus grand représente une unité de temps plus grande. Par exemple, DAY_OF_MONTH est supérieur à HOUR.

Voyons un exemple de la façon de cumuler les mois.

Dans ce cas, YEAR étant un champ plus grand ne sera pas incrémenté:

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

De même, nous pouvons dérouler des mois:

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

Nous pouvons directement définir un champ de calendrier sur une valeur spécifiée en utilisant la méthode set () . La valeur temporelle du calendrier en millisecondes ne sera pas recalculée jusqu'à ce que le prochain appel à get () , getTime () , add () ou roll () soit effectué.

Ainsi, plusieurs appels à set () ne déclenchent pas de calculs inutiles.

Voyons un exemple qui définira le champ du mois sur 3 (c'est-à-dire avril):

@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. Utilisation de XMLGregorianCalendar

JAXB permet de mapper des classes Java sur des représentations XML. Le type javax.xml.datatype.XMLGregorianCalendar peut aider à mapper les types de schéma XSD de base tels que xsd: date , xsd: time et xsd: dateTime .

Jetons un coup d'œil à un exemple de conversion du type GregorianCalendar en type 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

Dans cet article, nous avons exploré certains aspects de GregorianCalendar .

Comme toujours, l'exemple de code est disponible à l'adresse over sur GitHub.