在 Java8 之前,時間和日期的類庫很難用,並且有線程安全等諸多問題。java
Joda time 彌補了 Java 在這方面的不足,可是在 Java8 時,增長了 java.time
包,對 Java 在日期 API 方面的進行了加強,這些代碼實現了 JSR-310 的標準。Joda 的官方推薦遷移到 Java8 的時間類庫上來。安全
下面來詳細對比對比一下兩個類庫,看看 Java8 的日期 API 是否能真正替代 Joda time。微信
Joda Date 的核心概念,這些概念在 java time 中基本也能找到對應:spa
表示一個時刻,使用從 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();
複製代碼
表示兩個 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 標準中沒有這個概念。字符串
用毫秒錶示的時間段,一般從 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());
複製代碼
一樣表示時間段,好比 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());
複製代碼
年表,這是 joda-time 設計的基礎
Joda time:
DateTime dt = new DateTime();
Chronology chronology = dt.getChronology();
複製代碼
Java time:
LocalDateTime localDateTime = LocalDateTime.now();
Chronology ch = localDateTime.getChronology();
複製代碼
表示時區。
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 及後續版本,沒有額外的依賴。
爲了起到對比的效果,挑幾個比較經常使用的場景進行對比:
在代碼中,常常會使用這個功能來表示惟一性:
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 用起來更加順手一些,暫時還會繼續使用這個。
關注微信公衆號,聊點其餘的