昨晚整理完 Java 的常用日期時間相關類別之應用, 發現還有幾個常用的 javascript 版本的函式, 改寫如下 :
1. 判斷閏年 :
閏年的判斷演算法有一個公式, 在 Javascript 是這樣 :
return !(year % 4) && (year % 100) || !(year % 400) ? true : false;
即年份是 4 與 100 的公倍數, 或者是 400 的倍數. Java 處理閏年有現成的 GregorianCalendar 類別可用, 只要先建立 GregorianCalendar 物件, 再呼叫其 isLeapYear() 即可 :
GregorianCalendar g=new GregorianCalendar();
API 參見 :
# http://docs.oracle.com/javase/7/docs/api/java/util/GregorianCalendar.html
如下列範例所示 :
import java.util.*;
import java.text.*;
public class mytest {
public static void main(String[] args) {
System.out.println(isLeapYear()); //輸出 false (今年 2014 非閏年)
System.out.println(isLeapYear(2012)); //輸出 true
}
public static int getYear() {
SimpleDateFormat sdf=new SimpleDateFormat("yyyy");
return Integer.parseInt(sdf.format(new Date()));
}
public static boolean isLeapYear() {
return isLeapYear(getYear());
}
public static boolean isLeapYear(int year) {
GregorianCalendar g=new GregorianCalendar();
return g.isLeapYear(year);
}
}
此例中我使用了方法多載實現參數預設值功能, 無參數時預設為今年; 同時也用了 SimpleDateFormat 類別來求取今年年份.
2. 一年中的第幾天 :
一年 365/366 天, 若指定日期, 如何得知此為一年中的第幾天 ? 這可以利用 String 類別的 format() 方法, 將 Date 物件傳進去當地二參數, 利用第一參數 "%tj" 這個格式化字串傳回該日期是一年中的第幾天字串, 再轉成整數即可, 詳參 String 與 Formatter 兩類別 :
# http://docs.oracle.com/javase/7/docs/api/java/lang/String.html
# http://docs.oracle.com/javase/7/docs/api/java/util/Formatter.html
範例如下 :
import java.util.*;
import java.text.*;
public class mytest {
public static void main(String[] args) {
System.out.println(getDayOfYear()); //輸出 92 (今天是 2014-04-02)
System.out.println(getDayOfYear("2012-01-01")); //輸出 1
System.out.println(getDayOfYear("2012-12-31")); //輸出 366
}
public static String getDate() {
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
return sdf.format(new Date()); //傳回今日的日期字串
}
public static int getDayOfYear() {
return getDayOfYear(getDate());
}
public static int getDayOfYear(String date) {
Date d=new Date();
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
try {d=sdf.parse(date);} //將傳入日期剖析為 Date 物件
catch (ParseException e) {e.printStackTrace();}
return Integer.parseInt(String.format("%tj",d)); //轉成一年中的第幾天
}
}
此例中同樣使用方法多載處理預設值, 無參數傳入時表示求今日為一年中第幾日.
3. 一年中的第幾周 :
在 Calendar 類別中有一個 Calendar.WEEK_OF_YEAR 可以求得指定日期是一年中的第幾周. 先將指定日期字串分解為整數陣列後, 傳入 Calendar.set() 方法中將日曆設為指定日期, 即可由 Calendar.WEEK_OF_YEAR 取得答案.
# http://docs.oracle.com/javase/7/docs/api/java/util/Calendar.html
範例如下 :
import java.util.*;
import java.text.*;
public class mytest {
public static void main(String[] args) {
System.out.println(getWeekOfYear()); //輸出 14 (今天是 2014-04-02)
System.out.println(getWeekOfYear("2012-01-01")); //輸出 1
System.out.println(getWeekOfYear("2012-12-28")); //輸出 52
System.out.println(getWeekOfYear("2012-07-01")); //輸出 27
System.out.println(getWeekOfYear("2014-01-01")); //輸出 1
System.out.println(getWeekOfYear("2014-12-28")); //輸出 1
System.out.println(getWeekOfYear("2014-07-01")); //輸出 27
}
public static String getDate() { //傳回今日日期字串
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
return sdf.format(new Date());
}
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 int getWeekOfYear() {
return getWeekOfYear(getDate()); //傳入今日日期字串
}
public static int getWeekOfYear(String date) {
int[] d=parseDate(date); //將日期字串轉成陣列
Calendar c=Calendar.getInstance();
c.set(d[0],d[1]-1,d[2]); //設定日曆物件之日期 (注意月份要減 1)
return c.get(Calendar.WEEK_OF_YEAR);
}
}
此例中, 2012-12-28 為 2012 年的第 52 周; 但 2014-12-28 卻是第 1 周, 這是因為年尾的幾天有可能已被歸入下年度的第一週.
4. 一個月中的第幾周 :
與上面一年中的第幾周類似, 也是利用 Calendar 類別的 Calendar.WEEK_OF_MONTH 欄位來求解, 範例如下, 僅最後一行改變而已 :
import java.util.*;
import java.text.*;
public class mytest {
public static void main(String[] args) {
System.out.println(getWeekOfMonth());
System.out.println(getWeekOfMonth("2014-04-01"));
System.out.println(getWeekOfMonth("2014-04-30"));
}
public static String getDate() {
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
return sdf.format(new Date());
}
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 int getWeekOfMonth() {
return getWeekOfMonth(getDate());
}
public static int getWeekOfMonth(String date) {
int[] d=parseDate(date);
Calendar c=Calendar.getInstance();
c.set(d[0],d[1]-1,d[2]);
return c.get(Calendar.WEEK_OF_MONTH);
}
}
5. 取得星期名稱 :
有時在記錄到 log 或資料庫時, 會順便紀錄星期幾, 在上一篇曾用 switch 來處理, 現在改用陣列來做, 同時改良功能, 加入語言參數, 可以選擇傳回繁體中文的 "星期日" 或英文的 "Sunday". 範例如下 :
import java.util.*;
import java.text.*;
public class mytest {
public static void main(String[] args) {
System.out.println(getDayOfWeek()); //輸出 星期三 (今天 2014-04-02)
System.out.println(getDayOfWeek("2014-04-01")); //輸出 星期二
System.out.println(getDayOfWeek("2014-04-01","en")); //輸出 Tuesday
}
public static String getDate() {
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
return sdf.format(new Date());
}
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() {
return getDayOfWeek(getDate(),"zh");
}
public static String getDayOfWeek(String date) {
return getDayOfWeek(date,"zh");
}
public static String getDayOfWeek(String date, String language) {
int[] d=parseDate(date);
Calendar c=Calendar.getInstance();
c.set(d[0],d[1]-1,d[2]);
String[] zh=
{"星期日","星期一","星期二","星期三","星期四","星期五","星期六"};
String[] en=
{"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"};
String w=null;
if (language.equals("zh")) {w=zh[c.get(Calendar.DAY_OF_WEEK)-1];}
else {w=en[c.get(Calendar.DAY_OF_WEEK)-1];}
return w;
}
}
這裡要注意, Calendar.DAY_OF_WEEK 欄位之值為 1 (Sunday)~7 (Saturday), 而陣列索引為 0~6, 因此存取時要減 1. 第二參數 language 預設是 "zh" (中文), 若指定為 "en" 則傳回英文.
6. 取得月份名稱 :
如果給予日期, 要如何取得月份的中英文名稱? 跟上面取得星期名稱類似, 只要利用 Calendar.MONTH 欄位來判斷即可, 範例如下 :
import java.util.*;
import java.text.*;
public class mytest {
public static void main(String[] args) {
System.out.println(getMonthName()); //輸出 四月 (今天 2012-04-02)
System.out.println(getMonthName("2014-12-01")); //輸出 十二月
System.out.println(getMonthName("2014-12-01","en")); //輸出 December
}
public static String getDate() {
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
return sdf.format(new Date());
}
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 getMonthName() {
return getMonthName(getDate(),"zh");
}
public static String getMonthName(String date) {
return getMonthName(date,"zh");
}
public static String getMonthName(String date, String language) {
int[] d=parseDate(date);
Calendar c=Calendar.getInstance();
c.set(d[0],d[1]-1,d[2]);
String[] zh={"一月","二月","三月","四月","五月","六月","七月","八月",
"九月","十月","十一月","十二月"};
String[] en={"January","February","March","April","May","June","July",
"August","September","October","November","December"};
String m=null;
if (language.equals("zh")) {m=zh[c.get(Calendar.MONTH)];}
else {m=en[c.get(Calendar.MONTH)];}
return m;
}
}
參考 :
# JAVA String.format 方法使用介紹
6. 計算時間差 :
這在比較兩個演算法的運算效能時會用到, System 套件有一個 currentTimeMillis() 方法可以用來計算時間差, 它會傳回當時的時間戳 (毫秒, 長整數), 因此只要在演算法開始前後呼叫此方法, 再將兩值相減, 就可以得到所經過時間的毫秒值.
long start=System.currentTimeMillis();
......
long end=System.currentTimeMillis();
System.out.println(Arrays.toString(a));
# http://docs.oracle.com/javase/7/docs/api/java/lang/System.html
下列範例要利用此方法配合 Runtime 類別的 freeMemory() 方法來比較 String 與 StringBuffer 在執行速度與記憶體佔用的情形. Runtime 類別參見 :
# http://docs.oracle.com/javase/7/docs/api/java/lang/Runtime.html
import java.util.*;
public class mytest {
public static void main(String[] args) {
String str="Java";
long start=System.currentTimeMillis();
long mem1=Runtime.getRuntime().freeMemory();
for (int i=0; i<1000; i++) {str += "!";}
long end=System.currentTimeMillis();
long mem2=Runtime.getRuntime().freeMemory();
System.out.println("Elapsed : " + (end-start) + " ms");
System.out.println("Used : " + (mem1-mem2) + " bytes");
}
}
在我的電腦執行結果 :
Elapsed : 16 ms
Used : 39000 bytes
注意, 這裡迴圈若太大會導致執行時期錯誤 : java.lang.OutOfMemoryError: Java heap space.
# Java 内存溢出(java.lang.OutOfMemoryError)的常见情况
另外, 常用到的時間差計算是, 當使用者登入後顯示 "您上次登入是 3 天 14 時 23 分 45 秒前", 這通常是比對兩組時間字串, 例如 "2014-04-02 13:01:23" 與 "2013-02-09 21:34:00" 的時間差.
import java.util.*;
public class mytest {
public static void main(String[] args) {
String dt1="2012-01-01 00:00:00";
String dt2="2013-01-01 00:00:00";
System.out.println(timeDiff(dt1,dt2)); //輸出 31622400000
System.out.println(getDuration(dt1,dt2)); //輸出 366 日 0 時 0 分 0 秒
System.out.println(getDuration(dt1,dt2,"en")); //輸出 366 days 0 hours 0 minutes 0 seconds
}
public static int[] parseDateTime(String datetime) {
String[] a=datetime.split(" ");
String[] d=a[0].split("-");
String[] t=a[1].split(":");
int[] dt=new int[6];
dt[0]=Integer.parseInt(d[0]);
dt[1]=Integer.parseInt(d[1]);
dt[2]=Integer.parseInt(d[2]);
dt[3]=Integer.parseInt(t[0]);
dt[4]=Integer.parseInt(t[1]);
dt[5]=Integer.parseInt(t[2]);
return dt;
}
public static long timeDiff(String datetime1, String datetime2) {
int[] d=parseDateTime(datetime1);
Calendar c1=Calendar.getInstance();
c1.set(d[0],d[1]-1,d[2],d[3],d[4],d[5]);
d=parseDateTime(datetime2);
Calendar c2=Calendar.getInstance();
c2.set(d[0],d[1]-1,d[2],d[3],d[4],d[5]);
return c2.getTimeInMillis()-c1.getTimeInMillis();
}
public static String getDuration(String dt1, String dt2) {
return getDuration(dt1, dt2, "zh");
}
public static String getDuration(String dt1, String dt2, String language) {
long ms=Math.abs(timeDiff(dt1, dt2));
long d=ms/(1000 * 60 * 60 * 24);
long h=(ms%(1000 * 60 * 60 * 24))/(1000 * 60 * 60);
long m=(ms%(1000 * 60 * 60))/(1000 * 60);
long s=(ms%(1000 * 60))/1000;
String str=null;
if (language.equals("en")) {
str=d + " days " + h + " hours " + m + " minutes " + s + " seconds";
}
else {str=d + " 日 " + h + " 時 " + m + " 分 " + s + " 秒";}
return str;
}
}
執行結果 :
31622400000
366 日 0 時 0 分 0 秒
366 days 0 hours 0 minutes 0 seconds
此例中, timeDiff() 方法會傳回 dt2-dt1 毫秒差值, 故有正有負, 但在轉換為日時分秒前會先取絕對值再計算.
參考 :
# Java中将毫秒数转为*天*小时*分*秒
# 請問如何算得兩個時間的時間差
沒有留言 :
張貼留言