1. Introduction
1.介绍
In this tutorial, we’re going to take a quick peek at the GregorianCalendar class.
在本教程中,我们将快速浏览一下GregorianCalendar类。
2. GregorianCalendar
2.GregorianCalendar
GregorianCalendar is a concrete implementation of the abstract class java.util.Calendar. Not surprisingly, the Gregorian Calendar is the most widely used civil calendar in the world.
GregorianCalendar是抽象类java.util.Calendar的一个具体实现。毫不奇怪,公历是世界上使用最广泛的民用日历。
2.1. Getting an Instance
2.1.获得一个实例
There are two options available to get an instance of GregorianCalendar: Calendar.getInstance() and using one of the constructors.
有两种方法可以获得GregorianCalendar的实例:Calendar.getInstance()和使用其中一个构造函数。
Using the static factory method Calendar.getInstance() isn’t a recommended approach as it will return an instance subjective to the default locale.
使用静态工厂方法Calendar.getInstance()并不是一个值得推荐的方法,因为它将返回一个以默认区域为主题的实例。
It might return a BuddhistCalendar for Thai or JapaneseImperialCalendar for Japan. Not knowing the type of the instance being returned may lead to a ClassCastException:
它可能为泰国人返回一个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;
}
Using one of the seven overloaded constructors we can initialize the Calendar object either with the default date and time depending on the locale of our operating system or we can specify a combination of date, time, locale and time zone.
使用七个重载构造器中的一个,我们可以根据我们操作系统的区域设置,用默认的日期和时间来初始化Calendar对象,或者我们可以指定日期、时间、区域设置和时区的组合。
Let’s understand the different constructors by which a GregorianCalendar object can be instantiated.
让我们了解一下不同的构造函数,通过这些函数可以实例化一个GregorianCalendar对象。
The default constructor will initialize the calendar with the current date and time in the time zone and locale of the operating system:
默认构造函数将用操作系统的时区和地域的当前日期和时间来初始化日历。
new GregorianCalendar();
We can specify the year, month, dayOfMonth, hourOfDay, minute, and second for the default time zone with the default locale:
我们可以为默认时区指定年、月、dayOfMonth、hourOfDay、minute和second,使用默认locale。
new GregorianCalendar(2018, 6, 27, 16, 16, 47);
Note that we don’t have to specify hourOfDay, minute and second as there are other constructors without these parameters.
注意,我们不必指定hourOfDay、minute和second,因为有其他构造函数没有这些参数。
We can pass the time zone as a parameter to create a calendar in this time zone with the default locale:
我们可以把时区作为一个参数传给他,以便在这个时区创建一个带有默认区域的日历。
new GregorianCalendar(TimeZone.getTimeZone("GMT+5:30"));
We can pass the locale as a parameter to create a calendar in this locale with the default time zone:
我们可以把locale作为一个参数传过去,在这个locale中创建一个具有默认时区的日历。
new GregorianCalendar(new Locale("en", "IN"));
Finally, we can pass both the time zone and locale as parameters:
最后,我们可以把时区和locale都作为参数传递。
new GregorianCalendar(TimeZone.getTimeZone("GMT+5:30"), new Locale("en", "IN"));
2.2. New Methods With Java 8
2.2.Java 8的新方法
With Java 8, new methods have been introduced to GregorianCalendar.
随着Java 8的到来,新的方法被引入到GregorianCalendar.。
The from() method gets an instance of GregorianCalendar with the default locale from a ZonedDateTime object.
from()方法从一个ZonedDateTime对象中获得一个具有默认地点的GregorianCalendar实例。
Using getCalendarType() we can get the type of the calendar instance. The available calendar types are ‘gregory’, ‘buddhist’ and ‘japanese’.
使用getCalendarType()我们可以得到日历实例的类型。可用的日历类型是 “格雷戈里”、”佛教 “和 “日本”。
We can use this, for example, to make sure we have a calendar of a certain type before moving on with our application logic:
例如,我们可以用它来确保我们有一个特定类型的日历,然后再继续我们的应用逻辑。
@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 that represents the same point on the timeline as this GregorianCalendar.
调用toZonedDateTime(),我们可以将日历对象转换为ZonedDateTime对象,该对象代表时间线上与此GregorianCalendar相同的点。
2.3. Modifying Dates
2.3.修改日期
The calendar fields can be modified using the methods add(), roll() and set().
可以使用add()、roll()和set()方法修改日历字段。
The add() method allows us to add time to the calendar in a specified unit based on the calendar’s internal ruleset:
add()方法允许我们根据日历的内部规则集,以指定的单位向日历添加时间。
@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);
}
We can also use the add() method to subtract time from the calendar object:
我们还可以使用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);
}
Execution of the add() method forces an immediate re-computation of the calendar’s milliseconds and all fields.
执行add()方法会迫使立即重新计算日历的毫秒和所有字段。
Note that using add() may also change the higher calendar fields (MONTH in this case).
请注意,使用add()也可能改变较高的日历字段(本例中为MONTH)。
The roll() method adds a signed amount to the specified calendar field without changing the larger fields. A larger field represents a larger unit of time. For example, DAY_OF_MONTH is larger than HOUR.
roll()方法在不改变较大字段的情况下,向指定的日历字段添加一个有符号的金额。一个较大的字段代表一个较大的时间单位。例如,DAY_OF_MONTH比HOUR.大。
Let’s see an example of how to roll up months.
让我们看一个如何卷起月份的例子。
In this case, YEAR being a larger field will not be incremented:
在这种情况下,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);
}
Similarly, we can roll down months:
同样地,我们可以滚下几个月。
@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. The calendar’s time value in milliseconds will not recomputed until the next call to get(), getTime(), add() or roll() is made.
我们可以使用set()方法直接将日历字段设置为指定的值。日历的时间值(以毫秒为单位)不会重新计算,直到下一次调用get()、getTime()、add()或roll()。
Thus, multiple calls to set() don’t trigger unnecessary computations.
因此,对set()的多次调用不会触发不必要的计算。
Let’s see an example which will set the month field to 3 (i.e. April):
让我们看一个例子,它将把月份字段设置为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. Working With XMLGregorianCalendar
2.4.使用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.
JAXB允许将Java类映射到XML表示中。javax.xml.datatype.XMLGregorianCalendar类型可以帮助映射基本的XSD模式类型,如xsd:date,xsd:time和xsd:dateTime。
Let’s have a look at an example to convert from GregorianCalendar type into the XMLGregorianCalendar type:
让我们来看看从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));
}
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.
一旦日历对象被翻译成XML格式,它就可以被用于任何需要将日期序列化的用例中,比如消息传递或网络服务调用。
Let’s see an example on how to convert from XMLGregorianCalendar type back into GregorianCalendar:
让我们看看如何从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. Comparing Dates
2.5.比较日期
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:
我们可以使用Calendar类的compareTo()方法来比较日期。如果基准日期是在未来,结果将是正数;如果基准数据是在我们比较的日期的过去,结果将是负数。
@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
2.6.格式化日期
We can convert GregorianCalendar into a specific format by using a combination of ZonedDateTime and DateTimeFormatter to get the desired output:
我们可以通过使用ZonedDateTime和DateTimeFormatter的组合将GregorianCalendar转换为特定的格式,以获得所需的输出。
@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
2.7.获取有关日历的信息
GregorianCalendar provides several get methods which can be used to fetch different calendar attributes. Let’s look at the different options we have:
GregorianCalendar提供了几个获取方法,可以用来获取不同的日历属性。让我们来看看我们有哪些不同的选择。
- 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
3.结论
In this article, we explored certain aspects of GregorianCalendar.
在这篇文章中,我们探讨了GregorianCalendar的某些方面。
As always, the sample code is available over on GitHub.
像往常一样,样本代码可在GitHub上获得。