Java8 新特性連載——全新的時間庫(java.time)

Java老鳥肯定針對日期寫過DateUtils、DateTool或者DateHelper之類的日期操作工具類,或者用過Apache、Google guava、Joda時間庫來進行時間計算,Java8以前JDK內置的時間庫真是難用到爆,新入門的童鞋只要考慮一下以下幾個需求,然後用Java8之前的API實現一把就能有所體會了:

1、打印出當前時間所在月份的最後一天的日期;

2、計算兩個時間間隔時長,如果超過一天就按天數,超過一個小時就按小時數,超過一分鐘就按分鐘數……

3、給定日期判斷出是一年中的第幾天?

……

由於日期操作實在太常用了,如果系統中模塊多了,如果不加以控制,我敢保證,每個模塊都會有一個DateUtils……然後CTO規定統一日期操作庫,封裝或者規定統一使用Joda或Apache common或google guava,然後由於與數據庫可能不一定兼容,還要做一堆轉換,真酸爽……

Java8來了,將時間庫進行了重新設計,極大的改進了時間操作,兼容性更好,線程安全,使用方便……這個時間庫被單獨放在java.time包中,其中有幾個非常重要的包:我羅列一下,便於童鞋們後期查找相關API:

java.time – 包含值對象的基礎包
java.time.chrono – 提供對不同的日曆系統的訪問
java.time.format – 格式化和解析時間和日期
java.time.temporal – 包括底層框架和擴展特性
java.time.zone – 包含時區支持的類

一、常用的類

再羅列一下我們常用到的類:

LocalDateTime:只存儲了日期和時間,如:2017-03-21T14:02:43.455。(後面的.455表示毫秒值的最後三位,使用.withNano(0)可把毫秒值設為0)

LocalDate:只存儲了日期,如:2017-03-21。

LocalTime:只存儲了時間,如:14:02:43.455。(後面的.455表示毫秒值的最後三位,使用.withNano(0)可把毫秒值設為0)

Year:只表示年份。

Month:只表示月份。

YearMonth:只表示年月。

MonthDay:只表示月日。

Instant:相當於java.util的Date

Clock:它通過指定一個時區,然後就可以獲取到當前的時刻,日期與時間。Clock可以替換System.currentTimeMillis()與TimeZone.getDefault()。

Duration:是用來計算兩個日期的時間差

注:與老的時間庫不一樣的地方

*新的庫日期與老的一樣,1-7,但1代表週一,7代表週日;老的代表週日,7代表週六

*新庫中月份從1開始到12,老的從0開始到11

二、Java8時間庫對於API的統一命名規範

of:靜態工廠方法(用類名去調用)
parse:靜態工廠方法,關注於解析(用類名去調用)
now: 靜態工廠方法,用當前時間創建實例(用類名去調用)
get:獲取某些東西的值
is:檢查某些東西的是否是true
with:返回一個部分狀態改變了的時間日期對象拷貝(單獨一個with方法,參數為TemporalAdjusters類型)
plus:返回一個時間增加了的、時間日期對象拷貝(如果參數是負數也能夠有minus方法的效果)
minus:返回一個時間減少了的、時間日期對象拷貝
to:把當前時間日期對象轉換成另外一個,可能會損失部分狀態
at:把這個對象與另一個對象組合起來,例如: date.atTime(time)
format :根據某一個DateTimeFormatter格式化為字符串

童鞋們在用的時候應該就很容易辨別出想要的API了

三、常見用法

我總結常見的經典用法,其他方法童鞋們可以去挖掘,這個庫的東西還是蠻多的,一篇小短文是不足以涵蓋全部,也沒必要。

1、判斷當前是上午或者下午

LocalDateTime now = LocalDateTime.now();
int ampm = now.get(ChronoField.AMPM_OF_DAY);
// ampm=0:上午
// ampm=1:下午

2、獲取某個時間的年月日等

LocalDateTime now = LocalDateTime.now();
now.getYear();
now.getMonthValue();
now.getDayOfMonth();
now.getHour();// 24小時制
now.getMinute();
now.getSecond();
now.getNano();

3、時間類的初始化

// 可以指定年、月、日、時、分、秒、毫秒,來自由構造時間
LocalDateTime.of(..);
// 有LocalDateTime之後可以通過with單獨設置某個時間屬性
dt.withYear(2018);
dt.withMonth(11);

4、時間的計算

LocalDateTime now = LocalDateTime.now();
now.minusDays(3);// 三天前
now.plusHours(2);// 兩個小時後
// 時差轉換
ZoneOffset offset = ZoneOffset.of("+05:30");
OffsetDateTime date = OffsetDateTime.of(now, offset);
// 也可以通過時區ID來轉換
ZoneId america = ZoneId.of("America/New_York");
ZonedDateTime dateAndTimeInNewYork = ZonedDateTime.of(localtDateAndTime, america );

四、我們來看看文章篇頭提到的三個問題,我們來看看用Java8怎麼來計算:

1、打印出當前時間所在月份的最後一天的日期

now.with(TemporalAdjusters.lastDayOfMonth());
// 以此類推,我們可以得到這個月第一天的日期,當年的第一天、最後一天,下個月的第一天最後一天,明年的第一天最後一天……

2、計算兩個時間間隔時長,如果超過一天就按天數,超過一個小時就按小時數,超過一分鐘就按分鐘數……

LocalDateTime start = LocalDateTime.of(2017, 1, 1, 1, 1);
LocalDateTime end = LocalDateTime.of(2017, 2, 1, 1, 1);
// 計算間隔
Duration result = Duration.between(start, end);
// 間隔天數、小時數、分鐘數……
System.out.println(result.toDays()); //31
System.out.println(result.toHours()); //744
System.out.println(result.toMinutes()); //44640

System.out.println(result.toMillis()); //2678400000
System.out.println(result.toNanos()); //2678400000000000

注:Duration.between接受的是Temporal接口哦,所以凡是實現該接口的類都可以用於間隔計算,實現該接口的類庫中有好多:

HijrahDate, Instant, JapaneseDate, LocalDate, LocalDateTime, LocalTime, MinguoDate, OffsetDateTime, OffsetTime, ThaiBuddhistDate, Year, YearMonth, ZonedDateTime

3、給定日期判斷出是一年中的第幾天?

now.getDayOfYear();

五、如何兼容舊的的時間庫

未向下兼容,肯定得支持新庫與舊庫的轉換,這個Java設計師們肯定不會馬虎,也很簡單

Date.toInstant()
Date.from(Instant)
Calendar.toInstant()


分享到:


相關文章: