Java 8 的日期時間工具

Victor.濤發表於2021-01-03

之前有談過Java的兩套時間工具,分別是Date日期型別和Calendar日曆型別,但仍在開發中存在問題:

  • 日曆工具獲得當月份的時候,與Date一樣都是從0開始計數,比如通過get方法獲得一月份數值為0;
  • 日曆工具獲得當天是星期幾的時候,星期日是排在最前面的,通過get方法獲得的星期日數值為1,而星期一數值居然為2;
  • 日曆工具能夠表達的最小世界單位是毫秒,精度不高;
  • 日曆工具沒有提供閏年判斷方法;
  • 日曆工具缺乏自己的格式,還得藉助Date型別的格式化工具SimpleDateFormat,才能將日期時間按照指定格式輸出為字串。

為解決以上問題,Java 8 提供了全新的本地日期時間型別,它的成員主要有LocalDate、LocalTime、LocalDateTime等。

1. LocalDate 和 LocalTime

1.1 本地日期型別LocalDate

import java.time.LocalDate;

獲得本地日期例項很簡單,就直接呼叫該型別的now方法,顧名思議就是獲得當前日期,很符合我們常理,且還額外提供了幾個常用的統計方法。

注意:

  • getMonth() 返回的是英文月份,而 getMonthValue() 返回的是數字月份!

import java.time.Month;

  • getDayOfWeek() 返回的是英文星期,而後面加了getValue() 才返回數字星期幾!

import java.time.DayOfWeek;

【程式碼】

	// LocalDate的各種方法
		LocalDate date = LocalDate.now();// 獲得本地日期的例項
		System.out.println("date:" + date.toString());
		int year = date.getYear(); // 獲得該日期所在的年份
		System.out.println("year:" + year);
		
		//注意區分getMonth()返回的是英文月份,而getMonthValue()返回的是數字月份!
		int month1 = date.getMonthValue();
		Month month2 = date.getMonth();
		System.out.println("month:" + month1 + '\t' + month2);
		int dayOfYear = date.getDayOfYear();
		System.out.println("day:" + dayOfYear);
		
		//注意區分getDayOfWeek()返回的是英文星期,而後面加了getValue()才返回數字星期幾!
		int dayOfWeek1 = date.getDayOfWeek().getValue();
		DayOfWeek dayOfWeek2 = date.getDayOfWeek();
		System.out.println("week:" + dayOfWeek1 + '\t' + dayOfWeek2);
		int lengthOfYear = date.lengthOfYear();
		System.out.println("lengthOfYear:" + lengthOfYear);
		int lengthOfMonth = date.lengthOfMonth();
		System.out.println("lengthOfMonth:" + lengthOfMonth);
		boolean isLeapYear = date.isLeapYear();// 判斷該日期所在的年份是否為閏年
		System.out.println("isLeapYear:" + isLeapYear);

private static void showLocalDate() {
		LocalDate date = LocalDate.now(); // 獲得本地日期的例項
		System.out.println("date=" + date.toString());
		int year = date.getYear(); // 獲得該日期所在的年份
		System.out.println("year=" + year);
		// 獲得該日期所在的月份。注意getMonthValue返回的是數字月份,getMonth返回的是英文月份
		int month = date.getMonthValue();
		System.out.println("month=" + month + ", english month=" + date.getMonth());
		int dayOfMonth = date.getDayOfMonth(); // 獲得該日期所在的日子
		System.out.println("dayOfMonth=" + dayOfMonth);
		int dayOfYear = date.getDayOfYear(); // 獲得該日期在一年當中的序號
		System.out.println("dayOfYear=" + dayOfYear);
		// 獲得該日期是星期幾。注意getDayOfWeek返回的是英文,後面的getValue才返回數字星期幾
		int dayOfWeek = date.getDayOfWeek().getValue();
		System.out.println("dayOfWeek=" + dayOfWeek + ", english weekday=" + date.getDayOfWeek());
		int lengthOfYear = date.lengthOfYear(); // 獲得該日期所在的年份一共有多少天
		System.out.println("lengthOfYear=" + lengthOfYear);
		int lengthOfMonth = date.lengthOfMonth(); // 獲得該日期所在的月份一共有多少天
		System.out.println("lengthOfMonth=" + lengthOfMonth);
		boolean isLeapYear = date.isLeapYear(); // 判斷該日期所在的年份是否為閏年
		System.out.println("isLeapYear=" + isLeapYear);
		

你們是否曾想過上面的LocalDate是訪問當前本地例項,那是否支援訪問自己指定日期的本地例項呢?答案肯定是支援的!使用…of()。
【cope】

		LocalDate dateManual = LocalDate.of(2019,12,17); // 構建一個指定日期例項
		System.out.println("dateManual=" + dateManual.toString());

那我想只改變日期的單位數值,而不至於大幅度改動,那怎麼辦呢?
LocalDate特此提供了專門的增減改方法。

  • plus開頭方法:用於增加日期數值;
  • minus開頭方法:用來減少日期數值;
  • with開頭方法:用來設定日期數值。
		dateManual = dateManual.plusYears(0); // 增加若干年份
		dateManual = dateManual.plusMonths(0); // 增加若干月份
		dateManual = dateManual.plusDays(0); // 增加若干日子
		dateManual = dateManual.plusWeeks(0); // 增加若干星期
		dateManual = dateManual.minusYears(0); // 減少若干年份
		dateManual = dateManual.minusMonths(0); // 減少若干月份
		dateManual = dateManual.minusDays(0); // 減少若干日子
		dateManual = dateManual.minusWeeks(0); // 減少若干星期
		dateManual = dateManual.withYear(2000); // 設定指定的年份
		dateManual = dateManual.withMonth(12); // 設定指定的月份
		dateManual = dateManual.withDayOfYear(1); // 設定當年的日子
		dateManual = dateManual.withDayOfMonth(1); // 設定當月的日子

此外,作為一種日期型別,LocalDate一如既往地支援判斷兩個日期例項的早晚關係 equals、isBefore、isAfter等方法:

		boolean equalsDate = date.equals(dateManual); // 判斷兩個日期是否相等
		System.out.println("equalsDate=" + equalsDate);
		boolean isBeforeDate = date.isBefore(dateManual); // 判斷A日期是否在B日期之前
		System.out.println("isBeforeDate=" + isBeforeDate);
		boolean isAfterDate = date.isAfter(dateManual); // 判斷A日期是否在B日期之後
		System.out.println("isAfterDate=" + isAfterDate);
		boolean isEqualDate = date.isEqual(dateManual); // 判斷A日期是否與B日期相等
		System.out.println("isEqualDate=" + isEqualDate);

1.2 本地時間型別LocalTime

前面介紹的LocateDate只能操作年月日,而不能操作時分秒,屆時需通過LocalTime來操作,依然要呼叫該型別的now方法。

【程式碼】

		LocalTime time = LocalTime.now(); // 獲得本地時間的例項
		System.out.println("time=" + time.toString());
		int hour = time.getHour(); // 獲得該時間所在的時鐘
		System.out.println("hour=" + hour);
		int minute = time.getMinute(); // 獲得該時間所在的分鐘
		System.out.println("minute=" + minute);
		int second = time.getSecond(); // 獲得該時間所在的秒鐘
		System.out.println("second=" + second);
		// 一秒等於一千毫秒,一毫秒等於一千微秒,一微秒等於一千納秒,算下來一秒等於十億納秒
		int nano = time.getNano(); // 獲得該時間秒鐘後面的納秒單位
		System.out.println("nano=" + nano);

還支援自己建立例項time;

		LocalTime timeManual = LocalTime.of(14, 30, 25); // 構造一個指定時分秒的時間例項
		System.out.println("timeManual=" + timeManual.toString());

也支援LocalDate的增減改方法:

		timeManual = timeManual.plusHours(0); // 增加若干時鐘
		timeManual = timeManual.plusMinutes(0); // 增加若干分鐘
		timeManual = timeManual.plusSeconds(0); // 增加若干秒鐘
		timeManual = timeManual.plusNanos(0); // 增加若干納秒
		timeManual = timeManual.minusHours(0); // 減少若干時鐘
		timeManual = timeManual.minusMinutes(0); // 減少若干分鐘
		timeManual = timeManual.minusSeconds(0); // 減少若干秒鐘
		timeManual = timeManual.minusNanos(0); // 減少若干納秒
		timeManual = timeManual.withHour(0); // 設定指定的時鐘
		timeManual = timeManual.withMinute(0); // 設定指定的分鐘
		timeManual = timeManual.withSecond(0); // 設定指定的秒鐘
		timeManual = timeManual.withNano(0); // 設定指定的納秒

也會提供比較兩個時間的關係。

		boolean equalsTime = time.equals(timeManual); // 判斷兩個時間是否相等
		System.out.println("equalsTime=" + equalsTime);
		boolean isBeforeTime = time.isBefore(timeManual); // 判斷A時間是否在B時間之前
		System.out.println("isBeforeTime=" + isBeforeTime);
		boolean isAfterTime = time.isAfter(timeManual); // 判斷A時間是否在B時間之後
		System.out.println("isAfterTime=" + isAfterTime);

【小結】以上所用到的方法都是LocalDate所有的。

1.3 本地日期型別LocalDateTime

現在有LocalDate專門處理年月日,又有LocalTime專門處理時分秒,那有這部分提供他們倆的合集,即LocalDateTime,它同時擁有二者絕大部分方法,直接見程式碼:

而需注意的是LocalTime不提供lengthOfYear、lengthOfMonth、isLeapYear這三個方法。

		// 獲得本地日期時間的例項
		LocalDateTime datetime = LocalDateTime.now();
		System.out.println("datetime=" + datetime.toString());
		// LocalDateTime的方法是LocalDate與LocalTime的合集,
		// 也就是說LocalDate與LocalTime的大部分方法可以直接拿來給LocalDateTime使用,
		// 因而下面不再演示LocalDateTime的詳細方法如何呼叫了。
		// 注意LocalDateTime不提供lengthOfYear、lengthOfMonth、isLeapYear這三個方法。

2. 本地日期時間與字串的互相轉換

之前介紹了Date型別通過格式化工具SimpleDateFormat獲得字串,Java8也有專門本地日期時間的格式化工具DateTimeFormatter ,並定義幾種常見的日期時間格式。

 import java.time.format.DateTimeFormatter;
DateTimeFormatter類的格式型別對應的日期時間格式
BASIC_ISO_DATEyyyyMMdd
ISO_LOCAL_DATEyyyy-MM-dd
ISO_LOCAL_TIMEHH:mm:ss
ISO_LOCAL_DATE_TIMEyyyy-MM-ddTHH:mm:ss

現在只要呼叫本地日期時間的parse方法,即可將字串形式轉換為日期時間,無須像Calendar那樣還得藉助Date。

【程式碼】

		String strDateSimple = "20190729";
		// 把日期字串轉換為LocalDate例項。BASIC_ISO_DATE定義的日期格式為yyyyMMdd
		LocalDate dateSimple = LocalDate.parse(strDateSimple, DateTimeFormatter.BASIC_ISO_DATE);
		System.out.println("dateSimple=" + dateSimple.toString());
		String strDateWithLine = "2019-07-29";
		// 把日期字串轉換為LocalDate例項。ISO_LOCAL_DATE定義的日期格式為yyyy-MM-dd
		LocalDate dateWithLine = LocalDate.parse(strDateWithLine, DateTimeFormatter.ISO_LOCAL_DATE);
		System.out.println("dateWithLine=" + dateWithLine.toString());
		String strTimeWithColon = "12:44:50";
		// 把時間字串轉換為LocalTime例項。ISO_LOCAL_TIME定義的時間格式為HH:mm:ss
		LocalTime timeWithColon = LocalTime.parse(strTimeWithColon, DateTimeFormatter.ISO_LOCAL_TIME);
		System.out.println("timeWithColon=" + timeWithColon.toString());
		String strDateTimeISO = "2019-11-23T14:46:30";
		// 把日期時間字串轉換為LocalDateTime例項。ISO_LOCAL_DATE_TIME定義的日期時間格式為yyyy-MM-ddTHH:mm:ss
		LocalDateTime datetimeISO = LocalDateTime.parse(strDateTimeISO, DateTimeFormatter.ISO_LOCAL_DATE_TIME);
		System.out.println("datetimeISO=" + datetimeISO.toString());

除了系統自帶的幾種日期時間格式外,我們可以自己定義其他格式,此時需要呼叫DateTimeFormatter的ofPattern方法完成格式化定義,使用ofPattern方法得到某個格式化例項,就能直接代入本地日期時間的parse方法中。

【程式碼】

		String strDateWithSway = "2019/07/29";
		// 自己定義了一個形如“yyyy/MM/dd”的日期格式
		DateTimeFormatter dateFormatWithSway = DateTimeFormatter.ofPattern("yyyy/MM/dd");
		// 把日期字串按照格式“yyyy/MM/dd”轉換為LocalDate例項
		LocalDate dateWithSway = LocalDate.parse(strDateWithSway, dateFormatWithSway);
		System.out.println("dateWithSway=" + dateWithSway.toString());
		String strTimeSimple = "125809";
		// 自己定義了一個形如“HHmmss”的時間格式
		DateTimeFormatter timeFormatSimple = DateTimeFormatter.ofPattern("HHmmss");
		// 把時間字串按照格式“HHmmss”轉換為LocalTime例項
		LocalTime timeSimple = LocalTime.parse(strTimeSimple, timeFormatSimple);
		System.out.println("timeSimple=" + timeSimple.toString());
		String strWithCn = "2019年07月29日12時58分09秒";
		// 自己定義了一個形如“yyyy年MM月dd日HH時mm分ss秒”的日期時間格式
		DateTimeFormatter formatCn = DateTimeFormatter.ofPattern("yyyy年MM月dd日HH時mm分ss秒");
		// 把日期時間字串按照格式“yyyy年MM月dd日HH時mm分ss秒”轉換為LocalDateTime例項
		LocalDateTime datetimeWithCn = LocalDateTime.parse(strWithCn, formatCn);
		System.out.println("datetimeWithCn=" + datetimeWithCn.toString());

既然字串能通過parse方法轉化成為本地日期時間,反過來可以採用format方法將本地日期時間轉化成為字串型別。

【程式碼】

		LocalDate date = LocalDate.now(); // 獲得當前日期的例項
		// 把LocalDate例項轉換為日期字串。BASIC_ISO_DATE定義的日期格式為yyyyMMdd
		String strDateSimple = date.format(DateTimeFormatter.BASIC_ISO_DATE);
		System.out.println("strDateSimple=" + strDateSimple);
		// 把LocalDate例項轉換為日期字串。ISO_LOCAL_DATE定義的日期格式為yyyy-MM-dd
		String strDateWithLine = date.format(DateTimeFormatter.ISO_LOCAL_DATE);
		System.out.println("strDateWithLine=" + strDateWithLine);
		// 自己定義了一個形如“yyyy/MM/dd”的日期格式
		DateTimeFormatter dateFormatWithSway = DateTimeFormatter.ofPattern("yyyy/MM/dd");
		// 把LocalDate例項按照格式“yyyy/MM/dd”轉換為日期字串
		String strDateWithSway = date.format(dateFormatWithSway);
		System.out.println("strDateWithSway=" + strDateWithSway);
		LocalTime time = LocalTime.now(); // 獲得當前時間的例項
		// 把LocalTime例項轉換為時間字串。ISO_LOCAL_TIME定義的時間格式為HH:mm:ss
		String strTimeWithColon = time.format(DateTimeFormatter.ISO_LOCAL_TIME);
		System.out.println("strTimeWithColon=" + strTimeWithColon);
		// 自己定義了一個形如“HHmmss”的時間格式
		DateTimeFormatter timeFormatSimple = DateTimeFormatter.ofPattern("HHmmss");
		// 把LocalTime例項按照格式“HHmmss”轉換為時間字串
		String strTimeSimple = time.format(timeFormatSimple);
		System.out.println("strTimeSimple=" + strTimeSimple);
		LocalDateTime datetime = LocalDateTime.now(); // 獲得當前日期時間的例項
		// 自己定義了一個形如“yyyy年MM月dd日HH時mm分ss秒”的日期時間格式
		DateTimeFormatter formatCn = DateTimeFormatter.ofPattern("yyyy年MM月dd日HH時mm分ss秒");
		// 把LocalDateTime例項按照格式“yyyy年MM月dd日HH時mm分ss秒”轉換為日期時間字串
		String strWithCn = datetime.format(formatCn);
		System.out.println("strWithCn=" + strWithCn);

相關文章