Joda-Time 簡介


參考:http://www.ibm.com/developerworks/cn/java/j-jodatime.html

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

2000 年 1 月 1 日 0 時 0 分

使用 Joda,代碼應該類似如下所示:

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

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

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

輸出:2000/03/31 00:00:00.000

 

直接將不同對象傳遞給 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);

 

ReadablePartial

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

  • 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 DateCalendar 類。但是幸虧有 Joda,我可以執行任何必要的日期算法,然后再轉換回 JDK 類。這將兩者的優點集中到一起。您在本文中看到的所有 Joda 類都可以從 JDK CalendarDate 創建,正如您在 創建 Joda-Time 對象 中看到的那樣。出於同樣的原因,可以從您所見過的任何 Joda 類創建 JDK CalendarDate

清單 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. 創建表示 LocalDateDate 對象

				
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() 方法。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM