第一部分 Calendar介紹
Calendar 定義:
1
|
public abstract class Calendar implements Serializable, Cloneable, Comparable<Calendar> {} |
Calendar 可以看作是一個抽象類。
它的實現(xiàn),采用了設(shè)計模式中的工廠方法。表現(xiàn)在:當(dāng)我們獲取Calendar實例時,Calendar會根據(jù)傳入的參數(shù)來返回相應(yīng)的Calendar對象。獲取Calendar實例,有以下兩種方式:
(1) 當(dāng)我們通過 Calendar.getInstance() 獲取日歷時,默認(rèn)的是返回的一個GregorianCalendar對象。
GregorianCalendar是Calendar的一個實現(xiàn)類,它提供了世界上大多數(shù)國家/地區(qū)使用的標(biāo)準(zhǔn)日歷系統(tǒng)。
(2) 當(dāng)我們通過 Calendar.getInstance(TimeZone timezone, Locale locale) 或 Calendar.getInstance(TimeZone timezone) 或 Calendar.getInstance(Locale locale)獲取日歷時,是返回“對應(yīng)時區(qū)(zone) 或 地區(qū)(local)等所使用的日歷”。
例如,若是日本,則返回JapaneseImperialCalendar對象。
參考如下代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
public static Calendar getInstance() { // 調(diào)用createCalendar()創(chuàng)建日歷 Calendar cal = createCalendar(TimeZone.getDefaultRef(), Locale.getDefault()); cal.sharedZone = true ; return cal; } public static Calendar getInstance(TimeZone zone) { // 調(diào)用createCalendar()創(chuàng)建日歷 return createCalendar(zone, Locale.getDefault()); } public static Calendar getInstance(Locale aLocale) { // 調(diào)用createCalendar()創(chuàng)建日歷 Calendar cal = createCalendar(TimeZone.getDefaultRef(), aLocale); cal.sharedZone = true ; return cal; } public static Calendar getInstance(TimeZone zone, Locale aLocale) { // 調(diào)用createCalendar()創(chuàng)建日歷 return createCalendar(zone, aLocale); } private static Calendar createCalendar(TimeZone zone, Locale aLocale) { // (01) 若地區(qū)是“th”,則返回BuddhistCalendar對象 // (02) 若地區(qū)是“JP”,則返回JapaneseImperialCalendar對象 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) 否則,返回GregorianCalendar對象 return new GregorianCalendar(zone, aLocale); } |
當(dāng)我們獲取Calendar實例之后,就可以通過Calendar提供的一些列方法來操作日歷。
第二部分 Calendar的原理和思想
我們使用Calendar,無非是操作Calendar的“年、月、日、星期、時、分、秒”這些字段。下面,我們對這些字段的的來源、定義以及計算方法進(jìn)行學(xué)習(xí)。
1. Calendar 各個字段值的來源
我們使用Calendar,無非是使用“年、月、日、星期、時、分、秒”等信息。那么它是如何做到的呢? 本質(zhì)上,Calendar就是保存了一個時間。如下定義:
1
2
3
|
// time 是當(dāng)前時間,單位是毫秒。 // 它是當(dāng)前時間距離“January 1, 1970, 0:00:00 GMT”的差值。 protected long time; |
Calendar就是根據(jù) time 計算出 “Calendar的年、月、日、星期、時、分、秒”等等信息。
2. Calendar 各個字段的定義和初始化
Calendar 的“年、月、日、星期、時、分、秒”這些信息,一共是17個字段。
我們使用Calendar,無非是就是使用這17個字段。它們的定義如下:
(字段0) public final static int ERA = 0;
說明:紀(jì)元。
取值:只能為0 或 1。0表示BC(“before Christ”,即公元前),1表示AD(拉丁語“Anno Domini”,即公元)。
(字段1) public final static int YEAR = 1;
說明:年。
(字段2) public final static int MONTH = 2;
說明:月
取值:可以為,JANUARY, FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER, UNDECIMBER。
其中第一個月是 JANUARY,它為 0。
(字段3) public final static int WEEK_OF_YEAR = 3;
說明:當(dāng)前日期在本年中對應(yīng)第幾個星期。一年中第一個星期的值為 1。
(字段4) public final static int WEEK_OF_MONTH = 4;
說明:當(dāng)前日期在本月中對應(yīng)第幾個星期。一個月中第一個星期的值為 1。
(字段5) public final static int DATE = 5;
說明:日。一個月中第一天的值為 1。
(字段5) public final static int DAY_OF_MONTH = 5;
說明:同“DATE”,表示“日”。
(字段6) public final static int DAY_OF_YEAR = 6;
說明:當(dāng)前日期在本年中對應(yīng)第幾天。一年中第一天的值為 1。
(字段7) public final static int DAY_OF_WEEK = 7;
說明:星期幾。
取值:可以為,SUNDAY、MONDAY、TUESDAY、WEDNESDAY、THURSDAY、FRIDAY 和 SATURDAY。
其中,SUNDAY為1,MONDAY為2,依次類推。
(字段8) public final static int DAY_OF_WEEK_IN_MONTH = 8;
說明:當(dāng)前月中的第幾個星期。
取值:DAY_OF_MONTH 1 到 7 總是對應(yīng)于 DAY_OF_WEEK_IN_MONTH 1;8 到 14 總是對應(yīng)于 DAY_OF_WEEK_IN_MONTH 2,依此類推。
(字段9) public final static int AM_PM = 9;
說明:上午 還是 下午
取值:可以是AM 或 PM。AM為0,表示上午;PM為1,表示下午。
(字段10) public final static int HOUR = 10;
說明:指示一天中的第幾小時。
HOUR 用于 12 小時制時鐘 (0 - 11)。中午和午夜用 0 表示,不用 12 表示。
(字段11) public final static int HOUR_OF_DAY = 11;
說明:指示一天中的第幾小時。
HOUR_OF_DAY 用于 24 小時制時鐘。例如,在 10:04:15.250 PM 這一時刻,HOUR_OF_DAY 為 22。
(字段12) public final static int MINUTE = 12;
說明:一小時中的第幾分鐘。
例如,在 10:04:15.250 PM這一時刻,MINUTE 為 4。
(字段13) public final static int SECOND = 13;
說明:一分鐘中的第幾秒。
例如,在 10:04:15.250 PM 這一時刻,SECOND 為 15。
(字段14) public final static int MILLISECOND = 14;
說明:一秒中的第幾毫秒。
例如,在 10:04:15.250 PM 這一時刻,MILLISECOND 為 250。
(字段15) public final static int ZONE_OFFSET = 15;
說明:毫秒為單位指示距 GMT 的大致偏移量。
(字段16) public final static int DST_OFFSET = 16;
說明:毫秒為單位指示夏令時的偏移量。
public final static int FIELD_COUNT = 17;
這17個字段是保存在int數(shù)組中。定義如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
// 保存這17個字段的數(shù)組 protected int fields[]; // 數(shù)組的定義函數(shù) protected Calendar(TimeZone zone, Locale aLocale) { // 初始化“fields數(shù)組” 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) 這是Calendar的構(gòu)造函數(shù)。它會被它的子類的構(gòu)造函數(shù)調(diào)用到,從而新建“保存Calendar的17個字段數(shù)據(jù)”的數(shù)組。
3. Calendar 各個字段值的計算
下面以get(int field)為例,簡要的說明Calendar的17個字段的計算和操作。 get(int field)是獲取“field”字段的值。它的定義如下:
1
2
3
4
5
6
|
public int get( int field) { // 計算各個字段的值 complete(); // 返回field字段的值 return internalGet(field); } |
說明:get(int field)的代碼很簡單。先通過 complete() 計算各個字段的值,然后在通過 internalGet(field) 返回“field字段的值”。
complete() 的作用就是計算Calendar各個字段的值。它定義在Calendar.java中,代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
|
protected void complete() { if (!isTimeSet) updateTime(); if (!areFieldsSet || !areAllFieldsSet) { computeFields(); // fills in unset fields areAllFieldsSet = areFieldsSet = true ; } } private void updateTime() { computeTime(); isTimeSet = true ; } updateTime() 調(diào)用到的 computeTime() 定義在 Calendar.java的實現(xiàn)類中。下面,我列出GregorianCalendar.java中computeTime()的實現(xiàn): 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 calculateFixedDate; } jfd = fixedDate + getFixedDate(getJulianCalendarSystem(), year, fieldMask); } else if (year < gregorianCutoverYear && year < gregorianCutoverYearJulian) { jfd = fixedDate + getFixedDate(getJulianCalendarSystem(), year, fieldMask); if (jfd < gregorianCutoverDate) { fixedDate = jfd; break calculateFixedDate; } 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 designated 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 designated 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); } |
下面,我們看看internalGet(field)的定義。如下:
1
2
3
|
protected final int internalGet( int field) { return fields[field]; } |
從中,我們就看出,get(int field) 最終是通過 internalGet(int field)來返回值的。
而 internalGet(int field) ,實際上返回的是field數(shù)組中的第field個元素。這就正好和Calendar的17個元素所對應(yīng)了!
總之,我們需要了解的就是:Calendar就是以一個time(毫秒)為基數(shù),而計算出“年月日時分秒”等,從而方便我們對“年月日時分秒”等進(jìn)行操作。下面,介紹以下Calendar提供的相關(guān)操作函數(shù)。
第三部分 Calendar函數(shù)接口
1. Calendar的17個字段的公共接口
Calendar的這17個字段,都支持下面的公共函數(shù)接口。 這些公共接口的使用示例,請參考CalendarTest.java 示例中的 testAllCalendarSections() 函數(shù)。
(1) getMaximum(int field)
作用:獲取“字段的最大值”。注意“對比它和 getActualMaximum() 的區(qū)別”。 示例:以“MONTH”字段來說。使用方法為:
1
2
3
4
|
// 獲取Calendar實例 Calendar cal = Calendar.getInstance(); // 獲取MONTH的最大值 int max = cal.getMaximum(Calendar.MONTH); |
若要獲取其它字段的最大值,只需要將示例中的MONTH相應(yīng)的替換成其它字段名即可。
(2) getActualMaximum(int field)
作用:獲取“當(dāng)前日期下,該字段的最大值”。 示例:以“MONTH”字段來說。使用方法為:
1
2
3
4
|
// 獲取Calendar實例 Calendar cal = Calendar.getInstance(); // 獲取當(dāng)前MONTH的最大值 int max = cal.getActualMaximum(Calendar.MONTH); |
若要獲取其它字段的最大值,只需要將示例中的MONTH相應(yīng)的替換成其它字段名即可。
注意:對比getActualMaximum() 和 getMaximum() 的區(qū)別。參考下面的對比示例,
A、 getMaximum() 獲取的“字段最大值”,是指在綜合所有的日期,在所有這些日期中得出的“字段最大值”。
例如,getMaximum(Calendar.DATE)的目的是“獲取‘日的最大值'”。綜合所有的日期,得出一個月最多有31天。因此,getMaximum(Calendar.DATE)的返回值是“31”!
B、 getActualMaximum() 獲取的“當(dāng)前日期時,該字段的最大值”。
例如,當(dāng)日期為2013-09-01時,getActualMaximum(Calendar.DATE)是獲取“日的最大值”是“30”。當(dāng)前日期是9月份,而9月只有30天。因此,getActualMaximum(Calendar.DATE)的返回值是“30”!
(3) getMinimum(int field)
作用:獲取“字段的最小值”。注意“對比它和 getActualMinimum() 的區(qū)別”。 示例:以“MONTH”字段來說。使用方法為:
1
2
3
4
|
// 獲取Calendar實例 Calendar cal = Calendar.getInstance(); // 獲取MONTH的最小值 int min = cal.getMinimum(Calendar.MONTH); |
若要獲取其它字段的最小值,只需要將示例中的MONTH相應(yīng)的替換成其它字段名即可。
(4) getActualMinimum(int field)
1
2
3
4
5
|
作用:獲取“當(dāng)前日期下,該字段的最小值”。 示例:以“MONTH”字段來說。使用方法為: // 獲取Calendar實例 Calendar cal = Calendar.getInstance(); // 獲取MONTH的最小值 int min = cal.getMinimum(Calendar.MONTH); |
若要獲取其它字段的最小值,只需要將示例中的MONTH相應(yīng)的替換成其它字段名即可。
注意:在Java默認(rèn)的Calendar中,雖然 getMinimum() 和 getActualMinimum() 的含義不同;但是,它們的返回值是一樣的。因為Calendar的默認(rèn)是返回GregorianCalendar對象,而在GregorianCalendar.java中,getMinimum() 和 getActualMinimum() 返回值一樣。
(5) get(int field)
作用:獲取“字段的當(dāng)前值”。獲取field字段的當(dāng)前值。 示例:以“MONTH”字段來說。“獲取MONTH的當(dāng)前值”的方法為:
1
2
3
4
|
// 獲取Calendar實例 Calendar cal = Calendar.getInstance(); // 獲取“cal日歷”的當(dāng)前MONTH值 int MONTH = cal.get(Calendar.MONTH); |
若要獲取其它字段的當(dāng)前值,只需要將示例中的MONTH相應(yīng)的替換成其它字段名即可。
(6) set(int field, int value)
作用:設(shè)置“字段的當(dāng)前值”。設(shè)置field字段的當(dāng)前值為value 示例:以“MONTH”字段來說。“設(shè)置MONTH的當(dāng)前值”的方法為:
1
2
3
4
|
// 獲取Calendar實例 Calendar cal = Calendar.getInstance(); // 設(shè)置“cal日歷”的當(dāng)前MONTH值為 1988年 cal.set(Calendar.MONTH, 1988 ); |
說明:
A、1988 是想要設(shè)置的MONTH的當(dāng)前值。這個設(shè)置值必須是整數(shù)。
B、若要設(shè)置其它字段的當(dāng)前值,只需要將示例中的MONTH相應(yīng)的替換成其它字段名即可。
(7) add(int field, int value)
作用:給“字段的當(dāng)前值”添加值。給field字段的當(dāng)前值添加value。 示例:以“MONTH”字段來說。方法如下:
1
2
3
4
5
6
7
|
// 獲取Calendar實例,并設(shè)置日期為“2013-09-01” Calendar cal = Calendar.getInstance(); cal.set(Calendar.YEAR, 2013 ); cal.set(Calendar.MONTH, 8 ); cal.set(Calendar.DATE, 1 ); // 給“cal日歷”的當(dāng)前MONTH值 “添加-10” cal.add(Calendar.MONTH, - 10 ); |
說明:
A、 -10 是添加值。
添加值可以為正數(shù),也可以是負(fù)數(shù)。
正數(shù)表示將日期增加,負(fù)數(shù)表示將日期減少。
假設(shè):現(xiàn)在cal的值是“2013-09-01”,現(xiàn)在我們將MONTH字段值增加-10。得到的結(jié)果是:“2012-10-01”。
為什么會這樣呢?“2013-09-01”增加-10,也就是將日期向前減少10個月;得到的結(jié)果就是“2012-10-01”。
B、 Calendar的17個字段中:除了回滾Calendar.ZONE_OFFSET時,會拋出IllegalArgumentException異常;其它的字段都支持該操作。
C、 若要設(shè)置其它字段的當(dāng)前值,只需要將示例中的MONTH相應(yīng)的替換成其它字段名即可。
(8) roll(int field, int value)
作用:回滾“字段的當(dāng)前值” 示例:以“MONTH”字段來說。“回滾MONTH的當(dāng)前值”的方法為:
1
2
3
4
5
6
7
|
// 獲取Calendar實例,并設(shè)置日期為“2013-09-01” Calendar cal = Calendar.getInstance(); cal.set(Calendar.YEAR, 2013 ); cal.set(Calendar.MONTH, 8 ); cal.set(Calendar.DATE, 1 ); // 將“cal日歷”的當(dāng)前MONTH值 “向前滾動10” cal.roll(Calendar.MONTH, - 10 ); |
說明:
A、 -10 是回滾值。
當(dāng)回滾值是負(fù)數(shù)時,表示將當(dāng)前字段向前滾;
當(dāng)回滾值是正數(shù)時,表示將當(dāng)前字段向后滾。
回滾Calendar中某一字段時,不更改更大的字段!
這是roll()與add()的根據(jù)區(qū)別!add()可能會更改更大字段,比如“使用add()修改‘MONTH'字段,可能會引起‘YEAR'字段的改變”;但是roll()不會更改更大的字段,例如“使用roll()修改‘MONTH'字段,不回引起‘YEAR'字段的改變。”
假設(shè):現(xiàn)在cal的值是“2013-09-01”,現(xiàn)在我們將MONTH字段值增加-10。得到的結(jié)果是:“2013-10-01”。
為什么會這樣呢?這就是因為“回滾”就是“在最小值和最大值之間來回滾動”。本例中,MONTH是9月,前回滾10,得到的值是10月,但是roll()不會改變“比MONTH”更大的字段,所以YEAR字段不會改變。所以結(jié)果是“2013-10-01”。
B、 Calendar的17個字段中:除了回滾Calendar.ZONE_OFFSET時,會拋出IllegalArgumentException異常;其它的字段都支持該操作。
C、 若要設(shè)置其它字段的當(dāng)前值,只需要將示例中的MONTH相應(yīng)的替換成其它字段名即可。
(9) clear(int field)
作用:清空“字段的當(dāng)前值”。所謂清空,實際上是將“field”的值設(shè)置為0;若field最小值為1,則設(shè)置為1。 示例:以“MONTH”字段來說。“清空MONTH”的方法為:
1
2
3
4
5
|
// 獲取Calendar實例,并設(shè)置日期為“9月” Calendar cal = Calendar.getInstance(); cal.set(Calendar.MONTH, 9 ); // 清空MONTH cal.clear(Calendar.MONTH); |
若要清空其它字段,只需要將示例中的MONTH相應(yīng)的替換成其它字段名即可。
(10) isSet(int field)
作用:判斷“字段field”是否被設(shè)置。若調(diào)用clear()清空之后,則field變?yōu)?ldquo;沒有設(shè)置狀態(tài)”。 示例:以“MONTH”字段來說。“判斷MONTH是否被設(shè)置”的方法為:
1
2
3
4
|
// 獲取Calendar實例 Calendar cal = Calendar.getInstance(); // 判斷MONTH是否被設(shè)置 boolean bset = cal.isSet(Calendar.MONTH); |
若要判斷其它字段,只需要將示例中的MONTH相應(yīng)的替換成其它字段名即可。
2. Calendar的其它函數(shù)
(1) 日期比較函數(shù)
Calendar的比較函數(shù),主要有以下幾個:
1
2
3
4
5
6
7
8
9
10
11
|
// 比較“當(dāng)前Calendar對象”和“calendar” 的日期、時區(qū)等內(nèi)容是否相等。 boolean equals(Object object) // 當(dāng)前Calendar對象 是否 早于calendar boolean before(Object calendar) // 當(dāng)前Calendar對象 是否 晚于calendar boolean after(Object calendar) // 比較“當(dāng)前Calendar對象”和“calendar”。 // 若 早于 “calendar” 則,返回-1 // 若 相等, 則,返回0 // 若 晚于 “calendar” 則,返回1 int compareTo(Calendar anotherCalendar) |
這些函數(shù)的使用示例,請參考CalendarTest.java示例中的 testComparatorAPIs() 函數(shù)。
示例:假設(shè)cal1 和 cal2 都是Calendar的兩個對象。
1
2
3
4
5
|
// 它們的使用方法如下 boolean isEqual = cal1.equals(cal2); boolean isBefore = cal1.before(cal2); boolean isAfter = cal1.after(cal2); int icompare = cal1.compareTo(cal2); |
(2) “寬容”函數(shù)
1
2
3
4
|
// 設(shè)置“Calendar的寬容度” void setLenient( boolean value) // 獲取“Calendar的寬容度” boolean isLenient() |
這些函數(shù)的使用示例,請參考CalendarTest.java示例中的 testLenientAPIs() 函數(shù)。
說明:
Calendar 有兩種解釋日歷字段的模式,即 lenient 和 non-lenient。
A、 當(dāng) Calendar 處于 lenient 模式時,它可接受比它所生成的日歷字段范圍更大范圍內(nèi)的值。當(dāng) Calendar 重新計算日歷字段值,以便由 get() 返回這些值時,所有日歷字段都被標(biāo)準(zhǔn)化。
例如,lenient 模式下的 GregorianCalendar 將 MONTH == JANUARY、DAY_OF_MONTH == 32 解釋為 February 1。
B、 當(dāng) Calendar 處于 non-lenient 模式時,如果其日歷字段中存在任何不一致性,它都會拋出一個異常。
例如,GregorianCalendar 總是在 1 與月份的長度之間生成 DAY_OF_MONTH 值。如果已經(jīng)設(shè)置了任何超出范圍的字段值,那么在計算時間或日歷字段值時,處于 non-lenient 模式下的 GregorianCalendar 會拋出一個異常。
注意:在(02)步驟中的異常,在使用set()時不會拋出,而需要在使用get()、getTimeInMillis()、getTime()、add() 和 roll() 等函數(shù)中才拋出。因為set()只是設(shè)置了一個修改標(biāo)志,而get()等方法才會引起時間的重新計算,此時才會拋出異常!
(3) "年月日(時分秒)"、Date、TimeZone、MilliSecond函數(shù)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
// 設(shè)置“年月日” final void set( int year, int month, int day) // 設(shè)置“年月日時分” final void set( int year, int month, int day, int hourOfDay, int minute, int second) // 設(shè)置“年月日時分秒” final void set( int year, int month, int day, int hourOfDay, int minute) // 獲取Calendar對應(yīng)的日期 final Date getTime() // 設(shè)置Calendar為date final void setTime(Date date) // 獲取Calendar對應(yīng)的時區(qū) TimeZone getTimeZone() // 設(shè)置Calendar對應(yīng)的時區(qū) void setTimeZone(TimeZone timezone) // 獲取Calendar對應(yīng)的milliscondes值,就是“Calendar當(dāng)前日期”距離“1970-01-01 0:00:00 GMT”的毫秒數(shù) long getTimeInMillis() // 設(shè)置Calendar對應(yīng)的milliscondes值 void setTimeInMillis( long milliseconds) |
這些函數(shù)的使用示例,請參考CalendarTest.java示例中的 testTimeAPIs() 函數(shù)。
(4) 其它操作
1
2
3
4
5
6
7
8
9
10
|
// 克隆Calendar Object clone() // 獲取“每周的第一天是星期幾”。例如,在美國,這一天是 SUNDAY,而在法國,這一天是 MONDAY。 int getFirstDayOfWeek() // 設(shè)置“每周的第一天是星期幾”。例如,在美國,這一天是 SUNDAY,而在法國,這一天是 MONDAY。 void setFirstDayOfWeek( int value) // 獲取一年中第一個星期所需的最少天數(shù),例如,如果定義第一個星期包含一年第一個月的第一天,則此方法將返回 1。如果最少天數(shù)必須是一整個星期,則此方法將返回 7。 int getMinimalDaysInFirstWeek() // 設(shè)置一年中第一個星期所需的最少天數(shù),例如,如果定義第一個星期包含一年第一個月的第一天,則使用值 1 調(diào)用此方法。如果最少天數(shù)必須是一整個星期,則使用值 7 調(diào)用此方法。 void setMinimalDaysInFirstWeek( int value) |
這些函數(shù)的使用示例,請參考CalendarTest.java示例中的 testOtherAPIs() 函數(shù)。
第四部分 Calendar使用示例
下面,我們通過示例學(xué)習(xí)使用Calendar的API。CalendarTest.java的源碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
|
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) { // 測試Calendar的“17個字段的公共函數(shù)接口” testAllCalendarSections() ; // 測試Calendar的“比較接口” testComparatorAPIs() ; // 測試Calendar的“比較接口” testLenientAPIs() ; // 測試Calendar的Date、TimeZone、MilliSecond等相關(guān)函數(shù) testTimeAPIs() ; // 測試Calendar的clone(),getFirstDayOfWeek()等接口 testOtherAPIs() ; } /** * 測試“Calendar的字段” * * @param cal -- Calendar對象 * @param field -- 要測試的“Calendar字段”。可以為以下值: * Calendar.YEAR, Calendar.MONTH, Calendar.DATE, ... 等等 * @param title -- 標(biāo)題 */ 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); // 獲取"字段最小值" final int max = cal.getMaximum(field); // 獲取“字段最大值” final int actualMin = cal.getActualMinimum(field); // 獲取"當(dāng)前日期下,該字段最小值" final int actualMax = cal.getActualMaximum(field); // 獲取“當(dāng)前日期下,該字段的最大值” // 獲取“字段的當(dāng)前值” final int ori = cal.get(field); // 設(shè)置“字段的當(dāng)前值”, 并獲取“設(shè)置之后的值” final int r1 = random.nextInt(max); cal.set(field, r1); final int set = cal.get(field); try { // 回滾“字段的當(dāng)前值”:在“字段最小值”和“字段最大值”之間回滾。 // “回滾值”可以為正,也可以為負(fù)。 cal.roll(field, -max); } catch (IllegalArgumentException e) { // 當(dāng)field == Calendar.ZONE_OFFSET時,會拋出該異常! e.printStackTrace(); } final int roll = cal.get(field); // 獲取一個隨機(jī)值 final int sign = ( random.nextInt( 2 ) == 1 ) ? 1 : - 1 ; final int r2 = sign * random.nextInt(max); try { // 增加“字段的當(dāng)前值” ,并獲取“新的當(dāng)前字段值” // add的“參數(shù)值”可以為正,也可以為負(fù)。 cal.add(field, r2); } catch (IllegalArgumentException e) { // 當(dāng)field == Calendar.ZONE_OFFSET時,會拋出該異常! e.printStackTrace(); } final int add = cal.get(field); // 打印字段信息 System.out.printf( "%s:\n\trange 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); } /** * 測試Calendar的“17個字段的公共函數(shù)接口” */ private static void testAllCalendarSections() { // 00. ERA 字段 testSection(Calendar.getInstance(), Calendar.ERA, "Calendar.ERA" ); // 01. YEAR 字段 testSection(Calendar.getInstance(), Calendar.YEAR, "Calendar.YEAR" ); // 02. MONTH 字段 testSection(Calendar.getInstance(), Calendar.MONTH, "Calendar.MONTH" ); // 03. WEEK_OF_YEAR 字段 testSection(Calendar.getInstance(), Calendar.WEEK_OF_YEAR, "Calendar.WEEK_OF_YEAR" ); // 04. WEEK_OF_MONTH 字段 testSection(Calendar.getInstance(), Calendar.WEEK_OF_MONTH, "Calendar.WEEK_OF_MONTH" ); // 05. DATE 字段 testSection(Calendar.getInstance(), Calendar.DATE, "Calendar.DATE" ); // 06. DAY_OF_MONTH 字段 testSection(Calendar.getInstance(), Calendar.DAY_OF_MONTH, "Calendar.DAY_OF_MONTH" ); // 07. DAY_OF_YEAR 字段 testSection(Calendar.getInstance(), Calendar.DAY_OF_YEAR, "Calendar.DAY_OF_YEAR" ); // 08. DAY_OF_WEEK 字段 testSection(Calendar.getInstance(), Calendar.DAY_OF_WEEK, "Calendar.DAY_OF_WEEK" ); // 09. DAY_OF_WEEK_IN_MONTH 字段 testSection(Calendar.getInstance(), Calendar.DAY_OF_WEEK_IN_MONTH, "Calendar.DAY_OF_WEEK_IN_MONTH" ); // 10. AM_PM 字段 testSection(Calendar.getInstance(), Calendar.AM_PM, "Calendar.AM_PM" ); // 11. HOUR 字段 testSection(Calendar.getInstance(), Calendar.HOUR, "Calendar.HOUR" ); // 12. HOUR_OF_DAY 字段 testSection(Calendar.getInstance(), Calendar.HOUR_OF_DAY, "Calendar.HOUR_OF_DAY" ); // 13. MINUTE 字段 testSection(Calendar.getInstance(), Calendar.MINUTE, "Calendar.MINUTE" ); // 14. SECOND 字段 testSection(Calendar.getInstance(), Calendar.SECOND, "Calendar.SECOND" ); // 15. MILLISECOND 字段 testSection(Calendar.getInstance(), Calendar.MILLISECOND, "Calendar.MILLISECOND" ); // 16. ZONE_OFFSET 字段 testSection(Calendar.getInstance(), Calendar.ZONE_OFFSET, "Calendar.ZONE_OFFSET" ); } /** * 測試Calendar的“比較接口” */ private static void testComparatorAPIs() { // 新建cal1 ,且時間為1988年 Calendar cal1 = Calendar.getInstance(); cal1.set(Calendar.YEAR, 1988 ); // 新建cal2 ,且時間為2000年 Calendar cal2 = Calendar.getInstance(); cal2.set(Calendar.YEAR, 2000 ); // 新建cal3, 為cal1的克隆對象 Calendar cal3 = (Calendar)cal1.clone(); // equals 判斷 cal1和cal2的“時間、時區(qū)等”內(nèi)容是否相等 boolean isEqual12 = cal1.equals(cal2); // equals 判斷 cal1和cal3的“時間、時區(qū)等”內(nèi)容是否相等 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(); // 獲取默認(rèn)的“寬容度”。返回true boolean oriLenient = cal.isLenient(); // MONTH值只能是“0-11”,這里越界。但是由于當(dāng)前cal是寬容的,所以不會拋出異常 cal.set(Calendar.MONTH, 50 ); // 設(shè)置“寬容度”為false。 cal.setLenient( false ); // 獲取設(shè)置后的“寬容度” boolean curLenient = cal.isLenient(); try { // MONTH值只能是“0-11”,這里越界。而且當(dāng)前cal是不寬容的,所以會產(chǎn)生異常。 // 但是,異常到下次計算日期時才會拋出。即,set()中不回拋出異常,而要等到get()中才會拋出異常 cal.set(Calendar.MONTH, 50 ); // 此時,對cal進(jìn)行讀取。讀取會導(dǎo)致重新計算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等相關(guān)函數(shù) */ private static void testTimeAPIs() { Calendar cal = Calendar.getInstance(); // 設(shè)置cal的時區(qū)為“GMT+8” cal.setTimeZone(TimeZone.getTimeZone( "GMT+8" )); // 獲取當(dāng)前的cal時區(qū) TimeZone timezone = cal.getTimeZone(); // 設(shè)置 milliseconds cal.setTimeInMillis(1279419645742l); // 獲取 milliseconds long millis = cal.getTimeInMillis(); // 設(shè)置 milliseconds之后,時間也改變了。 // 獲取cal對應(yīng)的日期 Date date = cal.getTime(); // 設(shè)置時間為“1988-08-08” cal.set( 1988 , 08 , 08 ); // 設(shè)置時間為“1999-09-09 09:09” cal.set( 1999 , 09 , 09 , 9 , 9 ); // 設(shè)置時間為“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(); // 設(shè)置 為 2013-01-10。 // 注:2013-01-01 為“星期二”,2013-01-06為“星期天”, clone.set(Calendar.YEAR, 2013 ); clone.set(Calendar.MONTH, 0 ); clone.set(Calendar.DATE, 10 ); // 設(shè)置“本年的第一個星期最少包含1天”。 // 則2013-01-10屬于第2個星期 clone.setMinimalDaysInFirstWeek( 1 ); int m1 = clone.getMinimalDaysInFirstWeek(); int index1 = clone.get(Calendar.WEEK_OF_YEAR); // 設(shè)置“本年的第一個星期最少包含7天”。 // 則2013-01-10屬于第1個星期 clone.setMinimalDaysInFirstWeek( 7 ); int m2 = clone.getMinimalDaysInFirstWeek(); int index2 = clone.get(Calendar.WEEK_OF_YEAR); // 設(shè)置“每周的第一天是星期幾”。 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):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
|
import java.util.Calendar; /** * 根據(jù)Calendar的API封裝的一些常用函數(shù) */ public class CalendarSelfDefineTest { public static void main(String[] args) { Calendar cal = Calendar.getInstance(); // 設(shè)置日期為“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對應(yīng)星期幾 System.out.printf( "weekday: %s\n" , getWeekDay(cal) ); // 本月天數(shù) System.out.printf( "Current Month days: %s\n" , getMonthDays(cal) ); // 上月天數(shù) System.out.printf( "Previcous Month days: %s\n" , getPrevMonthDays(cal) ); // 下月天數(shù) System.out.printf( "Next Month days: %s\n" , getNextMonthDays(cal) ); // 獲取當(dāng)月第一天的星期幾 System.out.printf( "First day' weekday : %s\n" , getFirstDayWeekday(cal) ); // 獲取當(dāng)前月最后一天的星期幾 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); } /** * 獲取“本月的天數(shù)” * * @return 例如,2013-09-18,則返回30 * */ public static int getMonthDays(Calendar cal) { return cal.getActualMaximum(Calendar.DATE); } /** * 獲取“上一個月的天數(shù)” * * @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 ); // 設(shè)為“上一個月” return tmpCal.getActualMaximum(Calendar.DATE); } /** * 獲取“下一個月的天數(shù)” * * @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 ); // 設(shè)為“下一個月” return tmpCal.getActualMaximum(Calendar.DATE); } /** * 獲取Cal對應(yīng)星期幾 * * @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); } /** * 獲取當(dāng)月第一天對應(yīng)星期幾 * * @return SUNDAY為1,MONDAY為2,依次類推。 */ public static int getFirstDayWeekday(Calendar cal) { Calendar tmpCal = (Calendar)cal.clone(); // 克隆cal。后面對tmpCal操作,就不會改變cal tmpCal.set(Calendar.DATE, 1 ); // 把日期設(shè)置為當(dāng)月第一天 return tmpCal.get(Calendar.DAY_OF_WEEK); } /** * 獲取當(dāng)前月最后一天對應(yīng)星期幾 * * @return SUNDAY為1,MONDAY為2,依次類推。 */ public static int getLastDayWeekday(Calendar cal) { Calendar tmpCal = (Calendar)cal.clone(); // 克隆cal。后面對tmpCal操作,就不會改變cal tmpCal.set(Calendar.DATE, 1 ); // 把日期設(shè)置為當(dāng)月第一天 tmpCal.roll(Calendar.DATE, - 1 ); // 把日期設(shè)置為當(dāng)月最后一天 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 ); // 把日期設(shè)置為當(dāng)月第一天 tmpCal.add(Calendar.DATE, - 1 ); // 把日期設(shè)置為上一個月最后一天 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 ); // 設(shè)為“下一個月” tmpCal.set(Calendar.DATE, 1 ); // 設(shè)為“第一天” return tmpCal.get(Calendar.DAY_OF_WEEK); } } |