Java 語言的Calendar,GregorianCalendar (月曆),Date(日期)和DateFormat(日期格式)組成了Java标準的一個基本但是非常重要的部分。
我們将讨論下面的類:
1、 具體類(和抽象類相對)java.util.Date
2、 抽象類java.text.DateFormat 和它的一個具體子類,java.text.SimpleDateFormat
3、 抽象類java.util.Calendar 和它的一個具體子類,java.util.GregorianCalendar(公元月曆)
具體類可以被執行個體化, 但是抽象類卻不能。 你首先必須實作抽象類的一個具體子類。
Calendar c = Calendar.getInstance(); 等價于 Calendar gc = new GregorianCalendar();
Date date = new Date();
SimpleDateFormat df = new SimpleDateFormat(格式模式字元串);
1、Date及其格式化
Date 類從Java 開發包(JDK) 1.0 就開始進化,當時它隻包含了幾個取得或者設定一個日期資料的各個部分的方法, 比如說年、月、日。 這些方法現在遭到了批評并且已經被轉移到了Calendar類裡去了。這種改進旨在更好的處理日期資料的國際化格式。就在JDK 1.1中一樣, Date 類實際上隻是一個包裹類,它包含的是一個長整型long資料,表示的是從GMT(格林尼治标準時間)1970年1 月 1日00:00:00這一刻之前或者是之後經曆的毫秒數。Long類型表示的最大正值和最大負值可以輕松的表示290,000,000年(足夠使用)的時間。
讓我們看一個使用系統的目前日期和時間建立一個日期對象并傳回一個長整數的簡單例子。這個時間通常被稱為Java 虛拟機(JVM)主機環境的系統時間。
例如要得到今年的年份:date.getYear()+1900或者Calendar.get(Calendar.YEAR)
<span style="font-size:14px;">import java.util.Date;
public class Test_1 {
public static void main(String[] args) {
//目前系統時間,這個構造函數在内部使用了System.currentTimeMillis()方法來從系統擷取日期
Date date = new Date();
//傳回時間的long類型(毫秒數)
System.out.println("long類型(毫秒數):"+date.getTime());
//Calendar.get(Calendar.YEAR)-1900
System.out.println("年份x-1900:"+date.getYear());
//Calendar.get(Calendarendar.MONTH) <span style="color:#cc33cc;">(0-11)
</span> System.out.println("月份(<span style="color:#cc33cc;">0-11</span>):"+date.getMonth());
//Calendar.get(Calendar.DAY_OF_MONTH)
System.out.println("幾号:"+date.getDate());
//Calendar.get(Calendar.DAY_OF_WEEK) <span style="color:#6600cc;"> (1-日,2-周一,3-周二...7-周六)
</span> System.out.println("星期<span style="color:#cc33cc;">(0-日,1-1,2-2...6-6</span>):"+date.getDay());
//Calendar.get(Calendar.HOUR_OF_DAY)
System.out.println("小時(0-23):"+date.getHours());
//Calendar.get(Calendar.MINUTE)
System.out.println("分鐘(0-59):"+date.getMinutes());
//Calendar.get(Calendar.SECOND)
System.out.println("秒(0-59):"+date.getSeconds());
}
}</span>
同時,也有與get相應的set方法。
- 将日期格式化為字元串:
Date是一個long類型的資料,而我們想要将其格式化為我們能都讀取的日期格式,這裡就需要用到SimpleDateFormat了。SimpleDateFormat 是一個以與語言環境有關的方式來格式化和解析日期的具體類。它允許進行格式化(日期 -> 文本)、解析(文本 -> 日期)和規範化。
首先,先執行個體化一個自定義格式的SimpleDateFormat,例如SimpleDateFormat sdf = new SimpleDateFormat(“yyyy-MM-dd E”);模式字母參考API文檔中SimpleDateFormat。接下來将給定的
Date
格式化為日期/時間字元串,sdf.format(new Date()); 即得到 2014-05-13 星期二。
<span style="font-size:14px;color:#ff0000;"> SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd E");
System.out.println(sdf.format(new Date()));</span>
- 文本資料解析成日期對象
假設我們有一個已知格式化的日期對象的文本字元串,而我們希望解析這個字元串并從文本日期資料建立一個日期對象。我們将再次以格式化字元串"MM-dd-yyyy" 調用SimpleDateFormat類, 但是這一次, 我們使用格式化解析而不是生成一個文本日期資料。例如将文本字元串"05-13-2014"解析為一個值為1399910400000 的日期對象。
通過parse()方法,DateFormat能夠以一個字元串創立一個Date對象。這個方法能抛出ParseException異常,是以你必須使用适當的異常處理技術。
<span style="font-size:18px;"> </span><span style="font-size:14px;">SimpleDateFormat sdf = new SimpleDateFormat("MM-dd-yyyy");
String str = "05-13-2014";
Date date = null;
try {
date = <span style="color:#ff0000;">sdf.parse(str);</span>
} catch (ParseException e) {
e.printStackTrace();
}
System.out.println(date.getTime());</span>
這樣就将"05-13-2014"解析為一個值為1399910400000 的日期對象,當然,實際中我們很少需要這樣一個長整型的日期對象,這時就我們用到上面的将日期對象轉換為我們需要的字元串了。實際上我們是将日期對象date作為一個中轉,執行個體化兩個格式化對象作為轉換的通道。 String1 ——(sdf1)——> date ——(sdf2)——>String2
另外,各種求日期之間的計算,都可以将字元串類型轉換為Date的長整型,然後數學計算,之後再将Data類型轉換為String。例如:
<span style="font-size:14px;">import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Test_1 {
public static void main(String[] args){
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date = null;
Date mydate = null;
try {
date = sdf.parse("2003-05-1");
mydate= sdf.parse("1899-12-30");
} catch (ParseException e) {
e.printStackTrace();
}
long day =(date.getTime()-mydate.getTime())/(24*60*60*1000);
System.out.println(day);
}
}</span>
- 使用标準的日期格式化過程
我們已經可以生成和解析定制的日期格式了, 讓我們來看一看如何使用内建的格式化過程.
1.方法DateFormat df = DateFormat.getDateInstance();獲得一個預設的日期(隻是日期)格式化風格;
2.方法DateFormat.getTimeInstance()獲得一個預設的時間(隻是時間)格式化風格;
3.方法 DateFormat.getDateTimeInstance() 獲得标準的日期+時間格式化風格。
這三個方法都有想對應的可傳參改變日期風格或日期風格的的同類型方法。參數可用DateFormat中的常量,如下:
參數(int):DateFormat.SHORT DateFormat.MEDIUM DateFormat.LONG DateFormat.FULL
注意我們在對 getDateTimeInstance的每次調用中都傳遞了兩個值。第一個參數是日期風格,而第二個參數是時間風格。它們都是基本資料類型int(整型)。考慮到可讀性,我們使用了DateFormat 類提供的常量:SHORT, MEDIUM, LONG, 和 FULL。例如DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT);
2、 Calendar 月曆類
首先請記住 Calendar 隻是一個抽象類, 也就是說你無法直接獲得它的一個執行個體,換而言之你可以提供一個自己開發的 Calendar 對象。
那究竟什麼是一個 Calendar 呢?中文的翻譯就是月曆,那我們立刻可以想到我們生活中有陽(公)曆、陰(農)曆之分。它們的差別在哪呢?
比如有:月份的定義 - 陽`(公)曆 一年12 個月,每個月的天數各不同;陰(農)曆,每個月固定28天,每周的第一天 - 陽(公)曆星期日是第一天;陰(農)曆,星期一是第一天。實際上,在曆史上有着許多種紀元的方法。它們的差異實在太大了,比如說一個人的生日是"八月八日" 那麼一種可能是陽(公)曆的八月八日,但也可以是陰(農)曆的日期。是以為了計時的統一,必需指定一個月曆的選擇。那現在最為普及和通用的月曆就是 "Gregorian Calendar"。也就是我們在講述年份時常用 "公元幾幾年"。Calendar 抽象類定義了足夠的方法,讓我們能夠表述月曆的規則。Java 本身提供了對 "Gregorian Calendar" 規則的實作。我們從 Calendar.getInstance() 中所獲得的執行個體就是一個 "GreogrianCalendar" 對象(與您通過 new GregorianCalendar() 獲得的結果一緻)。
Calendar c = Calendar.getInstance(); 等價于 Calendar gc = new GregorianCalendar();獲得标準月曆系統(公元)
擷取目前的Date, Date date = c.getTime()就等價與Date date = new Date(),當然有getTime()就有setTime(Date),使用給定的
Date
設定此 Calendar 的時間。
設定月曆字段:
set(int field, int value) 将給定的月曆字段設定為給定值。field是指要設定的域,例如,要設定月份,則可以使用方法set(Calendar.MONTH, 4),将月份設定為5月(另外,月份的起始值為0而不是1,是以要設定五月時,我們用4而不是5)。為了增加可讀性和防止出錯,我們一般這樣使用:set(Calendar.MONTH, Calendar.MARCH)。
set(int field, int value) 還有3個重寫的方法,分别設定不同字段範圍的值,例如set(2014,4, 15, 14, 25, 33);設定年月日時分秒,2014年5月15日14點25分33秒。而要設定毫秒值必須用第一個方法。
獲得月曆字段:
使用get(int field)方法可以獲得想要的字段。例如:get(Calendar.YEAR);獲得目前月曆中的年份,當然還有很多值,MONTH(目前月份-1),DATE = DAY_OF_MONTH(幾号),DAY_OF_YEAR(一年中的第幾天),DAY_OR_WEEK(周日=1,周一=2,周二=3...周六=7)
值得注意的是
1. 在擷取月份時,Calendar.MONTH + 1 的原因
Java中的月份遵循了羅馬曆中的規則:當時一年中的月份數量是不固定的,第一個月是JANUARY。而Java中Calendar.MONTH傳回的數值其實是目前月距離第一個月有多少個月份的數值,JANUARY在Java中傳回“0”,是以我們需要+1。
2. 在擷取星期幾 Calendar.DAY_OF_WEEK – 1 的原因
Java中Calendar.DAY_OF_WEEK其實表示:一周中的第幾天,是以他會受到 第一天是星期幾 的影響。
有些地區以星期日作為一周的第一天,而有些地區以星期一作為一周的第一天,這2種情況是需要區分的。
看下表的傳回值
星期日為一周的第一天 | SUN | MON | TUE | WED | THU | FRI | SAT |
DAY_OF_WEEK傳回值 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
星期一為一周的第一天 | MON | TUE | WED | THU | FRI | SAT | SUN |
DAY_OF_WEEK傳回值 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
是以Calendar.Day_OF_WEEK需要根據本地設定的不同而确定是否需要“-1”,預設為第一種,即周日為第一天,java中設定不同地區的輸出可以使用Local.setDefalut(Locale.地區名)來實作。
3.擷取日期時Calendar.DAY_OF_MONTH不需要特殊的操作,它直接傳回一個月中的第幾天。即幾号就是幾。
錯誤日期:
add(field, value),add可以對Calendar的字段進行計算。如果需要減去值,那麼value使用負值就可以了。
add()可以對Calendar的字段進行計算。如果需要減去值,那麼使用負數值就可以了,如 add(field, -value)。add(f, delta) 将
delta
添加到
f
字段中。這等同于調用
set(f, get(f) + delta)
,但要帶以下兩個調整:
i. 當被修改的字段超出它可以的範圍時,那麼比它大的字段會自動修正,溢出的字段調整回其範圍内。如:
現在日期為2013年5月30日,調用add(Calendar.DAY_OF_MONTH,2) ,即2013年5月32日。而5月最多為31日,這是個錯誤的日期,是以,比錯誤字段(日)大的字段(月),就會自動修正,即得到整齊的日期2013年6月1日。是以,日的加減可以不用考慮是否合法,Calendar會自動變成合法的。但是月份就不同了。使用set()設定的時候同樣。
ii.另一個規則是,如果期望某一個更小的字段是不變的(由 Calendar 的實作類決定,如下,修改月份時,沒有修改日),那麼它的值被調整為盡量接近于所期望的值。更小的字段表示一個更小的時間單元。例如:
因為日是比月更小的單元,是以9-31會變為9-30而不是10-1。
<span style="font-size:14px;">Calendar cal1 = Calendar.getInstance();
cal1.set(2000, 7, 31, 0, 0 , 0); //2000-8-31
cal1.add(Calendar.MONTH, 1); //2000-9-31 => 2000-10-1,對嗎?
System.out.println(cal1.getTime()); //結果是 2000-9-30</span>
roll(f, delta)
将
delta
添加到
f
字段中,但不更改更大的字段。這等同于調用
add(f, delta)
,但要帶以下調整:
roll規則:在完成調用後,更大的字段無變化。更大的字段表示一個更大的時間單元。
DAY_OF_MONTH
是一個比
HOUR
大的字段。
以下是一個很實用的工具類,實作的日期與字元串還有月曆間的各種轉換
import java.util.Calendar;
import java.util.Date;
import java.text.*;
public class Date_test {
/**
* 将Date類型日期轉化成String類型"任意"格式
* java.sql.Date,java.sql.Timestamp類型是java.util.Date類型的子類
*
* @param date
* Date
* @param format
* String "2003-01-01"格式 "yyyy年M月d日" "yyyy-MM-dd HH:mm:ss"格式
* @return String
*/
public static String dateToString(java.util.Date date, String format) {
if (date == null || format == null) {
return null;
}
SimpleDateFormat sdf = new SimpleDateFormat(format);
String str = sdf.format(date);
return str;
}
/**
* 将String類型日期轉化成java.utl.Date類型"2003-01-01"格式
*
* @param str
* String 要格式化的字元串
* @param format
* String
* @return Date
*/
public static java.util.Date stringToUtilDate(String str, String format) {
if (str == null || format == null) {
return null;
}
SimpleDateFormat sdf = new SimpleDateFormat(format);
java.util.Date date = null;
try {
date = sdf.parse(str);
} catch (Exception e) {
e.printStackTrace();
}
return date;
}
/**
* 将String類型日期轉化成java.sql.Date類型"2003-01-01"格式
*
* @param str
* String
* @param format
* String
* @return Date
*/
public static java.sql.Date stringToSqlDate(String str, String format) {
if (str == null || format == null) {
return null;
}
SimpleDateFormat sdf = new SimpleDateFormat(format);
java.util.Date date = null;
try {
date = sdf.parse(str);
} catch (Exception e) {
return null;
}
return new java.sql.Date(date.getTime()); //預設調用java.sql.Date的toString()方法,傳回yyyy-MM-dd格式
}
/**
* 将String類型日期轉化成java.sql.Date類型"2003-01-01"格式
*
* @param str
* String
* @param format
* String
* @return Timestamp
*/
public static java.sql.Timestamp stringToTimestamp(String str, String format) {
if (str == null || format == null) {
return null;
}
SimpleDateFormat sdf = new SimpleDateFormat(format);
java.util.Date date = null;
try {
date = sdf.parse(str);
} catch (Exception e) {
return null;
}
return new java.sql.Timestamp(date.getTime());
}
/**
* 将java.util.Date日期轉化成java.sql.Date類型
*
* @param Date
* @return 格式化後的java.sql.Date
*/
public static java.sql.Date toSqlDate(Date date) {
if (date == null) {
return null;
}
return new java.sql.Date(date.getTime());
}
/**
* 将字元串轉化為時間格式 string to string
*
* @param str
* String
* @param format
* String
* @return String
*/
public static String toDateString(String str, String oldformat,
String newformat) {
return dateToString(stringToUtilDate(str, oldformat), newformat);
}
/**
* 将月曆轉化為日期
*
* @param calendar
* Calendar
* @return Date
*/
public static java.util.Date converToDate(java.util.Calendar calendar) {
return Calendar.getInstance().getTime();
}
/**
* 将日期轉化為月曆
*
* @param date
* Date
* @return Calendar
*/
public static java.util.Calendar converToCalendar(java.util.Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
return calendar;
}
/**
* 求得從某天開始,過了幾年幾月幾日幾時幾分幾秒後,日期是多少 幾年幾月幾日幾時幾分幾秒可以為負數
*
* @param date
* Date
* @param year
* int
* @param month
* int
* @param day
* int
* @param hour
* int
* @param min
* int
* @param sec
* int
* @return Date
*/
public static java.util.Date modifyDate(java.util.Date date, int year,
int month, int day, int hour, int min, int sec) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
cal.add(Calendar.YEAR, year);
cal.add(Calendar.MONTH, month);
cal.add(Calendar.DATE, day);
cal.add(Calendar.HOUR, hour);
cal.add(Calendar.MINUTE, min);
cal.add(Calendar.SECOND, sec);
return cal.getTime();
}
/**
* 取得目前日期時間 1:year 2:month 3:day
*/
public static int getCurTime(int i) {
if (i == 1) {
return java.util.Calendar.getInstance().get(Calendar.YEAR);
} else if (i == 2) {
return java.util.Calendar.getInstance().get(Calendar.MONTH) + 1;
} else if (i == 3) {
return java.util.Calendar.getInstance().get(Calendar.DATE);
}
return 0;
}
public static void main(String[] args) {
System.out.println(dateToString(
modifyDate(Calendar.getInstance().getTime(), -1, -1, -1, -1,
-1, -1), "yyyy-MM-dd HH:mm:ss"));
}
}