Java中處理日期最經常使用的類是Date類和Calendar類,掌握這兩個類的用法在項目中處理起日期來就輕鬆多了。下面是這個類的詳細用法。java
一.Date類sql
Java提供了Date類來處理日期、時間(此處的Date是指java.util包下的Date類,而不是java.sql包下的Date類),這個Date類從JDK1.0起就開始存在了。但正由於它歷史悠久,因此它的大部分構造器、方法都已通過時,再也不推薦使用了。安全
Date類提供了6個構造器,但其中4個已經被Deprecated(Java再也不推薦使用,使用再也不推薦的方法時編譯器會提出警告信息,並致使程序性能、安全性等方面的問題),剩下的兩個構造器分別爲:函數
Ø Date():生成一個表明當前日期時間的Date對象。該方法在底層調用System.currentTime工具
Millis()得到long整數做爲日期參數。性能
Ø Date(long date):根據指定的long型整數來生成一個Date對象。該構造器的參數表示建立的Date對象和GMT 1970年1月1日00:00:00之間時間差,以毫秒做爲計時單位。測試
與Date構造器相同的是,Date對象的大部分方法也被Deprecated了,剩下爲數很少的幾個方法:spa
Ø boolean after(Date when):測試該日期是否在指定日期when以後。 設計
Ø boolean before(Date when):測試該日期是否在指定日期when以前。 對象
Ø int compareTo(Date anotherDate):比較兩個日期的大小,後面的時間大於前面時間。
Ø boolean equals(Object obj):當兩個時間表示同一時刻時返回true。
Ø long getTime():返回該時間對應的long型整數,即從GMT 1970-01-01 00:00:00 到該Date對象之間時間差,以毫秒做爲計時單位。
Ø void setTime(long time):設置該Date對象的時間。
下面程序示範了Date類的用法:
public class TestDate
{
public static void main(String[] args)
{
Date d1 = new Date();
//獲取當前時間以後100ms的時間
Date d2 = new Date(System.currentTimeMillis() + 100);
System.out.println(d2);
System.out.println(d1.compareTo(d2));
System.out.println(d1.before(d2));
}
}
由於Date類的不少方法已經被不推薦使用了,因此Date類的功能已經被大大削弱了,例如全部對時間進行加減運算,獲取指定Date對象裏年、月、日的方法都已被Deprecated。若是須要對日期進行這些運算,應該使用Calendar工具類。
二. Calendar類
由於Date類的設計上存在一些缺陷,因此Java提供了Calendar類來更好地處理日期和時間。Calendar是一個抽象類,它用於表示日曆。
Calendar自己是一個抽象類,它是全部日曆類的模板,並提供了一些全部日曆通用的方法,但它自己不能直接實例化。程序只能建立Calendar子類的實例,Java 自己提供了一個GregorianCalendar類,一個表明GregorianCalendar的子類,它表明了咱們一般所說的公曆。
固然,也能夠建立本身的Calendar子類,而後將它做爲Calendar對象使用(這就是多態),在IBM的alphaWorks站點(http://www.alphaworks.ibm.com/tech/calendars)上,IBM的開發人員實現了多種日曆。在Internet上,也有對中國農曆的實現。
Calendar類是一個抽象類,因此不能使用構造器來建立Calendar對象。但它提供了幾個靜態getInstance方法來獲取Calendar對象。這些方法根據TimeZone,Locale類獲取特定Calendar,若是不指定TimeZone、Locale,則使用默認的TimeZone、Locale來建立Calendar。
Calendar與Date都是表示日期的工具類,它們直接能夠自由轉換,以下代碼所示:
//建立一個默認的Calendar對象
Calendar calendar = Calendar.getInstance();
//從Calendar 對象中取出Date 對象
Date date = calendar.getTime();
//經過Date對象得到對應的對象中,
//由於Calendar/GregorianCalendar沒有構造函數能夠接受Date對象
//因此必須先得到一個Calendar實例,而後調用其setTime方法
Calendar calendar2 = Calendar.getInstance();
calendar2.setTime(date);
Calendar提供了大量訪問、修改時間日期的方法,Calendar大體有以下幾個經常使用方法:
Ø void add(int field, int amount):根據日曆的規則,爲給定的日曆字段添加或減去指定的時間量。
Ø int get(int field):返回指定日曆字段的值。
Ø int getActualMaximum(int field):返回指定日曆字段可能使用的最大值。例如月,最大值爲11。
Ø int getActualMinimum(int field):返回指定日曆字段可能擁有的最小值。例如月,最小值爲0。
Ø void roll(int field, int amount):與add方法基本相似,區別在於加上的value超過了該字段所能表示的最大範圍後,也不會向上一個字段進位。
Ø void set(int field, int value):將給定的日曆字段設置爲給定值。
Ø void set(int year, int month, int date):設置Calendar對象年、月、日三個字段的值。
Ø void set(int year, int month, int date, int hourOfDay, int minute, int second):設置Calendar對象年、月、日、時、分、秒六個字段的值。
上面不少方法都須要一個int類型的field參數,field是Calendar類的靜態屬性,如Calendar.YEAR、Calendar.MONTH等,分別表明了年、月、日、小時、分鐘、秒、微秒等時間字段。Calendar.MONTH字段須要注意:月份的起始值爲0而不是1,因此要設置8月時,用7而不是8。
以下程序示範了Calendar類的常規用法:
public class TestCalendar
{
public static void main(String[] args)
{
Calendar c = Calendar.getInstance();
//取出年
System.out.println(c.get(YEAR));
//取出月份
System.out.println(c.get(MONTH));
//取出日
System.out.println(c.get(DATE));
//分別設置年、月、日、小時、分鐘、秒
c.set(2003 , 10 , 23 , 12, 32, 23); //2003-11-23 12:32:23
System.out.println(c.getTime());
//將Calendar的年前推1年
c.add(YEAR , -1); //2002-11-23 12:32:23
System.out.println(c.getTime());
//將Calendar的月前推8個月
c.roll(MONTH , -8); //2002-03-23 12:32:23
System.out.println(c.getTime());
}
}
上面程序中粗體字代碼示範了Calendar類的用法,Calendar能夠很靈活地改變它對應的Date。
Calendar類還有以下幾個注意點。
(1).add與roll的區別
add(int field, int amount)的功能很是強大,add 主要用於改變Calendar的特定字段的值。若是須要增長某字段的值,則讓amount爲正數;若是須要減小某字段的值,讓amount爲負數便可。
add(int field, int amount)有兩條規則:
Ø 當被修改的字段超出它容許的範圍時,會發生進位,即上一級字段也會增大。如:
Calendar cal1 = Calendar.getInstance();
cal1.set(2003, 7, 23, 0, 0 , 0); //2003-8-23
cal1.add(MONTH, 6); //2003-8-23 => 2004-2-23
Ø 若是下一級的字段也須要改變,那麼該字段會修正到變化最小的值。如:
Calendar cal1 = Calendar.getInstance();
cal1.set(2003, 7, 31, 0, 0 , 0); //2003-8-31
//由於進位到後月份改成2月,2月沒有31日,自動變成29日
cal1.add(MONTH, 6); //2003-8-23 => 2004-2-29
上面的例子,8-31就會變成2-29。由於MONTH的下一級字段是DATE,從31到29改變最小。因此上面2003-8-23的MONTH字段增長6後,不是變成2004-3-2,而是變成2004-2-29。
roll的規則與add的處理規則不一樣:當被修改的字段超出它容許的範圍時,上一級字段不會增大。
Calendar cal1 = Calendar.getInstance();
cal1.set(2003, 7, 23, 0, 0 , 0); //2003-8-23
//MONTH字段「進位」,但YEAR字段並不增長
cal1.roll(MONTH, 6); //2003-8-23 => 2003-2-23
下一級字段的處理規則與add類似:
Calendar cal1 = Calendar.getInstance();
cal1.set(2003, 7, 31, 0, 0 , 0); //2003-8-31
// MONTH字段「進位」後變成2,2月沒有31日,YEAR字段不會改變,2003年2月只有28天
cal1.roll(MONTH, 6); //2003-8-23 => 2003-2-28
(2).設置Calendar的容錯性
當咱們調用Calendar對象的set方法來改變指定時間字段上的值時,有可能傳入一個不合法的參數,例如爲MONTH字段設置13,這將會致使怎樣的後果呢?看以下程序:
public class TestLenient
{
public static void main(String[] args)
{
Calendar cal = Calendar.getInstance();
//結果是YEAR字段加1,MONTH字段爲1(二月)
cal.set(MONTH , 13); //①
System.out.println(cal.getTime());
//關閉容錯性
cal.setLenient(false);
//致使運行時異常
cal.set(MONTH , 13); //②
System.out.println(cal.getTime());
}
}
上面程序①、②兩處的代碼徹底類似,但它們運行的結果不同:①處代碼能夠正常運行,由於設置MONTH字段的值爲13,將會致使YEAR字段加1。②處代碼將會致使運行時異常,由於設置的MONTH字段值超出了MONTH字段容許的範圍。關鍵在於程序中粗體字代碼行,Calendar提供了一個setLenient用於設置它的容錯性,Calendar默認支持較好容錯性,經過setLenient(false)能夠關閉Calendar的容錯性,讓它進行嚴格的參數檢查。
(3).set方法延遲修改
set(f, value)方法將日曆字段f更改成 value,此外,它還設置了一個內部成員變量,以指示日曆字段f已經被更改。儘管日曆字段 f 是當即更改的,但該Calendar所表明時間卻不會當即修改。可是直到下次調用 get()、getTime()、getTimeInMillis()、add() 或 roll()時纔會從新計算日曆的時間。這被稱爲set方法的延遲修改,採用延遲修改的優點是屢次調用set()不會觸發屢次沒必要要的計算(須要計算出一個表明實際時間的long型整數)。
下面程序演示了set方法延遲修改的效果:
public class TestLazy
{
public static void main(String[] args)
{
Calendar cal = Calendar.getInstance();
cal.set(2003 , 7 , 31); //2003-8-31
cal.set(MONTH , 8); //理論上應該是是10月1日,但其實是9月31日(不合法的日期)
//下面代碼輸出10月1日
//System.out.println(cal.getTime()); //①
//設置DATE字段爲5
cal.set(DATE , 5); //②
System.out.println(cal.getTime()); //③
}
}
上面程序中建立了表明2003-8-31的Calendar對象,當把這個對象的MONTH字段加1後應該獲得2003-10-1(由於9月沒有31日),若是程序在①處代碼輸出當前Calendar裏的日期,也會看到輸出2003-10-1,③處輸出2003-9-5。
若是程序將①處代碼註釋起來,由於Calendar的set方法具備延遲修改的特性,即Calendar實際上並未計算真實的日期,它只是使用內部成員變量表記錄MONTH字段被修改成8,接着程序設置DATE字段值爲5,程序內部再次記錄DATE字段爲5——就是9月5日,所以看到③處輸出2003-9-5。
(參考資料:《瘋狂Java講義》)