Руководство по java.util.GregorianCalendar
1. Вступление
В этом руководстве мы кратко рассмотрим классGregorianCalendar.
2. GregorianCalendarс
GregorianCalendar - это конкретная реализация абстрактного классаjava.util.Calendar. Неудивительно, что григорианский календарьis the most widely used civil calendar in the world.
2.1. Получение экземпляра
Доступны два варианта получения экземпляраGregorianCalendar:Calendar.getInstance() и использования одного из конструкторов.
Использование статического фабричного методаCalendar.getInstance() не рекомендуется, так как он вернет экземпляр, субъективный к языку по умолчанию.
Он может вернутьBuddhistCalendar для тайского языка илиJapaneseImperialCalendar для Японии. Незнание типа возвращаемого экземпляра может привести к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;
}
Используя один из семи перегруженных конструкторов, мы можем инициализировать объектCalendar либо датой и временем по умолчанию в зависимости от языкового стандарта нашей операционной системы, либо мы можем указать комбинацию даты, времени, языкового стандарта и часового пояса.
Давайте разберемся с различными конструкторами, с помощью которых можно создать экземпляр объектаGregorianCalendar.
Конструктор по умолчанию инициализирует календарь с текущей датой и временем в часовом поясе и локали операционной системы:
new GregorianCalendar();
Мы можем указатьyear, month, dayOfMonth, hourOfDay, minute и секунду для часового пояса по умолчанию с локалью по умолчанию:
new GregorianCalendar(2018, 6, 27, 16, 16, 47);
Обратите внимание, что нам не нужно указыватьhourOfDay, minute иsecond, поскольку есть другие конструкторы без этих параметров.
Мы можем передать часовой пояс в качестве параметра для создания календаря в этом часовом поясе с языковым стандартом по умолчанию:
new GregorianCalendar(TimeZone.getTimeZone("GMT+5:30"));
Мы можем передать локаль в качестве параметра для создания календаря в этой локали с часовым поясом по умолчанию:
new GregorianCalendar(new Locale("en", "IN"));
Наконец, мы можем передать как часовой пояс, так и локаль в качестве параметров:
new GregorianCalendar(TimeZone.getTimeZone("GMT+5:30"), new Locale("en", "IN"));
2.2. Новые методы в Java 8
В Java 8 вGregorianCalendar. добавлены новые методы.
Методfrom() получает экземплярGregorianCalendar с локалью по умолчанию из объекта ZonedDateTime.
Using getCalendarType() we can get the type of the calendar instance. Доступные типы календаря: «грегори», «буддийский» и «японский».
Мы можем использовать это, например, чтобы убедиться, что у нас есть календарь определенного типа, прежде чем перейти к нашей логике приложения:
@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, который представляет ту же точку на временной шкале, что и этотGregorianCalendar.
2.3. Изменение дат
Поля календаря можно изменить с помощью методовadd(),roll() иset().
The add() method allows us to add time to the calendar in a specified unit на основе внутреннего набора правил календаря:
@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);
}
Мы также можем использовать методadd() для вычитания времени из объекта календаря:
@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);
}
Выполнение методаadd() приводит к немедленному пересчету календарных миллисекунд и всех полей.
Обратите внимание, что использованиеadd() может также изменить поля более высокого календаря (в данном случае MONTH).
Методroll() добавляет сумму со знаком в указанное поле календаря, не изменяя более крупные поля. Большее поле представляет большую единицу времени. Например,DAY_OF_MONTH больше, чемHOUR.
Давайте посмотрим на примере, как свести месяцы.
В этом случаеYEAR, являющееся большим полем, не будет увеличиваться:
@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);
}
Точно так же мы можем свернуть месяцы:
@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. Значение времени календаря в миллисекундах не будет пересчитано до тех пор, пока не будет выполнен следующий вызовget(),getTime(),add() илиroll().
Таким образом, несколько вызововset() не вызывают ненужных вычислений.
Давайте посмотрим на пример, в котором поле месяца будет установлено на 3 (т. Е. Апрель):
@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. Работа сXMLGregorianCalendar
JAXB позволяет отображать классы Java на представления XML. Типjavax.xml.datatype.XMLGregorianCalendar может помочь в сопоставлении основных типов схемы XSD, таких какxsd:date,xsd:time иxsd:dateTime.
Давайте посмотрим на пример преобразования типаGregorianCalendar в тип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));
}
После перевода объекта календаря в формат XML его можно использовать в любых случаях, когда требуется сериализация даты, например при обмене сообщениями или вызовах веб-службы.
Давайте посмотрим на пример того, как преобразовать типXMLGregorianCalendar обратно в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. Сравнение дат
Мы можем использовать методcompareTo() классовCalendar для сравнения дат. Результат будет положительным, если базовая дата находится в будущем, и отрицательным, если базовые данные находятся в прошлом от даты, с которой мы сравниваем:
@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. Даты форматирования
Мы можем преобразоватьGregorianCalendar в определенный формат, используя комбинациюZonedDateTime иDateTimeFormatter, чтобы получить желаемый результат:
@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. Получение информации о календаре
GregorianCalendar предоставляет несколько методов получения, которые можно использовать для получения различных атрибутов календаря. Давайте посмотрим на разные варианты, которые у нас есть:
-
getActualMaximum(int field) – возвращает максимальное значение для указанного календарного поля с учетом текущих значений времени. В следующем примере будет возвращено значение 30 для поляDAY_OF_MONTH, потому что в июне 30 дней:
GregorianCalendar calendar = new GregorianCalendar(2018 , 5, 28); assertTrue(30 == calendar.getActualMaximum(calendar.DAY_OF_MONTH));
-
getActualMinimum(int field) – возвращает минимальное значение для указанного календарного поля с учетом текущих значений времени:
GregorianCalendar calendar = new GregorianCalendar(2018 , 5, 28); assertTrue(1 == calendar.getActualMinimum(calendar.DAY_OF_MONTH));
-
getGreatestMinimum(int field) – возвращает максимальное минимальное значение для данного календарного поля:
GregorianCalendar calendar = new GregorianCalendar(2018 , 5, 28); assertTrue(1 == calendar.getGreatestMinimum(calendar.DAY_OF_MONTH));
-
getLeastMaximum(int field) – Возвращает наименьшее максимальное значение для данного календарного поля. Для поляDAY_OF_MONTH это 28, потому что в феврале может быть только 28 дней:
GregorianCalendar calendar = new GregorianCalendar(2018 , 5, 28); assertTrue(28 == calendar.getLeastMaximum(calendar.DAY_OF_MONTH));
-
getMaximum(int field) – возвращает максимальное значение для данного календарного поля:
GregorianCalendar calendar = new GregorianCalendar(2018 , 5, 28); assertTrue(31 == calendar.getMaximum(calendar.DAY_OF_MONTH));
-
getMinimum(int field) – возвращает минимальное значение для данного календарного поля:
GregorianCalendar calendar = new GregorianCalendar(2018 , 5, 28); assertTrue(1 == calendar.getMinimum(calendar.DAY_OF_MONTH));
-
getWeekYear() – возвращаетyear of the week , представленный этимGregorianCalendar:
GregorianCalendar calendar = new GregorianCalendar(2018 , 5, 28); assertTrue(2018 == calendar.getWeekYear());
-
getWeeksInWeekYear() – возвращает количество недель в недельном году для календарного года:
GregorianCalendar calendar = new GregorianCalendar(2018 , 5, 28); assertTrue(52 == calendar.getWeeksInWeekYear());
-
isLeapYear() – возвращает истину, если год високосный:
GregorianCalendar calendar = new GregorianCalendar(2018 , 5, 28); assertTrue(false == calendar.isLeapYear(calendar.YEAR));
3. Заключение
В этой статье мы исследовали некоторые аспектыGregorianCalendar.
Как всегда доступен пример кодаover on GitHub.