在JDK8以前,處理日期時間,咱們主要使用3個類,Date
、SimpleDateFormat
和Calendar
。java
這3個類在使用時都或多或少的存在一些問題,好比SimpleDateFormat
不是線程安全的,安全
好比Date
和Calendar
獲取到的月份是0到11,而不是現實生活中的1到12,關於這一點,《阿里巴巴Java開發手冊》中也有說起,由於很容易犯錯:微信
不過,JDK8推出了全新的日期時間處理類解決了這些問題,好比Instant
、LocalDate
、LocalTime
、LocalDateTime
、DateTimeFormatter
,在《阿里巴巴Java開發手冊》中也推薦使用Instant
、spa
LocalDateTime
、DateTimeFormatter
:線程
但我發現好多項目中其實並無使用這些類,使用的仍是以前的Date
、SimpleDateFormat
和Calendar
,因此本篇博客就講解下JDK8新推出的日期時間類,主要是下面幾個:設計
既然Instant
能夠代替Date
類,那它確定能夠獲取當前時間:code
Instant instant = Instant.now();
System.out.println(instant);
複製代碼
輸出結果:orm
2020-06-10T08:22:13.759Zcdn
細心的你會發現,這個時間比北京時間少了8個小時,若是要輸出北京時間,能夠加上默認時區:blog
System.out.println(instant.atZone(ZoneId.systemDefault()));
複製代碼
輸出結果:
2020-06-10T16:22:13.759+08:00[Asia/Shanghai]
Instant instant = Instant.now();
// 當前時間戳:單位爲秒
System.out.println(instant.getEpochSecond());
// 當前時間戳:單位爲毫秒
System.out.println(instant.toEpochMilli());
複製代碼
輸出結果:
1591777752
1591777752613
固然,也能夠經過System.currentTimeMillis()
獲取當前毫秒數。
1)根據秒數時間戳轉換:
Instant instant = Instant.now();
System.out.println(instant);
long epochSecond = instant.getEpochSecond();
System.out.println(Instant.ofEpochSecond(epochSecond));
System.out.println(Instant.ofEpochSecond(epochSecond, instant.getNano()));
複製代碼
輸出結果:
2020-06-10T08:40:54.046Z
2020-06-10T08:40:54Z
2020-06-10T08:40:54.046Z
2)根據毫秒數時間戳轉換:
Instant instant = Instant.now();
System.out.println(instant);
long epochMilli = instant.toEpochMilli();
System.out.println(Instant.ofEpochMilli(epochMilli));
複製代碼
輸出結果:
2020-06-10T08:43:25.607Z
2020-06-10T08:43:25.607Z
String text = "2020-06-10T08:46:55.967Z";
Instant parseInstant = Instant.parse(text);
System.out.println("秒時間戳:" + parseInstant.getEpochSecond());
System.out.println("豪秒時間戳:" + parseInstant.toEpochMilli());
System.out.println("納秒:" + parseInstant.getNano());
複製代碼
輸出結果:
秒時間戳:1591778815
豪秒時間戳:1591778815967
納秒:967000000
若是字符串格式不對,好比修改爲2020-06-10T08:46:55.967
,就會拋出java.time.format.DateTimeParseException
異常,以下圖所示:
使用LocalDate
獲取當前日期很是簡單,以下所示:
LocalDate today = LocalDate.now();
System.out.println("today: " + today);
複製代碼
輸出結果:
today: 2020-06-10
不用任何格式化,輸出結果就很是友好,若是使用Date
,輸出這樣的格式,還得配合SimpleDateFormat
指定yyyy-MM-dd
進行格式化,一不當心還會出個bug,好比去年年末很火的1個bug,我當時仍是截了圖的:
這2個好友是2019/12/31關注個人,但我2020年1月2號查看時,卻顯示成了2020/12/31,爲啥呢?格式化日期時格式寫錯了,應該是yyyy/MM/dd
,卻寫成了YYYY/MM/dd
,恰好那周跨年,就顯示成下一年,也就是2020年了,當時好幾個博主寫過文章解析緣由,我這裏就不作過多解釋了。
劃重點:都說到這了,給你們安利下我新註冊的公衆號「申城異鄉人」,歡迎你們關注,更多原創文章等着你哦,哈哈。
LocalDate today = LocalDate.now();
int year = today.getYear();
int month = today.getMonthValue();
int day = today.getDayOfMonth();
System.out.println("year: " + year);
System.out.println("month: " + month);
System.out.println("day: " + day);
複製代碼
輸出結果:
year: 2020
month: 6
day: 10
獲取月份終於返回1到12了,不像java.util.Calendar
獲取月份返回的是0到11,獲取完還得加1。
LocalDate specifiedDate = LocalDate.of(2020, 6, 1);
System.out.println("specifiedDate: " + specifiedDate);
複製代碼
輸出結果:
specifiedDate: 2020-06-01
若是肯定月份,推薦使用另外一個重載方法,使用枚舉指定月份:
LocalDate specifiedDate = LocalDate.of(2020, Month.JUNE, 1);
複製代碼
LocalDate localDate1 = LocalDate.now();
LocalDate localDate2 = LocalDate.of(2020, 6, 10);
if (localDate1.equals(localDate2)) {
System.out.println("localDate1 equals localDate2");
}
複製代碼
輸出結果:
localDate1 equals localDate2
LocalDate today = LocalDate.now();
System.out.println("Today:" + today);
System.out.println("Today is:" + today.getDayOfWeek());
System.out.println("今天是本週的第" + today.getDayOfWeek().getValue() + "天");
System.out.println("今天是本月的第" + today.getDayOfMonth() + "天");
System.out.println("今天是本年的第" + today.getDayOfYear() + "天");
複製代碼
輸出結果:
Today:2020-06-11
Today is:THURSDAY
今天是本週的第4天
今天是本月的第11天
今天是本年的第163天
LocalDate today = LocalDate.now();
System.out.println(today.getYear() + " is leap year:" + today.isLeapYear());
複製代碼
輸出結果:
2020 is leap year:true
若是使用java.util.Date
,那代碼是下面這樣的:
Date date = new Date();
int hour = date.getHours();
int minute = date.getMinutes();
int second = date.getSeconds();
System.out.println("hour: " + hour);
System.out.println("minute: " + minute);
System.out.println("second: " + second);
複製代碼
輸出結果:
注意事項:這幾個方法已通過期了,所以強烈不建議在項目中使用:
若是使用java.util.Calendar
,那代碼是下面這樣的:
Calendar calendar = Calendar.getInstance();
// 12小時制
int hourOf12 = calendar.get(Calendar.HOUR);
// 24小時制
int hourOf24 = calendar.get(Calendar.HOUR_OF_DAY);
int minute = calendar.get(Calendar.MINUTE);
int second = calendar.get(Calendar.SECOND);
int milliSecond = calendar.get(Calendar.MILLISECOND);
System.out.println("hourOf12: " + hourOf12);
System.out.println("hourOf24: " + hourOf24);
System.out.println("minute: " + minute);
System.out.println("second: " + second);
System.out.println("milliSecond: " + milliSecond);
複製代碼
輸出結果:
**注意事項:**獲取小時時,有2個選項,1個返回12小時制的小時數,1個返回24小時制的小時數,由於如今是晚上8點,因此calendar.get(Calendar.HOUR)
返回8,而calendar.get(Calendar.HOUR_OF_DAY)
返回20。
若是使用java.time.LocalTime
,那代碼是下面這樣的:
LocalTime localTime = LocalTime.now();
System.out.println("localTime:" + localTime);
int hour = localTime.getHour();
int minute = localTime.getMinute();
int second = localTime.getSecond();
System.out.println("hour: " + hour);
System.out.println("minute: " + minute);
System.out.println("second: " + second);
複製代碼
輸出結果:
能夠看出,LocalTime只有時間沒有日期。
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println("localDateTime:" + localDateTime);
複製代碼
輸出結果:
localDateTime: 2020-06-11T11:03:21.376
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println("localDateTime: " + localDateTime);
System.out.println("year: " + localDateTime.getYear());
System.out.println("month: " + localDateTime.getMonthValue());
System.out.println("day: " + localDateTime.getDayOfMonth());
System.out.println("hour: " + localDateTime.getHour());
System.out.println("minute: " + localDateTime.getMinute());
System.out.println("second: " + localDateTime.getSecond());
複製代碼
輸出結果:
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println("localDateTime: " + localDateTime);
LocalDateTime tomorrow = localDateTime.plusDays(1);
System.out.println("tomorrow: " + tomorrow);
LocalDateTime nextHour = localDateTime.plusHours(1);
System.out.println("nextHour: " + nextHour);
複製代碼
輸出結果:
localDateTime: 2020-06-11T11:13:44.979
tomorrow: 2020-06-12T11:13:44.979
nextHour: 2020-06-11T12:13:44.979
LocalDateTime
還提供了添加年、周、分鐘、秒這些方法,這裏就不一一列舉了:
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println("localDateTime: " + localDateTime);
LocalDateTime yesterday = localDateTime.minusDays(1);
System.out.println("yesterday: " + yesterday);
LocalDateTime lastHour = localDateTime.minusHours(1);
System.out.println("lastHour: " + lastHour);
複製代碼
輸出結果:
localDateTime: 2020-06-11T11:20:38.896
yesterday: 2020-06-10T11:20:38.896
lastHour: 2020-06-11T10:20:38.896
相似的,LocalDateTime
還提供了減小年、周、分鐘、秒這些方法,這裏就不一一列舉了:
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println("localDateTime: " + localDateTime);
System.out.println("DayOfWeek: " + localDateTime.getDayOfWeek().getValue());
System.out.println("DayOfYear: " + localDateTime.getDayOfYear());
複製代碼
輸出結果:
localDateTime: 2020-06-11T11:32:31.731
DayOfWeek: 4
DayOfYear: 163
JDK8中推出了java.time.format.DateTimeFormatter
來處理日期格式化問題,《阿里巴巴Java開發手冊》中也是建議使用DateTimeFormatter
代替SimpleDateFormat
。
LocalDate localDate = LocalDate.now();
System.out.println("ISO_DATE: " + localDate.format(DateTimeFormatter.ISO_DATE));
System.out.println("BASIC_ISO_DATE: " + localDate.format(DateTimeFormatter.BASIC_ISO_DATE));
System.out.println("ISO_WEEK_DATE: " + localDate.format(DateTimeFormatter.ISO_WEEK_DATE));
System.out.println("ISO_ORDINAL_DATE: " + localDate.format(DateTimeFormatter.ISO_ORDINAL_DATE));
複製代碼
輸出結果:
若是提供的格式沒法知足你的需求,你還能夠像之前同樣自定義格式:
LocalDate localDate = LocalDate.now();
System.out.println("yyyy/MM/dd: " + localDate.format(DateTimeFormatter.ofPattern("yyyy/MM/dd")));
複製代碼
輸出結果:
yyyy/MM/dd: 2020/06/11
LocalTime localTime = LocalTime.now();
System.out.println(localTime);
System.out.println("ISO_TIME: " + localTime.format(DateTimeFormatter.ISO_TIME));
System.out.println("HH:mm:ss: " + localTime.format(DateTimeFormatter.ofPattern("HH:mm:ss")));
複製代碼
輸出結果:
14:28:35.230
ISO_TIME: 14:28:35.23
HH:mm:ss: 14:28:35
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println(localDateTime);
System.out.println("ISO_DATE_TIME: " + localDateTime.format(DateTimeFormatter.ISO_DATE_TIME));
System.out.println("ISO_DATE: " + localDateTime.format(DateTimeFormatter.ISO_DATE));
複製代碼
輸出結果:
2020-06-11T14:33:18.303
ISO_DATE_TIME: 2020-06-11T14:33:18.303
ISO_DATE: 2020-06-11
JDK8中,Date
新增了from()
方法,將Instant
轉換爲Date
,代碼以下所示:
Instant instant = Instant.now();
System.out.println(instant);
Date dateFromInstant = Date.from(instant);
System.out.println(dateFromInstant);
複製代碼
輸出結果:
2020-06-11T06:39:34.979Z
Thu Jun 11 14:39:34 CST 2020
JDK8中,Date
新增了toInstant
方法,將Date
轉換爲Instant
,代碼以下所示:
Date date = new Date();
Instant dateToInstant = date.toInstant();
System.out.println(date);
System.out.println(dateToInstant);
複製代碼
輸出結果:
Thu Jun 11 14:46:12 CST 2020
2020-06-11T06:46:12.112Z
Date date = new Date();
Instant instant = date.toInstant();
LocalDateTime localDateTimeOfInstant = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
System.out.println(date);
System.out.println(localDateTimeOfInstant);
複製代碼
輸出結果:
Thu Jun 11 14:51:07 CST 2020
2020-06-11T14:51:07.904
Date date = new Date();
Instant instant = date.toInstant();
LocalDateTime localDateTimeOfInstant = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
LocalDate localDate = localDateTimeOfInstant.toLocalDate();
System.out.println(date);
System.out.println(localDate);
複製代碼
輸出結果:
Thu Jun 11 14:59:38 CST 2020
2020-06-11
能夠看出,Date
是先轉換爲Instant
,再轉換爲LocalDateTime
,而後經過LocalDateTime
獲取LocalDate
。
Date date = new Date();
Instant instant = date.toInstant();
LocalDateTime localDateTimeOfInstant = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
LocalTime toLocalTime = localDateTimeOfInstant.toLocalTime();
System.out.println(date);
System.out.println(toLocalTime);
複製代碼
輸出結果:
Thu Jun 11 15:06:14 CST 2020
15:06:14.531
能夠看出,Date
是先轉換爲Instant
,再轉換爲LocalDateTime
,而後經過LocalDateTime
獲取LocalTime
。
LocalDateTime localDateTime = LocalDateTime.now();
Instant toInstant = localDateTime.atZone(ZoneId.systemDefault()).toInstant();
Date dateFromInstant = Date.from(toInstant);
System.out.println(localDateTime);
System.out.println(dateFromInstant);
複製代碼
輸出結果:
2020-06-11T15:12:11.600
Thu Jun 11 15:12:11 CST 2020
LocalDate today = LocalDate.now();
LocalDateTime localDateTime = localDate.atStartOfDay();
Instant toInstant = localDateTime.atZone(ZoneId.systemDefault()).toInstant();
Date dateFromLocalDate = Date.from(toInstant);
System.out.println(dateFromLocalDate);
複製代碼
輸出結果:
Thu Jun 11 00:00:00 CST 2020
LocalDate localDate = LocalDate.now();
LocalTime localTime = LocalTime.now();
LocalDateTime localDateTime = LocalDateTime.of(localDate, localTime);
Instant instantFromLocalTime = localDateTime.atZone(ZoneId.systemDefault()).toInstant();
Date dateFromLocalTime = Date.from(instantFromLocalTime);
System.out.println(dateFromLocalTime);
複製代碼
輸出結果:
Thu Jun 11 15:24:18 CST 2020
JDK8推出了全新的日期時間類,如Instant
、LocaleDate
、LocalTime
、LocalDateTime
、DateTimeFormatter
,設計比以前更合理,也是線程安全的。
《阿里巴巴Java開發規範》中也推薦使用Instant
代替Date
,LocalDateTime
代替 Calendar
,DateTimeFormatter
代替 SimpleDateFormat
。
所以,若是條件容許,建議在項目中使用,沒有使用的,能夠考慮升級下。
注:若是以爲本篇博客有任何錯誤或者更好的建議,歡迎留言,我會及時跟進並更正博客內容!
文章持續更新,歡迎關注微信公衆號「申城異鄉人」第一時間閱讀!