Java基礎之如何取捨Joda與 Java8 日期庫

在 Java8 以前,時間和日期的類庫很難用,而且有線程安全等諸多問題。

Joda time 彌補了 Java 在這方面的不足,但是在 Java8 時,增加了 java.time 包,對 Java 在日期 API 方面的進行了增強,這些代碼實現了 JSR-310 的標準。Joda 的官方推薦遷移到 Java8 的時間類庫上來。

 

下面來詳細對比對比一下兩個類庫,看看 Java8 的日期 API 是否能真正替代 Joda time。

基礎概念對比

Joda Date 的核心概念,這些概念在 java time 中基本也能找到對應:

instant

表示一個時刻,使用從 1970-01-01 00:00:00 至今的毫秒數表示

Joda time:

DateTime dt = new DateTime();
Instant instant = dt.toInstant();
複製代碼

Java time:

Clock clock = Clock.systemDefaultZone();
Instant instant = clock.instant();
複製代碼

interval

表示兩個 instant 之間的間隔,左閉右開。

Joda time:

DateTime dt = new DateTime();
DateTime dt1 = new DateTime();
Interval interval = new Interval(dt.toInstant(), dt1.toInstant());
複製代碼

java time 中沒有提供類似的 API,因爲 JSR-310 標準中沒有這個概念。

duration

用毫秒錶示的時間段,通常從 interval 獲得 Joda time:

Java time:

LocalDateTime l1 = LocalDateTime.now();
LocalDateTime l2 = LocalDateTime.now();
Period period = Period.between(l1.toLocalDate(), l2.toLocalDate());
複製代碼

period

同樣表示時間段,比如 3年,5個月,而 duration 使用毫秒錶示

Joda time:

DateTime dt1 = new DateTime();
DateTime dt2 = new DateTime();
Period period = Period.fieldDifference(dt1.toLocalDateTime(), dt2.toLocalDateTime());
複製代碼

Java time:

LocalDateTime l1 = LocalDateTime.now();
LocalDateTime l2 = LocalDateTime.now();
Period period = Period.between(l1.toLocalDate(), l2.toLocalDate());
複製代碼

chronology

年表,這是 joda-time 設計的基礎

Joda time:

DateTime dt = new DateTime();
Chronology chronology = dt.getChronology();
複製代碼

Java time:

LocalDateTime localDateTime = LocalDateTime.now();
Chronology ch = localDateTime.getChronology();
複製代碼

timezones

表示時區。

Joda time:

DateTime dt = new DateTime();
DateTimeZone dateTimeZone = dt.getZone();
Set<String> zones = DateTimeZone.getAvailableIDs();
複製代碼

Java time:

Clock clock = Clock.systemDefaultZone();
ZoneId zoneId = clock.getZone();
Set<String> zones = ZoneId.getAvailableZoneIds();
複製代碼

從上面可以看到,除了 JSR-310 中沒有的 Interval 的定義之外,這兩個庫在基礎概念方面的實現相差不大。

因爲 Unix 系統從 1970-01-01 00:00:00 開始計時,這個時間也稱之爲 Epoch Time,後續使用 Unix 的這種計時方式。

具體使用

Joda time 依賴 JDK5 及後續版本,沒有額外的依賴。

爲了起到對比的效果,挑幾個比較常用的場景進行對比:

  • 獲取 1970 至今的毫秒數
  • 獲取當前時間
  • 獲取年、月、日、星期幾
  • 日期的增減
  • 日期的格式化

獲取時間戳

在代碼中,經常會使用這個功能來表示唯一性:

Joda time:

DateTime dt = new DateTime();
long mills = dt.getMillis();
複製代碼

Java time:

Clock clock = Clock.systemDefaultZone();
long mills = clock.millis();
複製代碼

獲取當前時間

這塊兩個庫沒有太大的差異:

Joda time:

DateTime dt = new DateTime();
LocalDateTime localDateTime = dt.toLocalDateTime();
複製代碼

Java time:

LocalDateTime localDateTime = LocalDateTime.now();
複製代碼

獲取年、月、日、星期幾

Joda time:

DateTime dt = new DateTime();
int dayOfYear = dt.getDayOfYear();
int dayOfMonth = dt.getDayOfMonth();
int dayOfWeek = dt.getDayOfWeek();
int hourOfDay = dt.getHourOfDay();
複製代碼

Java time:

Clock clock = Clock.systemDefaultZone();
LocalDateTime localDateTime = LocalDateTime.now(clock);
int dayOfYear = localDateTime.getDayOfYear();
int dayOfMonth = localDateTime.getDayOfMonth();
int dayOfWeek = localDateTime.getDayOfWeek().getValue();
int hourOfDay = localDateTime.getHour();
複製代碼

獲取這些值兩個庫也沒有太大的差異,但是對於一些場景,比如我想獲得 "星期四" 這個字符串。 在 Joda 庫中,可以 dt.dayOfWeek().getAsShortText(); // 星期四 這樣獲得。在 Java 中,localDateTime.getDayOfWeek().name(); //THURSDAY 只能獲取到英文。

Joda time 在本地化方面比 Java time做的更好。

日期增減

Joda time:

DateTime dt = new DateTime();
dt = dt.plusDays(2); //當前日期添加兩天
dt = dt.plusHours(5); // 當前時間加上兩個小時
dt = dt.minusDays(1); // 當前日期減一天
dt = dt.minusHours(2); // 當前日期減兩個小時
複製代碼

Java time:

LocalDateTime localDateTime = LocalDateTime.now();
localDateTime = localDateTime.plusDays(2); // 增加兩天
localDateTime = localDateTime.plusHours(2); // 增加兩個小時
localDateTime = localDateTime.minusDays(1); //減少一天
localDateTime = localDateTime.minusHours(1); // 減少一個小時
複製代碼

日期的格式化

日期格式化是日常使用最頻繁的功能,下面來對比一下這兩者的區別。

Joda time:

// 方式一
DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
DateTime dt = new DateTime();
System.out.println(dt.toString(formatter));

// 方式二
String dateFormat = "yyyy-MM-dd HH:mm:ss";
System.out.println(dt.toString(dateFormat));
複製代碼

Java time:

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime localDateTime = LocalDateTime.now();   System.out.println(formatter.format(localDateTime));
複製代碼

通過上面的對比,可以發現這兩個類庫都可以完成相同的功能。雖然在細節上是有一些細微的差別。

java.util.Date 是 Java 中最早的日期類,後來就不推薦使用這個類了,java.util.Calendar 用來替代 Date。Calendar 有 Date 的所有功能,並且提供了更加豐富的獲取年月日的 API。

Calendar 是一個虛擬類,GregorianCalendar 則是 Calendar 的實現類。

Java time 與 java.util 下的時間類相互轉化,可以將 Date 或者 Calendar 轉化成 Java time 中的 LocalDateTime.

java.util.Date 轉 java.time.LocalDateTime:

Date date = new Date();
LocalDateTime localDateTime = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
複製代碼

java.util.Carlendar 轉 java.time.LocalDateTime:

Calendar calendar = Calendar.getInstance();
LocalDateTime localDateTime = LocalDateTime.ofInstant(calendar.toInstant(), ZoneId.systemDefault());
複製代碼

Joda time 也可以與 java.util.Date 可以進行相互的轉化:

// from Joda to JDK
DateTime dt = new DateTime(); 
Date jdkDate = dt.toDate();
// from JDK to Joda
dt = new DateTime(jdkDate);

// from Joda to JDK
DateTime dt = new DateTime();
Calendar jdkCal = dt.toCalendar(Locale.CHINESE);
// from JDK to Joda
dt = new DateTime(jdkCal);

// from Joda to JDK
DateTime dt = new DateTime();
GregorianCalendar jdkGCal = dt.toGregorianCalendar();
// from JDK to Joda
dt = new DateTime(jdkGCal);
複製代碼

設計思想

Joda time 與 Java time 在功能上已經相差不大,常用的功能這兩個類庫都可以完成,而且兩個庫都是線程安全的。

但我認爲 Joda time 的 API 更加簡潔一些,Joda time 的使用可以直接從 DateTime 這個類開始。而 Java time 的使用則更加繁瑣。

從設計上來說 Java time 都不再使用 new 來創建實例,而是使用工廠方法來創建實例。這點上比 Joda time 的設計要更好,而且更加安全。

既然 Joda time 都推薦遷移回 Java time 了,那麼最終肯定是要遷移的。但是目前來說,我覺得 Joda time 用起來更加順手一些,暫時還會繼續使用這個。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章