Part One Introduction
Calendar definition:
public abstract class Calendar implements Serializable, Cloneable, Comparable<Calendar> {} Calendar can be regarded as an abstract class.
Its implementation adopts the factory method in the design pattern. It is manifested in: When we obtain the Calendar instance, the Calendar will return the corresponding Calendar object based on the passed parameters. There are two ways to obtain Calendar instance:
(1) When we get the calendar through Calendar.getInstance(), the default is a GregorianCalendar object returned.
GregorianCalendar is an implementation class of Calendar that provides a standard calendar system used in most countries in the world.
(2) When we get the calendar through Calendar.getInstance(TimeZone timezone, Locale locale) or Calendar.getInstance(TimeZone timezone) or Calendar.getInstance(Locale locale), it returns the "calendar used by the corresponding time zone (zone) or region (local), etc.".
For example, if it is Japan, the JapaneseImperialCalendar object is returned.
Refer to the following code:
public static Calendar getInstance(){ // Call createCalendar() to create calendar Calendar = createCalendar(TimeZone.getDefaultRef(), Locale.getDefault()); cal.sharedZone = true; return cal;}public static Calendar getInstance(TimeZone zone){ // Call createCalendar() to create calendar return createCalendar(zone, Locale.getDefault());}public static Calendar getInstance(Locale aLocale) { // Call createCalendar() to create calendar Calendar = createCalendar(TimeZone.getDefaultRef(), aLocale); cal.sharedZone = true; return cal;}public static Calendar getInstance(TimeZone zone, Locale aLocale){ // Call createCalendar() to create calendar return createCalendar(zone, aLocale);}private static Calendar createCalendar(TimeZone zone, Locale aLocale){ // (01) If the region is "th", return the BuddhaCalendar object// (02) If the region is "JP", it returns the JapaneseImperialCalendar object if ("th".equals(aLocale.getLanguage()) && ("TH".equals(aLocale.getCountry()))) { return new sun.util.BuddhistCalendar(zone, aLocale); } else if ("JP".equals(aLocale.getVariant()) && "JP".equals(aLocale.getCountry())) && "ja".equals(aLocale.getLanguage()))) { return new JapaneseImperialCalendar(zone, aLocale); } // (03) Otherwise, return the GregorianCalendar object. return new GregorianCalendar(zone, aLocale); }After we get the Calendar instance, we can manipulate the calendar through some column methods provided by Calendar.
Part 2 Principles and Thoughts of Calendar
When we use Calendar, we are nothing more than operating the fields of Calendar's "year, month, day, week, hour, minute, and second". Below, we learn the source, definition and calculation methods of these fields.
1. Calendar The source of each field value
When we use Calendar, we simply use information such as "year, month, day, week, hour, minute, and second". So how did it do it? Essentially, Calendar saves a time. The following definition:
// time is the current time, in milliseconds. // It is the difference between the current time distance "January 1, 1970, 0:00:00 GMT". protected long time;
Calendar calculates information such as "Calendar's year, month, day, week, hour, minute, second" based on time.
2. Definition and initialization of each field of Calendar
Calendar's "year, month, day, week, hour, minute, and second" information has a total of 17 fields.
We use Calendar, which is nothing more than these 17 fields. Their definitions are as follows:
(Field 0) public final static int ERA = 0;
Description: Era.
Value: can only be 0 or 1. 0 means BC ("before Christ", that is, BC), 1 means AD (Latin "Anno Domini", that is, AD).
(Field 1) public final static int YEAR = 1;
Description: Year.
(Field 2) public final static int MONTH = 2;
Description: Monthly value: can be JANUARY, FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER, UNDECIMBER.
The first month of this is JANUARY, which is 0.
(Field 3) public final static int WEEK_OF_YEAR = 3;
Note: The current date corresponds to the week of the year. The value for the first week of the year is 1.
(Field 4) public final static int WEEK_OF_MONTH = 4;
Note: The current date corresponds to the week of the month. The value for the first week of a month is 1.
(Field 5) public final static int DATE = 5;
Description: Day. The value for the first day of a month is 1.
(Field 5) public final static int DAY_OF_MONTH = 5;
Note: Same as "DATE", means "Day".
(Field 6) public final static int DAY_OF_YEAR = 6;
Note: What day does the current date correspond to this year? The value for the first day of the year is 1.
(Field 7) public final static int DAY_OF_WEEK = 7;
Description: What day of the week.
Values: can be SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY and SATURDAY.
Among them, SUNDAY is 1, MONDAY is 2, and so on.
(Field 8) public final static int DAY_OF_WEEK_IN_MONTH = 8;
Description: What week of the current month.
Values: DAY_OF_MONTH 1 to 7 always correspond to DAY_OF_WEEK_IN_MONTH 1; 8 to 14 always correspond to DAY_OF_WEEK_IN_MONTH 2, and so on.
(Field 9) public final static int AM_PM = 9;
Description: Morning or afternoon value: can be AM or PM. AM is 0, indicating morning; PM is 1, indicating afternoon.
(Field 10) public final static int HOUR = 10;
Description: Indicates the hour of the day.
HOUR is used for 12-hour clocks (0 - 11). Noon and midnight are represented by 0, not 12.
(Field 11) public final static int HOUR_OF_DAY = 11;
Description: Indicates the hour of the day.
HOUR_OF_DAY is used for 24-hour clock. For example, at the moment of 10:04:15.250 PM, HOUR_OF_DAY is 22.
(Field 12) public final static int MINUTE = 12;
Description: What minute of an hour?
For example, at the moment of 10:04:15.250 PM, MINUTE is 4.
(Field 13) public final static int SECOND = 13;
Description: What second in a minute.
For example, at the moment of 10:04:15.250 PM, SECOND is 15.
(Field 14) public final static int MILLISECOND = 14;
Description: What milliseconds of a second.
For example, at the moment of 10:04:15.250 PM, MILLISECOND is 250.
(Field 15) public final static int ZONE_OFFSET = 15;
Note: Milliseconds indicate the approximate offset from GMT.
(Field 16) public final static int DST_OFFSET = 16;
Description: Milliseconds indicate the offset of daylight saving time.
public final static int FIELD_COUNT = 17;
These 17 fields are saved in the int array. Definition is as follows:
// Save the array of these 17 fields protected int fields[];// The array definition function protected Calendar(TimeZone zone, Locale aLocale){ // Initialize "fields array" fields = new int[FIELD_COUNT]; isSet = new boolean[FIELD_COUNT]; stamp = new int[FIELD_COUNT]; this.zone = zone; setWeekCountData(aLocale);}protected Calendar(TimeZone zone, Locale aLocale) This is the constructor of Calendar. It will be called by its subclass constructor, thus creating a new array of "save 17 field data of Calendar".
3. Calendar Calendar The calculation of each field value
Let’s take get(int field) as an example to briefly explain the calculation and operation of Calendar’s 17 fields. get(int field) is to get the value of the "field" field. Its definition is as follows:
public int get(int field) { // Calculate the values of each field complete(); // Return the value of the field field return internalGet(field);} Note: The code of get(int field) is very simple. First, calculate the values of each field through complete(), and then return "the value of the field field" through internalGet(field).
The function of complete() is to calculate the values of each field of Calendar. It is defined in Calendar.java, the code is as follows:
protected void complete(){ if (!isTimeSet) updateTime(); if (!areFieldsSet || !areAllFieldsSet) { computeFields(); // fills in unset fields areAllFieldsSet = areFieldsSet = true; }}private void updateTime() { computeTime(); isTimeSet = true;}updateTime() The computeTime() called is defined in the implementation class of Calendar.java. Below, I list the implementation of computeTime() in GregorianCalendar.java: protected void computeTime() { // In non-lenient mode, perform brief checking of calendar // fields which have been set externally. Through this // checking, the field values are stored in originalFields[] // to see if any of them are normalized later. if (!isLenient()) { if (originalFields == null) { originalFields = new int[FIELD_COUNT]; } for (int field = 0; field < FIELD_COUNT; field++) { int value = internalGet(field); if (isExternallySet(field)) { // Quick validation for any out of range values if (value < getMinimum(field) || value > getMaximum(field)) { throw new IllegalArgumentException(getFieldName(field)); } } originalFields[field] = value; } } // Let the super class determine which calendar fields to be // used to calculate the time. int fieldMask = selectFields(); // The year defaults to the epoch start. We don't check // fieldMask for YEAR because YEAR is a mandatory field to // determine the date. int year = isSet(YEAR) ? internalGet(YEAR) : EPOCH_YEAR; int era = internalGetEra(); if (era == BCE) { year = 1 - year; } else if (era != CE) { // Even in lenient mode we disallow ERA values other than CE & BCE. // (The same normalization rule as add()/roll() could be // applied here in lenient mode. But this checking is kept // unchanged for compatibility as of 1.5.) throw new IllegalArgumentException("Invalid era"); } // If year is 0 or negative, we need to set the ERA value later. if (year <= 0 && !isSet(ERA)) { fieldMask |= ERA_MASK; setFieldsComputed(ERA_MASK); } // Calculate the time of day. We rely on the convention that // an UNSET field has 0. long timeOfDay = 0; if (isFieldSet(fieldMask, HOUR_OF_DAY)) { timeOfDay += (long) internalGet(HOUR_OF_DAY); } else { timeOfDay += internalGet(HOUR); // The default value of AM_PM is 0 which designates AM. if (isFieldSet(fieldMask, AM_PM)) { timeOfDay += 12 * internalGet(AM_PM); } } timeOfDay *= 60; timeOfDay += internalGet(MINUTE); timeOfDay *= 60; timeOfDay += internalGet(SECOND); timeOfDay *= 1000; timeOfDay += internalGet(MILLISECOND); // Convert the time of day to the number of days and the // millisecond offset from midnight. long fixedDate = timeOfDay / ONE_DAY; timeOfDay %= ONE_DAY; while (timeOfDay < 0) { timeOfDay += ONE_DAY; --fixedDate; } // Calculate the fixed date since January 1, 1 (Gregorian). calculateFixedDate: { long gfd, jfd; if (year > gregorianCutoverYear && year > gregorianCutoverYearJulian) { gfd = fixedDate + getFixedDate(gcal, year, fieldMask); if (gfd >= gregorianCutoverDate) { fixedDate = gfd; break calculatedFixedDate; } jfd = fixedDate + getFixedDate(getJulianCalendarSystem(), year, fieldMask); } else if (year < gregorianCutoverYear && year < gregorianCutoverYearJulian) { jfd = fixedDate + getFixedDate(getJulianCalendarSystem(), year, fieldMask); if (jfd < gregorianCutoverDate) { fixedDate = jfd; break calculatedFixedDate; } gfd = fixedDate + getFixedDate(gcal, year, fieldMask); } else { gfd = fixedDate + getFixedDate(gcal, year, fieldMask); jfd = fixedDate + getFixedDate(getJulianCalendarSystem(), year, fieldMask); } // Now we have to determine which calendar date it is. if (gfd >= gregorianCutoverDate) { if (jfd >= gregorianCutoverDate) { fixedDate = gfd; } else { // The date is in an "overlapping" period. No way // to disambiguate it. Determine it using the // previous date calculation. if (calsys == gcal || calsys == null) { fixedDate = gfd; } else { fixedDate = jfd; } } } else { if (jfd < gregorianCutoverDate) { fixedDate = jfd; } else { // The date is in a "missing" period. if (!isLenient()) { throw new IllegalArgumentException("the specified date doesn't exist"); } // Take the Julian date for compatibility, which // will produce a Gregorian date. fixedDate = jfd; } } } // millis represents local wall-clock time in milliseconds. long millis = (fixedDate - EPOCH_OFFSET) * ONE_DAY + timeOfDay; // Compute the time zone offset and DST offset. There are two potential // ambiguities here. We'll assume a 2:00 am (wall time) switchover time // for discussion purposes here. // 1. The transition into DST. Here, a designed time of 2:00 am - 2:59 am // can be in standard or in DST depending. However, 2:00 am is an invalid // representation (the representation jumps from 1:59:59 am Std to 3:00:00 am DST). // We assume standard time. // 2. The transition out of DST. Here, a designed time of 1:00 am - 1:59 am // can be in standard or DST. Both are valid representations (the rep // jumps from 1:59:59 DST to 1:00:00 Std). // Again, we assume standard time. // We use the TimeZone object, unless the user has explicitly set the ZONE_OFFSET // or DST_OFFSET fields; then we use those fields. TimeZone zone = getZone(); if (zoneOffsets == null) { zoneOffsets = new int[2]; } int tzMask = fieldMask & (ZONE_OFFSET_MASK|DST_OFFSET_MASK); if (tzMask != (ZONE_OFFSET_MASK|DST_OFFSET_MASK)) { if (zone instanceof ZoneInfo) { ((ZoneInfo)zone).getOffsetsByWall(millis, zoneOffsets); } else { int gmtOffset = isFieldSet(fieldMask, ZONE_OFFSET) ? internalGet(ZONE_OFFSET) : zone.getRawOffset(); zone.getOffsets(millis - gmtOffset, zoneOffsets); } } if (tzMask != 0) { if (isFieldSet(tzMask, ZONE_OFFSET)) { zoneOffsets[0] = internalGet(ZONE_OFFSET); } if (isFieldSet(tzMask, DST_OFFSET)) { zoneOffsets[1] = internalGet(DST_OFFSET); } } // Adjust the time zone offset values to get the UTC time. millis -= zoneOffsets[0] + zoneOffsets[1]; // Set this calendar's time in milliseconds time = millis; int mask = computeFields(fieldMask | getSetStateFields(), tzMask); if (!isLenient()) { for (int field = 0; field < FIELD_COUNT; field++) { if (!isExternallySet(field)) { continue; } if (originalFields[field] != internalGet(field)) { // Restore the original field values System.arraycopy(originalFields, 0, fields, 0, fields.length); throw new IllegalArgumentException(getFieldName(field)); } } } setFieldsNormalized(mask);} Next, let's take a look at the definition of internalGet(field). as follows:
protected final int internalGet(int field) { return fields[field];} From this we can see that get(int field) ultimately returns the value through internalGet(int field).
internalGet(int field) actually returns the field element in the field array. This corresponds to the 17 elements of Calendar!
In short, what we need to understand is: Calendar calculates "year, month, day, hour, minute, second" and so on based on a time (milliseconds), so as to facilitate our operations on "year, month, day, hour, minute, second" and so on. Below, we introduce the relevant operation functions provided by Calendar below.
Part 3 Calendar function interface
1. Common interface of 17 fields of Calendar
These 17 fields of Calendar support the following public function interface. For examples of using these common interfaces, please refer to the testAllCalendarSections() function in the CalendarTest.java example.
(1) getMaximum(int field)
Function: Get the "maximum value of the field". Note "Compare the difference between it and getActualMaximum()". Example: In terms of the "MONTH" field. How to use it is:
// Get Calendar instance Calendar cal = Calendar.getInstance();// Get the maximum value of MONTH int max = cal.getMaximum(Calendar.MONTH);
To get the maximum value of other fields, you only need to replace the corresponding MONTH in the example with other field names.
(2) getActualMaximum(int field)
Function: Get the "maximum value of this field under the current date". Example: In terms of the "MONTH" field. How to use it is:
// Get Calendar instance Calendar cal = Calendar.getInstance();// Get the maximum value of the current MONTH int max = cal.getActualMaximum(Calendar.MONTH);
To get the maximum value of other fields, you only need to replace the corresponding MONTH in the example with other field names.
Note: Compare the difference between getActualMaximum() and getMaximum(). Refer to the comparison example below,
A. The "field maximum value" obtained by getMaximum() refers to the "field maximum value" obtained in all dates combined.
For example, the purpose of getMaximum(Calendar.DATE) is to "get the 'maximum of day'". Based on all dates, a maximum of 31 days per month is obtained. Therefore, the return value of getMaximum(Calendar.DATE) is "31"!
B. getActualMaximum() gets the "maximum value of this field at the current date".
For example, when the date is 2013-09-01, getActualMaximum(Calendar.DATE) is to get "maximum of day" and is "30". The current date is September, and September is only 30 days. Therefore, the return value of getActualMaximum(Calendar.DATE) is "30"!
(3) getMinimum(int field)
Function: Get the "minimum value of the field". Note "Compare the difference between it and getActualMinimum()". Example: In terms of the "MONTH" field. How to use it is:
// Get Calendar instance Calendar cal = Calendar.getInstance();// Get the minimum value of MONTH int min = cal.getMinimum(Calendar.MONTH);
To get the minimum value of other fields, you only need to replace the corresponding MONTH in the example with other field names.
(4) getActualMinimum(int field)
Function: Get the "minimum value of this field under the current date". Example: In terms of the "MONTH" field. Use method: // Get Calendar instance Calendar cal = Calendar.getInstance();// Get the minimum value of MONTH int min = cal.getMinimum(Calendar.MONTH);
To get the minimum value of other fields, you only need to replace the corresponding MONTH in the example with other field names.
Note: In Java's default Calendar, although getMinimum() and getActualMinimum() have different meanings; however, their return values are the same. Because the default of Calendar is to return the GregorianCalendar object, in GregorianCalendar.java, getMinimum() and getActualMinimum() return the same value.
(5) get(int field)
Function: Get the "current value of the field". Gets the current value of the field field. Example: In terms of the "MONTH" field. The method of "get the current value of MONTH" is:
// Get Calendar instance Calendar cal = Calendar.getInstance();// Get the current MONTH value of "cal calendar" int MONTH = cal.get(Calendar.MONTH);
To get the current value of other fields, you only need to replace the corresponding MONTH in the example with other field names.
(6) set(int field, int value)
Function: Set the "current value of the field". Set the current value of the field field to value Example: In terms of the "MONTH" field. The method of "setting the current value of MONTH" is:
// Get Calendar instance Calendar cal = Calendar.getInstance();// Set the current MONTH value of "cal calendar" to 1988 cal.set(Calendar.MONTH, 1988);
illustrate:
A. 1988 is the current value of the MONTH you want to set. This setting value must be an integer.
B. To set the current value of other fields, you only need to replace the corresponding MONTH in the example with other field names.
(7) add(int field, int value)
Function: Add a value to the "current value of the field". Add a value to the current value of the field field. Example: In terms of the "MONTH" field. The method is as follows:
// Get Calendar instance and set the date to "2013-09-01" Calendar cal = Calendar.getInstance();cal.set(Calendar.YEAR, 2013);cal.set(Calendar.MONTH, 8);cal.set(Calendar.DATE, 1);// Add -10" cal.add(Calendar.MONTH, -10);
illustrate:
A. -10 is the added value.
The added value can be a positive or negative number.
A positive number indicates that the date is increased, and a negative number indicates that the date is decreased.
Assumption: Now the value of cal is "2013-09-01", now we increase the MONTH field value -10. The result is: "2012-10-01".
Why is this happening? "2013-09-01" increases -10, which means reducing the date forward by 10 months; the result is "2012-10-01".
B. Among the 17 fields of Calendar: Except for rolling back Calendar.ZONE_OFFSET, an IllegalArgumentException exception will be thrown; other fields support this operation.
C. To set the current value of other fields, you only need to replace the corresponding MONTH in the example with other field names.
(8) roll(int field, int value)
Function: Roll back the "current value of the field" Example: Take the "MONTH" field. The method of "rolling back the current value of MONTH" is:
// Get Calendar instance and set the date to "2013-09-01" Calendar cal = Calendar.getInstance();cal.set(Calendar.YEAR, 2013);cal.set(Calendar.MONTH, 8);cal.set(Calendar.DATE, 1);// "Scroll forward 10" cal.roll(Calendar.MONTH, -10);
illustrate:
A. -10 is the rollback value.
When the rollback value is a negative number, it means rolling the current field forward;
When the rollback value is a positive number, it means rolling the current field backward.
When rolling back a field in Calendar, do not change the larger field!
This is the basis difference between roll() and add()! add() may change larger fields, such as "Using add() to modify the 'MONTH' field, it may cause a change in the 'YEAR' field"; but roll() will not change larger fields, such as "Using roll() to modify the 'MONTH' field, it will not cause a change in the 'YEAR' field."
Assumption: Now the value of cal is "2013-09-01", now we increase the MONTH field value -10. The result is: "2013-10-01".
Why is this happening? This is because "rollback" means "rolling back and forth between the minimum and the maximum". In this example, MONTH is September, and the previous rollback is 10, and the value obtained is October, but roll() will not change the field "larger than MONTH", so the YEAR field will not change. So the result is "2013-10-01".
B. Among the 17 fields of Calendar: Except for rolling back Calendar.ZONE_OFFSET, an IllegalArgumentException exception will be thrown; other fields support this operation.
C. To set the current value of other fields, you only need to replace the corresponding MONTH in the example with other field names.
(9) clear(int field)
Function: Clear the "current value of the field". The so-called clearing actually sets the value of "field" to 0; if the minimum value of field is 1, it is set to 1. Example: In terms of the "MONTH" field. The method of "clear MONTH" is:
// Get Calendar instance and set the date to "September" Calendar cal = Calendar.getInstance();cal.set(Calendar.MONTH, 9);// Clear MONTHcal.clear(Calendar.MONTH);
To clear other fields, you only need to replace the corresponding MONTH in the example with other field names.
(10) isSet(int field)
Function: determine whether “field field” is set. If clear() is called, the field becomes "no set state". Example: In terms of the "MONTH" field. The method of "judging whether MONTH is set" is:
// Get Calendar instance Calendar cal = Calendar.getInstance();// Determine whether MONTH is set boolean bset = cal.isSet(Calendar.MONTH);
To determine other fields, you only need to replace the corresponding MONTH in the example with other field names.
2. Other functions of Calendar
(1) Date comparison function
Calendar's comparison function mainly includes the following:
// Compare whether the date, time zone and other content of "current Calendar object" and "calendar" are equal. boolean equals(Object object)// Whether the current Calendar object is earlier than calendarboolean before(Object calendar)// Whether the current Calendar object is later than calendarboolean after(Object calendar)// Compare "current Calendar object" and "calendar". // If earlier than "calendar", return -1// If equal, return 0// If later than "calendar", return 1int comparedTo(Calendar anotherCalendar)
For examples of using these functions, please refer to the testComparatorAPIs() function in the CalendarTest.java example.
Example: Assume that cal1 and cal2 are both two objects of Calendar.
//Their usage methods are as follows boolean isEqual = cal1.equals(cal2);boolean isBefore = cal1.before(cal2);boolean isAfter = cal1.after(cal2);int icompare = cal1.compareTo(cal2);
(2) "Tolerance" function
// Set "Calendar tolerance" void setLenient(boolean value)// Get "Calendar tolerance" boolean isLenient()
For examples of using these functions, please refer to the testLenientAPIs() function in the CalendarTest.java example.
illustrate:
Calendar has two modes that interpret calendar fields, namely lenient and non-lenient.
A. When Calendar is in lenient mode, it can accept values within a larger range than the range of calendar fields it generates. When Calendar recalculates the calendar field values so that these values are returned by get(), all calendar fields are normalized.
For example, GregorianCalendar in lenient mode interprets MONTH == JANUARY, DAY_OF_MONTH == 32 as February 1.
B. When Calendar is in non-lenient mode, if there is any inconsistency in its calendar field, it will throw an exception.
For example, GregorianCalendar always generates a DAY_OF_MONTH value between 1 and the length of the month. If any field values outside the range have been set, GregorianCalendar in non-lenient mode throws an exception when calculating the time or calendar field values.
Note: The exception in step (02) will not be thrown when using set(), but will only be thrown in functions such as get(), getTimeInMillis(), getTime(), add() and roll(). Because set() just sets a modification flag, and methods such as get() will cause time recalculation, and an exception will be thrown at this time!
(3) "Year, Month, Day, TimeZone, MilliSecond functions
// Set "year, month, day," final void set(int year, month, day, time, time, int second)// Set "year, month, day, time, time, int second)// Set "year, month, day, time, minute, second" final void set(int year, month, day, time, minute, second)// Get the date corresponding to Calendar final Date getTime()// Set Calendar to datefinal void setTime(Date date)// Get the time zone corresponding to Calendar TimeZone getTimeZone()// Set the time zone corresponding to Calendar void setTimeZone(TimeZone timezone)// Get the milliscondes value corresponding to Calendar, which is the milliseconds of "Calendar current date" distance from "1970-01-01 0:00:00 GMT" long getTimeInMillis()// Set the milliscondes value corresponding to Calendar void setTimeInMillis(long milliseconds)
For examples of using these functions, please refer to the testTimeAPIs() function in the CalendarTest.java example.
(4) Other operations
//Clone CalendarObject clone()// Get "What day of the week is the first day of the week". For example, in the United States, this day is SUNDAY, and in France, this day is MONDAY. int getFirstDayOfWeek()// Set "What day of the week is the first day of the week". For example, in the United States, this day is SUNDAY, and in France, this day is MONDAY. void setFirstDayOfWeek(int value)// Gets the minimum number of days required for the first week of the year. For example, if the first week contains the first day of the first month of the year, this method will return 1. If the minimum number of days must be a full week, this method returns 7. int getMinimalDaysInFirstWeek()// Sets the minimum number of days required for the first week of the year, for example, if the first week contains the first day of the first month of the year, this method is called with a value of 1. If the minimum number of days must be a full week, this method is called with a value of 7. void setMinimalDaysInFirstWeek(int value)
For examples of using these functions, please refer to the testOtherAPIs() function in the CalendarTest.java example.
Part 4 Calendar usage example
Below, we learn the API using Calendar through examples. The source code of CalendarTest.java is as follows:
import java.util.Date;import java.util.Calendar;import java.util.TimeZone;import java.util.Random;public class CalendarTest { public static void main(String[] args) { // Test Calendar's "public function interface with 17 fields" testAllCalendarSections() ; // Test Calendar's "comparative interface" testComparatorAPIs() ; // Test Calendar's "comparative interface" testLenientAPIs() ; // Test Calendar's Date, TimeZone, MilliSecond and other related functions testTimeAPIs(); // Test Calendar's clone(), getFirstDayOfWeek() and other interfaces testOtherAPIs(); } /** * Test "Calendar's field" * * @param cal -- Calendar object* @param field -- "Calendar field" to be tested. Can be the following values: * Calendar.YEAR, Calendar.MONTH, Calendar.DATE, ... etc* @param title -- Title */ private static void testSection(Calendar cal, int field, String title) { final Random random = new Random(); final Date date = cal.getTime(); final int min = cal.getMinimum(field); // Get "field minimum value" final int max = cal.getMaximum(field); // Get "field maximum value" final int actualMin = cal.getActualMinimum(field); // Get "the minimum value of the field under the current date" final int actualMax = cal.getActualMaximum(field); // Get "the maximum value of the field under the current date" // Get "the current value of the field" final int ori = cal.get(field); // Set "the current value of the field" and get "the value after setting" final int r1 = random.nextInt(max); cal.set(field, r1); final int set = cal.get(field); try { // Roll back "the current value of the field": Roll back between "the minimum value of the field" and "the maximum value of the field". // "Roller value" can be positive or negative. cal.roll(field, -max); } catch (IllegalArgumentException e) { // When field == Calendar.ZONE_OFFSET, the exception will be thrown! e.printStackTrace(); } final int roll = cal.get(field); // Get a random value final int sign = ( random.nextInt(2) == 1) ? 1 : -1; final int r2 = sign * random.nextInt(max); try { // Add "current value of field" and get "new current field value" // The "parameter value" of add can be positive or negative. cal.add(field, r2); } catch (IllegalArgumentException e) { // When field == Calendar.ZONE_OFFSET, the exception will be thrown! e.printStackTrace(); } final int add = cal.get(field); // Print field information System.out.printf("%s:/n/trang is [%d - %d] actualRange is [%d - %d]. original=%d, set(%d)=%d, roll(%d)=%d, add(%d)=%d/n", title, min, max, actualMin, actualMax, ori, r1, set, -max, roll, r2, add); } /** * Test Calendar's "public function interface with 17 fields" */ private static void testAllCalendarSections() { // 00. ERA field testSection(Calendar.getInstance(), Calendar.ERA, "Calendar.ERA"); // 01. YEAR field testSection(Calendar.getInstance(), Calendar.YEAR, "Calendar.YEAR"); // 02. MONTH field testSection(Calendar.getInstance(), Calendar.MONTH, "Calendar.MONTH"); // 03. WEEK_OF_YEAR Field testSection(Calendar.getInstance(), Calendar.WEEK_OF_YEAR, "Calendar.WEEK_OF_YEAR"); // 04. WEEK_OF_MONTH Field testSection(Calendar.getInstance(), Calendar.WEEK_OF_MONTH, "Calendar.WEEK_OF_MONTH"); // 05. DATE field testSection(Calendar.getInstance(), Calendar.DATE, "Calendar.DATE"); // 06. DAY_OF_MONTH Field testSection(Calendar.getInstance(), Calendar.DAY_OF_MONTH, "Calendar.DAY_OF_MONTH"); // 07. DAY_OF_YEAR field testSection(Calendar.getInstance(), Calendar.DAY_OF_YEAR, "Calendar.DAY_OF_YEAR"); // 08. DAY_OF_WEEK field testSection(Calendar.getInstance(), Calendar.DAY_OF_WEEK, "Calendar.DAY_OF_WEEK"); // 09. DAY_OF_WEEK_IN_MONTH field testSection(Calendar.getInstance(), Calendar.DAY_OF_WEEK_IN_MONTH, "Calendar.DAY_OF_WEEK_IN_MONTH"); // 10. AM_PM field testSection(Calendar.getInstance(), Calendar.AM_PM, "Calendar.AM_PM"); // 11. HOUR field testSection(Calendar.getInstance(), Calendar.HOUR, "Calendar.HOUR"); // 12. HOUR_OF_DAY field testSection(Calendar.getInstance(), Calendar.HOUR_OF_DAY, "Calendar.HOUR_OF_DAY"); // 13. MINUTE field testSection(Calendar.getInstance(), Calendar.MINUTE, "Calendar.MINUTE"); // 14. SECOND field testSection(Calendar.getInstance(), Calendar.SECOND, "Calendar.SECOND"); // 15. MILLISECOND Field testSection(Calendar.getInstance(), Calendar.MILLISECOND, "Calendar.MILLISECOND"); // 16. ZONE_OFFSET Field testSection(Calendar.getInstance(), Calendar.ZONE_OFFSET, "Calendar.ZONE_OFFSET"); } /** * Test Calendar's "Compare Interface" */ private static void testComparatorAPIs() { // Create new cal1, and the time was 1988 Calendar cal1 = Calendar.getInstance(); cal1.set(Calendar.YEAR, 1988); // Create cal2, and the time is 2000 Calendar cal2 = Calendar.getInstance(); cal2.set(Calendar.YEAR, 2000); // Create cal3, which is a cloned object of cal111 Calendar cal3 = (Calendar)cal1.clone(); // equals determine whether the contents of "time, time zone, etc." of cal1 and cal2 are equal boolean isEqual12 = cal1.equals(cal2); // equals determine whether the contents of "time, time zone, etc." of cal1 and cal3 are equal boolean isEqual13 = cal1.equals(cal3); // cal1是否比cal2早boolean isBefore = cal1.before(cal2); // cal1是否比cal2晚boolean isAfter = cal1.after(cal2); // 比较cal1和cal2 // (01) 若cal1 早于cal2,返回-1 // (02) 若cal1 等于cal2,返回0 // (03) 若cal1 晚于cal2,返回1 int icompare = cal1.compareTo(cal2); System.out.printf("/ntestComparatorAPIs: isEuqal12=%s, isEqual13=%s, isBefore=%s, isAfter=%s, icompare=%s/n", isEqual12, isEqual13, isBefore, isAfter, icompare); } /** * 测试Calendar的“比较接口” */ private static void testLenientAPIs() { Calendar cal = Calendar.getInstance(); // 获取默认的“宽容度”。返回true boolean oriLenient = cal.isLenient(); // MONTH值只能是“0-11”,这里越界。但是由于当前cal是宽容的,所以不会抛出异常cal.set(Calendar.MONTH, 50); // 设置“宽容度”为false。 cal.setLenient(false); // 获取设置后的“宽容度” boolean curLenient = cal.isLenient(); try { // MONTH值只能是“0-11”,这里越界。而且当前cal是不宽容的,所以会产生异常。 // 但是,异常到下次计算日期时才会抛出。即,set()中不回抛出异常,而要等到get()中才会抛出异常cal.set(Calendar.MONTH, 50); // 此时,对cal进行读取。读取会导致重新计算cal的值,所以此时抛出异常! int m2 = cal.get(Calendar.MONTH); } catch (IllegalArgumentException e) { e.printStackTrace(); } System.out.printf("/ntestLenientAPIs: oriLenient=%s, curLenient=%s/n", oriLenient, curLenient); } /** * 测试Calendar的Date、TimeZone、MilliSecond等相关函数*/ private static void testTimeAPIs() { Calendar cal = Calendar.getInstance(); // 设置cal的时区为“GMT+8” cal.setTimeZone(TimeZone.getTimeZone("GMT+8")); // 获取当前的cal时区TimeZone timezone = cal.getTimeZone(); // 设置milliseconds cal.setTimeInMillis(1279419645742l); // 获取milliseconds long millis = cal.getTimeInMillis(); // 设置milliseconds之后,时间也改变了。 // 获取cal对应的日期Date date = cal.getTime(); // 设置时间为“1988-08-08” cal.set(1988, 08, 08); // 设置时间为“1999-09-09 09:09” cal.set(1999, 09, 09, 9, 9); // 设置时间为“2000-10-10 10:10:10” cal.set(2000, 10, 10, 10, 10, 10); System.out.printf("/ntestTimeAPIs: date=%s, timezone=%s, millis=%s/n", date, timezone, millis); } /** * 测试Calendar的clone(),getFirstDayOfWeek()等接口*/ private static void testOtherAPIs() { Calendar cal = Calendar.getInstance(); // 克隆cal Calendar clone = (Calendar)cal.clone(); // 设置为2013-01-10。 // 注:2013-01-01 为“星期二”,2013-01-06为“星期天”, clone.set(Calendar.YEAR, 2013); clone.set(Calendar.MONTH, 0); clone.set(Calendar.DATE, 10); // 设置“本年的第一个星期最少包含1天”。 // 则2013-01-10属于第2个星期clone.setMinimalDaysInFirstWeek(1); int m1 = clone.getMinimalDaysInFirstWeek(); int index1 = clone.get(Calendar.WEEK_OF_YEAR); // 设置“本年的第一个星期最少包含7天”。 // 则2013-01-10属于第1个星期clone.setMinimalDaysInFirstWeek(7); int m2 = clone.getMinimalDaysInFirstWeek(); int index2 = clone.get(Calendar.WEEK_OF_YEAR); // 设置“每周的第一天是星期几”。 clone.setFirstDayOfWeek(Calendar.WEDNESDAY); // 获取“每周的第一天是星期几”。 int firstdayOfWeek = clone.getFirstDayOfWeek(); System.out.printf("/ntestOtherAPIs: firstdayOfWeek=%s, [minimalDay, WeekOfYear]={(%s, %s), (%s, %s)} %s/n", firstdayOfWeek, m1, index1, m2, index2, clone.getTime()); }}第五部分自定义的Calendar接口示例
这些接口在写日历程序时可能会用到。
源代码如下(CalendarSelfDefineTest.java):
import java.util.Calendar;/** * 根据Calendar的API封装的一些常用函数*/public class CalendarSelfDefineTest { public static void main(String[] args) { Calendar cal = Calendar.getInstance(); // 设置日期为“2013-09-18” cal.set(2013, Calendar.SEPTEMBER, 18); // 获取“年” System.out.printf("year: %s/n", getYear(cal) ); // 获取“月” System.out.printf("month: %s/n", getMonth(cal) ); // 获取“上月” System.out.printf("previcou month: %s/n", getLastMonth(cal) ); // 获取“下月” System.out.printf("next month: %s/n", getNextMonth(cal) ); // 获取“日” System.out.printf("day: %s/n", getDay(cal) ); // 获取Cal对应星期几System.out.printf("weekday: %s/n", getWeekDay(cal) ); // 本月天数System.out.printf("Current Month days: %s/n", getMonthDays(cal) ); // 上月天数System.out.printf("Previcous Month days: %s/n", getPrevMonthDays(cal) ); // 下月天数System.out.printf("Next Month days: %s/n", getNextMonthDays(cal) ); // 获取当月第一天的星期几System.out.printf("First day' weekday : %s/n", getFirstDayWeekday(cal) ); // 获取当前月最后一天的星期几System.out.printf("Last day' weekday : %s/n", getLastDayWeekday(cal) ); // 获取上月最后一天的星期几System.out.printf("PrevMonth Last day' weekday: %s/n", getLastDayWeekdayOfPrevMonth(cal) ); // 获取下月第一天的星期几System.out.printf("NextMonth First day' weekday: %s/n", getFirstDayWeekdayOfNextMonth(cal) ); } /** * 获取“年” * * @return 例如,2013-09-18,则返回2013 */ public static int getYear(Calendar cal) { return cal.get(Calendar.YEAR); } /** * 获取“月” * * @return 返回值可以为以下值: * JANUARY, FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER, UNDECIMBER。 * 其中第一个月是JANUARY,它为0。 * * 例如,2013-09-18,则返回8 */ public static int getMonth(Calendar cal) { return cal.get(Calendar.MONTH); } /** * 获取“上一个月” * * @return 返回值可以为以下值: * JANUARY, FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER, UNDECIMBER。 * 其中第一个月是JANUARY,它为0。 * * 例如,2012-01-12的上一个月是“11”(即DECEMBER)。 */ public static int getLastMonth(Calendar cal) { return (cal.get(Calendar.MONTH) + 11) % 12; } /** * 获取“下一个月” * * @return 返回值可以为以下值: * JANUARY, FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER, UNDECIMBER。 * 其中第一个月是JANUARY,它为0。 * * 例如,2013-12-12的下一个月是“1”(即DECEMBER)。 */ public static int getNextMonth(Calendar cal) { return (cal.get(Calendar.MONTH) + 13) % 12; } /** * 获取“日” * * @return 例如,2013-09-18,则返回18 * */ public static int getDay(Calendar cal) { return cal.get(Calendar.DATE); } /** * 获取“本月的天数” * * @return 例如,2013-09-18,则返回30 * */ public static int getMonthDays(Calendar cal) { return cal.getActualMaximum(Calendar.DATE); } /** * 获取“上一个月的天数” * * @return 例如,2013-01-18,则返回31 (因为2012-12有31天) * */ public static int getPrevMonthDays(Calendar cal) { Calendar tmpCal = (Calendar)cal.clone(); // 克隆cal。后面对tmpCal操作,就不会改变cal tmpCal.add(Calendar.MONTH, -1); // 设为“上一个月” return tmpCal.getActualMaximum(Calendar.DATE); } /** * 获取“下一个月的天数” * * @return 例如,2013-12-18,则返回31 (因为2014-01有31天) * */ public static int getNextMonthDays(Calendar cal) { Calendar tmpCal = (Calendar)cal.clone(); // 克隆cal。后面对tmpCal操作,就不会改变cal tmpCal.add(Calendar.MONTH, 1); // 设为“下一个月” return tmpCal.getActualMaximum(Calendar.DATE); } /** * 获取Cal对应星期几* * @return 返回“星期几”,可以为以下值: * SUNDAY、MONDAY、TUESDAY、WEDNESDAY、THURSDAY、FRIDAY 和SATURDAY。 * SUNDAY为1,MONDAY为2,依次类推。 * 例如,2013-09-18(星期三),则返回4 */ public static int getWeekDay(Calendar cal) { return cal.get(Calendar.DAY_OF_WEEK); } /** * 获取当月第一天对应星期几* * @return SUNDAY为1,MONDAY为2,依次类推。 */ public static int getFirstDayWeekday(Calendar cal) { Calendar tmpCal = (Calendar)cal.clone(); // 克隆cal。后面对tmpCal操作,就不会改变cal tmpCal.set(Calendar.DATE, 1); // 把日期设置为当月第一天return tmpCal.get(Calendar.DAY_OF_WEEK); } /** * 获取当前月最后一天对应星期几* * @return SUNDAY为1,MONDAY为2,依次类推。 */ public static int getLastDayWeekday(Calendar cal) { Calendar tmpCal = (Calendar)cal.clone(); // 克隆cal。后面对tmpCal操作,就不会改变cal tmpCal.set(Calendar.DATE, 1); // 把日期设置为当月第一天tmpCal.roll(Calendar.DATE, -1); // 把日期设置为当月最后一天return tmpCal.get(Calendar.DAY_OF_WEEK); } /** * 获取上月最后一天的星期几* * @return SUNDAY为1,MONDAY为2,依次类推。 */ public static int getLastDayWeekdayOfPrevMonth(Calendar cal) { Calendar tmpCal = (Calendar)cal.clone(); // 克隆cal。后面对tmpCal操作,就不会改变cal tmpCal.set(Calendar.DATE, 1); // 把日期设置为当月第一天tmpCal.add(Calendar.DATE, -1); // 把日期设置为上一个月最后一天return tmpCal.get(Calendar.DAY_OF_WEEK); } /** * 获取下月第一天的星期偏移* * @return SUNDAY为1,MONDAY为2,依次类推。 */ public static int getFirstDayWeekdayOfNextMonth(Calendar cal) { Calendar tmpCal = (Calendar)cal.clone(); // 克隆cal。后面对tmpCal操作,就不会改变cal tmpCal.add(Calendar.MONTH, 1); // 设为“下一个月” tmpCal.set(Calendar.DATE, 1); // 设为“第一天” return tmpCal.get(Calendar.DAY_OF_WEEK); } }