Note: JT.java uses or overrides a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
檢查 API 才發現, 原來 java.util.Date 的方法大部分早已經被廢棄 (deprecated), 參見 :
# http://docs.oracle.com/javase/7/docs/api/java/util/Date.html
一. java.util.Date類別 :
Date 物件僅剩下列四個是常用的方法 :
- after(Date when) : 檢查日期物件時間是否在本物件後 (true/false)
- before(Date when) : 檢查日期物件時間是否在本物件前 (true/false)
- getTime() : 傳回自 1970/1/1 以來之毫秒數
- setTime(int ms) : 將時間設定為 1970/1/1 後之毫秒數
- toString() : 把 Date 物件轉成字串
import java.util.*;
public class mytest {
public static void main(String[] args) {
Date d=new Date(); //建立目前時間之 Date 物件
System.out.println(d.getTime()); //輸出 1396313616224
System.out.println(System.currentTimeMillis()); //輸出 1396313616224
System.out.println(d.toString()); //輸出 Tue Apr 01 08:53:36 CST 2014
Date d1=new Date(1); //建立時間戳記為 1ms 之 Date 物件 (自 1970/1/1)
System.out.println(d1.before(d)); //輸出 true
System.out.println(d.before(d1)); //輸出 false
System.out.println(d1.after(d)); //輸出 false
System.out.println(d.after(d1)); //輸出 true
d1.setTime(4396267507921L); //須為長整數
System.out.println(d.after(d1)); //輸出 false
}
}
要取得自 1970/1/1 以來的毫秒數也可以用 System.currentTimeMillis() 方法, 事實上, 在 new Date() 時, 也是使用此方法取得系統時間的.
Date 類別其他以前常用的 getYear(), getDate() 等都被廢棄了, 我離開 Java 太久了, 竟然一無所知. 現在要改用 java.util.Calendar 類別, 其 API 如下 :
# http://docs.oracle.com/javase/7/docs/api/java/util/Calendar.html
二. java.util.Calendar 類別 :
使用 Calender 時只要呼叫其靜態方法 getInstance() 就會傳回一個 Calendar 物件 :
Calendar c=Calendar.getInstance();
要取得年月日時分秒資訊可直接擷取其欄位, 傳回值均為整數, 我們可將其放入陣列 :
int[] a={c.get(Calendar.YEAR),
c.get(Calendar.MONTH),
c.get(Calendar.DAY_OF_MONTH),
c.get(Calendar.HOUR_OF_DAY),
c.get(Calendar.MINUTE),
c.get(Calendar.SECOND)
};
注意這裡 DAY_OF_MONTH 之值為 0~11, 與 Javascript 的 Date 物件之 getMonth() 一樣, 所以必須加一轉成我們習慣的 1~12 月. 現在是 3 月 31 日, 下面的範例卻顯示 2 月 31 日 :
import java.util.*;
public class mytest {
public static void main(String[] args) {
Calendar c=Calendar.getInstance();
int[] a={c.get(Calendar.YEAR),
c.get(Calendar.MONTH),
c.get(Calendar.DAY_OF_MONTH),
c.get(Calendar.HOUR_OF_DAY),
c.get(Calendar.MINUTE),
c.get(Calendar.SECOND)
};
for (int i:a) {System.out.print(i + " ");} //輸出 2014 2 31 16 6 33
}
}
如果要指定日期時間, 則要呼叫 set() 方法,
set(int year, int month, int date, int hourOfDay, int minute, int second)
注意, 其中的月份也是要傳入實際月份減一才對.
我的常用類別庫對日期時間的要求其時很簡單, 最常用的是傳回目前的日期時間字串, 以便寫入資料庫或 log 檔中, 慣用格式為 "2014-03-31 13:24:41". 這可以用下列靜態方法達成 :
import java.util.Calendar;
public class mytest {
public static void main(String[] args) {
System.out.println(getDateTime()); //輸出 2014-03-31 16:15:45
System.out.println(getDateTime(2014,3,31,0,59,59)); //輸出 2014-03-31 00:59:59
}
public static String getDateTime() { //無參數=傳回現在時間
Calendar c=Calendar.getInstance();
return getYMDHMS(c);
}
public static String getDateTime(int Y, int M, int D, int H, int m, int S) { //指定時間
Calendar c=Calendar.getInstance();
c.set(Y, --M, D, H, m, S); //傳進來的實際月份要減 1
return getYMDHMS(c);
}
public static String getYMDHMS(Calendar c) { //輸出格式製作
int[] a={c.get(Calendar.YEAR),
c.get(Calendar.MONTH),
c.get(Calendar.DAY_OF_MONTH),
c.get(Calendar.HOUR_OF_DAY),
c.get(Calendar.MINUTE),
c.get(Calendar.SECOND)
};
StringBuffer sb=new StringBuffer();
sb.append(a[0]);
if (a[1]<9) {sb.append("-0" + (a[1] + 1));} //加 1 才會得到實際月份
else {sb.append("-" + (a[1] + 1));}
if (a[2]<10) {sb.append("-0" + (a[2]));}
else {sb.append("-" + (a[2]));}
if (a[3]<10) {sb.append(" 0" + (a[3]));}
else {sb.append(" " + (a[3]));}
if (a[4]<10) {sb.append(":0" + a[4]);}
else {sb.append(":" + a[4]);}
if (a[5]<10) {sb.append(":0" + a[5]);}
else {sb.append(":" + a[5]);}
return sb.toString();
}
}
可見對於小於 10 之值前端補 0, 就會傳回我要的標準格式. 注意, 上面的 getDateTime() 方法已經針對月份做加 1 處理過了, 因此呼叫時要傳入實際的月份, 不須再加 1 了.
Calendar 也跟 Date 一樣有一個 getTime() 方法, 但它會傳回一個 Date 物件, 而非自 1970/1/1 的毫秒數. Calendar 類別中相同功能的方法為 getTimeInMillis(). 同樣的, Calendar 也有一個 setTime() 方法, 但其傳入參數不是一個長整數, 而是一個 Date 物件 :
import java.util.*;
public class mytest {
public static void main(String[] args) {
Calendar c=Calendar.getInstance();
Date d=c.getTime(); //傳回 Date 物件
System.out.println(d.getTime()); //輸出 1396267507921
System.out.println(c.getTimeInMillis()); //輸出 1396267507921
d.setTime(1396277507921L); //傳入長整數
c.setTime(d); //傳入 Date 物件
int[] a={c.get(Calendar.YEAR),
c.get(Calendar.MONTH),
c.get(Calendar.DAY_OF_MONTH),
c.get(Calendar.HOUR_OF_DAY),
c.get(Calendar.MINUTE),
c.get(Calendar.SECOND)
};
for (int i:a) {System.out.print(i + " ");} //輸出 2014 2 31 22 51 47
}
}
Calendar 類別也有 before() 與 after() 用來比較兩個 Calendar 物件的時間先後, 例如
import java.util.*;
public class mytest {
public static void main(String[] args) {
Date d=new Date();
Calendar c1=Calendar.getInstance();
Calendar c2=Calendar.getInstance();
d.setTime(1); //設定時戳為 1ms
c1.setTime(d);
d.setTime(2); //設定時戳為 2ms
c2.setTime(d);
System.out.println(c1.before(c2)); //輸出 true
System.out.println(c1.after(c2)); //輸出 false
}
}
Calendar 類別還有一個常用的應用是求指定日期是星期幾. 這個必須用到 Calendar.DAY_OF_WEEK 這個欄位, 其值為 0 (Sunday) ~ 6 (Saturday), 相對應 Calendar.SUNDAY~Calendar.SATURDAY. 透過判別 Calendar.DAY_OF_WEEK 之值, 即傳回 "星期日" ~ "星期六" 字串, 如下列範例所示 :
import java.util.*;
import java.text.*;
public class mytest {
public static void main(String[] args) {
System.out.println(getDayOfWeek("2014-04-01")); //輸出 星期二
}
public static int[] parseDate(String date) {
String[] d=date.split("-");
int[] dt=new int[3];
dt[0]=Integer.parseInt(d[0]);
dt[1]=Integer.parseInt(d[1]);
dt[2]=Integer.parseInt(d[2]);
return dt;
}
public static String getDayOfWeek(String date) {
int[] d=parseDate(date);
Calendar c=Calendar.getInstance();
c.set(d[0],d[1]-1,d[2]); //這裡務必減 1
String w="";
switch(c.get(Calendar.DAY_OF_WEEK)) {
case Calendar.SUNDAY : {w="星期日";break;}
case Calendar.MONDAY : {w="星期一";break;}
case Calendar.TUESDAY : {w="星期二";break;}
case Calendar.WEDNESDAY : {w="星期三";break;}
case Calendar.THURSDAY : {w="星期四";break;}
case Calendar.FRIDAY : {w="星期五";break;}
case Calendar.SATURDAY : {w="星期六";break;}
}
return w;
}
}
三. DateFormat 與 SimpleDateFormat 類別 :
這兩個類別與上面的 Date 跟 Calendar 源頭不同, 它們並非來自 java.util 類別庫, 而是源自 java.text.Format 類別, SimpleDateFormat 則是 DateFormat 的子類別.
java.lang.Object
|__ java.text.Format
|__ java.text.DateFormat
|__ java.text.SimpleDateFormat
這兩個類別主要是用來轉換日期字串與 Date 物件, 剖析日期字串可能因為格式錯誤而拋出例外, 所以使用 DateFormat 與 SimpleDateFormat 這兩個類別時, 必須匯入 ParseException 類別 :
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.text.ParseException;
或者乾脆 :
import java.text.*;
# http://docs.oracle.com/javase/7/docs/api/java/text/DateFormat.html
# http://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html
DateFormat 類別有四個欄位用來設定日期字串的顯示格式 (style) :
欄位 | 說明 |
DateFormat.SHORT (3) | "3/31/14" 2014 年 3 月 31 日 (美式) |
DateFormat.MEDIUM (2) | "Mar 31, 2014" |
DateFormat.LONG (1) | "March 31, 2014" |
DateFormat.SHORT (0) | "Monday, March 31, 2014" |
此四種格式是用來設定日期物件的顯示格式. 跟 Calendar 類別一樣, 要取得 DateFormat 物件可以直接呼叫類別方法 getDateTimeInstance() :
DateFormat df=DateFormat.getDateTimeInstance();
沒有傳入參數的話, 傳回的 DateFormat 物件會以預設的日期與時間格式與區域 (Locale) 來進行格式化. 呼叫 format() 方法即傳回值其格式化字串, 如下所示 :
import java.util.*;
import java.text.*;
public class mytest {
public static void main(String[] args) {
Date d=new Date();
DateFormat df=DateFormat.getDateTimeInstance(); //取得預設格式化物件
System.out.println(df.format(d)); //輸出 2014/4/1
}
}
也可以傳入日期與時間格式參數 :
getDateTimeInstance(int dateStyle, int timeStyle)
這樣就會依照指定格式顯示, 這裡為了簡單起見, 傳入整數代碼 :
import java.util.*;
import java.text.*;
public class mytest {
public static void main(String[] args) {
Date d=new Date();
DateFormat df_short=DateFormat.getDateTimeInstance(3,3); //SHORT 格式
DateFormat df_medium=DateFormat.getDateTimeInstance(2,2); //MEDIUM 格式
DateFormat df_long=DateFormat.getDateTimeInstance(1,1); //LONG 格式
DateFormat df_full=DateFormat.getDateTimeInstance(0,0); //FULL 格式
System.out.println(df_short.format(d)); //輸出 2014/4/1 上午 10:18
System.out.println(df_medium.format(d)); //輸出 2014/4/1 上午 10:18:06
System.out.println(df_long.format(d)); //輸出 2014年4月1日 上午10時18分06秒
System.out.println(df_full.format(d)); //輸出 2014年4月1日 星期二 上午10時18分06秒 TST
}
}
可見預設是顯示本地的區域語言 (Locale), 如果要顯示英文, 則要傳入第三參數 locale :
getDateTimeInstance(int dateStyle, int timeStyle, Local locale)
這就需要用到 java.util.Local 類別來建立一個 Locale 物件 :
Locale locale=new Locale("en", "US");
第一個參數為語言, 第二個參數是國家 :
Locale(String language, String country)
台灣的話, language 傳入 "zh", country 傳入 "zh_TW". 如下表所示 :
語言 | Language | Country |
美式英文 | en | US |
英式英文 | en | en_GB |
加式英文 | en | en_CA |
繁體中文 | zh | zh_TW |
日文 | ja | ja_JP |
韓文 | ko | ko_KR |
簡體中文 | zh | zh_CN |
德文 | de | de_DE |
義大利文 | it | it_IT |
法文 | fr | fr_FR |
加式法文 | fr | fr_CA |
# http://docs.oracle.com/javase/7/docs/api/java/util/Locale.html
下列範例設定為英文格式輸出 :
import java.util.*;
import java.text.*;
public class mytest {
public static void main(String[] args) {
Date d=new Date();
Locale locale=new Locale("en", "US");
DateFormat df_short=DateFormat.getDateTimeInstance(3,3,locale);
DateFormat df_medium=DateFormat.getDateTimeInstance(2,2,locale);
DateFormat df_long=DateFormat.getDateTimeInstance(1,1,locale);
DateFormat df_full=DateFormat.getDateTimeInstance(0,0,locale);
System.out.println(df_short.format(d)); //輸出 4/1/14 11:05 AM
System.out.println(df_medium.format(d)); //輸出 Apr 1, 2014 11:05:48 AM
System.out.println(df_long.format(d)); //輸出 April 1, 2014 11:05:48 AM CST
System.out.println(df_full.format(d)); //輸出 Tuesday, April 1, 2014 11:05:48 AM CST
}
}
可見傳入美國的 Locale 後就全部洋化了. 以上是把 Date 物件格式化為字串輸出, 反過來要把日期時間字串轉成 Date 物件該怎麼做? 這可以呼叫 parse() 方法來剖析字串, 此方法會傳回一個 Date 物件 :
Date parse(String source)
但日期時間字串格式不見得正確, 可能會拋出例外, 因此 parse() 必須放在 try catch 區塊裡面, 如下例所示 :
import java.util.*;
import java.text.*;
public class mytest {
public static void main(String[] args) {
Date d=new Date();
Locale locale=new Locale("en", "US");
DateFormat df_short=DateFormat.getDateTimeInstance(3,3,locale);
DateFormat df_medium=DateFormat.getDateTimeInstance(2,2,locale);
DateFormat df_long=DateFormat.getDateTimeInstance(1,1,locale);
DateFormat df_full=DateFormat.getDateTimeInstance(0,0,locale);
try {d=df_medium.parse("Apr 1, 2014 11:05:48 AM");}
catch (ParseException e) {e.printStackTrace();}
System.out.println(df_short.format(d)); //輸出 4/1/14 11:05 AM
System.out.println(df_medium.format(d)); //輸出 Apr 1, 2014 11:05:48 AM
System.out.println(df_long.format(d)); //輸出 April 1, 2014 11:05:48 AM CST
System.out.println(df_full.format(d)); //輸出 Tuesday, April 1, 2014 11:05:48 AM CST
}
}
注意, 傳入的日期時間字串, 格式必須符合 DateFormat 之設定, 否則執行時期會拋出例外. 由於 DateFormat 只提供了四種格式, 因此無法產生我需要的 "YYYY-MM-DD HH:mm:SS" 格式, 這可以用 DateFormat 的子類別 SimpleDateFormat 來解決.
SimpleDateFormat 跟 DateFormat 一樣用在 Date 物件與格式字串的互轉, 但 SimpleDateFormat 定義了一些特定的格式字元, 可藉著格式字元來產生所需要的輸出. 參考 :
# http://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html
與 DateFormat 不同的是, 建立一個 SimpleDateFormat 物件是必須呼叫其建構子 :
SimpleDateFormat sdf=new SimpleDateFormat();
此類別的 toPattern() 方法會傳回目前的格式字串, 而 applyPattern() 方法則可以傳入格式字串以套用新的格式, 如下例所示 :
import java.util.*;
import java.text.*;
public class mytest {
public static void main(String[] args) {
Date d=new Date();
SimpleDateFormat sdf=new SimpleDateFormat();
System.out.println(sdf.toPattern()); //輸出 yyyy/M/d a h:mm
System.out.println(sdf.format(d)); //輸出 2014/4/1 下午 1:44
sdf.applyPattern("yyyy-MM-dd HH:mm:ss"); //套用新格式
System.out.println(sdf.format(d)); //輸出 2014-04-01 13:44:36
}
}
可見, 如果建立 SimpleDateFormat 物件時沒有指定格式, 則預設的格式字串為 "yyyy/M/d a h:mm". 也可以在建立物件時就指定格式字串與 Locale 物件 :
SimpleDateFormat(String pattern, Locale locale)
如下範例所示 :
import java.util.*;
import java.text.*;
public class mytest {
public static void main(String[] args) {
Date d=new Date();
Locale locale=new Locale("it", "it_IT"); //義大利語
String pattern="yyyy.MM.dd G 'at' HH:mm:ss z";
SimpleDateFormat sdf=new SimpleDateFormat(pattern,locale); //指定格式與區域語言
System.out.println(sdf.toPattern()); //輸出 yyyy.MM.dd G 'at' HH:mm:ss z
System.out.println(sdf.format(d)); //輸出 2014.04.01 dopo Cristo at 14:51:27 CST
}
}
輸出格式中的 G (Era designator 年代) 就顯示義大利文的 "dopo Cristo" (西元 : 主後).
既然 SimpleDateFormat 是 DateFormat 的子類別, 當然可以使用 format() 與 parse() 方法來互轉 Date 物件與日期時間字串, 如下列範例所示 :
import java.util.*;
import java.text.*;
public class mytest {
public static void main(String[] args) {
Date d=new Date();
System.out.println(d.toString()); //輸出 Tue Apr 01 15:04:12 CST 2014
String pattern="yyyy-MM-dd HH:mm:ss";
SimpleDateFormat sdf=new SimpleDateFormat(pattern);
System.out.println(sdf.format(d)); //輸出 2014-04-01 15:04:12
try {d=sdf.parse("2013-12-25 23:59:59");}
catch (ParseException e) {e.printStackTrace();}
System.out.println(d.toString()); //輸出 Wed Dec 25 23:59:59 CST 2013
}
}
最後, 我們可以利用 SimpleDateFormate 來改良上面用 Calendar 類別寫的 getDateTime() 方法 :
import java.util.*;
import java.text.*;
public class mytest {
public static void main(String[] args) {
System.out.println(getDateTime());
}
public static String getDateTime() {
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return sdf.format(new Date());
}
}
實在是太簡單了, 不須再去處理年月日時分秒了, 難怪取名為 "Simple" !
參考 :
# Java Calendar取得年(year)、月(month)、日(day)
# Java Gossip: 使用 Calendar
# 深入理解Java:SimpleDateFormat安全的时间格式化
# JAVA的日期時間取得
# Java Gossip: 使用 Date、DateFormat
# Java 获得指定日期是一年中的第几天
感謝~~~還好要寫前有看到您這篇
回覆刪除我差點像以前一樣直接用Date XD