寫在前面
如果覺得有所收穫,寫的還不錯,記得點個贊或者點個關注哦,不勝感激。我們使用Java的時候,經常會用到的一個類就是時間類,但是很多時候我們只是匆匆而過,並沒有深入去了解時間類。在我開發歷程中,碰到了許多有關時間類的問題,所以今天抽空,把Java的時間類闡述總結一下,希望看完這篇的小夥伴能有所收穫。本篇文章分四個部分講,分別是 Java 基礎時間類
、Java sql 時間類
、Joda Time 時間類
、 java.time 時間類
。
文章目錄
Java 基礎時間類
在Java8之前對日期、日曆及時間的處理一直飽受詬病,尤其是它決定將java.util.Date
定義爲可修改的以及將SimpleDateFormat
實現成非線程安全的。直到Java8 大版本的發佈,才完善了相關類。這裏簡單說一下這兩個包,java.util
包是 Java 的實用工具類庫包,包含 Java 的集合類、時間類、事件模型類等;java.text
包是跟文本、格式化打交道的包,比如處理時間、數字等。這兩個包都是 Java 很老的基礎包。
Date 類
Date 類是 Java 裏時間類中老資歷了,所以在講其他的API之前呢,這裏先要來講講這個類。Date類在保留着日期和時間最基本用法的同時,總能用其偏執的使用思路讓人覺得擰巴。但是在程序員懶得找其他替代品時,它又幾乎是第一選擇,因爲它的確是足夠基礎,當然了,使用時還要容忍它的反人類。如下是Date的源碼,我們可以看到Date 類有兩種構造函數,一種是獲取當前時間,一種是根據你的輸入時間來實例化時間,注意了輸入的時間是時間戳,類型用的是long
。
Date 類有很多方法,大部分均已標記 @Deprecated
(已廢棄),剩下的幾個基本只有一個方法能用:getTime()
,而這個方法非常硬核,它 get 到的 Time 不是年月日,而是一個 long
類型的毫秒數,表示在格林尼治時間 1900 年開始之後,經過了多少毫秒。
Date date = new Date();
System.out.println(date.getTime());
//控制檯輸出:1585825773101
這裏要吐槽一下Date類的一些設計,讓人抓狂的一些地方
- Date 類計算年份時,是跟 1900 年進行比較的,比如今年(2020 年)對於 Date 類而言,它是 119 年,當調用
getYear()
方法時(該方法已被官方建議不要使用),它會說這是 119 年。 - Date 類計算月份是,是從 0 開始計算的,因此這個月(4 月)對於 Date 類而言,它是 3 。
getDay()
方法是獲取當週的第幾天, getDate() 方法是獲取當月的第幾天(這兩個方法也已被遺棄)。- Date 類自己的一切
getXXX()
方法,實際上只剩下了getTime()
方法,表示獲取當前時間(精確到毫秒)與 1900 年 1 月 1 日 0 時 0 分 0 秒這一瞬間(包含時差),中間間隔的毫秒數,其他獲取年月日等時間的方法均被遺棄,官方建議使用 Calendar 類。 - Date 類的
getTime()
方法是指獲取毫秒數,比如現在時間的 getTime() 的值爲 1585825773101 ,太硬核了。更硬核的是,Date 類的構造函數只剩下兩種能用,一種是無參構造(得到當下的時間),另一種是以剛纔的那個毫秒數爲參數。 - Date 類的值不是 final 的,是可以在實例化之後通過
setTime()
改變值的,非線程安全。 - 當調用 Date 類的
toString()
方法時,它會打印出例如Thu Apr 02 19:14:14 CST 2020
(中國標準時間 2020 年 4 月 02 日 19 時 14 分 14 秒)的值,你發現這裏包含時區信息 CST,但令人無語的是,這個時區信息是 Date 類在調用toString()
方法時,根據系統時區動態打印的。換句話說,剛纔那個時間的程序在中國執行,時區是 CST,在美國執行,那時區就是 PDT。
Calendar
calendar 是日曆的意思,因此見名知意,Calendar 類是用來跟年月日等時間打交道的類。Calendar 類本身是一個抽象類,它代表着日曆類的標準與規範,有 GregorianCalendar 類(格林尼治日曆時間)等實現類。實例化一個 Calendar 類,如果不使用子類,那就要通過工廠方法獲得了。
// Calendar類的實例化方法
Calendar calendar = Calendar.getInstance();
// 下面這種是錯誤的
Calendar calendar = new Calendar();
這裏通過 Calendar.getInstance() 獲得的,是一個 GregorianCalendar 對象。不過也會根據其他的一些信息返回其他對象,具體可以查看源碼,這裏貼一部分出來
Calendar 類最實用的方法是它的 get() 方法,用這個方法獲取年、月、日、周、小時等等 17 類不同的信息。
// 獲取calendar的年份信息 如2020
int year = calendar.get(Calendar.YEAR);
// 獲取calendar的月份信息 如9
int month = calendar.get(Calendar.MONTH);
// 獲取calendar的當月天數信息,如10
int date = calendar.get(Calendar.DATE);
上面諸如 Calendar.YEAR
之類的值,其實是 Calendar 類定義的常量值,Calendar.YEAR
其實就是 1,換句話說,下面兩行代碼是一樣的:
int year1 = calendar.get(Calendar.YEAR);
int year2 = calendar.get(1);
通過 Calendar 類的 get()
方法能得到 17 類不同的時間信息,這 17 個常量值列在下面:
Calendar 的“年、月、日、星期、時、分、秒”這些信息,一共是17個字段。
我們使用Calendar,無非是就是使用這17個字段。它們的定義如下:
(字段0) public final static int ERA = 0;
說明:紀元。
取值:只能爲0 或 1。0表示BC(“before Christ”,即公元前),1表示AD(拉丁語“Anno Domini”,即公元)。
(字段1) public final static int YEAR = 1;
說明:年。
(字段2) public final static int MONTH = 2;
說明:月
取值:可以爲,JANUARY, FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER, UNDECIMBER。
其中第一個月是 JANUARY,它爲 0。
(字段3) public final static int WEEK_OF_YEAR = 3;
(字段4) public final static int WEEK_OF_MONTH = 4;
說明:當前日期在本月中對應第幾個星期。一個月中第一個星期的值爲 1。
(字段5) public final static int DATE = 5;
說明:日。一個月中第一天的值爲 1。
(字段5) public final static int DAY_OF_MONTH = 5;
說明:同“DATE”,表示“日”。
(字段6) public final static int DAY_OF_YEAR = 6;
說明:當前日期在本年中對應第幾天。一年中第一天的值爲 1。
(字段7) public final static int DAY_OF_WEEK = 7;
說明:星期幾。
取值:可以爲,SUNDAY、MONDAY、TUESDAY、WEDNESDAY、THURSDAY、FRIDAY 和 SATURDAY。
其中,SUNDAY爲1,MONDAY爲2,依次類推。
(字段8) public final static int DAY_OF_WEEK_IN_MONTH = 8;
說明:當前月中的第幾個星期。
(字段9) public final static int AM_PM = 9;
說明:上午 還是 下午
取值:可以是AM 或 PM。AM爲0,表示上午;PM爲1,表示下午。
(字段10) public final static int HOUR = 10;
說明:指示一天中的第幾小時。
HOUR 用於 12 小時制時鐘 (0 - 11)。中午和午夜用 0 表示,不用 12 表示。
(字段11) public final static int HOUR_OF_DAY = 11;
說明:指示一天中的第幾小時。
HOUR_OF_DAY 用於 24 小時制時鐘。例如,在 10:04:15.250 PM 這一時刻,HOUR_OF_DAY 爲 22。
(字段12) public final static int MINUTE = 12;
說明:一小時中的第幾分鐘。
例如,在 10:04:15.250 PM這一時刻,MINUTE 爲 4。
(字段13) public final static int SECOND = 13;
說明:一分鐘中的第幾秒。
例如,在 10:04:15.250 PM 這一時刻,SECOND 爲 15。
(字段14) public final static int MILLISECOND = 14;
說明:一秒中的第幾毫秒。
例如,在 10:04:15.250 PM 這一時刻,MILLISECOND 爲 250。
(字段15) public final static int ZONE_OFFSET = 15;
說明:毫秒爲單位指示距 GMT 的大致偏移量。
(字段16) public final static int DST_OFFSET = 16;
說明:毫秒爲單位指示夏令時的偏移量。
public final static int FIELD_COUNT = 17;
這17個字段是保存在int數組中。定義如下:
// 保存這17個字段的數組
protected int fields[];
// 數組的定義函數
protected Calendar(TimeZone zone, Locale aLocale)
{
// 初始化“fields數組”
fields = new int[FIELD_COUNT];
isSet = new boolean[FIELD_COUNT];
stamp = new int[FIELD_COUNT];
this.zone = zone;
setWeekCountData(aLocale);
}
protected Calendar(TimeZone zone, Locale aLocale) 這是Calendar的構造函數。
它會被它的子類的構造函數調用到,從而新建“保存Calendar的17個字段數據”的數組。
但讓人依舊無語的是,Calendar 類的月份也是從 0 開始的。此外 Calendar 類不支持格式化。
SimpleDateFormat
SimpleDateFormat 類是一個【格式化】和【解析日期】的工具類,即 Date 轉 Text 或者 Text 轉 Date,而且能夠按照要求格式轉換,如輸出 2019-09-10 12:00:00
這種時間文本。下面就是最常見的用法,聲明好格式之後,使用 format()
方法把時間轉換成字符串。
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss zzz");
String dateStr = simpleDateFormat.format(date);
// dateStr : "2020-04-02 22:55:42 CST"
另一種常見的用法是把字符串轉換成時間,但是要異常處理,畢竟是處理字符串。
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss zzz");
try {
Date date = simpleDateFormat.parse("2020-04-02 22:55:42 CST");
} catch (ParseException e) {
e.printStackTrace();
}
// date.toString() : Fou Apr 26 22:55:42 CST 2020
字母 | 日期或時間元素 | 表示 | 示例 |
---|---|---|---|
G | Era 標誌符 | Text | AD |
y | 年 | Year | 1996; 96 |
M | 年中的月份 | Month | July; Jul; 07 |
w | 年中的週數 | Number | 27 |
W | 月份中的週數 | Number | 2 |
D | 年中的天數 | Number | 189 |
d | 月份中的天數 | Number | 10 |
F | 月份中的星期 | Number | 2 |
E | 星期中的天數 | Text | Tuesday; Tue |
a | Am/pm 標記 | Text | PM |
H | 一天中的小時數 | (0-23) | Number |
k | 一天中的小時數(1-24) | Number | 24 |
K | am/pm 中的小時數(0-11) | Number | 0 |
h | am/pm 中的小時數(1-12) | Number | 12 |
m | 小時中的分鐘數 | Number | 30 |
s | 分鐘中的秒數 | Number | 55 |
S | 毫秒數 | Number | 978 |
z | 時區 | General time zone | Pacific Standard Time; PST; GMT-08:00 |
Z | 時區 | RFC 822 time zone | -0800 |
雖然使用 SimpleDateFormat 類能進行文本處理了,但是使用起來還是挺不方便的,而且還要考慮異常處理,此外它還線程不安全。
java.sql 包中的時間類
在 java 中有一個與數據庫相對應的類包,是 java.sql
包,該包下有三個對應數據庫時間類型的類,分別是 Date 類、 Time 類和 TimeStamp 類
,可以這麼說,個人感覺這是三個廢物類,一無是處。這三個類是與數據庫中的時間數據類型完全對應的:
數據庫的時間類型 | java.sql 時間類型 | 示例 |
---|---|---|
DATE | Date | 2019-09-01 |
TIME | Time | 12:00:00 |
TIMESTAMP | Timestamp | 2019-09-01 12:00:00.000 |
這三個類廢物,不是沒有根據的:
- 這三個時間類的構造方法都只有一種(另一種官方廢棄不建議使用),那就是【當下時間距離 1970 年 1 月 1 日 0 時 0 分 0 秒 0 毫秒】的毫秒數,反人類。
- 這三個時間類沒有諸如 getDate() 之類獲取時間的方法,它們有什麼方法呢,只有轉換成別的時間類的方法 :)
- 除了這三個類之外,別的時間類也可以對接數據庫。
Joda Time 時間類
從上面兩部分的時間類看得出,用 JDK 自帶的時間類編程,還是比較痛苦的:其一,想完成某個需求,可能需要好幾個時間類同時使用;其二,上述時間類還存在着許多例如月份從 0 開始計數、時區信息僞造等暗坑。這種痛苦的局面在 JDK 8 得到了解決,因爲 JDK 8 設計了全新的時間類,但是低版本的 JDK 依舊痛苦。想解決這種痛苦,就要使用第三方類庫,Joda Time 就是一個優秀的第三方時間類庫。
org.joda.time
包下的類,大致可以分爲三種:
- 時間類(類似於上文的 Date 類)
- 格式化與解析類(類似於上文的 SimpleDateFormat 類)
- 時間跨度類
時間類就是真正用來記錄如 2019-10-07 22:48:03
這類時間的類,格式化與解析類是把時間類型和字符串類型進行相互轉換的類,時間跨度類是記錄如 2年零3個月 這類間隔時間的類。接下來逐個類型講解。
Joda Time 的時間類
首先要注意:Joda Time 所設計的時間類,統統都不可改變(immutable),跟 String 是一樣的,一經實例化,不得改變其值,從源頭上實現了線程安全。當需要改變時間時,Joda Time 會返回一個全新的 Joda 實例,也跟 String 的設計是一樣的。org.joda.time
包下有五個常用的時間類,以表格形式列在下面:
類名 | 作用 | 示例(2019 年 10 月 1 日 12 時整) |
---|---|---|
DateTime | 日期+時間(含時區信息) | 2019-10-01T00:00:00.000+08:00 |
Instant | 日期+時間(格林威治時間,存疑) | 2019-10-01T12:00:00.000Z |
LocalDateTime | 日期+時間(不含時區信息) | 2019-10-01T12:00:00.000 |
LocalDate | 日期(不含時區信息) | 2019-10-01 |
LocalTime | 時間(不含時區信息) | 12:00:00.000 |
Instant 類是指時間軸上一個確定的時間點(精確到微妙),但是我自認爲用處實在是不多,還是其他四個類:DateTime 類、LocalDateTime 類、LocalDate 類、LocalTime 類使
用比較頻繁,如果需要時區信息則使用第一個,如果不需要時區信息,那就使用後面三個以“Local”開頭的類。以上五個時間類,使用方法可以用隨心所欲來形容,你想怎麼用就怎麼用。以 DateTime 類爲例,介紹 Joda Time 時間類的主要用法:
- 得到一個時間對象,有超級多的方法,以下只列舉幾種:
// 當前時間
DateTime dateTime1 = new DateTime();
// 任意一種時間類的實例,自動轉換
DateTime dateTime2 = new DateTime(dateTime1);
// 手動填寫年月日時間等信息,有9種填寫規則
DateTime dateTime3 = new DateTime(2020, 04, 2, 12, 0);
// 自1970年1月1日0日整之後的毫秒數
DateTime dateTime4 = new DateTime(1585825773101L);
// 使用靜態方法,讀取一個字符串轉換成時間
DateTime dateTime5 = DateTime.parse("2020-04-02 T12:00:00.000+08:00");
- 獲取時間信息,同樣有超級多的方法,以下只列舉幾種:
// 獲取當前月份
int monthOfYear = dateTime.getMonthOfYear();
// 獲取當天過了多少秒
int secondOfDay = dateTime.getSecondOfDay();
// 獲取自1970年1月1日0時之後過了多少微秒
long millis = dateTime.getMillis();
- 修改時間信息(會返回一個全新的 DateTime 實例),再次有超級多的方法,以下只列舉幾種:
// 天數 + 1(plus)
DateTime plusDateTime = dateTime.plusDays(1);
// 小時數 - 10(minus)
DateTime minusDateTime = dateTime.minusHours(2);
// 設置月份爲 8 月(with)
DateTime withDateTime = dateTime.withMonthOfYear(8);
- 其他操作
// 該時間是否比當下時間早
boolean beforeNow = dateTime.isBeforeNow();
// 對比另一個時間(隨意一個時間類的實例),判斷是否在其之後
boolean afterTime = dateTime.isAfter(dateTime2);
// 轉換成廢物的java.util.date類
Date date = dateTime.toDate();
你只要知道,Joda Time 幾乎無所不能,使用時隨心所欲,就可以了。
Joda Time 的格式化與解析類
Joda Time 的格式化與解析類,常用的有三個類,分別是 DateTimeFormatter 類、DateTimeFormat 類和 DateTimeFormatterBuilder 類。其實不使用這三個類,也可以實現時間解析與格式化處理,直接用字符串指定好樣式就可以了,使用這三個類是爲了簡便和統一操作。
DateTimeFormatter 類,時間解析與格式化處理類,用於日期和時間與字符串之間的轉換。當時間類 -> 字符串時,使用時間類的toString(DateTimeFormatter formatter)
方法。
DateTimeFormatter dateTimeFormatter = DateTimeFormat.fullDateTime();
String dateTimeStr = dateTime.toString(dateTimeFormatter);
// dateTimeStr: "2020年04月2日 星期四 下午01時00分00秒 CST"
當字符串 -> 時間類時,使用時間類的靜態方法parse(String str, DateTimeFormatter formatter)
。
DateTime dateTime = DateTime.parse("2020年04月2日 星期四 下午01時00分00秒 CST", dateTimeFormatter);
// dateTime.toString: "2020-04-02 T13:00:00.000-05:00"
DateTimeFormat 類,這是 DateTimeFormatter 類的工廠類,提供各種創建 DateTimeFormatter 類的實例方法。
工廠方法名 | 示例( 2019 年 10 月 1 日 13 時整) |
---|---|
fullDateTime() | 2019年10月1日 星期二 下午01時00分00秒 CST |
fullDate() | 2019年10月1日 星期二 |
fullTime() | 下午01時00分00秒 CST |
longDateTime() | 2019年10月1日 下午01時00分00秒 |
longDate() | 2019年10月1日 |
longTime() | 下午01時00分00秒 |
mediumDateTime() | 2019-10-1 13:00:00 |
mediumDate() | 2019-10-1 |
mediumTime() | 13:00:00 |
shortDateTime() | 19-10-1 下午01:00 |
shortDate() | 19-10-1 |
shortTime() | 下午01:00 |
forPattern(String pattern) | 自定義格式 |
forStyle(String style) | 按樣式,建議閱讀官方API |
patternForStyle(String style, Locale locale) | 根據地區告知樣式內容,返回一個樣式字符串如樣式是”MM”且地區爲中國時,返回:yyyy’年’M’月’d’日’ EEEE ahh’時’mm’分’ss’秒’ z |
DateTimeFormatterBuilder 類,這個類是用作生成複雜時間樣式的類,可以自由拼接時間,自由指定間隔樣式等等,例如“十月 01 日 星期二 下午”。這個類本身是可以改變的(非線程安全),但是它可以轉換成 DateTimeFormatter 類,此時就是不能改變的(線程安全)。本類的操作跟 StringBuilder 類幾乎是一致的,使用場景不多,用起來也比較順手,只貼出一段代碼示例。
DateTimeFormatterBuilder dateTimeFormatterBuilder = new DateTimeFormatterBuilder()
.appendEraText() // 紀元(由於是Text,不需要自己指定精度)
.appendLiteral(' ') // 分隔(此處用空格分隔)
.appendYear(4, 4) // 年(參數表示數字精度,最少4位,最多四位)
.appendLiteral(' ')
.appendMonthOfYear(2) // 月份
.appendLiteral(' ')
.appendDayOfMonth(2) // 日
.appendLiteral(' ')
.appendDayOfWeekText() // 周幾
.appendLiteral(" 該天已度過") // 分隔(此處用語句分隔)
.appendFractionOfDay(2, 2) // 當天已過去多少百分比
.appendLiteral("%");
DateTimeFormatter dateTimeFormatter = dateTimeFormatterBuilder.toFormatter();
// 打印示例:公元 2020 04 02 星期四 該天已度過54%
Joda Time 的時間跨度類
Joda Time 設計了三個類,用來表示時間跨度,分別是 Duration 類、Period 類和 Interval 類
。
- Duration 類保存了一個精確的毫秒數,比如你設置它爲一天,它會記錄下這是 86400 秒(如有毫秒會精確到小數點後三位)。
- Period 類保存了一段時間,例如 1 年 10 個月 1 小時 1 毫秒(它記錄成 P1Y10MT-1H-0.001S)
- Interval 類保存了一個開始時刻和一個結束時刻,因而也能夠表示一段時間。
java.time 包中的時間類
當我們迎來 JDK 8 時,我們再也不需要 Joda Time 之類的第三方類庫了,因爲官方給我們提供了全新的時間類,這些類都屬於 java.time
包下。當一個個類接觸下去之後,你會發現 JDK 8 所提供的 java.time
包中的時間類,和 Joda Time 是何其相似,相似到你覺得簡直像是 Joda Time 備胎轉正,我猜想這跟 Joda Time 的作者參與到 java.time
包的開發中有關。最主要的的區別只有一處,那就是:JDK 8 的 java.time
包中的時間類,不再具有 public
的構造方法,而只有類靜態方法。也就是說,通過類構造方法實例化對象,是錯誤的,需要使用如下方法實例化:
// 靜態方法 now() 當前時間
LocalDate localDate = LocalDate.now();
// 靜態方法 of() 構造時間
LocalDate localDate = LocalDate.of(2019, 10, 1);
java.time 包中各類使用示例
- Java 8中獲取今天的日期,Java 8 中的 LocalDate 用於表示當天日期。和
java.util.Date
不同,它只有日期,不包含時間。當你僅需要表示日期時就用這個類。
public static void main(String[] args) {
LocalDate today = LocalDate.now();
System.out.println("今天的日期:"+today);
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);
}
- Java 8中處理特定日期,我們通過靜態工廠方法
now()
非常容易地創建了當天日期,你還可以調用另一個有用的工廠方法LocalDate.of()
創建任意日期, 該方法需要傳入年、月、日做參數,返回對應的LocalDate實例。這個方法的好處是沒再犯老API的設計錯誤,比如年度起始於1900,月份是從0開 始等等。
public static void main(String[] args) {
LocalDate date = LocalDate.of(2018,2,6);
System.out.println("自定義日期:"+date);
}
- Java 8中判斷兩個日期是否相等
public static void main(String[] args) {
LocalDate date1 = LocalDate.now();
LocalDate date2 = LocalDate.of(2018,2,5);
if(date1.equals(date2)){
System.out.println("時間相等");
}else{
System.out.println("時間不等");
}
}
- Java 8中檢查像生日這種週期性事件,只要當天的日期和生日匹配,無論是哪一年都會打印出祝賀信息。你可以把程序整合進系統時鐘,看看生日時是否會受到提醒,或者寫一個單元測試來檢測代碼是否運行正確。
//import java.time.LocalDate;
//import java.time.MonthDay;
public static void main(String[] args) {
LocalDate date1 = LocalDate.now();
LocalDate date2 = LocalDate.of(2020,4,2);
MonthDay birthday = MonthDay.of(date2.getMonth(),date2.getDayOfMonth());
MonthDay currentMonthDay = MonthDay.from(date1);
if(currentMonthDay.equals(birthday)){
System.out.println("是你的生日");
}else{
System.out.println("你的生日還沒有到");
}
}
- Java 8中獲取當前時間,通過增加小時、分、秒來計算將來的時間很常見。Java 8除了不變類型和線程安全的好處之外,還提供了更好的
plusHours()
方法替換add()
,並且是兼容的。注意,這些方法返回一個全新的LocalTime實例,由於其不可變性,返回後一定要用變量賦值。
public static void main(String[] args) {
LocalTime time = LocalTime.now();
LocalTime newTime = time.plusHours(3);
System.out.println("三個小時後的時間爲:"+newTime);
}
- Java 8如何計算一週後的日期,和上個例子計算3小時以後的時間類似,這個例子會計算一週後的日期。LocalDate日期不包含時間信息,它的
plus()
方法用來增加天、周、月,ChronoUnit類聲明瞭這些時間單位。由於LocalDate也是不變類型,返回後一定要用變量賦值。可以看到新日期離當天日期是7天,也就是一週。你可以用同樣的方法增加1個月、1年、1小時、1分鐘甚至一個世紀,更多選項可以查看Java 8 API中的ChronoUnit類。
public static void main(String[] args) {
LocalDate today = LocalDate.now();
System.out.println("今天的日期爲:"+today);
LocalDate nextWeek = today.plus(1, ChronoUnit.WEEKS);
System.out.println("一週後的日期爲:"+nextWeek);
}
- Java 8計算一年前或一年後的日期,利用
minus()
方法計算一年前的日期
public static void main(String[] args) {
LocalDate today = LocalDate.now();
LocalDate previousYear = today.minus(1, ChronoUnit.YEARS);
System.out.println("一年前的日期 : " + previousYear);
LocalDate nextYear = today.plus(1, ChronoUnit.YEARS);
System.out.println("一年後的日期:"+nextYear);
}
- Java 8的Clock時鐘類,Java 8增加了一個Clock時鐘類用於獲取當時的時間戳,或當前時區下的日期時間信息。以前用到
System.currentTimeInMillis()
和TimeZone.getDefault()
的地方都可用Clock替換。
public static void main(String[] args) {
Clock clock = Clock.systemUTC();
System.out.println("Clock : " + clock.millis());
Clock defaultClock = Clock.systemDefaultZone();
System.out.println("Clock : " + defaultClock.millis());
}
- 如何用Java判斷日期是早於還是晚於另一個日期,另一個工作中常見的操作就是如何判斷給定的一個日期是大於某天還是小於某天?在Java 8中,LocalDate類有兩類方法
isBefore()
和isAfter()用
於比較日期。調用isBefore()
方法時,如果給定日期小於當前日期則返回true。
//import java.time.LocalDate;
//import java.time.temporal.ChronoUnit;
public static void main(String[] args) {
LocalDate today = LocalDate.now();
LocalDate tomorrow = LocalDate.of(2018,2,6);
if(tomorrow.isAfter(today)){
System.out.println("之後的日期:"+tomorrow);
}
LocalDate yesterday = today.minus(1, ChronoUnit.DAYS);
if(yesterday.isBefore(today)){
System.out.println("之前的日期:"+yesterday);
}
}
- 如何表示信用卡到期這類固定日期,答案就在YearMonth,與 MonthDay檢查重複事件的例子相似,YearMonth是另一個組合類,用於表示信用卡到期日、FD到期日、期貨期權到期日等。還可以用這個類得到 當月共有多少天,YearMonth實例的
lengthOfMonth()
方法可以返回當月的天數,在判斷2月有28天還是29天時非常有用。
public static void main(String[] args) {
YearMonth currentYearMonth = YearMonth.now();
System.out.printf("Days in month year %s: %d%n", currentYearMonth, currentYearMonth.lengthOfMonth());
YearMonth creditCardExpiry = YearMonth.of(2021, Month.FEBRUARY);
System.out.printf("Your credit card expires on %s %n", creditCardExpiry);
}
- 如何在Java 8中檢查閏年
public static void main(String[] args) {
LocalDate today = LocalDate.now();
if(today.isLeapYear()){
System.out.println("This year is Leap year");
}else {
System.out.println("2018 is not a Leap year");
}
}
- 計算兩個日期之間的天數和月數,有一個常見日期操作是計算兩個日期之間的天數、週數或月數。在Java 8中可以用
java.time.Period
類來做計算。下面這個例子中,我們計算了當天和將來某一天之間的月數。
//import java.time.LocalDate;
//import java.time.Period;
public static void main(String[] args) {
LocalDate today = LocalDate.now();
LocalDate java8Release = LocalDate.of(2018, 12, 14);
Period periodToNextJavaRelease = Period.between(today, java8Release);
System.out.println("Months left between today and Java 8 release : "
+ periodToNextJavaRelease.getMonths() );
}
- 在Java 8中獲取當前的時間戳,Instant類有一個靜態工廠方法now()會返回當前的時間戳。時間戳信息裏同時包含了日期和時間,這和
java.util.Date
很像。實際上Instant類確實等同於 Java 8之前的Date類,你可以使用Date類和Instant類各自的轉換方法互相轉換,例如:Date.from(Instant)
將Instant轉換成java.util.Date
,Date.toInstant()
則是將Date類轉換成Instant類。
public static void main(String[] args) {
Instant timestamp = Instant.now();
System.out.println("What is value of this instant " + timestamp.toEpochMilli());
}
- Java 8中如何使用預定義的格式化工具去解析或格式化日期
public static void main(String[] args) {
String dayAfterTommorrow = "20180205";
LocalDate formatted = LocalDate.parse(dayAfterTommorrow,
DateTimeFormatter.BASIC_ISO_DATE);
System.out.println(dayAfterTommorrow+" 格式化後的日期爲: "+formatted);
}
- 字符串互轉日期類型
public static void main(String[] args) {
LocalDateTime date = LocalDateTime.now();
DateTimeFormatter format1 = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
String str = date.format(format1);
System.out.println("日期轉換爲字符串:"+str);
DateTimeFormatter format2 = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
LocalDate date2 = LocalDate.parse(str,format2);
System.out.println("日期類型:"+date2);
}