在Java8之前,在Java開發過程中,如果要操作時間,是使用Date這個類,在Java8中新增了LocalTime、LocalDate和LocalDateTime,日期和時間的處理變得更加方便和容易。用了一段時間,剛開始每次用的時候都要上網查一波才能找到要的答案,後來認真看一下官網的API,發現也不是那麼難理解,現在能夠通過自己的理解找到自己想要的表達式,在這裏做個小小的學習總結。
爲什麼要有新的時間API
既然Date類已經存在了那麼多年,爲什麼要花那麼大的精力去做這個改動?收益是什麼呢?
首先,因爲Date類真的很難用,有很多過於Geek的設計,比如月份是從0開始,0是一月,11是十二月。好吧,我已經知道程序員是從0開始計數了,但是每次用的時候都要做各種轉換,特別是跟其他輸出端有交互的時候,改錯一個地方就凌亂了。在新的APIjava.time
裏,這些都用常量表示了,不會用錯,代碼看起來也更加清晰。
在業務代碼中,往往有很多種需求,獲取某一天的0點,獲取下一天的中午時間,將當前時間往前或者往後移動幾天,等等這類的需求,這些功能使用Date類配合Calendar要寫好多代碼,代碼簡潔性也不夠好。
另外一個,Date裏面的很多方法都棄用了,如果新的項目還敢用這些類,那就是給自己埋坑了,還是趁早改了爲好。
舊的時間類java.util.Date
和格式化類SimpleDateFormatter
都是可變類,不是線程安全的,在多線程環境下對共享變量Date進行操作時,需要自己保證線程安全。而新的時間APILocalTime
和LocalDate
和格式化類DateTimeFormatter
都是final類(不可變)且是線程安全的。
基於上面的這些原因,就沒有理由不使用新的時間API了。
從一個用着習慣了很多年的工具切換到新的工具總是很不習慣,過程是痛苦的,但是結果是美好的。
怎麼理解新的時間API
在新的時間API裏,有LocalTime
、LocalDate
、LocalDateTime
三個類,LocalTime
只處理時間,無法包含日期,LocalDate
只處理日期,無法包含時間,只有LocalDateTime
能同時處理日期和時間。
怎麼使用?
如果理解了三個類的區別,那麼在使用上,需要根據具體情況來處理,下面看看比較常遇到的場景。
LocalDate
只取日期,年月日。
獲取今天的日期
LocalDate today = LocalDate.now();// 2020-05-20
使用年月日構造一個日期
// 月份和日期是從1開始
LocalDate valentineDay = LocalDate.of(2020, 5, 20);
指定對象,獲取年、月、日、星期幾
int year = localDate.getYear();
Month month = localDate.getMonth();int day = localDate.getDayOfMonth();
DayOfWeek dayOfWeek = localDate.getDayOfWeek();
或者
int year = localDate.get(ChronoField.YEAR);
int month = localDate.get(ChronoField.MONTH_OF_YEAR);
int day = localDate.get(ChronoField.DAY_OF_MONTH);
int dayOfWeek = localDate.get(ChronoField.DAY_OF_WEEK);
LocalTime
獲取時間,只取幾點幾分幾秒。
初始化時間對象
LocalTime localTime = LocalTime.now();
使用時分秒構造一個對象
LocalTime localTime = LocalTime.of(12, 0, 0);
指定對象,獲取時分秒
LocalTime localTime = LocalTime.now();
int hour = localTime.getHour();
int minute = localTime.getMinute();
int second = localTime.getSecond();
int hour = localTime.get(ChronoField.HOUR_OF_DAY);
int minute = localTime.get(ChronoField.MINUTE_OF_HOUR);
int second = localTime.get(ChronoField.SECOND_OF_MINUTE);
LocalDateTime
獲取日期+時間,年月日+時分秒,含義等於LocalDate+LocalTime
創建時間對象
LocalDateTime localDateTime = LocalDateTime.now();
使用LocalDate結合LocalTime構造時間對象
LocalDateTime localDateTime = LocalDateTime.of(localData, localTime);
LocalDateTime localDateTime = localDate.atTime(localTime);
LocalDateTime localDateTime = localTime.atDate(localDate);
通過LocalDateTime獲取LocalDate和LocalTime
LocalDate localDate = localDateTime.toLocalDate();
LocalTime localDate = localDateTime.toLocalTime();
Instant
這個類是表示時間軸上的某一個時刻的時間點。從1970-01-01 00:00:00這個時間開始計算,主要用於獲取時間戳,與System.currentTimeMillis()
(精確到毫秒)類似,但是Instant類可以精確到納秒。
創建Instant對象
Instant instant = Instant.now();
使用時間戳創建Instant對象
Instant instant = Instant.ofEpochSecond(100, 100000);
獲取秒數和毫秒
instant.getEpochSecond();
instant.getEpochMill();
舉例子加深印象
介紹了這幾個類的基本API後,再通過實現某些具體的需求來加深印象。
獲取當前時間戳
// 獲取當前時間對象->設置時->轉換成時間戳
public static long getCurrentSeconds() {
return Instant.now().atZone(ZoneOffset.of("+8")).toEpochSecond();
}
獲取當天零點/結束時間的時間戳
// 使用日期和時間構造日期時間對象->指定時區轉換成時間戳
public static long getTodayStartTime() {
return LocalDateTime.of(LocalDate.now(), LocalTime.MIN).toEpochSecond(ZoneOffset.of("+8"));
}
public static long getTodayEndTime() {
return LocalDateTime.of(LocalDate.now(), LocalTime.MAX).toEpochSecond(ZoneOffset.of("+8"));
}
獲取前一天零點
// 使用日期和時間構造日期時間對象->修改日期->指定時區轉換成時間戳
public static long getYesterdayStartTime() {
return LocalDateTime.of(LocalDate.now(), LocalTime.MIN).minusDays(1).toEpochSecond(ZoneOffset.of("+8"));
}
根據時間戳獲取時間戳表示的時間當天0點
// 使用時間戳構造日期時間對象->修改日期->指定時區轉換成時間戳
public static long getDayStartTime(long ) {
return LocalDateTime.of(LocalDate.now(), LocalTime.MIN).minusDays(1).toEpochSecond(ZoneOffset.of("+8"));
}
判斷是否月初第一天
public static boolean isFirstDayOfMonth(String ymd) {
LocalDate localDate = LocalDate.parse(ymd, DateTimeFormatter.ofPattern("yyyyMMdd")); return localDate.equals(localDate.withDayOfMonth(1));
}
總結
Java新的時間API很強大,這裏只能舉幾個自己遇到比較多的場景給大家介紹,所講的只是最基礎最皮毛的東西,要熟練的掌握所有的細節,還是需要去看看API或源碼的實現,然後在平時具體的需求場景中慢慢積累。
原創文章,文筆有限,才疏學淺,文中若有不正之處,萬望告知。
如果本文對你有幫助,請點個贊吧,謝謝
更多精彩內容,請關注個人公衆號。