Joda-Time 簡介

Joda-Time 簡介

既然沒法擺脫時間,爲什麼不設法簡化時間處理?
J Steven Perry, 首席顧問, Makoto Consulting Group, Inc.
J Steven Perry 的照片
J Steven Perry 是一名軟件開發人員、架構師和全能 Java 專家,他從 1991 年起就從事專業的軟件開發。他的專業興趣包括 JVM 的內部工做原理和 UML 建模,以及介於二者之間的全部內容。Steve 編寫了從技術文檔到 Java 代碼等各類內容,而且對教學和培訓也充滿了熱情。Steve 是 Java Management Extensions(O’Reilly)的做者,Java Enterprise Best Practices(O’Reilly)的合著者,並撰寫了有關軟件開發主題和 O'Reilly ShortCut: Log4J 的雜誌文章。

簡介: 任何企業應用程序都須要處理時間問題。應用程序須要知道當前的時間點和下一個時間點,有時它們還必須計算這兩個時間點之間的路徑。使用 JDK 完成這項任務將很是痛苦和繁瑣。如今來看看 Joda Time,一個面向 Java™ 平臺的易於使用的開源時間/日期庫。正如您在本文中瞭解的那樣,Joda-Time 輕鬆化解了處理日期和時間的痛苦和繁瑣。

本文的標籤:  joda-time, 簡介

標記本文!

發佈日期: 2009 年 12 月 14 日
級別: 中級
其餘語言版本: 英文
訪問狀況 : 3349 次瀏覽
評論: 0 (查看 | 添加評論 - 登陸)
平均分 4 星 共 9 個評分 平均分 (9個評分)
爲本文評分

在編寫企業應用程序時,我經常須要處理日期。而且在個人最新項目中 — 保險行業 — 糾正日期計算尤爲重要。使用 java.util.Calendar 讓我有些不安。若是您也曾使用這個類處理過日期/時間值,那麼您就知道它使用起來有多麻煩。所以當我接觸到 Joda-Time — 面向 Java 應用程序的日期/時間庫的替代選擇 — 我決定研究一下。其結果是:我很慶幸我這麼作了。

Joda-Time 令時間和日期值變得易於管理、操做和理解。事實上,易於使用是 Joda 的主要設計目標。其餘目標包括可擴展性、完整的特性集以及對多種日曆系統的支持。而且 Joda 與 JDK 是百分之百可互操做的,所以您無需替換全部 Java 代碼,只須要替換執行日期/時間計算的那部分代碼。
Joda 大型項目

Joda 其實是涵蓋衆多用於 Java 語言的替代 API 的大型項目,所以從技術上講,使用 Joda 和 Joda-Time 名稱表示相同的意思是一種誤稱。但在撰寫本文之際,Joda-Time API 目前彷佛是惟一處於活躍開發狀態下的 Joda API。考慮到 Joda 大型項目的當前狀態,我想將 Joda-Time 簡稱爲 Joda 應該沒什麼問題。

本文將介紹並展現如何使用它。我將介紹如下主題:

    * 日期/時間替代庫簡介
    * Joda 的關鍵概念
    * 建立 Joda-Time 對象
    * 以 Joda 的方式操做時間 style
    * 以 Joda 的方式格式化時間

您能夠 下載 演示這些概念的樣例應用程序的源代碼。

Joda 簡介

爲何要使用 Joda?考慮建立一個用時間表示的某個隨意的時刻 — 好比,2000 年 1 月 1 日 0 時 0 分。我如何建立一個用時間表示這個瞬間的 JDK 對象?使用 java.util.Date?事實上這是行不通的,由於自 JDK 1.1 以後的每一個 Java 版本的 Javadoc 都聲明應當使用 java.util.Calendar。Date 中不同意使用的構造函數的數量嚴重限制了您建立此類對象的途徑。

然而,Date 確實有一個構造函數,您能夠用來建立用時間表示某個瞬間的對象(除 「如今」 之外)。該方法使用距離 1970 年 1 月 1 日子時格林威治標準時間(也稱爲 epoch)以來的毫秒數做爲一個參數,對時區進行校訂。考慮到 Y2K 對軟件開發企業的重要性,您可能會認爲我已經記住了這個值 — 可是我沒有。Date 也不過如此。

那麼 Calendar 又如何呢?我將使用下面的方式建立必需的實例:

Calendar calendar = Calendar.getInstance();
calendar.set(2000, Calendar.JANUARY, 1, 0, 0, 0);


使用 Joda,代碼應該相似以下所示:

DateTime dateTime = new DateTime(2000, 1, 1, 0, 0, 0, 0);


這一行簡單代碼沒有太大的區別。可是如今我將使問題稍微複雜化。假設我但願在這個日期上加上 90 天並輸出結果。使用 JDK,我須要使用清單 1 中的代碼:

清單 1. 以 JDK 的方式向某一個瞬間加上 90 天並輸出結果

               
Calendar calendar = Calendar.getInstance();
calendar.set(2000, Calendar.JANUARY, 1, 0, 0, 0);
SimpleDateFormat sdf =
  new SimpleDateFormat("E MM/dd/yyyy HH:mm:ss.SSS");
calendar.add(Calendar.DAY_OF_MONTH, 90);
System.out.println(sdf.format(calendar.getTime()));


使用 Joda,代碼如清單 2 所示:

清單 2. 以 Joda 的方式向某一個瞬間加上 90 天並輸出結果

               
DateTime dateTime = new DateTime(2000, 1, 1, 0, 0, 0, 0);
System.out.println(dateTime.plusDays(90).toString("E MM/dd/yyyy HH:mm:ss.SSS");


二者之間的差距拉大了(Joda 用了兩行代碼,JDK 則是 5 行代碼)。

如今假設我但願輸出這樣一個日期:距離 Y2K 45 天以後的某天在下一個月的當前周的最後一天的日期。坦白地說,我甚至不想使用 Calendar 處理這個問題。使用 JDK 實在太痛苦了,即便是簡單的日期計算,好比上面這個計算。正是多年前的這樣一個時刻,我第一次領略到 Joda-Time 的強大。使用 Joda,用於計算的代碼如清單 3 所示:

清單 3. 改用 Joda

               
DateTime dateTime = new DateTime(2000, 1, 1, 0, 0, 0, 0);
System.out.println(dateTime.plusDays(45).plusMonths(1).dayOfWeek()
  .withMaximumValue().toString("E MM/dd/yyyy HH:mm:ss.SSS");


清單 3 的輸出爲:

Sun 03/19/2000 00:00:00.000


若是您正在尋找一種易於使用的方式替代 JDK 日期處理,那麼您真的應該考慮 Joda。若是不是這樣的話,那麼繼續痛苦地使用 Calendar 完成全部日期計算吧。當您作到這一點後,您徹底能夠作到使用幾把剪刀修建草坪並使用一把舊牙刷清洗您的汽車。

Joda 和 JDK 互操做性

JDK Calendar 類缺少可用性,這一點很快就能體會到,而 Joda 彌補了這一不足。Joda 的設計者還作出了一個決定,我認爲這是它取得成功的構建:JDK 互操做性。Joda 的類可以生成(可是,正如您將看到的同樣,有時會採用一種比較迂迴的方式)java.util.Date 的實例(和 Calendar)。這使您可以保留現有的依賴 JDK 的代碼,可是又可以使用 Joda 處理複雜的日期/時間計算。

例如,完成 清單 3 中的計算後。我只須要作出如清單 4 所示的更改就能夠返回到 JDK 中:

清單 4. 將 Joda 計算結果插入到 JDK 對象中

               
Calendar calendar = Calendar.getInstance();
DateTime dateTime = new DateTime(2000, 1, 1, 0, 0, 0, 0);
System.out.println(dateTime.plusDays(45).plusMonths(1).dayOfWeek()
  .withMaximumValue().toString("E MM/dd/yyyy HH:mm:ss.SSS");
calendar.setTime(dateTime.toDate());


就是這麼簡單。我完成了計算,可是能夠繼續在 JDK 對象中處理結果。這是 Joda 的一個很是棒的特性。

回頁首

Joda 的關鍵日期/時間概念

Joda 使用如下概念,它們能夠應用到任何日期/時間庫:

    * 不可變性(Immutability)
    * 瞬間性(Instant)
    * 局部性(Partial)
    * 年表(Chronology)
    * 時區(Time zone)

我將針對 Joda 依次討論每個概念。

不可變性

我在本文討論的 Joda 類具備不可變性,所以它們的實例沒法被修改。(不可變類的一個優勢就是它們是線程安全的)。我將向您展現的用於處理日期計算的 API 方法所有返回一個對應 Joda 類的新實例,同時保持原始實例不變。當您經過一個 API 方法操做 Joda 類時,您必須捕捉該方法的返回值,由於您正在處理的實例不能被修改。您可能對這種模式很熟悉;好比,這正是 java.lang.String 的各類操做方法的工做方式。

瞬間性

Instant 表示時間上的某個精確的時刻,使用從 epoch 開始計算的毫秒錶示。這必定義與 JDK 相同,這就是爲何任何 Joda Instant 子類均可以與 JDK Date 和 Calendar 類兼容的緣由。

更通用一點的定義是:一個瞬間 就是指時間線上只出現一次且惟一的一個時間點,而且這種日期結構只能以一種有意義的方式出現一次。

局部性

一個局部時間,正如我將在本文中將其稱爲局部時間片斷同樣,它指的是時間的一部分片斷。瞬間性指定了與 epoch 相對的時間上的一個精確時刻,與此相反,局部時間片斷指的是在時間上能夠來回 「移動」 的一個時刻,這樣它即可以應用於多個實例。好比,6 月 2 日 能夠應用於任意一年的 6 月份(使用 Gregorian 日曆)的次日的任意瞬間。一樣,11:06 p.m. 能夠應用於任意一年的任意一天,而且天天只能使用一次。即便它們沒有指定一個時間上的精確時刻,局部時間片斷仍然是有用的。

我喜歡將局部時間片斷看做一個重複週期中的一點,這樣的話,若是我正在考慮的日期構建能夠以一種有意義的方式出現屢次(即重複的),那麼它就是一個局部時間。

年表

Joda 本質 — 以及其設計核心 — 的關鍵就是年表(它的含義由一個同名抽象類捕捉)。從根本上講,年表是一種日曆系統 — 一種計算時間的特殊方式 — 而且是一種在其中執行日曆算法的框架。受 Joda 支持的年表的例子包括:

    * ISO(默認)
    * Coptic
    * Julian
    * Islamic

Joda-Time 1.6 支持 8 種年表,每一種均可以做爲特定日曆系統的計算引擎。

時區

時區是值一個相對於英國格林威治的地理位置,用於計算時間。要了解事件發生的精確時間,還必須知道發生此事件的位置。任何嚴格的時間計算都必須涉及時區(或相對於 GMT),除非在同一個時區內發生了相對時間計算(即時這樣時區也很重要,若是事件對於位於另外一個時區的各方存在利益關係的話)。

DateTimeZone 是 Joda 庫用於封裝位置概念的類。許多日期和時間計算均可以在不涉及時區的狀況下完成,可是仍然須要瞭解 DateTimeZone 如何影響 Joda 的操做。默認時間,即從運行代碼的機器的系統時鐘檢索到的時間,在大部分狀況下被使用。

回頁首

建立 Joda-Time 對象

如今,我將展現在採用該庫時會常常遇到的一些 Joda 類,並展現如何建立這些類的實例。
可變的 Joda 類

我並非可變實用類的粉絲;我只是認爲它們的用例並不適合普遍使用。可是若是您認爲您的確須要使用可變 Joda 類的話,本節的內容應當會對您的項目有幫助。Readable 和 ReadWritable API 之間的惟一區別在於 ReadWritable 類可以改變封裝的日期/時間值,所以我在這裏將再也不介紹這一點。

本節中介紹的全部實現都具備若干構造函數,容許您初始化封裝的日期/時間。它們能夠分爲 4 個類別:

    * 使用系統時間。
    * 使用多個字段指定一個瞬間時刻(或局部時間片斷),達到這個特定實現所能支持的最細粒度的精確度。
    * 指定一個瞬間時刻(或局部時間片斷),以毫秒爲單位。
    * 使用另外一個對象(例如,java.util.Date,或者是另外一個 Joda 對象)。

我將在第一個類中介紹這些構造函數: DateTime。當您使用其餘 Joda 類的相應構造函數時,也可使用這裏介紹的內容。
重載方法

若是您建立了一個 DateTime 的實例,而且沒有提供 Chronology 或 DateTimeZone,Joda 將使用 ISOChronology(默認)和 DateTimeZone(來自系統設置)。然而,Joda ReadableInstant 子類的全部構造函數都包含一個超載方法,該方法以一個 Chronology 或 DateTimeZone 爲參數。本文附帶的應用程序的的樣例代碼展現瞭如何使用這些超載方法(參見 下載)。我在這裏不會再詳細介紹它們,由於這些方法使用起來很是簡單。然而,我建議您試着使用一下這個樣例應用程序,看看編寫您的應用程序代碼有多麼簡單,這樣您就能夠隨意地在 Joda 的 Chronology 和 DateTimeZone 之間切換,同時不會影響到代碼的其他部分。

ReadableInstant

Joda 經過 ReadableInstant 類實現了瞬間性這一律念。表示時間上的不可變瞬間的 Joda 類都屬於這個類的子類。(將這個類命名爲 ReadOnlyInstant 可能更好,我認爲這纔是設計者須要傳達的意思)。換句話說,ReadableInstant 表示時間上的某一個不可修改的瞬間)。其中的兩個子類分別爲 DateTime 和 DateMidnight:

    * DateTime:這是最經常使用的一個類。它以毫秒級的精度封裝時間上的某個瞬間時刻。DateTime 始終與 DateTimeZone 相關,若是您不指定它的話,它將被默認設置爲運行代碼的機器所在的時區。

      可使用多種方式構建 DateTime 對象。這個構造函數使用系統時間:

      DateTime dateTime = new DateTime();


      通常來說,我會盡可能避免使用系統時鐘來初始化應用程序的實際,而是傾向於外部化設置應用程序代碼使用的系統時間。樣例應用程序執行如下代碼:

      DateTime dateTime = SystemFactory.getClock().getDateTime();


      這使得使用不一樣日期/時間測試個人代碼變得更加簡單:我不須要修改代碼來在應用程序中運行不一樣的日期場景,由於時間是在 SystemClock 實現的內部設置的,而不是在應用程序的內部。(我能夠修改系統時間,可是那實在太痛苦了!)

      下面的代碼使用一些字段值構建了一個 DateTime 對象:

      DateTime dateTime = new DateTime(
        2000, //year
        1,    // month
        1,    // day
        0,    // hour (midnight is zero)
        0,    // minute
        0,    // second
        0     // milliseconds
      );


      正如您所見,Joda 可使您精確地控制建立 DateTime 對象的方式,該對象表示時間上的某個特定的瞬間。每個 Joda 類都有一個與此相似的構造函數,您在此構造函數中指定 Joda 類能夠包含的全部字段。您能夠用它快速瞭解特定類在哪種粒度級別上操做。

      下一個構造函數將指定從 epoch 到某個時刻所通過的毫秒數。它根據 JDK Date 對象的毫秒值建立一個 DateTime 對象,其時間精度用毫秒錶示,由於 epoch 與 Joda 是相同的:

      java.util.Date jdkDate = obtainDateSomehow();
      long timeInMillis = jdkDate.getTime();
      DateTime dateTime = new DateTime(timeInMillis);


      而且這個例子與前例相似,惟一不一樣之處是我在這裏將 Date 對象直接傳遞給構造函數:

      java.util.Date jdkDate = obtainDateSomehow();
      dateTime = new DateTime(jdkDate);


      Joda 支持使用許多其餘對象做爲構造函數的參數,用於建立 DateTime,如清單 5 所示:


      清單 5. 直接將不一樣對象傳遞給 DateTime 的構造函數

                             
      // Use a Calendar
      java.util.Calendar calendar = obtainCalendarSomehow();
      dateTime = new DateTime(calendar);
      // Use another Joda DateTime
      DateTime anotherDateTime = obtainDateTimeSomehow();
      dateTime = new DateTime(anotherDateTime);
      // Use a String (must be formatted properly)
      String timeString = "2006-01-26T13:30:00-06:00";
      dateTime = new DateTime(timeString);
      timeString = "2006-01-26";
      dateTime = new DateTime(timeString);


      注意,若是您準備使用 String(必須通過解析),您必須對其進行精確地格式化。參考 Javadoc,得到有關 Joda 的 ISODateTimeFormat 類的更多信息(參見 參考資料)。
    * DateMidnight:這個類封裝某個時區(一般爲默認時區)在特定年/月/日的午夜時分的時刻。它基本上相似於 DateTime,不一樣之處在於時間部分老是爲與該對象關聯的特定 DateTimeZone 時區的午夜時分。

您將在本文看到的其餘類都遵循與 ReadableInstant 類相同的模式(Joda Javadoc 將顯示這些內容),所以爲了節省篇幅,我將不會在如下小節介紹這些內容。

ReadablePartial

應用程序所需處理的日期問題並不所有都與時間上的某個完整時刻有關,所以您能夠處理一個局部時刻。例如,有時您比較關心年/月/日,或者一天中的時間,甚至是一週中的某天。Joda 設計者使用 ReadablePartial 接口捕捉這種表示局部時間的概念,這是一個不可變的局部時間片斷。用於處理這種時間片斷的兩個有用類分別爲 LocalDate 和 LocalTime:

    * LocalDate:該類封裝了一個年/月/日的組合。當地理位置(即時區)變得不重要時,使用它存儲日期將很是方便。例如,某個特定對象的出生日期 可能爲 1999 年 4 月 16 日,可是從技術角度來看,在保存全部業務值的同時不會了解有關此日期的任何其餘信息(好比這是一週中的星期幾,或者這我的出生地所在的時區)。在這種狀況下,應當使用 LocalDate。

      樣例應用程序使用 SystemClock 來獲取被初始化爲系統時間的 LocalDate 的實例:

      LocalDate localDate = SystemFactory.getClock().getLocalDate();


      也能夠經過顯式地提供所含的每一個字段的值來建立 LocalDate:

      LocalDate localDate = new LocalDate(2009, 9, 6);// September 6, 2009


      LocalDate 替代了在早期 Joda 版本中使用的 YearMonthDay。
    * LocalTime:這個類封裝一天中的某個時間,當地理位置不重要的狀況下,可使用這個類來只存儲一天當中的某個時間。例如,晚上 11:52 多是一天當中的一個重要時刻(好比,一個 cron 任務將啓動,它將備份文件系統的某個部分),可是這個時間並無特定於某一天,所以我不須要了解有關這一時刻的其餘信息。

      樣例應用程序使用 SystemClock 獲取被初始化爲系統時間的 LocalTime 的一個實例:

      LocalTime localTime = SystemFactory.getClock().getLocalTime();


      也能夠經過顯式地提供所含的每一個字段的值來建立 LocalTime:

      LocalTime localTime = new LocalTime(13, 30, 26, 0);// 1:30:26PM


時間跨度

瞭解特定的時刻或是某個局部時間片斷將很是有用,可是若是可以表達一段時間跨度的話,一般也頗有用。Joda 提供了三個類來簡化這個過程。您能夠選擇用於表示不一樣跨度的類:

    * Duration:這個類表示一個絕對的精確跨度,使用毫秒爲單位。這個類提供的方法能夠用於經過標準的數學轉換(好比 1 分鐘 = 60 秒,1 天 = 24 小時),將時間跨度轉換爲標準單位(好比秒、分和小時)。

      您只在如下狀況使用 Duration 的實例:您但願轉換一個時間跨度,可是您並不關心這個時間跨度在什麼時候發生,或者使用毫秒處理時間跨度比較方便。
    * Period:這個類表示與 Duration 相同的概念,可是以人們比較熟悉的單位表示,好比年、月、周。

      您能夠在如下狀況使用 Period:您並不關心這段時期必須在什麼時候發生,或者您更關心檢索單個字段的能力,這些字段描述由 Period 封裝的時間跨度。
    * Interval:這個類表示一個特定的時間跨度,將使用一個明確的時刻界定這段時間跨度的範圍。Interval 爲半開 區間,這表示由 Interval 封裝的時間跨度包括這段時間的起始時刻,可是不包含結束時刻。

      能夠在如下狀況使用 Interval:須要表示在時間連續區間中以特定的點開始和結束的一段時間跨度。

回頁首

以 Joda 的方式處理時間

如今,您已經瞭解瞭如何建立一些很是有用的 Joda 類,我將向您展現如何使用它們執行日期計算。接着您將瞭解到 Joda 如何輕鬆地與 JDK 進行互操做。

日期計算

若是您只是須要對日期/時間信息使用佔位符,那麼 JDK 徹底能夠勝任,可是它在日期/時間計算方面的表現十分糟糕,而這正是 Joda 的長處。我將向您展現一些簡單的例子。

假設在當前的系統日期下,我但願計算上一個月的最後一天。對於這個例子,我並不關心一天中的時間,由於我只須要得到年/月/日,如清單 6 所示:

清單 6. 使用 Joda 計算日期

               
LocalDate now = SystemFactory.getClock().getLocalDate();
LocalDate lastDayOfPreviousMonth =\
  now.minusMonths(1).dayOfMonth().withMaximumValue();


您可能對清單 6 中的 dayOfMonth() 調用感興趣。這在 Joda 中被稱爲屬性(property)。它至關於 Java 對象的屬性。屬性是根據所表示的常見結構命名的,而且它被用於訪問這個結構,用於完成計算目的。屬性是實現 Joda 計算威力的關鍵。您目前所見到的全部 4 個 Joda 類都具備這樣的屬性。一些例子包括:

    * yearOfCentury
    * dayOfYear
    * monthOfYear
    * dayOfMonth
    * dayOfWeek

我將詳細介紹清單 6 中的示例,以向您展現整個計算過程。首先,我從當前月份減去一個月,獲得 「上一個月」。接着,我要求得到 dayOfMonth 的最大值,它使我獲得這個月的最後一天。注意,這些調用被鏈接到一塊兒(注意 Joda ReadableInstant 子類是不可變的),這樣您只須要捕捉調用鏈中最後一個方法的結果,從而得到整個計算的結果。

當計算的中間結果對我不重要時,我常常會使用這種計算模式。(我以相同的方式使用 JDK 的 BigDecimal)。假設您但願得到任何一年中的第 11 月的第一個星期二的日期,而這天必須是在這個月的第一個星期一以後。清單 7 展現瞭如何完成這個計算:

清單 7. 計算 11 月中第一個星期一以後的第一個星期二

               
LocalDate now = SystemFactory.getClock().getLocalDate();
LocalDate electionDate = now.monthOfYear()
 .setCopy(11)        // November
 .dayOfMonth()       // Access Day Of Month Property
 .withMinimumValue() // Get its minimum value
 .plusDays(6)        // Add 6 days
 .dayOfWeek()        // Access Day Of Week Property
 .setCopy("Monday")  // Set to Monday (it will round down)
 .plusDays(1);       // Gives us Tuesday


清單 7 的註釋幫助您瞭解代碼如何得到結果。.setCopy("Monday") 是整個計算的關鍵。無論中間 LocalDate 值是多少,將其 dayOfWeek 屬性設置爲 Monday 老是可以四捨五入,這樣的話,在每個月的開始再加上 6 天就可以讓您獲得第一個星期一。再加上一天就獲得第一個星期二。Joda 使得執行此類計算變得很是容易。

下面是其餘一些由於使用 Joda 而變得超級簡單的計算:

如下代碼計算從如今開始通過兩個星期以後的日期:

DateTime now = SystemFactory.getClock().getDateTime();
DateTime then = now.plusWeeks(2);


您能夠以這種方式計算從明天起 90 天之後的日期:

DateTime now = SystemFactory.getClock().getDateTime();
DateTime tomorrow = now.plusDays(1);
DateTime then = tomorrow.plusDays(90);


(是的,我也能夠向 now 加 91 天,那又如何呢?)

下面是計算從如今起 156 秒以後的時間:

DateTime now = SystemFactory.getClock().getDateTime();
DateTime then = now.plusSeconds(156);


下面的代碼將計算五年後的第二個月的最後一天:

DateTime now = SystemFactory.getClock().getDateTime();
DateTime then = now.minusYears(5) // five years ago
               .monthOfYear()     // get monthOfYear property
               .setCopy(2)        // set it to February
               .dayOfMonth()      // get dayOfMonth property
               .withMaximumValue();// the last day of the month


這樣的例子實在太多了,我向您已經知道了如何計算。嘗試操做一下樣例應用程序,親自體驗一下使用 Joda 計算任何日期是多麼有趣。

JDK 互操做性

個人許多代碼都使用了 JDK Date 和 Calendar 類。可是幸好有 Joda,我能夠執行任何須要的日期算法,而後再轉換回 JDK 類。這將二者的優勢集中到一塊兒。您在本文中看到的全部 Joda 類均可以從 JDK Calendar 或 Date 建立,正如您在 建立 Joda-Time 對象 中看到的那樣。出於一樣的緣由,能夠從您所見過的任何 Joda 類建立 JDK Calendar 或 Date。

清單 8 展現了從 Joda ReadableInstant 子類轉換爲 JDK 類有多麼簡單:

清單 8. 從 Joda DateTime 類建立 JDK 類

               
DateTime dateTime = SystemFactory.getClock().getDateTime();
Calendar calendar = dateTime.toCalendar(Locale.getDefault());
Date date = dateTime.toDate();
DateMidnight dateMidnight = SystemFactory.getClock()
  .getDateMidnight();
date = dateMidnight.toDate();


對於 ReadablePartial 子類,您還須要通過額外一步,如清單 9 所示:

清單 9. 建立表示 LocalDate 的 Date 對象

               
LocalDate localDate = SystemFactory.getClock().getLocalDate();
Date date = localDate.toDateMidnight().toDate();


要建立 Date 對象,它表示從清單 9 所示的 SystemClock 中得到的 LocalDate,您必須首先將它轉換爲一個 DateMidnight 對象,而後只須要將 DateMidnight 對象做爲 Date。(固然,產生的 Date 對象將把它本身的時間部分設置爲午夜時刻)。

JDK 互操做性被內置到 Joda API 中,所以您無需所有替換本身的接口,若是它們被綁定到 JDK 的話。好比,您可使用 Joda 完成複雜的部分,而後使用 JDK 處理接口。

回頁首

以 Joda 方式格式化時間

使用 JDK 格式化日期以實現打印是徹底能夠的,可是我始終認爲它應該更簡單一些。這是 Joda 設計者進行了改進的另外一個特性。要格式化一個 Joda 對象,調用它的 toString() 方法,而且若是您願意的話,傳遞一個標準的 ISO-8601 或一個 JDK 兼容的控制字符串,以告訴 JDK 如何執行格式化。不須要建立單獨的 SimpleDateFormat 對象(可是 Joda 的確爲那些喜歡自找麻煩的人提供了一個 DateTimeFormatter 類)。調用 Joda 對象的 toString() 方法,僅此而已。我將展現一些例子。

清單 10 使用了 ISODateTimeFormat 的靜態方法:

清單 10. 使用 ISO-8601

               
DateTime dateTime = SystemFactory.getClock().getDateTime();
dateTime.toString(ISODateTimeFormat.basicDateTime());
dateTime.toString(ISODateTimeFormat.basicDateTimeNoMillis());
dateTime.toString(ISODateTimeFormat.basicOrdinalDateTime());
dateTime.toString(ISODateTimeFormat.basicWeekDateTime());


清單 10 中的四個 toString() 調用分別建立了如下內容:

20090906T080000.000-0500
20090906T080000-0500
2009249T080000.000-0500
2009W367T080000.000-0500


您也能夠傳遞與 SimpleDateFormat JDK 兼容的格式字符串,如清單 11 所示:

清單 11. 傳遞 SimpleDateFormat 字符串

               
DateTime dateTime = SystemFactory.getClock().getDateTime();
dateTime.toString("MM/dd/yyyy hh:mm:ss.SSSa");
dateTime.toString("dd-MM-yyyy HH:mm:ss");
dateTime.toString("EEEE dd MMMM, yyyy HH:mm:ssa");
dateTime.toString("MM/dd/yyyy HH:mm ZZZZ");
dateTime.toString("MM/dd/yyyy HH:mm Z");

09/06/2009 02:30:00.000PM
06-Sep-2009 14:30:00
Sunday 06 September, 2009 14:30:00PM
09/06/2009 14:30 America/Chicago
09/06/2009 14:30 -0500


查看 Javadoc 中有關 joda.time.format.DateTimeFormat 的內容,得到與 JDK SimpleDateFormat 兼容的格式字符串的更多信息,而且能夠將其傳遞給 Joda 對象的 toString() 方法。

回頁首

結束語

談到日期處理,Joda 是一種使人驚奇的高效工具。不管您是計算日期、打印日期,或是解析日期,Joda 都將是工具箱中的便捷工具。在本文中,我首先介紹了 Joda,它能夠做爲 JDK 日期/時間庫的替代選擇。而後介紹了一些 Joda 概念,以及如何使用 Joda 執行日期計算和格式化。

Joda-Time 衍生了一些相關的項目,您可能會發現這些項目頗有用。如今出現了一個針對 Grails Web 開發框架的 Joda-Time 插件。joda-time-jpox 項目的目標就是添加一些必需的映射,以使用 DataNucleus 持久化引擎持久化 Joda-Time 對象。而且,一個針對 Google Web Toolkit(也稱爲 Goda-Time)的 Joda-Time 實現目前正在開發當中,可是在撰寫本文之際由於許可問題而被暫停。訪問 參考資料 得到更多信息。java

相關文章
相關標籤/搜索