Guia para java.util.GregorianCalendar
1. Introdução
Neste tutorial, vamos dar uma olhada rápida na classeGregorianCalendar.
2. GregorianCalendar
GregorianCalendar é uma implementação concreta da classe abstratajava.util.Calendar. Não surpreendentemente, o calendário gregorianois the most widely used civil calendar in the world.
2.1. Obtendo uma instância
Existem duas opções disponíveis para obter uma instância deGregorianCalendar:Calendar.getInstance()e usando um dos construtores.
Usar o método de fábrica estáticoCalendar.getInstance() não é uma abordagem recomendada, pois retornará uma instância subjetiva ao local padrão.
Ele pode retornar umBuddhistCalendar para tailandês ouJapaneseImperialCalendar para o Japão. Não saber o tipo de instância que está sendo retornada pode levar a umClassCastException:
@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;
}
Usando um dos sete construtores sobrecarregados, podemos inicializar o objetoCalendar com a data e hora padrão dependendo da localidade do nosso sistema operacional ou podemos especificar uma combinação de data, hora, localidade e fuso horário.
Vamos entender os diferentes construtores pelos quais um objetoGregorianCalendar pode ser instanciado.
O construtor padrão inicializará o calendário com a data e hora atuais no fuso horário e na localidade do sistema operacional:
new GregorianCalendar();
Podemos especificar oyear, month, dayOfMonth, hourOfDay, minute e o segundo para o fuso horário padrão com a localidade padrão:
new GregorianCalendar(2018, 6, 27, 16, 16, 47);
Observe que não temos que especificarhourOfDay, minuteesecond, pois existem outros construtores sem esses parâmetros.
Podemos passar o fuso horário como um parâmetro para criar um calendário nesse fuso horário com o código do idioma padrão:
new GregorianCalendar(TimeZone.getTimeZone("GMT+5:30"));
Podemos passar a localidade como parâmetro para criar um calendário nessa localidade com o fuso horário padrão:
new GregorianCalendar(new Locale("en", "IN"));
Finalmente, podemos passar o fuso horário e a localidade como parâmetros:
new GregorianCalendar(TimeZone.getTimeZone("GMT+5:30"), new Locale("en", "IN"));
2.2. Novos métodos com Java 8
Com o Java 8, novos métodos foram introduzidos emGregorianCalendar.
O métodofrom() obtém uma instância deGregorianCalendar com a localidade padrão de um objeto ZonedDateTime.
Using getCalendarType() we can get the type of the calendar instance. Os tipos de calendário disponíveis são 'gregory', 'budista' e 'japonês'.
Podemos usar isso, por exemplo, para garantir que tenhamos um calendário de um determinado tipo antes de prosseguir com nossa lógica de aplicativo:
@Test
public void test_Calendar_Return_Type_Valid() {
Calendar calendar = Calendar.getInstance();
assert ("gregory".equals(calendar.getCalendarType()));
}
Calling toZonedDateTime() we can convert the calendar object into a ZonedDateTime object que representa o mesmo ponto na linha do tempo que esteGregorianCalendar.
2.3. Modificando Datas
Os campos do calendário podem ser modificados usando os métodosadd(),roll()eset().
The add() method allows us to add time to the calendar in a specified unit com base no conjunto de regras internas do calendário:
@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);
}
Também podemos usar o métodoadd() para subtrair o tempo do objeto de calendário:
@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);
}
A execução do métodoadd() força um recálculo imediato dos milissegundos do calendário e de todos os campos.
Observe que o uso deadd() também pode alterar os campos superiores do calendário (MONTH, neste caso).
O métodoroll() adiciona uma quantia assinada ao campo de calendário especificado sem alterar os campos maiores. Um campo maior representa uma unidade de tempo maior. Por exemplo,DAY_OF_MONTH é maior queHOUR.
Vamos ver um exemplo de como acumular meses.
Neste caso,YEAR sendo um campo maior não será incrementado:
@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);
}
Da mesma forma, podemos rolar meses:
@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);
}
We can directly set a calendar field to a specified value using the set() method. O valor de tempo do calendário em milissegundos não será recomputado até que a próxima chamada paraget(),getTime(),add() ouroll() seja feita.
Assim, várias chamadas paraset() não acionam cálculos desnecessários.
Vejamos um exemplo que definirá o campo do mês para 3 (ou seja, Abril):
@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. Trabalhando comXMLGregorianCalendar
O JAXB permite mapear classes Java para representações XML. O tipojavax.xml.datatype.XMLGregorianCalendar pode ajudar no mapeamento dos tipos de esquema XSD básicos, comoxsd:date,xsd:timeexsd:dateTime.
Vamos dar uma olhada em um exemplo para converter do tipoGregorianCalendar para o tipoXMLGregorianCalendar:
@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));
}
Após a tradução do objeto de calendário para o formato XML, ele pode ser usado em qualquer caso de uso que exija a serialização de uma data, como mensagens ou chamadas de serviço da web.
Vamos ver um exemplo de como converter do tipoXMLGregorianCalendar de volta paraGregorianCalendar:
@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. Comparando datas
Podemos usar o métodocompareTo() das classesCalendar para comparar datas. O resultado será positivo se a data base for no futuro e negativo se os dados base estiverem no passado da data em que comparamos com:
@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. Formatar datas
Podemos converterGregorianCalendar em um formato específico usando uma combinação deZonedDateTimeeDateTimeFormatter para obter a saída desejada:
@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. Obtendo informações sobre o calendário
GregorianCalendar fornece vários métodos get que podem ser usados para obter diferentes atributos do calendário. Vejamos as diferentes opções que temos:
-
getActualMaximum(int field) – retorna o valor máximo para o campo do calendário especificado, levando em consideração os valores de hora atuais. O exemplo a seguir retornará o valor 30 para o campoDAY_OF_MONTH porque junho tem 30 dias:
GregorianCalendar calendar = new GregorianCalendar(2018 , 5, 28); assertTrue(30 == calendar.getActualMaximum(calendar.DAY_OF_MONTH));
-
getActualMinimum(int field) – retorna o valor mínimo para o campo do calendário especificado, levando em consideração os valores de hora atuais:
GregorianCalendar calendar = new GregorianCalendar(2018 , 5, 28); assertTrue(1 == calendar.getActualMinimum(calendar.DAY_OF_MONTH));
-
getGreatestMinimum(int field) – retorna o valor mínimo mais alto para o campo de calendário fornecido:
GregorianCalendar calendar = new GregorianCalendar(2018 , 5, 28); assertTrue(1 == calendar.getGreatestMinimum(calendar.DAY_OF_MONTH));
-
getLeastMaximum(int field) – Retorna o valor máximo mais baixo para o campo do calendário fornecido. Para o campoDAY_OF_MONTH, é 28, porque fevereiro pode ter apenas 28 dias:
GregorianCalendar calendar = new GregorianCalendar(2018 , 5, 28); assertTrue(28 == calendar.getLeastMaximum(calendar.DAY_OF_MONTH));
-
getMaximum(int field) – retorna o valor máximo para o campo de calendário fornecido:
GregorianCalendar calendar = new GregorianCalendar(2018 , 5, 28); assertTrue(31 == calendar.getMaximum(calendar.DAY_OF_MONTH));
-
getMinimum(int field) – retorna o valor mínimo para o campo de calendário fornecido:
GregorianCalendar calendar = new GregorianCalendar(2018 , 5, 28); assertTrue(1 == calendar.getMinimum(calendar.DAY_OF_MONTH));
-
getWeekYear() – retorna oyear of the week representado por esteGregorianCalendar:
GregorianCalendar calendar = new GregorianCalendar(2018 , 5, 28); assertTrue(2018 == calendar.getWeekYear());
-
getWeeksInWeekYear() – retorna o número de semanas no ano da semana para o ano civil:
GregorianCalendar calendar = new GregorianCalendar(2018 , 5, 28); assertTrue(52 == calendar.getWeeksInWeekYear());
-
isLeapYear() – retorna verdadeiro se o ano for um ano bissexto:
GregorianCalendar calendar = new GregorianCalendar(2018 , 5, 28); assertTrue(false == calendar.isLeapYear(calendar.YEAR));
3. Conclusão
Neste artigo, exploramos certos aspectos deGregorianCalendar.
Como sempre, o código de amostra está disponívelover on GitHub.