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

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

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

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

基礎概念對比

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

instant

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

Joda time:設計

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

Java time:code

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

interval

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

Joda time:cdn

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:

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

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 用起來更加順手一些,暫時還會繼續使用這個。

原文

關注微信公衆號,聊點其餘的

相關文章
相關標籤/搜索