一文帶你學會Java8的時間API!

前言

Java8之前日期/時間API存在的問題

  • 非線程安全 − java.util.Date 是非線程安全的,所有的日期類都是可變的,這是Java日期類最大的問題之一。
  • 設計很差 − Java的日期/時間類的定義並不一致,在java.util和java.sql的包中都有日期類,此外用於格式化和解析的類在java.text包中定義。java.util.Date同時包含日期和時間,而java.sql.Date僅包含日期,將其納入java.sql包並不合理。另外這兩個類都有相同的名字,這本身就是一個非常糟糕的設計。
  • 時區處理麻煩 − 日期類並不提供國際化,沒有時區支持,因此Java引入了java.util.Calendar和java.util.TimeZone類,但他們同樣存在上述所有的問題。

​ 因爲上面這些原因,誕生了第三方庫Joda-Time,可以替代Java的時間管理API。Java 8中新的時間和日期管理API深受Joda-Time影響,並吸收了很多Joda-Time的精華。新的java.time包包含了所有關於日期、時間、時區、Instant(跟日期類似但是精確到納秒)、duration(持續時間)和時鐘操作的類。新設計的API認真考慮了這些類的不變性(從java.util.Calendar吸取的教訓),如果某個實例需要修改,則返回一個新的對象。

Java8新日期/時間API的改變

Java 8日期/時間API是JSR-310的實現,它的實現目標是克服舊的日期時間實現中所有的缺陷,新的日期/時間API的一些設計原則是:

  • 不變性:新的日期/時間API中,所有的類都是不可變的,這對多線程環境有好處。
  • 關注點分離:新的API將人可讀的日期時間和機器時間(unix timestamp)明確分離,它爲日期(Date)、時間(Time)、日期時間(DateTime)、時間戳(unix timestamp)以及時區定義了不同的類。
  • 清晰:在所有的類中,方法都被明確定義用以完成相同的行爲。舉個例子,要拿到當前實例我們可以使用now()方法,在所有的類中都定義了format()和parse()方法,而不是像以前那樣專門有一個獨立的類。爲了更好的處理問題,所有的類都使用了工廠模式和策略模式,一旦你使用了其中某個類的方法,與其他類協同工作並不困難。
  • 實用操作:所有新的日期/時間API類都實現了一系列方法用以完成通用的任務,如:加、減、格式化、解析、從日期/時間中提取單獨部分,等等。
  • 可擴展性:新的日期/時間API是工作在ISO-8601日曆系統上的,但我們也可以將其應用在非IOS的日曆上。

Java日期/時間API包含以下相應的包:

  • java.time包:這是新的Java日期/時間API的基礎包,所有的主要基礎類都是這個包的一部分,如:LocalDate, LocalTime, LocalDateTime, Instant, Period, Duration等等。所有這些類都是不可變的和線程安全的,在絕大多數情況下,這些類能夠有效地處理一些公共的需求。
  • java.time.chrono包:這個包爲非ISO的日曆系統定義了一些泛化的API,我們可以擴展AbstractChronology類來創建自己的日曆系統。
  • java.time.format包:這個包包含能夠格式化和解析日期時間對象的類,在絕大多數情況下,我們不應該直接使用它們,因爲java.time包中相應的類已經提供了格式化和解析的方法。
  • java.time.temporal包:這個包包含一些時態對象,我們可以用其找出關於日期/時間對象的某個特定日期或時間,比如說,可以找到某月的第一天或最後一天。你可以非常容易地認出這些方法,因爲它們都具有“withXXX”的格式。
  • java.time.zone包:這個包包含支持不同時區以及相關規則的類。

Java8提供的LocalDate和DateTimeFormat是如何保證線程安全的?

LocalDate類和DateTimeFormatter類都是final類型的,也就是說,它們是不可變的,一旦實例化,值就固定了。而Java8之前的Date類和SimpleDateFormat類都不是final的。

分析一下源碼。

LocalDateTime-Src

DateTimeFormatter-Src

Java8日期/時間API介紹

Java8新增類型

Instant:時間戳
Duration:持續時間,時間差
LocalDate:只包含日期,比如:2016-10-20
LocalTime:只包含時間,比如:23:12:10
LocalDateTime:包含日期和時間,比如:2016-10-20 23:14:21
Period:時間段
ZoneOffset:時區偏移量,比如:+8:00
ZonedDateTime:帶時區的時間
Clock:時鐘,比如獲取目前美國紐約的時間
java.time.format.DateTimeFormatter:時間格式化類

下面介紹下如何使用:

LocalDate 只會獲取年月日

// 創建 LocalDate
// 獲取當前年月日
LocalDate localDate = LocalDate.now();
// 構造指定的年月日
LocalDate localDate1 = LocalDate.of(2019, 9, 12);
// 獲取年、月、日、星期幾
int year = localDate1.getYear();
int year1 = localDate1.get(ChronoField.YEAR);
Month month = localDate1.getMonth();
int month1 = localDate1.get(ChronoField.MONTH_OF_YEAR);
// 月份中的第幾天:12
int day = localDate1.getDayOfMonth();
int day1 = localDate1.get(ChronoField.DAY_OF_MONTH);
// 一週的第幾天:THURSDAY
DayOfWeek dayOfWeek = localDate1.getDayOfWeek();
// 一週的第幾天:4
int dayOfWeek1 = localDate1.get(ChronoField.DAY_OF_WEEK);
// 是否爲閏年:false
boolean leapYear = localDate1.isLeapYear();  
// 紐約日期
LocalDate todayNewYork = LocalDate.now(ZoneId.of("America/New_York"));

LocalTime 只會獲取時分秒

// 創建 LocalTime
LocalTime localTime = LocalTime.of(14, 14, 14);
LocalTime localTime1 = LocalTime.now();
// 獲取小時
int hour = localTime.getHour();
int hour1 = localTime.get(ChronoField.HOUR_OF_DAY);
// 獲取分
int minute = localTime.getMinute();
int minute1 = localTime.get(ChronoField.MINUTE_OF_HOUR);
// 獲取秒
int second = localTime.getMinute();
int second1 = localTime.get(ChronoField.SECOND_OF_MINUTE);
// 紐約時間
LocalTime timeNewYork = LocalTime.now(ZoneId.of("America/New_York"));

LocalDateTime 獲取年月日時分秒

相當於 LocalDate + LocalTime

// 創建 LocalDateTime
LocalDateTime localDateTime = LocalDateTime.now();
LocalDateTime localDateTime1 = LocalDateTime.of(2019, Month.SEPTEMBER, 10, 14, 46, 56);
LocalDateTime localDateTime2 = LocalDateTime.of(localDate, localTime);
LocalDateTime localDateTime3 = localDate.atTime(localTime);
LocalDateTime localDateTime4 = localTime.atDate(localDate);
// 獲取LocalDate
LocalDate localDate2 = localDateTime.toLocalDate();
// 獲取LocalTime
LocalTime localTime2 = localDateTime.toLocalTime();
// 紐約日期+時間
LocalDateTime timeNewYork = LocalDateTime.now(ZoneId.of("America/New_York"));

Instant 獲取秒數

用於表示一個時間戳(精確到納秒)

它與我們常使用的System.currentTimeMillis()有些類似,不過Instant可以精確到納秒(Nano-Second),System.currentTimeMillis()方法只精確到毫秒(Milli-Second)。如果查看Instant源碼,發現它的內部使用了兩個常量,seconds表示從1970-01-01 00:00:00開始到現在的秒數,nanos表示納秒部分(nanos的值不會超過999,999,999)。Instant除了使用now()方法創建外,還可以通過ofEpochSecond方法創建.

// ofEpochSecond()方法的第一個參數爲秒,第二個參數爲納秒,上面的代碼表示從1970-01-01 00:00:00開始後兩分鐘的10萬納秒的時刻,控制檯上的輸出爲:
// 1970-01-01T00:02:00.000100Z
Instant instant = Instant.ofEpochSecond(120, 100000);

// 創建Instant對象
Instant instant = Instant.now();
// 獲取秒數
long currentSecond = instant.getEpochSecond();
// 獲取毫秒數
long currentMilli = instant.toEpochMilli();

Period/Duration 時間差

  • Period - 處理有關基於時間的日期數量。
  • Duration - 處理有關基於時間的時間量。

Duration 表示一個時間段

// Duration.between()方法創建 Duration 對象
LocalDateTime from = LocalDateTime.of(2017, Month.JANUARY, 1, 00, 0, 0);    // 2017-01-01 00:00:00
LocalDateTime to = LocalDateTime.of(2019, Month.SEPTEMBER, 12, 14, 28, 0);   // 2019-09-15 14:28:00
Duration duration = Duration.between(from, to);     // 表示從 from 到 to 這段時間
long days = duration.toDays();              // 這段時間的總天數
long hours = duration.toHours();            // 這段時間的小時數
long minutes = duration.toMinutes();        // 這段時間的分鐘數
long seconds = duration.getSeconds();       // 這段時間的秒數
long milliSeconds = duration.toMillis();    // 這段時間的毫秒數
long nanoSeconds = duration.toNanos();      // 這段時間的納秒數
Duration duration1 = Duration.of(5, ChronoUnit.DAYS);       // 5天
Duration duration2 = Duration.of(1000, ChronoUnit.MILLIS);  // 1000毫秒

Period 表示日期上的時間差

Period在概念上和Duration類似,區別在於Period是以年月日來衡量一個時間段,比如2年3個月6天:

Period period = Period.of(2, 3, 6);

Period對象也可以通過between()方法創建,值得注意的是,由於Period是以年月日衡量時間段,所以between()方法只能接收LocalDate類型的參數:

// 2017-01-05 到 2017-02-05 這段時間
Period period = Period.between(
                LocalDate.of(2017, 1, 5),
                LocalDate.of(2017, 2, 5));

ChronoUnit 時間枚舉類

LocalDate today = LocalDate.now();
LocalDate nextWeek = today.plus(1, ChronoUnit.WEEKS);

Clock

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

Clock clock = Clock.systemUTC();
System.out.println(clock.instant() );//2020-05-26T16:54:54.141Z
System.out.println(clock.millis() );//1590512094273

時區

Java 8中的時區操作被很大程度上簡化了,新的時區類java.time.ZoneId是原有的java.util.TimeZone類的替代品。ZoneId對象可以通過ZoneId.of()方法創建,也可以通過ZoneId.systemDefault()獲取系統默認時區:

ZoneId shanghaiZoneId = ZoneId.of("Asia/Shanghai");
ZoneId systemZoneId = ZoneId.systemDefault();

of()方法接收一個“區域/城市”的字符串作爲參數,你可以通過getAvailableZoneIds()方法獲取所有合法的“區域/城市”字符串:

Set<String> zoneIds = ZoneId.getAvailableZoneIds();

對於老的時區類TimeZone,Java 8也提供了轉化方法:

ZoneId oldToNewZoneId = TimeZone.getDefault().toZoneId();

有了ZoneId,我們就可以將一個LocalDateLocalTimeLocalDateTime對象轉化爲ZonedDateTime對象:

LocalDateTime localDateTime = LocalDateTime.now();
ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, shanghaiZoneId);

zonedDateTime打印到控制檯爲:

2017-01-05T15:26:56.147+08:00[Asia/Shanghai]

ZonedDateTime 帶時區日期時間處理

對象由兩部分構成,LocalDateTimeZoneId,其中2017-01-05T15:26:56.147部分爲LocalDateTime+08:00[Asia/Shanghai]部分爲ZoneId

另一種表示時區的方式是使用ZoneOffset,它是以當前時間和**世界標準時間(UTC)/格林威治時間(GMT)**的偏差來計算,例如:

ZoneOffset zoneOffset = ZoneOffset.of("+09:00");
LocalDateTime localDateTime = LocalDateTime.now();
OffsetDateTime offsetDateTime = OffsetDateTime.of(localDateTime, zoneOffset);

GMT(格林威治時間)、CST(可視爲美國、澳大利亞、古巴或中國的標準時間)、PST(太平洋時間)

GMT: UTC +0    =    GMT: GMT +0
CST: UTC +8    =    CST: GMT +8
PST: UTC -8    =    PST: GMT -8

ZonedDateTime

從上面的圖中我們可以看出,LocalDateTime,並不能表示我們人類世界中完整的時間,而ZonedDateTime可以。

而且上面的轉換中我們可以知道,LocalDateTime轉Instant或者OffsetDatetime都是需要加上偏移時區的(ZoneOffset)。

所以可以得出 OffsetDatetime和Instant也是可以表示人類世界中完整的時間的,和ZoneDateTime是等效的。

OffsetDatetime、Instant和 ZoneDateTime區別

OffsetDateTime ,ZonedDateTime 和 Instant 都會在時間線上存儲一個納秒級精度。 Instant 是最簡單的,只需代表instant。 OffsetDateTime 添加到UTC / Greenwich的偏移瞬間,這允許獲得本地日期時間。 ZonedDateTime 添加完整的時區規則。

因此 OffsetDateTime 和之間的區別ZonedDateTime 是後者包括涵蓋夏令時調整的規則。

國際時區 TimeZone ID列表 獲取方法:TimeZone.getAvailableIDs()

其他曆法

Java中使用的歷法是ISO 8601日曆系統,它是世界民用曆法,也就是我們所說的公曆。平年有365天,閏年是366天。閏年的定義是:非世紀年,能被4整除;世紀年能被400整除。爲了計算的一致性,公元1年的前一年被當做公元0年,以此類推。

此外Java 8還提供了4套其他曆法(很奇怪爲什麼沒有漢族人使用的農曆),每套曆法都包含一個日期類,分別是:

  • ThaiBuddhistDate:泰國佛教歷
  • MinguoDate:中華民國曆
  • JapaneseDate:日本歷
  • HijrahDate:伊斯蘭曆

每個日期類都繼承ChronoLocalDate類,所以可以在不知道具體曆法的情況下也可以操作。不過這些曆法一般不常用,除非是有某些特殊需求情況下才會使用。

這些不同的歷法也可以用於向公曆轉換:

LocalDate date = LocalDate.now();
JapaneseDate jpDate = JapaneseDate.from(date);

由於它們都繼承ChronoLocalDate類,所以在不知道具體曆法情況下,可以通過ChronoLocalDate類操作日期:

Chronology jpChronology = Chronology.ofLocale(Locale.JAPANESE);
ChronoLocalDate jpChronoLocalDate = jpChronology.dateNow();

我們在開發過程中應該儘量避免使用ChronoLocalDate,儘量用與曆法無關的方式操作時間,因爲不同的歷法計算日期的方式不一樣,比如開發者會在程序中做一些假設,假設一年中有12個月,如果是中國農曆中包含了閏月,一年有可能是13個月,但開發者認爲是12個月,多出來的一個月屬於明年的。再比如假設年份是累加的,過了一年就在原來的年份上加一,但日本天皇在換代之後需要重新紀年,所以過了一年年份可能會從1開始計算。

在實際開發過程中建議使用LocalDate,包括存儲、操作、業務規則的解讀;除非需要將程序的輸入或者輸出本地化,這時可以使用ChronoLocalDate類。

日期的操作和格式化

增加和減少日期-簡單操作

LocalDate date = LocalDate.of(2017, 1, 5);          // 2017-01-05
LocalDate date1 = date.withYear(2016);              // 修改爲 2016-01-05
LocalDate date2 = date.withMonth(2);                // 修改爲 2017-02-05
LocalDate date3 = date.withDayOfMonth(1);           // 修改爲 2017-01-01

LocalDate date4 = date.plusYears(1);                // 增加一年 2018-01-05
LocalDate date5 = date.minusMonths(2);              // 減少兩個月 2016-11-05
LocalDate date6 = date.plus(5, ChronoUnit.DAYS);    // 增加5天 2017-01-10

像LocalDate、LocalTime、LocalDateTime以及Instant這樣表示時間點的日期-時間類提供了大量通用的方法,

下表對這些通用的方法進行了總結

方法名 描述
from 靜態方法,依據傳入的 Temporal 對象創建對象實例
now 靜態方法,依據系統時鐘創建 Temporal 對象
of 靜態方法,由 Temporal 對象的某個部分創建該對象的實例
parse 靜態方法,由字符串創建 Temporal 對象的實例
atOffset 非靜態方法,將 Temporal 對象和某個時區偏移相結合
atZone 非靜態方法,將 Temporal 對象和某個時區相結合
format 非靜態方法,使用某個指定的格式器將Temporal對象轉換爲字符串(Instant類不提供該方法)
get 非靜態方法,讀取 Temporal 對象的某一部分的值
minus 非靜態方法,創建 Temporal 對象的一個副本,通過將當前 Temporal 對象的值減去一定的時長創建該副本
plus 非靜態方法,創建 Temporal 對象的一個副本,通過將當前 Temporal 對象的值加上一定的時長創建該副本
with 非靜態方法,以該 Temporal 對象爲模板,對某些狀態進行修改創建該對象的副本

TemporalField-複雜操作

TemporalField是一個接口,它定義瞭如何訪問temporal對象某個字段的值。ChronoField枚舉類實現了這一接口,所以你可以很方便地使用get方法得到枚舉元素的值:

int year = LocalDate.now().get(ChronoField.YEAR); 

LocalDate date1 = LocalDate.now();
// 下一個週二 
LocalDate nextTuesday = date1.with(TemporalAdjusters.next(DayOfWeek.TUESDAY));
// 當月的第二個週六
LocalDate firstInMonth = LocalDate.of(date1.getYear(), date1.getMonth(), 1);
LocalDate secondSaturday = firstInMonth.with(TemporalAdjusters.nextOrSame(DayOfWeek.SATURDAY)).with(TemporalAdjusters.next(DayOfWeek.SATURDAY));

注:TemporalAdjusters類中有許多常用的特殊的日期的方法(類方法),使用時可以仔細查看,可以很大程度減少日期判斷的代碼量!

TemporalAdjusters 包含許多靜態方法,可以直接調用,以下列舉一些:

方法名 描述
dayOfWeekInMonth 返回同一個月中每週的第幾天
firstDayOfMonth 返回當月的第一天
firstDayOfNextMonth 返回下月的第一天
firstDayOfNextYear 返回下一年的第一天
firstDayOfYear 返回本年的第一天
firstInMonth 返回同一個月中第一個星期幾
lastDayOfMonth 返回當月的最後一天
lastDayOfNextMonth 返回下月的最後一天
lastDayOfNextYear 返回下一年的最後一天
lastDayOfYear 返回本年的最後一天
lastInMonth 返回同一個月中最後一個星期幾
next / previous 返回後一個/前一個給定的星期幾
nextOrSame / previousOrSame 返回後一個/前一個給定的星期幾,如果這個值滿足條件,直接返回

DateTimeFormatter 格式化日期

LocalDate localDate = LocalDate.of(2019, 9, 12);
String s1 = localDate.format(DateTimeFormatter.BASIC_ISO_DATE);
String s2 = localDate.format(DateTimeFormatter.ISO_LOCAL_DATE);
System.out.println("s1:"+ s1); // 20190912
System.out.println("s2:"+ s2); // 2019-09-12
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println("獲取當前時間:"+localDateTime); // 2019-09-16T14:54:36.520
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:MM:SS");
String s = localDateTime.format(formatter);
System.out.println("格式化當前時間:"+ s); // 2019-09-16 14:09:52


LocalDate localDate1 = LocalDate.parse("20190912", DateTimeFormatter.BASIC_ISO_DATE);
LocalDate localDate2 = LocalDate.parse("2019-09-12", DateTimeFormatter.ISO_LOCAL_DATE);

DateTimeFormatter我們更多的是直接使用pattern來做轉換,其實這個類本身已經提供了一些預定義好的實例供我們使用。
下面把兩者的具體釋義和示例都貼出來供大家參考。

預定義

Predefined Formatters Formatter Description Example
ofLocalizedDate(dateStyle) Formatter with date style from the locale ‘2011-12-03’
ofLocalizedTime(timeStyle) Formatter with time style from the locale ‘10:15:30’
ofLocalizedDateTime(dateTimeStyle) Formatter with a style for date and time from the locale ‘3 Jun 2008 11:05:30’
ofLocalizedDateTime(dateStyle,timeStyle) Formatter with date and time styles from the locale ‘3 Jun 2008 11:05’
BASIC_ISO_DATE Basic ISO date ‘20111203’
ISO_LOCAL_DATE ISO Local Date ‘2011-12-03’
ISO_OFFSET_DATE ISO Date with offset ‘2011-12-03+01:00’
ISO_DATE ISO Date with or without offset ‘2011-12-03+01:00’; ‘2011-12-03’
ISO_LOCAL_TIME Time without offset ‘10:15:30’
ISO_OFFSET_TIME Time with offset ‘10:15:30+01:00’
ISO_TIME Time with or without offset ‘10:15:30+01:00’; ‘10:15:30’
ISO_LOCAL_DATE_TIME ISO Local Date and Time ‘2011-12-03T10:15:30’
ISO_OFFSET_DATE_TIME Date Time with Offset ‘2011-12-03T10:15:30+01:00’
ISO_ZONED_DATE_TIME Zoned Date Time ‘2011-12-03T10:15:30+01:00[Europe/Paris]’
ISO_DATE_TIME Date and time with ZoneId ‘2011-12-03T10:15:30+01:00[Europe/Paris]’
ISO_ORDINAL_DATE Year and day of year ‘2012-337’
ISO_WEEK_DATE Year and Week ‘2012-W48-6’
ISO_INSTANT Date and Time of an Instant ‘2011-12-03T10:15:30Z’
RFC_1123_DATE_TIME RFC 1123 / RFC 822 ‘Tue, 3 Jun 2008 11:05:30 GMT’

Pattern

All letters ‘A’ to ‘Z’ and ‘a’ to ‘z’ are reserved as pattern letters. The following pattern letters are defined:

Symbol Meaning Presentation Examples
G era text AD; Anno Domini; A
u year year 2004; 04
y year-of-era year 2004; 04
D day-of-year number 189
M/L month-of-year number/text 7; 07; Jul; July; J
d day-of-month number 10
Q/q quarter-of-year number/text 3; 03; Q3; 3rd quarter
Y week-based-year year 1996; 96
w week-of-week-based-year number 27
W week-of-month number 4
E day-of-week text Tue; Tuesday; T
e/c localized day-of-week number/text 2; 02; Tue; Tuesday; T
F week-of-month number 3
a am-pm-of-day text PM
h clock-hour-of-am-pm (1-12) number 12
K hour-of-am-pm (0-11) number 0
k clock-hour-of-am-pm (1-24) number 0
H hour-of-day (0-23) number 0
m minute-of-hour number 30
s second-of-minute number 55
S fraction-of-second fraction 978
A milli-of-day number 1234
n nano-of-second number 987654321
N nano-of-day number 1234000000
V time-zone ID zone-id America/Los_Angeles; Z; -08:30
z time-zone name zone-name Pacific Standard Time; PST
O localized zone-offset offset-O GMT+8; GMT+08:00; UTC-08:00;
X zone-offset ‘Z’ for zero offset-X Z; -08; -0830; -08:30; -083015; -08:30:15;
x zone-offset offset-x +0000; -08; -0830; -08:30; -083015; -08:30:15;
Z zone-offset offset-Z +0000; -0800; -08:00;
p pad next pad modifier 1
escape for text delimiter
‘’ single quote literal
[ optional section start
] optional section end
# reserved for future use
{ reserved for future use
} reserved for future use

舊的日期時間支持

Date 和 LocalDate 互轉

// Date -> LocalDateTime/LocalDate
Date date = new Date();
LocalDateTime localDateTime = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
LocalDate localDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

// LocalDate -> Date
LocalDate nowLocalDate = LocalDate.now();
Date date = Date.from(nowLocalDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
// LocalDateTime -> Date
LocalDateTime localDateTime = LocalDateTime.now();
Date date = Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());

Date 和 Instant 互轉

// Date -> Instant
Instant timestamp = new Date().toInstant();
// Instant -> Date
Date date = Date.from(Instant.now());

TimeZone 和 ZoneId 互轉

ZoneId defaultZone = TimeZone.getDefault().toZoneId();
TimeZone tz = TimeZone.getTimeZone(defaultZone);

ZonedDateTime 和 GregorianCalendar 互轉

ZonedDateTime gregorianCalendarDateTime = new GregorianCalendar().toZonedDateTime();//GregorianCalendar -> ZonedDateTime
GregorianCalendar gc = GregorianCalendar.from(gregorianCalendarDateTime);//ZonedDateTime -> GregorianCalendar

其他相關轉換

Long時間戳 和 LocalDateTime 互轉

// Long時間戳 -> LocalDateTime
long timestamp = System.currentTimeMillis();
LocalDateTime localDateTime = Instant.ofEpochMilli(timestamp).atZone(ZoneId.systemDefault()).toLocalDateTime();

// LocalDate -> Long時間戳
LocalDate localDate = LocalDate.now();
long timestamp = localDate.atStartOfDay(ZoneId.systemDefault()).toInstant().toEpochMilli();
// LocalDateTime -> Long時間戳
LocalDateTime localDateTime = LocalDateTime.now();
long timestamp = localDateTime.toInstant(ZoneOffset.ofHours(8)).toEpochMilli(); // GMT +8時區

Instant 和 LocalDateTime互轉

// LocalDateTime -> Instant 
Instant instant =  LocalDateTime.now().toInstant(ZoneOffset.of("+8"));
// 或者
Instant instant1 =  LocalDateTime.now().toInstant(ZoneOffset.ofHours(8));

// Instant -> LocalDateTime
LocalDateTime instantToLocalDateTime = LocalDateTime.ofInstant(Instant.now(), ZoneId.systemDefault());

String 和 LocalDateTime 互轉

// String -> LocalDateTime
LocalDateTime stringToLocalDateTime = LocalDateTime.parse("2018-03-11 15:30:11", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));

// LocalDateTime -> String
String localDateTimeToString = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")

String 和 Date 互轉

// String -> Date
Date stringToDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2018-03-11 15:30:11");

//Date -> String
String dateToString = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());

Timestamp 和 LocalDateTime 互轉

// Timestamp -> LocalDateTime
LocalDateTime timeStampToLocalDateTime = LocalDateTime.ofInstant(new Timestamp(1520754566856L).toInstant(), ZoneId.systemDefault());

// LocalDateTime -> TimeStamp
Timestamp localDateTimeToTimeStamp = Timestamp.valueOf(LocalDateTime.now());

Timestamp 和 Date 互轉

// Timestamp -> Date
Date timestampToDate = Date.from(new Timestamp(1520754566856L).toInstant());

// Date -> LocalDateTime
LocalDateTime dateToLocalDateTime = LocalDateTime.ofInstant(new Date().toInstant(), ZoneId.systemDefault());

參考

Java 8 日期時間 API 指南 | Java 8 教程彙總

Java8新特性之日期和時間 - mrjade - 博客園

Java 8新特性(四):新的時間和日期API | 一書生VOID的博客

Java8新特性總結 -6.Date/Time API_java_BlueKitty的博客-CSDN博客

Java8新特性整理之新的時間和日期API(終章)_java_一大三千的博客-CSDN博客

Java8學習筆記:LocalDateTime、Instant 和 OffsetDateTime 相互轉換_java_山鬼謠的專欄-CSDN博客


求關注、分享、在看!!! 你的支持是我創作最大的動力。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章