當(dāng)你開始使用Java操作日期和時間的時候阱当,會有一些棘手斗蒋。你也許會通過System.currentTimeMillis() 來返回1970年1月1日到今天的毫秒數(shù)辑舷∮钪牵或者使用Date類來操作日期砾莱;當(dāng)遇到加減月份瑞筐、天數(shù)的時候 你又需要用到Calendar類;當(dāng)需要格式化日期的時候需要使用java.text.DateFormat類腊瑟。 總而言之在Java中操作日期不是很方便聚假,以至于很多開發(fā)者不得不使用第三方庫,比如: joda-time闰非。
現(xiàn)有API存在的問題
線程安全: Date和Calendar不是線程安全的膘格,你需要編寫額外的代碼處理線程安全問題
API設(shè)計和易用性: 由于Date和Calendar的設(shè)計不當(dāng)你無法完成日常的日期操作
ZonedDate和Time: 你必須編寫額外的邏輯處理時區(qū)和那些舊的邏輯
好在JSR 310規(guī)范中為Java8添加了新的API, 在java.time包中财松,新的API糾正了過去的缺陷瘪贱,
新的日期API
ZoneId: 時區(qū)ID,用來確定Instant和LocalDateTime互相轉(zhuǎn)換的規(guī)則
Instant: 用來表示時間線上的一個點
LocalDate: 表示沒有時區(qū)的日期, LocalDate是不可變并且線程安全的
LocalTime: 表示沒有時區(qū)的時間, LocalTime是不可變并且線程安全的
LocalDateTime: 表示沒有時區(qū)的日期時間, LocalDateTime是不可變并且線程安全的
Clock: 用于訪問當(dāng)前時刻辆毡、日期菜秦、時間,用到時區(qū)
Duration: 用秒和納秒表示時間的數(shù)量
最常用的就是LocalDate舶掖、LocalTime球昨、LocalDateTime了,從它們的名字就可以看出是操作日期 和時間的访锻。這些類是主要用于當(dāng)時區(qū)不需要顯式地指定的上下文褪尝。在本章節(jié)中我們將討論最常用的api。
LocalDate
LocalDate代表一個IOS格式(yyyy-MM-dd)的日期期犬,可以存儲 生日河哑、紀(jì)念日等日期。 獲取當(dāng)前的日期:
LocalDate localDate = LocalDate.now();
System.out.println("localDate: " + localDate);
localDate: 2017-07-20
LocalDate可以指定特定的日期龟虎,調(diào)用of或parse方法返回該實例:
LocalDate.of(2017, 07, 20);
LocalDate.parse("2017-07-20");
當(dāng)然它還有一些其他方法璃谨,我們一起來看看:
為今天添加一天,也就是獲取明天
LocalDate tomorrow = LocalDate.now().plusDays(1);
從今天減去一個月
LocalDate prevMonth = LocalDate.now().minus(1, ChronoUnit.MONTHS);
下面寫兩個例子,分別解析日期 2017-07-20佳吞,獲取每周中的星期和每月中的日:
DayOfWeek thursday = LocalDate.parse("2017-07-20").getDayOfWeek();
System.out.println("周四: " + thursday);
int twenty = LocalDate.parse("2017-07-20").getDayOfMonth();
System.out.println("twenty: " + twenty);
試試今年是不是閏年:
boolean leapYear = LocalDate.now().isLeapYear();
System.out.println("是否閏年: " + leapYear);
判斷是否在日期之前或之后:
boolean notBefore = LocalDate.parse("2017-07-20")
.isBefore(LocalDate.parse("2017-07-22"));
System.out.println("notBefore: " + notBefore);
boolean isAfter = LocalDate.parse("2017-07-20").isAfter(LocalDate.parse("2017-07-22"));
System.out.println("isAfter: " + isAfter);
獲取這個月的第一天:
LocalDate firstDayOfMonth = LocalDate.parse("2017-07-20")
.with(TemporalAdjusters.firstDayOfMonth());
System.out.println("這個月的第一天: " + firstDayOfMonth);
firstDayOfMonth = firstDayOfMonth.withDayOfMonth(1);
System.out.println("這個月的第一天: " + firstDayOfMonth);
判斷今天是否是我的生日拱雏,例如我的生日是 2009-07-20
LocalDate birthday = LocalDate.of(2009, 07, 20);
MonthDay birthdayMd = MonthDay.of(birthday.getMonth(), birthday.getDayOfMonth());
MonthDay today = MonthDay.from(LocalDate.now());
System.out.println("今天是否是我的生日: " + today.equals(birthdayMd));
LocalTime
LocalTime表示一個時間,而不是日期底扳,下面介紹一下它的使用方法铸抑。
獲取現(xiàn)在的時間,輸出15:01:22.144
LocalTime now = LocalTime.now();
System.out.println("現(xiàn)在的時間: " + now);
將一個字符串時間解析為LocalTime衷模,輸出15:02
LocalTime nowTime = LocalTime.parse("15:02");
System.out.println("時間是: " + nowTime);
使用靜態(tài)方法of創(chuàng)建一個時間
LocalTime nowTime = LocalTime.of(15, 02);
System.out.println("時間是: " + nowTime);
使用解析字符串的方式并添加一小時鹊汛,輸出16:02
LocalTime nextHour = LocalTime.parse("15:02").plus(1, ChronoUnit.HOURS);
System.out.println("下一個小時: " + nextHour);
獲取時間的小時、分鐘
int hour = LocalTime.parse("15:02").getHour();
System.out.println("小時: " + hour);
int minute = LocalTime.parse("15:02").getMinute();
System.out.println("分鐘: " + minute);
我們也可以通過之前類似的API檢查一個時間是否在另一個時間之前阱冶、之后
boolean isBefore = LocalTime.parse("15:02").isBefore(LocalTime.parse("16:02"));
boolean isAfter = LocalTime.parse("15:02").isAfter(LocalTime.parse("16:02"));
System.out.println("isBefore: " + isBefore);
System.out.println("isAfter: " + isAfter);
輸出 isBefore: true, isAfter: false刁憋。
在LocalTime類中也將每天的開始和結(jié)束作為常量供我們使用:
System.out.println(LocalTime.MAX);
System.out.println(LocalTime.MIN);
輸出:
23:59:59.999999999
00:00
LocalTime就這些了,下面我們來了解一下LocalDateTime
LocalDateTime
LocalDateTime是用來表示日期和時間的木蹬,這是一個最常用的類之一至耻。
獲取當(dāng)前的日期和時間:
LocalDateTime now = LocalDateTime.now();
System.out.println("現(xiàn)在: " + now);
輸出
現(xiàn)在: 2017-07-20T15:17:19.926
下面使用靜態(tài)方法和字符串的方式分別創(chuàng)建LocalDateTime對象
LocalDateTime.of(2017, Month.JULY, 20, 15, 18);
LocalDateTime.parse("2017-07-20T15:18:00");
``
同時`LocalDateTime`也提供了相關(guān)API來對日期和時間進行增減操作:
```java
LocalDateTime tomorrow = now.plusDays(1);
System.out.println("明天的這個時間: " + tomorrow);
LocalDateTime minusTowHour = now.minusHours(2);
System.out.println("兩小時前: " + minusTowHour);
這個類也提供一系列的get方法來獲取特定單位:
Month month = now.getMonth();
System.out.println("當(dāng)前月份: " + month);
日期格式化
在日常開發(fā)中我們用到最多的也許就是日期、時間的格式化了镊叁,那在Java8種該如何操作呢尘颓?
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
System.out.println("默認(rèn)格式化: " + now);
System.out.println("自定義格式化: " + now.format(dateTimeFormatter));
LocalDateTime localDateTime = LocalDateTime.parse("2017-07-20 15:27:44", dateTimeFormatter);
System.out.println("字符串轉(zhuǎn)LocalDateTime: " + localDateTime);
也可以使用DateTimeFormatter的format方法將日期、時間格式化為字符串
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
String dateString = dateTimeFormatter.format(LocalDate.now());
System.out.println("日期轉(zhuǎn)字符串: " + dateString);
日期周期
Period類用于修改給定日期或獲得的兩個日期之間的區(qū)別意系。
給初始化的日期添加5天:
LocalDate initialDate = LocalDate.parse("2017-07-20");
LocalDate finalDate = initialDate.plus(Period.ofDays(5));
System.out.println("初始化日期: " + initialDate);
System.out.println("加日期之后: " + finalDate);
周期API中提供給我們可以比較兩個日期的差別泥耀,像下面這樣獲取差距天數(shù):
long between = ChronoUnit.DAYS.between(initialDate, finalDate);
System.out.println("差距天數(shù): " + between);
上面的代碼會返回5,當(dāng)然你想獲取兩個日期相差多少小時也是簡單的蛔添。
與遺留代碼轉(zhuǎn)換
在之前的代碼中你可能出現(xiàn)了大量的Date類痰催,如何將它轉(zhuǎn)換為Java8種的時間類呢?
Date和Instant互相轉(zhuǎn)換
Date date = Date.from(Instant.now());
Instant instant = date.toInstant();
Date轉(zhuǎn)換為LocalDateTime
LocalDateTime localDateTime = LocalDateTime.from(new Date());
System.out.println(localDateTime);
LocalDateTime轉(zhuǎn)Date
Date date =
Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
LocalDate轉(zhuǎn)Date
Date date =
Date.from(LocalDate.now().atStartOfDay().atZone(ZoneId.systemDefault()).toInstant