明海棠文集之Java日期時間1.0__摘

明海棠文集之日期時間1.0

--------它不是原創,是一種思念

Java 語言的Calendar,GregorianCalendar (日曆),Date(日期), 和DateFormat(日期格式)組成了Java標準的一個基本但是非常重要的部分. 日期是商業邏輯計算一個關鍵的部分. 所有的開發者都應該能夠計算未來的日期, 定製日期的顯示格式, 並將文本數據解析成日期對象。學習日期, 日期格式, 日期的解析和日期的計算。

我們將討論下面的類:

1、  具體類(和抽象類相對)java.util.Date

2、  抽象類java.text.DateFormat 和它的一個具體子類,java.text.SimpleDateFormat

3、  抽象類java.util.Calendar 和它的一個具體子類,java.util.GregorianCalendar

具體類可以被實例化, 但是抽象類卻不能. 你首先必須實現抽象類的一個具體子類.

1.   java.util.Date及其格式化
Date 類從Java 開發包(JDK) 1.0 就開始進化, 當時它只包含了幾個取得或者設置一個日期數據的各個部分的方法, 比如說月, 日, 和年. 這些方法現在遭到了批評並且已經被轉移到了Calendar類裏去了, 我們將在本文中進一步討論它. 這種改進旨在更好的處理日期數據的國際化格式. 就象在JDK 1.1中一樣, Date 類實際上只是一個包裹類, 它包含的是一個長整型數據, 表示的是從GMT(格林尼治標準時間)1970年, 1 月 1日00:00:00這一刻之前或者是之後經歷的毫秒數.

1.1. 創建java.util.Date
Java統計從1970年1月1日起的毫秒的數量表示日期。也就是說,例如,1970年1月2日,是在1月1日後的86,400,000毫秒。同樣的,1969年12月31日是在1970年1月1日前86,400,000毫秒。Java的Date類使用long類型紀錄這些毫秒值.因爲long是有符號整數,所以日期可以在1970年1月1日之前,也可以在這之後。Long類型表示的最大正值和最大負值可以輕鬆的表示290,000,000年的時間,這適合大多數人的時間要求。

讓我們看一個使用系統的當前日期和時間創建一個日期對象並返回一個長整數的簡單例子. 這個時間通常被稱爲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() 方法來從系統獲取日期.

//1年前日期

   java.util.Date myDate=new java.util.Date(); 

   long myTime=(myDate.getTime()/1000)-60*60*24*365;

   myDate.setTime(myTime*1000);

   String mDate=formatter.format(myDate);

//明天日期

   myDate=new java.util.Date();

   myTime=(myDate.getTime()/1000)+60*60*24;

   myDate.setTime(myTime*1000);

   mDate=formatter.format(myDate);

//兩個時間之間的天數

   SimpleDateFormat myFormatter = new SimpleDateFormat("yyyy-MM-dd");

   java.util.Date date= myFormatter.parse("2003-05-1");

   java.util.Date mydate= myFormatter.parse("1899-12-30");

   long  day=(date.getTime()-mydate.getTime())/(24*60*60*1000);

//加半小時

SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");

java.util.Date date1 = format.parse("2002-02-28 23:16:00");

long Time=(date1.getTime()/1000)+60*30;

date1.setTime(Time*1000);

String mydate1=formatter.format(date1);

//年月周求日期

SimpleDateFormat formatter2 = new SimpleDateFormat("yyyy-MM F E");

java.util.Date date2= formatter2.parse("2003-05 5 星期五");

SimpleDateFormat formatter3 = new SimpleDateFormat("yyyy-MM-dd");

String mydate2=formatter3.format(date2);

//求是星期幾

mydate= myFormatter.parse("2001-1-1");

SimpleDateFormat formatter4 = new SimpleDateFormat("E");

String mydate3=formatter4.format(mydate);






1.2. Date格式化
能以一種用戶明白的格式來顯示這個日期呢? 在這裏類java.text.SimpleDateFormat 和它的抽象基類 java.text.DateFormat。那麼, 現在我們已經知道了如何獲取從1970年1月1日開始經歷的毫秒數了. 我們如何才format 就派得上用場了.

// 我們能不能用下面的代碼構件出 2001/8/8 8:8
    import java.io.*;
    import java.util.*;

    public class WhatIsDate
    {
        public static void main(String[] args) {
            Date date = new Date(2001, 8, 8, 8, 8,;
            System.out.println(date);
        }
    }


Java 的編譯器竟然報如下信息 (Sun JDK1.3, Windows 2000 中文下)

注意:
WhatIsDate.java 使用或覆蓋一個不鼓勵使用的API。
注意:
使用-deprecation重新編譯,以得到詳細信息。!


那麼 Date 對象究竟是爲了滿足哪個需求呢?看來它不是用來實現基於年/月/日小時:分鐘 的時間表述。我們查看 Java 的文檔,我們看到有 getTime() 方法,它返回的竟然是一個 long 值。

文檔進一步又告訴我們這個值代表了當前系統的時間離1970/1/1 0:0 的毫秒差,而且是在 GMT 時區下(也被稱爲 EPOC)。如果我們指定的時間是在此之前的,那它將返回一個負數值。

這個發現讓我們對 Date 對象有了一個全新的認識-Date 存放的是與 EPOC 的偏差值。換而言之我們也可通過 long 類型來表示時間?對了,這個猜想是得到了 Java 的支持:

   // 第二種獲得當前時間的方法
    long dateInMilliSeconds = System.currentTimeMillis();
    // 這時候打印出的只是一串數字而已
    System.out.println(dateInMilliSeconds);


對程序執行效率敏感的程序員可以發現這個方法只是生成一個 Java 的原始類型 (primitive type) long, 不需要實例化一個對象。因此如果我們對時間的處理只是在內部進行時,可以用 long 來代替 Date 對象。

最典型的應用就是在一段代碼開始和結束時,分別獲得系統當前的時間,然後計算出代碼執行所需的時間(微秒級)。

   long start = System.currentTimeMillis();
    // 代碼段
    System.out.println("需要 "+(System.currentTimeMillis()-start)+" 微秒");


那麼當我們要把這個 long 值已更爲友好的表現形式顯示處理的時候,我們可以用它來構造 Date 對象:

Date date = new Date(dateInMilliSeconds);

System.out.println(date);


我們看到了在 Java 中對時間最爲基本的表示,有通過對EPOC 的偏差值進行處理。Date 對象是對它的一個對象的封裝。我們同時也看到了,在現時世界中我們對時間的描述通常是通過"某年某月某日某時某分"來定義的。Date 的顯示(實際上是 toString() 方法)描述了這些信息,但 Java 並不建議我們用這種方式直接來構件 Date 對象。因此我們需要找出哪個對象可以實現這個需求。這就是我們下面就要講述的 Calendar 對象的功能。

在我們進一步研究 Calendar 之前,請記住 Date 只是一個對 long 值(基於 GMT 時區)的對象封裝。它所表現出來的年/月/日小時:分鐘時區的時間表述,只是它的 toString() 方法所提供的。千萬不要爲這個假象所迷惑。

假如我們希望定製日期數據的格式, 比方星期六-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 站點獲取日期格式化選項的完整的指示.

1.3. 文本數據解析成日期對象
假設我們有一個文本字符串包含了一個格式化了的日期對象, 而我們希望解析這個字符串並從文本日期數據創建一個日期對象. 我們將再次以格式化字符串"MM-dd-yyyy" 調用SimpleDateFormat類, 但是這一次, 我們使用格式化解析而不是生成一個文本日期數據. 我們的例子, 顯示在下面, 將解析文本字符串"9-29-2001"並創建一個值爲001736000000 的日期對象.

通過parse()方法,DateFormat能夠以一個字符串創立一個Date對象。這個方法能拋出ParseException異常,所以你必須使用適當的異常處理技術。

例子程序:

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());

}

}

}


1.4. 使用標準的日期格式化過程
既然我們已經可以生成和解析定製的日期格式了, 讓我們來看一看如何使用內建的格式化過程. 方法 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

2.   Calendar 日曆類
首先請記住 Calendar 只是一個抽象類, 也就是說你無法直接獲得它的一個實例,換而言之你可以提供一個自己開發的 Calendar 對象。

那究竟什麼是一個 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");
        }
    }




Calendar 在 Java 中是一個抽象類(Abstract Class),GregorianCalendar 是它的一個具體實現。

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"));
            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"));
            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");
            else
                System.out.println("NotEqual");
            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");
            else
                System.out.println("NotEqual");
            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"));
            out.writeObject(cal1);
            out.close();
            ObjectInputStream in =
                new ObjectInputStream(
                new FileInputStream("newCalendar.out"));
            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"));
            out.writeObject(cal1);
            out.close();
            ObjectInputStream in =
                new ObjectInputStream(
                new FileInputStream("newCalendar.out"));
            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 字段。


我們現在已經能夠格式化並創建一個日期對象了, 但是我們如何才能設置和獲取日期數據的特定部分呢, 比如說小時, 日, 或者分鐘? 我們又如何在日期的這些部分加上或者減去值呢? 答案是使用Calendar 類. 就如我們前面提到的那樣, Calendar 類中的方法替代了Date 類中被人唾罵的方法.

假設你想要設置, 獲取, 和操縱一個日期對象的各個部分, 比方一個月的一天或者是一個星期的一天. 爲了演示這個過程, 我們將使用具體的子類 java.util.GregorianCalendar. 考慮下面的例子, 它計算得到下面的第十個星期五是13號.

import java.util.GregorianCalendar;

import java.util.Date;

import java.text.DateFormat;

public class DateExample5 {

public static void main(String[] args) {

DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.FULL);

// Create our Gregorian Calendar.

GregorianCalendar cal = new GregorianCalendar();

// Set the date and time of our calendar

// to the system&s date and time

cal.setTime(new Date());

System.out.println("System Date: " + dateFormat.format(cal.getTime())); // Set the day of week to FRIDAY

cal.set(GregorianCalendar.DAY_OF_WEEK, GregorianCalendar.FRIDAY); System.out.println("After Setting Day of Week to Friday: " + dateFormat.format(cal.getTime()));

int friday13Counter = 0;

while (friday13Counter <= 10) {

// Go to the next Friday by adding 7 days. cal.add(GregorianCalendar.DAY_OF_MONTH, 7);

// If the day of month is 13 we have

// another Friday the 13th.

if (cal.get(GregorianCalendar.DAY_OF_MONTH) == 13) {

friday13Counter++; System.out.println(dateFormat.format(cal.getTime()));

}

}

}

}

在這個例子中我們作了有趣的函數調用:

cal.set(GregorianCalendar.DAY_OF_WEEK, GregorianCalendar.FRIDAY);

和:cal.add(GregorianCalendar.DAY_OF_MONTH, 7);

set 方法能夠讓我們通過簡單的設置星期中的哪一天這個域來將我們的時間調整爲星期五. 注意到這裏我們使用了常量 DAY_OF_WEEK 和 FRIDAY來增強代碼的可讀性. add 方法讓我們能夠在日期上加上數值. 潤年的所有複雜的計算都由這個方法自動處理.

我們這個例子的輸出結果是:

System Date: Saturday, September 29, 2001

當我們將它設置成星期五以後就成了: Friday, September 28, 2001

Friday, September 13, 2002

Friday, December 13, 2002

Friday, June 13, 2003

Friday, February 13, 2004

Friday, August 13, 2004

Friday, May 13, 2005

Friday, January 13, 2006

Friday, October 13, 2006

Friday, April 13, 2007

Friday, July 13, 2007

Friday, June 13, 2008

Calendar類的基礎即有變量域的觀念。每個類元素都是域,並且這些域在Calendar類中表現爲靜態變量。這些變量域,可以通過get/set類方法來獲得或者設置域值。

// 獲得默認的Calendar實例,給它設置時間
Calendarcal = Calendar.getInstance();
intyear = cal.get(Calendar.YEAR);
cal.set(Calendar.MONTH,Calendar.NOVEMBER);
Calendar類的add和roll方法提供在日期之間轉換的能力。每個方法都由一個參數變量和一個參數值來修改,通過這個可爲正數或負數的參數值來修改它。僅僅不同的是,add方法可以向高階的變量域溢出。例如,如果從九月三號向後倒退三天,將得到:

Calendar cal = Calendar.getInstance();

cal.add(Calendar.DATE,-3);

// 值爲: 星期六八月 31 23:43:19 EDT 2002

然而使用roll方法向後回滾三天得出:

Calendar cal = Calendar.getInstance();

cal.roll(Calendar.DATE,-3);

// 值爲: 星期一九月 30 23:43:47 EDT 2002
這就是爲什麼通常主要使用add方法的原因。

還有一個隱藏在最通用的Calendar的子類中的功能性方法--isLeapYear(判斷是否爲閏年)方法。

Calendar cal = Calendar.getInstance();

booleanleapYear = ( (GregorianCalendar)cal ).isLeapYear(2002);

// 這個值是false

儘管它是一個實例方法,isLeapYear方法的行爲表現像靜態方法,需要提供年份的參數傳值給日曆。

其實求幾天幾月幾年前/後的方法,應該用Calendar類比較好的(比Date)。

Calendar cal = Calendar.getInstance();

cal.setTime(date);

cal.add(Calendar.MONTH,1);

cal.add(Calendar.YEAR,2000);

date = cal.getTime();

通過接管日期修改的功能,java.util.Calendar類看上去更像是Data類的複雜版本。但是它還提供額外的功能,更不用說它的國際化支持,使得它值得擁有學習的難度曲線。

3.      使用GregorianCalendar類
創建一個代表任意日期的一個途徑使用GregorianCalendar類的構造函數,它包含在java.util包中:

GregorianCalendar(int year, int month, int date)
注意月份的表示,一月是0,二月是1,以此類推,是12月是11。因爲大多數人習慣於使用單詞而不是使用數字來表示月份,這樣程序也許更易讀,父類Calendar使用常量來表示月份:JANUARY, FEBRUARY,等等。所以,創建Wilbur 和 Orville製造第一架動力飛機的日期(December 17, 1903),你可以使用:

GregorianCalendar firstFlight = new GregorianCalendar(1903, Calendar.DECEMBER, 17);

出於清楚的考慮,你應該使用前面的形式。但是,你也應該學習怎樣閱讀下面的短格式。下面的例子同樣表示December 17,1903(記住,在短格式中,11表示December)

       GregorianCalendar firstFlight = new GregorianCalendar(1903, 11, 17);   在上一節中,你學習了轉換Date對象到字符串。這裏,你可以做同樣的事情;但是首先,你需要將GregorianCalendar對象轉換到Date。要做到這一點,你可以使用getTime()方法,從它得父類Calendar繼承而來。GetTime()方法返回GregorianCalendar相應的Date對象。你能夠創建GregorianCalendar對象,轉換到Date對象,得到和輸出相應的字符串這樣一個過程。下面是例子:

import java.util.*;

import java.text.*;

public class Flight {

   public static void main(String[] args) {

GregorianCalendar firstFlight = new GregorianCalendar(1903, Calendar.DECEMBER, 17);   

Date d = firstFlight.getTime();

DateFormat df = DateFormat.getDateInstance();

String s = df.format(d);

System.out.println("First flight was " + s);

}

有時候創建一個代表當前時刻的GregorianCalendar類的實例是很有用的。你可以簡單的使用沒有參數的GregorianCalendar構造函數,象這樣:

GregorianCalendar thisday = new GregorianCalendar();
一個輸出今天日期的例子程序,使用GregorianCalendar對象:

import java.util.*;
import java.text.*;
class Today {
   public static void main(String[] args) {
GregorianCalendar thisday = new GregorianCalendar();
Date d = thisday.getTime();
DateFormat df = DateFormat.getDateInstance();
String s = df.format(d);      System.out.println("Today is " + s);
   }
}
注意到,Date()構造函數和GregorianCalendar()構造函數很類似:都創建一個對象,條件簡單,代表今天。
GregorianCalendar類提供處理日期的方法。一個有用的方法是add().使用add()方法,你能夠增加象年,月數,天數到日期對象中。要使用add()方法,你必須提供要增加的字段,要增加的數量。一些有用的字段是DATE, MONTH, YEAR, 和 WEEK_OF_YEAR。下面的程序使用add()方法計算未來80天的一個日期。在Jules的<環球80天>是一個重要的數字,使用這個程序可以計算Phileas Fogg從出發的那一天1872年10月2日後80天的日期:

import java.util.*;
import java.text.*;
public class World {
   public static void main(String[] args) {
GregorianCalendar worldTour = new GregorianCalendar(1872, Calendar.OCTOBER, 2);      worldTour.add(GregorianCalendar.DATE, 80);
Date d = worldTour.getTime();
DateFormat df = DateFormat.getDateInstance();
String s = df.format(d);
System.out.println("80 day trip will end " + s);
   }
}
add()一個重要的副作用是它改變了原來的日期。有時候,擁有原始日期和修改後的日期很重要。不幸的是,你不能簡單的創建一個GregorianCalendar對象,設置它和原來的相等(equal)。原因是兩個變量指向同一個Date()對象地址。如果Date對象改變,兩個變量就指向改變後的日期對象。代替這種做法,應該創建一個新對象。下面的程序示範了這種做法:import java.util.*;

import java.text.*;

public class ThreeDates {

   public static void main(String[] args) {

GregorianCalendar gc1 = new GregorianCalendar(2000, Calendar.JANUARY, 1);

GregorianCalendar gc2 = gc1;

GregorianCalendar gc3 = new GregorianCalendar(2000, Calendar.JANUARY, 1);
      //Three dates all equal to January 1, 2000

gc1.add(Calendar.YEAR, 1);

//gc1 and gc2 are changed     

DateFormat df = DateFormat.getDateInstance();

Date d1 = gc1.getTime();

Date d2 = gc2.getTime();

Date d3 = gc3.getTime();

String s1 = df.format(d1);

String s2 = df.format(d2);

String s3 = df.format(d3);

System.out.println("gc1 is " + s1);

System.out.println("gc2 is " + s2);

System.out.println("gc3 is " + s3);

   }

}

         程序運行後,gc1和gc2被變成2001年(因爲兩個對象指向同一個Date,而Date已經被改變了)。對象gc3指向一個單獨的Date,它沒有被改變。
package com.minght.sys.util;

/**
* <p>Title: 開源,開放</p>
* <p>Description: opeansource</p>
* <p>Copyright: Copyright (c) 2004</p>
* <p>Company: 眀海棠</p>
* @author HaiTang Ming
* @version 1.0
*/

import java.util.*;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Timestamp;
import java.text.*;


public class timeUtil {

  /**
   * 將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)
      {
      }
      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());
  }

  /**
   * 將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"));

  }



}

發佈了6 篇原創文章 · 獲贊 1 · 訪問量 16萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章