Java中 LocalDate、LocalTime、LocalDateTime三個時間工具類的使用介紹
一、背景:
之前在做項目的過程中,對日期時間類沒有一個系統的瞭解,總是在用的時候去搜索一下,解決問題即完事,久而久之,導致對這個概念特別模糊。直到近期,做項目的過程中使用了mybatis-plus框架,這個框架自動生成映射文件的工具會將MySQL中的datetime類型轉化成Java中的LocalDateTime類型,由於幾次都出現了轉化錯誤、轉化繁瑣的問題,因此,就打算詳細的瞭解一下Java中的時間類的相關知識,希望下次再使用能夠做到心中有底。經過了幾天的瞭解,對這個時間概念算是有了一個大致的瞭解,記錄下來供以後參考。看來解決問題還得要抓住問題的本質,瞭解技術的來龍去脈,不能浮於表面。
二、介紹:
在JDK8發佈的時候,推出了LocalDate、LocalTime、LocalDateTime這個三個時間處理類,以此來彌補之前的日期時間類的不足,簡化日期時間的操作。在Java8之前,處理日期時間的類是Date、Calendar,這兩個在使用起來總是讓人感覺不是很舒服,在設計上面有一些缺陷,並且還不是線程安全的。
想要詳細的瞭解這幾個類,我們得要了解一點關於時間、時區劃分的一些知識。1884 年, 國際經度會議將地球表面按經線等分爲24 區,稱爲時區。即以本初子午線爲基準, 東西經度各7.5 度的範圍作爲零時區, 然後每隔15度爲一時區,每個時區相差一小時。北京時區爲東八區,要比零時區早8個小時。如果現在零時區的時間是10點的話,那北京時間就是18點。
我們平時在程序裏面所見到的UTC時間,就是零時區的時間,它的全稱是Coordinated Universal Time ,即世界協調時間。另一個常見的縮寫是GMT,即格林威治標準時間,格林威治位於 零時區,因此,我們平時說的UTC時間和GMT時間在數值上面都是一樣的。
可能會有一些疑問,同樣是在地球上啊,不同的地區時間怎麼還不一樣了?難道我現在從北京乘個飛機飛到格林威治,還可以來個時光倒流?如果這樣,豈不很神奇?哈哈,當然事情的真相並不是這樣的。時間的流逝、細胞的衰老對於整個地球來說都是一樣的,因此,不管你在地球的哪裏,這一秒過去了,就是過去了,它最爲公平,不會多你一分,也不會少你一秒。那怎麼記錄這流逝的分分秒秒呢?有一個名詞,叫做時間戳,它是指格林威治(地球零時區)時間1970年01月01日00時00分00秒(北京時間1970年01月01日08時00分00秒)起至現在的總秒數,這個時間戳,在地球的各個地方都是一致的。在1970年以前,有其他的計時方式,由於沒有統一,還造成了一些軟件的運行在時間上的錯亂,險些釀成了的行業災難(具體的事件可以網上搜索)。如果單純指望這個時間戳作爲人們的計時標準,那也是不現實的,因爲這對人類的生產生活來說沒有任何的意義。舉個例子:每天早上八點上課(上班)符合我們的習慣,如果是***秒到了上課時間就有違人的正常腦回路了。這時候,根據地球上的不同經緯度、地球自轉的特點,就劃分了時區,時間戳根據不同的時區轉化成當地的時間,以此作爲作息標準,從而方便人們的生產生活。北京時間的8點我們可以見到太陽的升起,倫敦時間的八點他們也能見到太陽的升起。
就這樣,可以知道,時間戳對地球上的任何一個地方都是一樣的,如果我們想要把時間戳轉化成當地的時間,就需要根據所在地區的時區進行轉化。不同時區之間進行時間轉化也是一樣的道理,我們需要根據時區的差異來轉化當地的時間。
三、使用方法:
3.1 Java8 以前的時間處理:
1,Date類的使用:
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
public class TestTime {
public static void main(String[] args) {
try {
//獲取Date對象,存放的是時間戳
Date date = new Date();
//獲取時間戳(毫秒)
long seconds = date.getTime();
System.out.println("當前時間戳: " + seconds);
//當前GMT(格林威治)時間、當前計算機系統所在時區的時間
SimpleDateFormat beijingFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("本地(東八區)時間: " + beijingFormat.format(date) +"; GMT時間: " + date.toGMTString());
//東八區時間轉換成東九區(東京)時間,比北京早一個小時
SimpleDateFormat tokyoFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
tokyoFormat.setTimeZone(TimeZone.getTimeZone("Asia/Tokyo"));
System.out.println("東京(東九區)時間: "+tokyoFormat.format(date));
//時間戳轉化成Date
SimpleDateFormat timestampFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String fotmatString = timestampFormat.format(seconds);
Date parseDate = timestampFormat.parse(fotmatString);
System.out.println("時間戳轉化成Date之後的時間: "+parseDate + ";格式化之後的: "+ fotmatString);
} catch (Exception e) {
e.printStackTrace();
}
}
}
輸出結果如下:
Date的無參構造函數如下圖:
我們可以看到,Date中存放的是時間戳,因此,我們在世界各地調用這個方法,獲取到的值都是一樣的。只是在不同的地方,這個值會根據時區轉化成當地的時間而已。
3.2 Java8 之後的時間處理:
從Java8開始,推出了LocalDate、LocalTime、LocalDateTime這三個工具類,實現了更好地時間處理,我們先看如何使用,然後,再進行比較。
1,工具類的獲取與使用:
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
public class TestLocalTime {
public static void main(String[] args) {
//獲取當前時區的日期
LocalDate localDate = LocalDate.now();
System.out.println("localDate: " + localDate);
//時間
LocalTime localTime = LocalTime.now();
System.out.println("localTime: " + localTime);
//根據上面兩個對象,獲取日期時間
LocalDateTime localDateTime = LocalDateTime.of(localDate,localTime);
System.out.println("localDateTime: " + localDateTime);
//使用靜態方法生成此對象
LocalDateTime localDateTime2 = LocalDateTime.now();
System.out.println("localDateTime2: " + localDateTime2);
//格式化時間
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("YYYY-MM-dd HH:mm:ss");
System.out.println("格式化之後的時間: " + localDateTime2.format(formatter));
//轉化爲時間戳(秒)
long epochSecond = localDateTime2.toEpochSecond(ZoneOffset.of("+8"));
//轉化爲毫秒
long epochMilli = localDateTime2.atZone(ZoneOffset.systemDefault()).toInstant().toEpochMilli();
System.out.println("時間戳爲:(秒) " + epochSecond + "; (毫秒): " + epochMilli);
//時間戳(毫秒)轉化成LocalDateTime
Instant instant = Instant.ofEpochMilli(epochMilli);
LocalDateTime localDateTime3 = LocalDateTime.ofInstant(instant, ZoneOffset.systemDefault());
System.out.println("時間戳(毫秒)轉化成LocalDateTime: " + localDateTime3.format(formatter));
//時間戳(秒)轉化成LocalDateTime
Instant instant2 = Instant.ofEpochSecond(epochSecond);
LocalDateTime localDateTime4 = LocalDateTime.ofInstant(instant2, ZoneOffset.systemDefault());
System.out.println("時間戳(秒)轉化成LocalDateTime: " + localDateTime4.format(formatter));
}
}
上述程序運行結果如下圖所示:
新推出來的這三個類,與MySQL中的日期時間類型正好對應,如果我們使用MySQL數據庫的話,在插入相應字段的時候,都不需要再進行任何的轉化了。對應關係如下:
LocalTime 對應 time
LocalDate 對應 date
LocalDateTime 對應 datetime(timestamp)
2,增加、減去時間:
看看上圖,是不是非常的簡單方便呢。
3,LocalDateTime 與 Date 的相互轉化
// Date 轉化成 LocalDateTime
public static LocalDateTime dateToLocalDate(Date date) {
Instant instant = date.toInstant();
ZoneId zoneId = ZoneId.systemDefault();
return instant.atZone(zoneId).toLocalDateTime();
}
// LocalDateTime 轉化成 Date
public static Date localDateTimeToDate(LocalDateTime localDateTime) {
ZoneId zoneId = ZoneId.systemDefault();
ZonedDateTime zdt = localDateTime.atZone(zoneId);
return Date.from(zdt.toInstant());
}
由於 LocalDate、LocalTime 或者只含有日期,或者只含有時間,因此,不能和Date直接進行轉化。
四、總結:
瞭解好時區,時間戳等這幾個概念,對於我們瞭解程序語言中時間類的構造非常有幫助。Java8 新推出來的這三個類,不僅讓我們在日常編程中更爲高效方便,而且,在與數據庫時間類型的對應上更爲友好。
最後總結:
1,時間戳: 是指格林威治(地球零時區)時間1970年01月01日00時00分00秒起至現在的總秒數,這個時間戳,在地球的各個地方都是一致的;
2,時區:由於地球的自轉,根據接收太陽光照的順序將地球劃分成24個區,從而方便當地人的生產生活,每個時區相差一小時,可以根據時間戳和時區計算當地的時間。格林威治處於零時區,北京處於東八區,因此,北京時間比格林威治時間早8個小時。
3,LocalDateTime 比 Date使用起來更爲方便,兩者可以相互進行轉化。