<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 73,  comments - 55,  trackbacks - 0


    學(xué)習(xí)日期, 日期格式, 日期的解析和日期的計算

    Java 語言的 Calendar,GregorianCalendar (日歷),Date(日期), 和DateFormat(日期格式)組成了Java標(biāo)準(zhǔn)的一個基本但是非常重要的部分. 日期是商業(yè)邏輯計算一個關(guān)鍵的部分. 所有的開發(fā)者都應(yīng)該能夠計算未來的日期, 定制日期的顯示格式, 并將文本數(shù)據(jù)解析成日期對象。學(xué)習(xí)日期, 日期格式, 日期的解析和日期的計算。

    我們將討論下面的類:

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

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

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

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

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

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

    讓我們看一個使用系統(tǒng)的當(dāng)前日期和時間創(chuàng)建一個日期對象并返回一個長整數(shù)的簡單例子. 這個時間通常被稱為Java 虛擬機(jī)(JVM)主機(jī)環(huán)境的系統(tǒng)時間.
    import java.util.Date;

    public class DateExample1 {

    public static void main(String[] args) {

    // Get the system date/time

    Date date = new Date();

    // 打印出具體的年,月,日,小時,分鐘,秒鐘以及時區(qū)

    System.out.println(date.getTime());

    }??

    }

    在星期六, 2001年9月29日, 下午大約是6:50的樣子, 上面的例子在系統(tǒng)輸出設(shè)備上顯示的結(jié)果是 1001803809710. 在這個例子中,值得注意的是我們使用了Date 構(gòu)造函數(shù)創(chuàng)建一個日期對象, 這個構(gòu)造函數(shù)沒有接受任何參數(shù). 而這個構(gòu)造函數(shù)在內(nèi)部使用了 System.currentTimeMillis() 方法來從系統(tǒng)獲取日期.

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

    //兩個時間之間的天數(shù)

    ? 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。那么, 現(xiàn)在我們已經(jīng)知道了如何獲取從1970年1月1日開始經(jīng)歷的毫秒數(shù)了. 我們?nèi)绾尾舊ormat 就派得上用場了.

    // 我們能不能用下面的代碼構(gòu)件出 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, 8);
    ??????? System.out.println(date);
    ??? }
    ? }


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

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


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

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

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

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


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

    最典型的應(yīng)用就是在一段代碼開始和結(jié)束時,分別獲得系統(tǒng)當(dāng)前的時間,然后計算出代碼執(zhí)行所需的時間(微秒級)。

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


    那么當(dāng)我們要把這個 long 值已更為友好的表現(xiàn)形式顯示處理的時候,我們可以用它來構(gòu)造 Date 對象:

    Date date = new Date(dateInMilliSeconds);

    System.out.println(date);


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

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

    假如我們希望定制日期數(shù)據(jù)的格式, 比方星期六-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 的構(gòu)造函數(shù)傳遞格式字符串"EEE-MMMM-dd-yyyy", 我們就能夠指明自己想要的格式. 你應(yīng)該可以看見, 格式字符串中的ASCII 字符告訴格式化函數(shù)下面顯示日期數(shù)據(jù)的哪一個部分. EEEE是星期, MMMM是月, dd是日, yyyy是年. 字符的個數(shù)決定了日期是如何格式化的.傳遞"EE-MM-dd-yy"會顯示 Sat-09-29-01. 請察看Sun 公司的Web 站點獲取日期格式化選項的完整的指示.

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

    通過parse()方法,DateFormat能夠以一個字符串創(chuàng)立一個Date對象。這個方法能拋出ParseException異常,所以你必須使用適當(dāng)?shù)漠惓L幚砑夹g(shù)。

    例子程序:

    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. 使用標(biāo)準(zhǔn)的日期格式化過程
    既然我們已經(jīng)可以生成和解析定制的日期格式了, 讓我們來看一看如何使用內(nèi)建的格式化過程. 方法 DateFormat.getDateTimeInstance() 讓我們得以用幾種不同的方法獲得標(biāo)準(zhǔn)的日期格式化過程. 在下面的例子中, 我們獲取了四個內(nèi)建的日期格式化過程. 它們包括一個短的, 中等的, 長的, 和完整的日期格式.

    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的每次調(diào)用中都傳遞了兩個值. 第一個參數(shù)是日期風(fēng)格, 而第二個參數(shù)是時間風(fēng)格. 它們都是基本數(shù)據(jù)類型int(整型). 考慮到可讀性, 我們使用了DateFormat 類提供的常量: SHORT, MEDIUM, LONG, 和 FULL. 要知道獲取時間和日期格式化過程的更多的方法和選項, 請看Sun 公司W(wǎng)eb 站點上的解釋.

    運行我們的例子程序的時候, 它將向標(biāo)準(zhǔn)輸出設(shè)備輸出下面的內(nèi)容:
    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 只是一個抽象類, 也就是說你無法直接獲得它的一個實例,換而言之你可以提供一個自己開發(fā)的 Calendar 對象。

    那究竟什么是一個 Calendar 呢?中文的翻譯就是日歷,那我們立刻可以想到我們生活中有陽(公)歷、陰(農(nóng))歷之分。它們的區(qū)別在哪呢?

    比如有:

    月份的定義 - 陽`(公)歷 一年12 個月,每個月的天數(shù)各不同;陰(農(nóng))歷,每個月固定28天,每周的第一天 - 陽(公)歷星期日是第一天;陰(農(nóng))歷,星期一是第一天

    實際上,在歷史上有著許多種紀(jì)元的方法。它們的差異實在太大了,比如說一個人的生日是"八月八日" 那么一種可能是陽(公)歷的八月八日,但也可以是陰 (農(nóng))歷的日期。所以為了計時的統(tǒng)一,必需指定一個日歷的選擇。那現(xiàn)在最為普及和通用的日歷就是 "Gregorian Calendar"。也就是我們在講述年份時常用 "公元幾幾年"。Calendar 抽象類定義了足夠的方法,讓我們能夠表述日歷的規(guī)則。Java 本身提供了對 "Gregorian Calendar" 規(guī)則的實現(xiàn)。我們從 Calendar.getInstance() 中所獲得的實例就是一個 "GreogrianCalendar" 對象(與您通過 new GregorianCalendar() 獲得的結(jié)果一致)。

    下面的代碼可以證明這一點:

    ? 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 是它的一個具體實現(xiàn)。

    Calendar 與 Date 的轉(zhuǎn)換非常簡單:

    ? Calendar calendar = Calendar.getInstance();
    ? // 從一個 Calendar 對象中獲取 Date 對象
    ? Date date = calendar.getTime();
    ? // 將 Date 對象反應(yīng)到一個 Calendar 對象中,
    ? // Calendar/GregorianCalendar 沒有構(gòu)造函數(shù)可以接受 Date 對象
    ? // 所以我們必需先獲得一個實例,然后設(shè)置 Date 對象
    ? calendar.setTime(date);

    ?

    ?

    Calendar 對象在使用時,有一些值得注意的事項:

    1. Calendar 的 set() 方法

    set(int field, int value) - 是用來設(shè)置"年/月/日/小時/分鐘/秒/微秒"等值

    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,所以要設(shè)置八月時,我們用7而不是8。

    calendar.set(Calendar.MONTH, 7);

    我們通常需要在程序邏輯中set(Calendar.MILLISECOND, 0),否則可能會出現(xiàn)下面的情況:
    //ObjectOutputStream和ObjectOutputStream是對象存儲的類
    //Calendar.MILLISECOND如不設(shè)為0則會是個與當(dāng)前系統(tǒng)時間有關(guān)的數(shù)

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


    然后再另外一個程序中取回來(模擬對數(shù)據(jù)庫的存儲),但是執(zhí)行的結(jié)果是:

    NotEqual
    Old calendar 965113200422 <------------ 最后三位的MilliSecond與當(dāng)前時間有關(guān)
    New calendar 965113200059 <-----------/
    Equals
    Processed Old calendar 965113200000
    Processed New calendar 965113200000

    ?

    另外我們要注意的一點是,Calendar 為了性能原因?qū)?set() 方法采取延緩計算的方法。在 JavaDoc 中有下面的例子來說明這個問題:

    Calendar cal1 = Calendar.getInstance();
    ? cal1.set(2000, 7, 31, 0, 0 , 0); //2000-8-31
    ? cal1.set(Calendar.MONTH, Calendar.SEPTEMBER); //應(yīng)該是 2000-9-31,也就是 2000-10-1
    ? cal1.set(Calendar.DAY_OF_MONTH, 30); //如果 Calendar 轉(zhuǎn)化到 2000-10-1,那么現(xiàn)在的結(jié)果就該是 2000-10-30
    ? System.out.println(cal1.getTime()); //輸出的是2000-9-30,說明 Calendar 不是馬上就刷新其內(nèi)部的記錄


    在 Calendar 的方法中,get() 和 add() 會讓 Calendar 立刻刷新。Set() 的這個特性會給我們的開發(fā)帶來一些意想不到的結(jié)果。我們后面會看到這個問題。

    2. Calendar 對象的容錯性,Lenient 設(shè)置

    我們知道特定的月份有不同的日期,當(dāng)一個用戶給出錯誤的日期時,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());
    ??? }
    ? }


    它的執(zhí)行結(jié)果是:

    ? 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)


    當(dāng)我們設(shè)置該 Calendar 為 Lenient false 時,它會依據(jù)特定的月份檢查出錯誤的賦值。

    3. 不穩(wěn)定的 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());
    ??? }
    ? }

    ?


    運行的結(jié)果竟然是: Thu Jan 01 00:00:00 PST 1970

    它被復(fù)原到 EPOC 的起始點,我們稱該 Calendar 是處于不穩(wěn)定狀態(tài)。這個問題的根本原因是 Java 在 serialize GregorianCalendar 時沒有保存所有的信息,所以當(dāng)它被恢復(fù)到內(nèi)存中,又缺少足夠的信息時,Calendar 會被恢復(fù)到 EPOCH 的起始值。Calendar 對象由兩部分構(gòu)成:字段和相對于 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); //先調(diào)用 get(),強制 Calendar 刷新
    ??????? cal2.set(Calendar.MILLISECOND, 0); //再設(shè)值
    ??????? System.out.println(cal2.getTime());
    ??? }
    ? }


    運行的結(jié)果是: Tue Aug 01 00:00:00 PDT 2000,這個問題主要會影響到在 EJB 編程中,參數(shù)對象中包含 Calendar 時。經(jīng)過 Serialize/Deserialize 后,直接操作 Calendar 會產(chǎn)生不穩(wěn)定的情況。

    4. add() 與 roll() 的區(qū)別

    add() 的功能非常強大,add 可以對 Calendar 的字段進(jìn)行計算。如果需要減去值,那么使用負(fù)數(shù)值就可以了,如 add(field, -value)。

    add() 有兩條規(guī)則:

    當(dāng)被修改的字段超出它可以的范圍時,那么比它大的字段會自動修正。如:

    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()); //結(jié)果是 2000-9-30


    另一個規(guī)則是,如果比它小的字段是不可變的(由 Calendar 的實現(xiàn)類決定),那么該小字段會修正到變化最小的值。

    以上面的例子,9-31 就會變成 9-30,因為變化最小。

    Roll() 的規(guī)則只有一條:當(dāng)被修改的字段超出它可以的范圍時,那么比它大的字段不會被修正。如:

    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 字段。


    我們現(xiàn)在已經(jīng)能夠格式化并創(chuàng)建一個日期對象了, 但是我們?nèi)绾尾拍茉O(shè)置和獲取日期數(shù)據(jù)的特定部分呢, 比如說小時, 日, 或者分鐘? 我們又如何在日期的這些部分加上或者減去值呢? 答案是使用Calendar 類. 就如我們前面提到的那樣, Calendar 類中的方法替代了Date 類中被人唾罵的方法.

    假設(shè)你想要設(shè)置, 獲取, 和操縱一個日期對象的各個部分, 比方一個月的一天或者是一個星期的一天. 為了演示這個過程, 我們將使用具體的子類 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()));

    }

    }

    }

    }

    在這個例子中我們作了有趣的函數(shù)調(diào)用:

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

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

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

    我們這個例子的輸出結(jié)果是:

    System Date: Saturday, September 29, 2001

    當(dāng)我們將它設(shè)置成星期五以后就成了: 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類的基礎(chǔ)即有變量域的觀念。每個類元素都是域,并且這些域在Calendar類中表現(xiàn)為靜態(tài)變量。這些變量域,可以通過get/set類方法來獲得或者設(shè)置域值。

    // 獲得默認(rèn)的Calendar實例,給它設(shè)置時間
    Calendarcal = Calendar.getInstance();
    intyear = cal.get(Calendar.YEAR);
    cal.set(Calendar.MONTH,Calendar.NOVEMBER);
    Calendar類的add和roll方法提供在日期之間轉(zhuǎn)換的能力。每個方法都由一個參數(shù)變量和一個參數(shù)值來修改,通過這個可為正數(shù)或負(fù)數(shù)的參數(shù)值來修改它。僅僅不同的是,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方法的行為表現(xiàn)像靜態(tài)方法,需要提供年份的參數(shù)傳值給日歷。

    其實求幾天幾月幾年前/后的方法,應(yīng)該用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類的復(fù)雜版本。但是它還提供額外的功能,更不用說它的國際化支持,使得它值得擁有學(xué)習(xí)的難度曲線。

    3.???? 使用GregorianCalendar類
    創(chuàng)建一個代表任意日期的一個途徑使用GregorianCalendar類的構(gòu)造函數(shù),它包含在java.util包中:

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

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

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

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

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

    }

    有時候創(chuàng)建一個代表當(dāng)前時刻的GregorianCalendar類的實例是很有用的。你可以簡單的使用沒有參數(shù)的GregorianCalendar構(gòu)造函數(shù),象這樣:

    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()構(gòu)造函數(shù)和GregorianCalendar()構(gòu)造函數(shù)很類似:都創(chuàng)建一個對象,條件簡單,代表今天。
    GregorianCalendar 類提供處理日期的方法。一個有用的方法是add().使用add()方法,你能夠增加象年,月數(shù),天數(shù)到日期對象中。要使用add()方法,你必須提供要增加的字段,要增加的數(shù)量。一些有用的字段是DATE, MONTH, YEAR, 和 WEEK_OF_YEAR。下面的程序使用add()方法計算未來80天的一個日期。在Jules的<環(huán)球80天>是一個重要的數(shù)字,使用這個程序可以計算Phileas Fogg從出發(fā)的那一天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 ()一個重要的副作用是它改變了原來的日期。有時候,擁有原始日期和修改后的日期很重要。不幸的是,你不能簡單的創(chuàng)建一個 GregorianCalendar對象,設(shè)置它和原來的相等(equal)。原因是兩個變量指向同一個Date()對象地址。如果Date對象改變,兩個變量就指向改變后的日期對象。代替這種做法,應(yīng)該創(chuàng)建一個新對象。下面的程序示范了這種做法: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已經(jīng)被改變了)。對象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類型日期轉(zhuǎn)化成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類型日期轉(zhuǎn)化成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類型日期轉(zhuǎn)化成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類型日期轉(zhuǎn)化成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日期轉(zhuǎn)化成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());
    }
    /**
    ? * 將字符串轉(zhuǎn)化為時間格式 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);

    }

    /**
    ? * 將日歷轉(zhuǎn)化為日期
    ? * @param calendar Calendar
    ? * @return Date
    ? */
    public static java.util.Date converToDate(java.util.Calendar calendar){
    ? return Calendar.getInstance().getTime();
    }

    /**
    ? * 將日期轉(zhuǎn)化為日歷
    ? * @param date Date
    ? * @return Calendar
    ? */
    public static java.util.Calendar converToCalendar(java.util.Date date){
    ? Calendar calendar = Calendar.getInstance();
    ? calendar.setTime(date);
    ? return calendar;
    }

    /**
    ? * 求得從某天開始,過了幾年幾月幾日幾時幾分幾秒后,日期是多少
    ? * 幾年幾月幾日幾時幾分幾秒可以為負(fù)數(shù)
    ? * @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();

    }


    /**
    ? * 取得當(dāng)前日期時間
    ? * 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"));

    }

    }

    ?

    posted on 2006-06-01 15:05 保爾任 閱讀(254) 評論(0)  編輯  收藏

    只有注冊用戶登錄后才能發(fā)表評論。


    網(wǎng)站導(dǎo)航:
     

    <2025年5月>
    27282930123
    45678910
    11121314151617
    18192021222324
    25262728293031
    1234567

    常用鏈接

    留言簿(4)

    隨筆分類

    隨筆檔案

    文章分類

    文章檔案

    搜索

    •  

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 免费A级毛片无码A∨男男| 亚洲精品理论电影在线观看| 日本免费一区尤物| 一级毛片免费毛片一级毛片免费| 免费大片av手机看片| 亚洲一区精彩视频| 亚洲黑人嫩小videos| 精品久久久久久亚洲| 男人的天堂亚洲一区二区三区 | 久久国产免费一区| 国产精品免费久久久久影院 | 永久免费看mv网站入口| 5g影院5g天天爽永久免费影院| 成人性生交大片免费看中文| 一个人看的在线免费视频| 亚洲a∨无码精品色午夜| 伊人久久亚洲综合影院首页| 亚洲天堂电影在线观看| 亚洲免费在线播放| 久久久综合亚洲色一区二区三区| 亚洲综合在线另类色区奇米| 国产成人99久久亚洲综合精品| 亚洲AV无码成人精品区大在线| 免费看的一级毛片| 日韩免费无砖专区2020狼| 女人让男人免费桶爽30分钟| 成年女人看片免费视频播放器 | 久久亚洲精品高潮综合色a片| 伊人久久五月丁香综合中文亚洲| 亚洲人成电影网站| xxx毛茸茸的亚洲| 亚洲综合激情五月色一区| 亚洲情A成黄在线观看动漫软件| 亚洲中文字幕一二三四区| 亚洲中文字幕无码爆乳| 国产人成亚洲第一网站在线播放| 亚洲日韩国产精品乱-久| 亚洲国产成人精品无码区花野真一| 亚洲国产精品18久久久久久| 阿v免费在线观看| 国产福利免费视频 |