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

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

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

    posts - 56, comments - 54, trackbacks - 0, articles - 4
       ::  ::  :: 聯(lián)系 :: 聚合  :: 管理

    Calendar使用方法(轉(zhuǎn)載)

    Posted on 2005-12-05 10:15 Terry的Blog 閱讀(12050) 評(píng)論(1)  編輯  收藏 所屬分類(lèi): java語(yǔ)言 、轉(zhuǎn)載
    明海棠文集之日期時(shí)間1.0

    --------它不是原創(chuàng),是一種思念

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

    我們將討論下面的類(lèi):

    1、  具體類(lèi)(和抽象類(lèi)相對(duì))java.util.Date

    2、  抽象類(lèi)java.text.DateFormat 和它的一個(gè)具體子類(lèi),java.text.SimpleDateFormat

    3、  抽象類(lèi)java.util.Calendar 和它的一個(gè)具體子類(lèi),java.util.GregorianCalendar

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

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

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

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

    public class DateExample1 {

    public static void main(String[] args) {

    // Get the system date/time

    Date date = new Date();

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

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

    }  

    }

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

    //兩個(gè)時(shí)間之間的天數(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);

    //加半小時(shí)

    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格式化
    能以一種用戶(hù)明白的格式來(lái)顯示這個(gè)日期呢? 在這里類(lèi)java.text.SimpleDateFormat 和它的抽象基類(lèi) java.text.DateFormat。那么, 現(xiàn)在我們已經(jīng)知道了如何獲取從1970年1月1日開(kāi)始經(jīng)歷的毫秒數(shù)了. 我們?nèi)绾尾舊ormat 就派得上用場(chǎng)了.

    // 我們能不能用下面的代碼構(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 的編譯器竟然報(bào)如下信息 (Sun JDK1.3, Windows 2000 中文下)

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

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

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

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

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

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

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

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

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

    Date date = new Date(dateInMilliSeconds);

    System.out.println(date);
     

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

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

    假如我們希望定制日期數(shù)據(jù)的格式, 比方星期六-9月-29日-2001年. 下面的例子展示了如何完成這個(gè)工作:

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

    }

    }
     

    只要通過(guò)向SimpleDateFormat 的構(gòu)造函數(shù)傳遞格式字符串"EEE-MMMM-dd-yyyy", 我們就能夠指明自己想要的格式. 你應(yīng)該可以看見(jiàn), 格式字符串中的ASCII 字符告訴格式化函數(shù)下面顯示日期數(shù)據(jù)的哪一個(gè)部分. EEEE是星期, MMMM是月, dd是日, yyyy是年. 字符的個(gè)數(shù)決定了日期是如何格式化的.傳遞"EE-MM-dd-yy"會(huì)顯示 Sat-09-29-01. 請(qǐng)察看Sun 公司的Web 站點(diǎn)獲取日期格式化選項(xiàng)的完整的指示.

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

    通過(guò)parse()方法,DateFormat能夠以一個(gè)字符串創(chuàng)立一個(gè)Date對(duì)象。這個(gè)方法能拋出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)的日期格式化過(guò)程
    既然我們已經(jīng)可以生成和解析定制的日期格式了, 讓我們來(lái)看一看如何使用內(nèi)建的格式化過(guò)程. 方法 DateFormat.getDateTimeInstance() 讓我們得以用幾種不同的方法獲得標(biāo)準(zhǔn)的日期格式化過(guò)程. 在下面的例子中, 我們獲取了四個(gè)內(nèi)建的日期格式化過(guò)程. 它們包括一個(gè)短的, 中等的, 長(zhǎng)的, 和完整的日期格式.

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

    }

    }

    注意我們?cè)趯?duì) getDateTimeInstance的每次調(diào)用中都傳遞了兩個(gè)值. 第一個(gè)參數(shù)是日期風(fēng)格, 而第二個(gè)參數(shù)是時(shí)間風(fēng)格. 它們都是基本數(shù)據(jù)類(lèi)型int(整型). 考慮到可讀性, 我們使用了DateFormat 類(lèi)提供的常量: SHORT, MEDIUM, LONG, 和 FULL. 要知道獲取時(shí)間和日期格式化過(guò)程的更多的方法和選項(xiàng), 請(qǐng)看Sun 公司W(wǎng)eb 站點(diǎn)上的解釋.

    運(yùn)行我們的例子程序的時(shí)候, 它將向標(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 日歷類(lèi)
    首先請(qǐng)記住 Calendar 只是一個(gè)抽象類(lèi), 也就是說(shuō)你無(wú)法直接獲得它的一個(gè)實(shí)例,換而言之你可以提供一個(gè)自己開(kāi)發(fā)的 Calendar 對(duì)象。

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

    比如有:

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

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

    下面的代碼可以證明這一點(diǎn):

       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 中是一個(gè)抽象類(lèi)(Abstract Class),GregorianCalendar 是它的一個(gè)具體實(shí)現(xiàn)。

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

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

     

    Calendar 對(duì)象在使用時(shí),有一些值得注意的事項(xiàng):

    1. Calendar 的 set() 方法

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

    field 的定義在 Calendar 中

    set(int year, int month, int day, int hour, int minute, int second) 但沒(méi)有set(int year, int month, int day, int hour, int minute, int second, int millisecond) 前面 set(int,int,int,int,int,int) 方法不會(huì)自動(dòng)將 MilliSecond 清為 0。

    另外,月份的起始值為0而不是1,所以要設(shè)置八月時(shí),我們用7而不是8。

    calendar.set(Calendar.MONTH, 7);

    我們通常需要在程序邏輯中將它清為 0,否則可能會(huì)出現(xiàn)下面的情況:

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

    然后再另外一個(gè)程序中取回來(lái)(模擬對(duì)數(shù)據(jù)庫(kù)的存儲(chǔ)),但是執(zhí)行的結(jié)果是:

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

    另外我們要注意的一點(diǎn)是,Calendar 為了性能原因?qū)?set() 方法采取延緩計(jì)算的方法。在 JavaDoc 中有下面的例子來(lái)說(shuō)明這個(gè)問(wèn)題:

    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,說(shuō)明 Calendar 不是馬上就刷新其內(nèi)部的記錄
     

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

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

    我們知道特定的月份有不同的日期,當(dāng)一個(gè)用戶(hù)給出錯(cuò)誤的日期時(shí),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)我們?cè)O(shè)置該 Calendar 為 Lenient false 時(shí),它會(huì)依據(jù)特定的月份檢查出錯(cuò)誤的賦值。

    3. 不穩(wěn)定的 Calendar

    我們知道 Calendar 是可以被 serialize 的,但是我們要注意下面的問(wèn)題

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

     

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

    它被復(fù)原到 EPOC 的起始點(diǎn),我們稱(chēng)該 Calendar 是處于不穩(wěn)定狀態(tài)。這個(gè)問(wèn)題的根本原因是 Java 在 serialize GregorianCalendar 時(shí)沒(méi)有保存所有的信息,所以當(dāng)它被恢復(fù)到內(nèi)存中,又缺少足夠的信息時(shí),Calendar 會(huì)被恢復(fù)到 EPOCH 的起始值。Calendar 對(duì)象由兩部分構(gòu)成:字段和相對(duì)于 EPOC 的微秒時(shí)間差。字段信息是由微秒時(shí)間差計(jì)算出的,而 set() 方法不會(huì)強(qiáng)制 Calendar 重新計(jì)算字段。這樣字段值就不對(duì)了。

    下面的代碼可以解決這個(gè)問(wèn)題:

       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(),強(qiáng)制 Calendar 刷新
                cal2.set(Calendar.MILLISECOND, 0);  //再設(shè)值
                System.out.println(cal2.getTime());
            }
        }
     

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

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

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

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

    當(dāng)被修改的字段超出它可以的范圍時(shí),那么比它大的字段會(huì)自動(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,對(duì)嗎?System.out.println(cal1.getTime()); //結(jié)果是 2000-9-30
     

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

    以上面的例子,9-31 就會(huì)變成 9-30,因?yàn)樽兓钚 ?br>
    Roll() 的規(guī)則只有一條:當(dāng)被修改的字段超出它可以的范圍時(shí),那么比它大的字段不會(huì)被修正。如:

    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)建一個(gè)日期對(duì)象了, 但是我們?nèi)绾尾拍茉O(shè)置和獲取日期數(shù)據(jù)的特定部分呢, 比如說(shuō)小時(shí), 日, 或者分鐘? 我們又如何在日期的這些部分加上或者減去值呢? 答案是使用Calendar 類(lèi). 就如我們前面提到的那樣, Calendar 類(lèi)中的方法替代了Date 類(lèi)中被人唾罵的方法.

    假設(shè)你想要設(shè)置, 獲取, 和操縱一個(gè)日期對(duì)象的各個(gè)部分, 比方一個(gè)月的一天或者是一個(gè)星期的一天. 為了演示這個(gè)過(guò)程, 我們將使用具體的子類(lèi) java.util.GregorianCalendar. 考慮下面的例子, 它計(jì)算得到下面的第十個(gè)星期五是13號(hào).

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

    }

    }

    }

    }

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

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

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

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

    我們這個(gè)例子的輸出結(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類(lèi)的基礎(chǔ)即有變量域的觀念。每個(gè)類(lèi)元素都是域,并且這些域在Calendar類(lèi)中表現(xiàn)為靜態(tài)變量。這些變量域,可以通過(guò)get/set類(lèi)方法來(lái)獲得或者設(shè)置域值。

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

    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方法的原因。

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

    Calendar cal = Calendar.getInstance();

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

    // 這個(gè)值是false

    盡管它是一個(gè)實(shí)例方法,isLeapYear方法的行為表現(xiàn)像靜態(tài)方法,需要提供年份的參數(shù)傳值給日歷。

    其實(shí)求幾天幾月幾年前/后的方法,應(yīng)該用Calendar類(lèi)比較好的(比Date)。

    Calendar cal = Calendar.getInstance();

    cal.setTime(date);

    cal.add(Calendar.MONTH,1);

    cal.add(Calendar.YEAR,2000);

    date = cal.getTime();

    通過(guò)接管日期修改的功能,java.util.Calendar類(lèi)看上去更像是Data類(lèi)的復(fù)雜版本。但是它還提供額外的功能,更不用說(shuō)它的國(guó)際化支持,使得它值得擁有學(xué)習(xí)的難度曲線。

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

    GregorianCalendar(int year, int month, int date)
    注意月份的表示,一月是0,二月是1,以此類(lèi)推,是12月是11。因?yàn)榇蠖鄶?shù)人習(xí)慣于使用單詞而不是使用數(shù)字來(lái)表示月份,這樣程序也許更易讀,父類(lèi)Calendar使用常量來(lái)表示月份:JANUARY, FEBRUARY,等等。所以,創(chuàng)建Wilbur 和 Orville制造第一架動(dòng)力飛機(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對(duì)象到字符串。這里,你可以做同樣的事情;但是首先,你需要將GregorianCalendar對(duì)象轉(zhuǎn)換到Date。要做到這一點(diǎn),你可以使用getTime()方法,從它得父類(lèi)Calendar繼承而來(lái)。GetTime()方法返回GregorianCalendar相應(yīng)的Date對(duì)象。你能夠創(chuàng)建GregorianCalendar對(duì)象,轉(zhuǎn)換到Date對(duì)象,得到和輸出相應(yīng)的字符串這樣一個(gè)過(guò)程。下面是例子:

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

    }

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

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

    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ù)很類(lèi)似:都創(chuàng)建一個(gè)對(duì)象,條件簡(jiǎn)單,代表今天。
    GregorianCalendar類(lèi)提供處理日期的方法。一個(gè)有用的方法是add().使用add()方法,你能夠增加象年,月數(shù),天數(shù)到日期對(duì)象中。要使用add()方法,你必須提供要增加的字段,要增加的數(shù)量。一些有用的字段是DATE, MONTH, YEAR, 和 WEEK_OF_YEAR。下面的程序使用add()方法計(jì)算未來(lái)80天的一個(gè)日期。在Jules的<環(huán)球80天>是一個(gè)重要的數(shù)字,使用這個(gè)程序可以計(jì)算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()一個(gè)重要的副作用是它改變了原來(lái)的日期。有時(shí)候,擁有原始日期和修改后的日期很重要。不幸的是,你不能簡(jiǎn)單的創(chuàng)建一個(gè)GregorianCalendar對(duì)象,設(shè)置它和原來(lái)的相等(equal)。原因是兩個(gè)變量指向同一個(gè)Date()對(duì)象地址。如果Date對(duì)象改變,兩個(gè)變量就指向改變后的日期對(duì)象。代替這種做法,應(yīng)該創(chuàng)建一個(gè)新對(duì)象。下面的程序示范了這種做法: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);

       }

    }

             程序運(yùn)行后,gc1和gc2被變成2001年(因?yàn)閮蓚€(gè)對(duì)象指向同一個(gè)Date,而Date已經(jīng)被改變了)。對(duì)象gc3指向一個(gè)單獨(dú)的Date,它沒(méi)有被改變。
     package com.minght.sys.util;

    /**
     * <p>Title: 開(kāi)源,開(kāi)放</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類(lèi)型日期轉(zhuǎn)化成String類(lèi)型"任意"格式
       * java.sql.Date,java.sql.Timestamp類(lèi)型是java.util.Date類(lèi)型的子類(lèi)
       * @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類(lèi)型日期轉(zhuǎn)化成java.utl.Date類(lèi)型"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類(lèi)型日期轉(zhuǎn)化成java.sql.Date類(lèi)型"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類(lèi)型日期轉(zhuǎn)化成java.sql.Date類(lèi)型"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類(lèi)型
       * @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)化為時(shí)間格式 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;
      }

      /**
       * 求得從某天開(kāi)始,過(guò)了幾年幾月幾日幾時(shí)幾分幾秒后,日期是多少
       * 幾年幾月幾日幾時(shí)幾分幾秒可以為負(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)前日期時(shí)間
       * 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"));
      }

    }

    評(píng)論

    # re: Calendar使用方法(轉(zhuǎn)載)  回復(fù)  更多評(píng)論   

    2010-07-15 16:49 by 啊啊啊啊
    大廈大廈
    主站蜘蛛池模板: 国产精品亚洲精品日韩已方| 久久久久亚洲AV无码麻豆| a毛片全部播放免费视频完整18| 亚洲va中文字幕无码久久不卡| 国产h肉在线视频免费观看| 亚洲色大成网站www| 久久影院亚洲一区| 永久免费在线观看视频| 日韩色日韩视频亚洲网站| 亚洲国产美女精品久久久久∴| 一个人看www在线高清免费看| 一级午夜免费视频| 97se亚洲国产综合自在线 | 亚洲中文无韩国r级电影| 99re热精品视频国产免费| 精品一区二区三区无码免费直播| 久久久久亚洲AV成人无码| 国产免费69成人精品视频| 99在线热视频只有精品免费| 老司机午夜在线视频免费观| 亚洲欧洲另类春色校园小说| 国产亚洲精品拍拍拍拍拍| 成人毛片免费在线观看| 四虎影视在线影院在线观看免费视频 | 99在线视频免费观看视频| 一级毛片人与动免费观看| 色婷五月综激情亚洲综合| 亚洲AV无码久久精品蜜桃| 免费人成网站7777视频| 亚洲性线免费观看视频成熟 | 波多野结衣中文一区二区免费| 91麻豆国产免费观看| 又大又硬又粗又黄的视频免费看| 激情亚洲一区国产精品| 亚洲国产一区二区三区青草影视| 亚洲日韩涩涩成人午夜私人影院| 欧洲精品成人免费视频在线观看| 日韩av无码久久精品免费| 久久WWW免费人成—看片| 黄色a三级三级三级免费看| 色天使亚洲综合在线观看|