級別: 中級
J Steven Perry, 首席顧問, Makoto Consulting Group, Inc.
2009 年 12 月 14 日
任
何企業應用程序都需要處理時間問題。應用程序需要知道當前的時間點和下一個時間點,有時它們還必須計算這兩個時間點之間的路徑。使用 JDK
完成這項任務將非常痛苦和繁瑣。現在來看看 Joda Time,一個面向 Java™
平臺的易于使用的開源時間/日期庫。正如您在本文中了解的那樣,Joda-Time 輕松化解了處理日期和時間的痛苦和繁瑣。
在編寫企業應用程序時,我常常需要處理日期。并且在我的最新項目中 — 保險行業 — 糾正日期計算尤其重要。使用 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
實現目前正在開發當中,但是在撰寫本文之際因為許可問題而被暫停。訪問 參考資料 獲得更多信息。
下載
描述 | 名字 | 大小 | 下載方法 |
源代碼 |
j-jodatime.zip |
812KB |
HTTP |
參考資料
學習
獲得產品和技術
討論
關于作者
 |

|
 |
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 的雜志文章。
|