JAVA 獲取未來時間以及Java Calendar類詳解

直接上代碼:

SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
        Date date = new Date();
        linkMap.put("time_start",df.format(date)+"");//交易起始時間
        Calendar c = new GregorianCalendar();
        c.setTime(date);//設置參數時間
        c.add(Calendar.SECOND,200);//把日期往後增加 SECOND 秒.整數往後推,負數往前移動
        date=c.getTime(); //獲取未來200秒數據
        String str = df.format(date);
            linkMap.put("time_expire",df.format(date)+"");    //交易結束時間

下面放上更詳細代碼: 原文在這裏

究竟什麼是一個 Calendar 呢?中文的翻譯就是日曆,那我們立刻可以想到我們生活中有陽(公)歷、陰(農)歷之分。它們的區別在哪呢?
 
比如有:
月份的定義 - 陽`(公)歷 一年12 個月,每個月的天數各不同;陰(農)歷,每個月固定28天
每週的第一天 - 陽(公)歷星期日是第一天;陰(農)歷,星期一是第一天
 
實際上,在歷史上有着許多種紀元的方法。它們的差異實在太大了,比如說一個人的生日是"八月八日" 那麼一種可能是陽(公)歷的八月八日,但也可以是陰(農)歷的日期。所以爲了計時的統一,必需指定一個日曆的選擇。那現在最爲普及和通用的日曆就是 "Gregorian Calendar"。也就是我們在講述年份時常用 "公元几几年"。Calendar 抽象類定義了足夠的方法,讓我們能夠表述日曆的規則。Java 本身提供了對 "Gregorian Calendar" 規則的實現。我們從 Calendar.getInstance() 中所獲得的實例就是一個 "GreogrianCalendar" 對象(與您通過 new GregorianCalendar() 獲得的結果一致)。
 
下面的代碼可以證明這一點:
 
import java.io.*;
import java.util.*;
 
public class WhatIsCalendar
{
public static void main(String[] args) {
Calendar calendar = Calendar.getInstance();
if (calendar instanceof GregorianCalendar)
System.out.println("It is an instance of GregorianCalendar"t;
}
}
 
Calendar 在 Java 中是一個抽象類(Abstract Class),GregorianCalendar 是它的一個具體實現。
 
我們也可以自己的 Calendar 實現類,然後將它作爲 Calendar 對象返回(面向對象的特性)。在 IBM alphaWorks 上,IBM 的開發人員實現了多種日曆(http://www.alphaworks.ibm.com/tech/calendars)。同樣在 Internet 上,也有對中國農曆的實現。本文對如何擴展 Calendar 不作討論,大家可以通過察看上述 Calendar 的源碼來學習。
 
Calendar 與 Date 的轉換非常簡單:
 
Calendar calendar = Calendar.getInstance();
// 從一個 Calendar 對象中獲取 Date 對象
Date date = calendar.getTime();
// 將 Date 對象反應到一個 Calendar 對象中,
// Calendar/GregorianCalendar 沒有構造函數可以接受 Date 對象
// 所以我們必需先獲得一個實例,然後設置 Date 對象
calendar.setTime(date);
 
 
Calendar 對象在使用時,有一些值得注意的事項:
 
1. Calendar 的 set() 方法
 
set(int field, int value) - 是用來設置"年/月/日/小時/分鐘/秒/微秒"等值
 
field 的定義在 Calendar 中
 
set(int year, int month, int day, int hour, int minute, int second) 但沒有
 
set(int year, int month, int day, int hour, int minute, int second, int millisecond) 前面 set(int,int,int,int,int,int) 方法不會自動將 MilliSecond 清爲 0。
 
另外,月份的起始值爲0而不是1,所以要設置八月時,我們用7而不是8。
 
calendar.set(Calendar.MONTH, 7);
 
我們通常需要在程序邏輯中將它清爲 0,否則可能會出現下面的情況:
 
import java.io.*;
import java.util.*;
 
public class WhatIsCalendarWrite
{
public static void main(String[] args) throws Exception{
ObjectOutputStream out =
new ObjectOutputStream(
new FileOutputStream("calendar.out"t);
Calendar cal1 = Calendar.getInstance();
cal1.set(2000, 7, 1, 0, 0, 0);
out.writeObject(cal1);
Calendar cal2 = Calendar.getInstance();
cal2.set(2000, 7, 1, 0, 0, 0);
cal2.set(Calendar.MILLISECOND, 0);
out.writeObject(cal2);
out.close();
}
}
 
我們將 Calendar 保存到文件中
 
import java.io.*;
import java.util.*;
 
public class WhatIsCalendarRead
{
public static void main(String[] args) throws Exception{
ObjectInputStream in =
new ObjectInputStream(
new FileInputStream("calendar.out"t);
Calendar cal2 = (Calendar)in.readObject();
Calendar cal1 = Calendar.getInstance();
cal1.set(2000, 7, 1, 0, 0, 0);
if (cal1.equals(cal2))
System.out.println("Equals"t;
else
System.out.println("NotEqual"t;
System.out.println("Old calendar "+cal2.getTime().getTime());
System.out.println("New calendar "+cal1.getTime().getTime());
cal1.set(Calendar.MILLISECOND, 0);
cal2 = (Calendar)in.readObject();
if (cal1.equals(cal2))
System.out.println("Equals"t;
else
System.out.println("NotEqual"t;
System.out.println("Processed Old calendar "+cal2.getTime().getTime());
System.out.println("Processed New calendar "+cal1.getTime().getTime());
}
}
 
然後再另外一個程序中取回來(模擬對數據庫的存儲),但是執行的結果是:
 
NotEqual
Old calendar 965113200422 <------------ 最後三位的MilliSecond與當前時間有關
New calendar 965113200059 <-----------/
Equals
Processed Old calendar 965113200000
Processed New calendar 965113200000
 
 
另外我們要注意的一點是,Calendar 爲了性能原因對 set() 方法採取延緩計算的方法。在 JavaDoc 中有下面的例子來說明這個問題:
 
Calendar cal1 = Calendar.getInstance();
cal1.set(2000, 7, 31, 0, 0 , 0); //2000-8-31
cal1.set(Calendar.MONTH, Calendar.SEPTEMBER); //應該是 2000-9-31,也就是 2000-10-1
cal1.set(Calendar.DAY_OF_MONTH, 30); //如果 Calendar 轉化到 2000-10-1,那麼現在的結果就該是 2000-10-30
System.out.println(cal1.getTime()); //輸出的是2000-9-30,說明 Calendar 不是馬上就刷新其內部的記錄
 
在 Calendar 的方法中,get() 和 add() 會讓 Calendar 立刻刷新。Set() 的這個特性會給我們的開發帶來一些意想不到的結果。我們後面會看到這個問題。
 
2. Calendar 對象的容錯性,Lenient 設置
我們知道特定的月份有不同的日期,當一個用戶給出錯誤的日期時,Calendar 如何處理的呢?
 
import java.io.*;
import java.util.*;
 
public class WhatIsCalendar
{
public static void main(String[] args) throws Exception{
Calendar cal1 = Calendar.getInstance();
cal1.set(2000, 1, 32, 0, 0, 0);
System.out.println(cal1.getTime());
cal1.setLenient(false);
cal1.set(2000, 1, 32, 0, 0, 0);
System.out.println(cal1.getTime());
}
}
 
它的執行結果是:
 
Tue Feb 01 00:00:00 PST 2000
Exception in thread "main" java.lang.IllegalArgumentException
at java.util.GregorianCalendar.computeTime(GregorianCalendar.java:1368)
at java.util.Calendar.updateTime(Calendar.java:1508)
at java.util.Calendar.getTimeInMillis(Calendar.java:890)
at java.util.Calendar.getTime(Calendar.java:871)
at WhatIsCalendar.main(WhatIsCalendar.java:12)
當我們設置該 Calendar 爲 Lenient false 時,它會依據特定的月份檢查出錯誤的賦值。
 
3. 不穩定的 Calendar
 
我們知道 Calendar 是可以被 serialize 的,但是我們要注意下面的問題
 
import java.io.*;
import java.util.*;
 
public class UnstableCalendar implements Serializable
{
 
public static void main(String[] args) throws Exception{
Calendar cal1 = Calendar.getInstance();
cal1.set(2000, 7, 1, 0, 0 , 0);
cal1.set(Calendar.MILLISECOND, 0);
ObjectOutputStream out =
new ObjectOutputStream(
new FileOutputStream("newCalendar.out"t);
out.writeObject(cal1);
out.close();
ObjectInputStream in =
new ObjectInputStream(
new FileInputStream("newCalendar.out"t);
Calendar cal2 = (Calendar)in.readObject();
cal2.set(Calendar.MILLISECOND, 0);
System.out.println(cal2.getTime());
}
}
 
運行的結果竟然是: Thu Jan 01 00:00:00 PST 1970
 
它被複原到 EPOC 的起始點,我們稱該 Calendar 是處於不穩定狀態。這個問題的根本原因是 Java 在 serialize GregorianCalendar 時沒有保存所有的信息,所以當它被恢復到內存中,又缺少足夠的信息時,Calendar 會被恢復到 EPOCH 的起始值。Calendar 對象由兩部分構成:字段和相對於 EPOC 的微秒時間差。字段信息是由微秒時間差計算出的,而 set() 方法不會強制 Calendar 重新計算字段。這樣字段值就不對了。
 
下面的代碼可以解決這個問題:
 
import java.io.*;
import java.util.*;
 
public class StableCalendar implements Serializable
{
 
public static void main(String[] args) throws Exception{
Calendar cal1 = Calendar.getInstance();
cal1.set(2000, 7, 1, 0, 0 , 0);
cal1.set(Calendar.MILLISECOND, 0);
ObjectOutputStream out =
new ObjectOutputStream(
new FileOutputStream("newCalendar.out"t);
out.writeObject(cal1);
out.close();
ObjectInputStream in =
new ObjectInputStream(
new FileInputStream("newCalendar.out"t);
Calendar cal2 = (Calendar)in.readObject();
cal2.get(Calendar.MILLISECOND); //先調用 get(),強制 Calendar 刷新
cal2.set(Calendar.MILLISECOND, 0);//再設值
System.out.println(cal2.getTime());
}
}
 
運行的結果是: Tue Aug 01 00:00:00 PDT 2000
 
這個問題主要會影響到在 EJB 編程中,參數對象中包含 Calendar 時。經過 Serialize/Deserialize 後,直接操作 Calendar 會產生不穩定的情況。
 
4. add() 與 roll() 的區別
 
add() 的功能非常強大,add 可以對 Calendar 的字段進行計算。如果需要減去值,那麼使用負數值就可以了,如 add(field, -value)。
 
add() 有兩條規則:
 
當被修改的字段超出它可以的範圍時,那麼比它大的字段會自動修正。如:
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
 
另一個規則是,如果比它小的字段是不可變的(由 Calendar 的實現類決定),那麼該小字段會修正到變化最小的值。
 
以上面的例子,9-31 就會變成 9-30,因爲變化最小。
 
Roll() 的規則只有一條:
當被修改的字段超出它可以的範圍時,那麼比它大的字段不會被修正。如:
 
Calendar cal1 = Calendar.getInstance();
cal1.set(1999, 5, 6, 0, 0, 0); //1999-6-6, 週日
cal1.roll(Calendar.WEEK_OF_MONTH, -1); //1999-6-1, 週二
cal1.set(1999, 5, 6, 0, 0, 0); //1999-6-6, 週日
cal1.add(Calendar.WEEK_OF_MONTH, -1); //1999-5-30, 週日
WEEK_OF_MONTH 比 MONTH 字段小,所以 roll 不能修正 MONTH 字段。
 
Date類介紹
 
Data和Calendar類:
一、創建一個日期對象r
 
讓我們看一個使用系統的當前日期和時間創建一個日期對象並返回一個長整數的簡
單例子. 這個時間通常被稱爲Java 虛擬機(JVM)主機環境的系統時間.
import java.util.Date;
 
public class DateExample1 {
public static void main(String[] args) {
// Get the system date/time
Date date = new Date();
 
System.out.println(date.getTime());
}
}
 
在星期六, 2001年9月29日, 下午大約是6:50的樣子, 上面的例子在系統輸出設備上
顯示的結果是 1001803809710. 在這個例子中,值得注意的是我們使用了Date 構造
函數創建一個日期對象, 這個構造函數沒有接受任何參數. 而這個構造函數在內部
使用了System.currentTimeMillis() 方法來從系統獲取日期.如果用
 
System.out.println(new Date());
 
則輸出形式爲:Tue Nov 08 14:28:07 CST 2005
 
那麼, 現在我們已經知道了如何獲取從1970年1月1日開始經歷的毫秒數了. 我們如
何才能以一種用戶明白的格式來顯示這個日期呢? 在這裏類java.text.
SimpleDateFormat 和它的抽象基類 java.text.DateFormat 就派得上用場了.
 
二、日期數據的定製格式
 
假如我們希望定製日期數據的格式, 比方星期六-9月-29日-2001年. 下面的例子展
示瞭如何完成這個工作:
 
import java.text.SimpleDateFormat;
import java.util.Date;
 
public class DateExample2 {
 
public static void main(String[] args) {
 
SimpleDateFormat bartDateFormat =
new SimpleDateFormat("EEEE-MMMM-dd-yyyy");
 
Date date = new Date();
 
System.out.println(bartDateFormat.format(date));
}
}
 
只要通過向SimpleDateFormat 的構造函數傳遞格式字符串"EEE-MMMM-dd-yyyy", 
我們就能夠指明自己想要的格式. 你應該可以看見, 格式字符串中的ASCII 字符
告訴格式化函數下面顯示日期數據的哪一個部分. EEEE是星期, MMMM是月, dd是日
, yyyy是年. 字符的個數決定了日期是如何格式化的.傳遞"EE-MM-dd-yy"會顯示
Sat-09-29-01. 請察看Sun 公司的Web 站點獲取日期格式化選項的完整的指示.
 
三、將文本數據解析成日期對象r
 
假設我們有一個文本字符串包含了一個格式化了的日期對象, 而我們希望解析這個
字符串並從文本日期數據創建一個日期對象. 我們將再次以格式化字符串
"MM-dd-yyyy" 調用SimpleDateFormat類, 但是這一次, 我們使用格式化解析而不
是生成一個文本日期數據. 我們的例子, 顯示在下面, 將解析文本字符串
"9-29-2001"並創建一個值爲001736000000 的日期對象.
 
例子程序:
 
import java.text.SimpleDateFormat;
import java.util.Date;
 
public class DateExample3 {
 
public static void main(String[] args) {
// Create a date formatter that can parse dates of
// the form MM-dd-yyyy.
SimpleDateFormat bartDateFormat =
new SimpleDateFormat("MM-dd-yyyy");
 
// Create a string containing a text date to be parsed.
String dateStringToParse = "9-29-2001";
 
try {
// Parse the text version of the date.
// We have to perform the parse method in a
// try-catch construct in case dateStringToParse
// does not contain a date in the format we are expecting.
Date date = bartDateFormat.parse(dateStringToParse);
 
// Now send the parsed date as a long value
// to the system output.
System.out.println(date.getTime());
}
catch (Exception ex) {
System.out.println(ex.getMessage());
}
}
}
 
五、使用標準的日期格式化過程
 
既然我們已經可以生成和解析定製的日期格式了, 讓我們來看一看如何使用內建的
格式化過程. 方法 DateFormat.getDateTimeInstance() 讓我們得以用幾種不同的
方法獲得標準的日期格式化過程. 在下面的例子中, 我們獲取了四個內建的日期格
式化過程. 它們包括一個短的, 中等的, 長的, 和完整的日期格式.
 
import java.text.DateFormat;
import java.util.Date;
 
public class DateExample4 {
 
public static void main(String[] args) {
Date date = new Date();
 
DateFormat shortDateFormat =
DateFormat.getDateTimeInstance(
DateFormat.SHORT,
DateFormat.SHORT);
 
DateFormat mediumDateFormat =
DateFormat.getDateTimeInstance(
DateFormat.MEDIUM,
DateFormat.MEDIUM);
 
DateFormat longDateFormat =
DateFormat.getDateTimeInstance(
DateFormat.LONG,
DateFormat.LONG);
 
DateFormat fullDateFormat =
DateFormat.getDateTimeInstance(
DateFormat.FULL,
DateFormat.FULL);
 
System.out.println(shortDateFormat.format(date));
System.out.println(mediumDateFormat.format(date));
System.out.println(longDateFormat.format(date));
System.out.println(fullDateFormat.format(date));
}
}
 
注意我們在對 getDateTimeInstance的每次調用中都傳遞了兩個值. 第一個參數
是日期風格, 而第二個參數是時間風格. 它們都是基本數據類型int(整型). 考慮
到可讀性, 我們使用了DateFormat 類提供的常量: SHORT, MEDIUM, LONG, 和 
FULL. 要知道獲取時間和日期格式化過程的更多的方法和選項, 請看Sun 公司Web
站點上的解釋.
 
運行我們的例子程序的時候, 它將向標準輸出設備輸出下面的內容:
9/29/01 8:44 PM
Sep 29, 2001 8:44:45 PM
September 29, 2001 8:44:45 PM EDT
Saturday, September 29, 2001 8:44:45 PM EDT

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章