1. 程式人生 > >夯實Java基礎(十四)——Java8新的日期處理類

夯實Java基礎(十四)——Java8新的日期處理類

1、前言

Java8之前處理日期一直是Java程式設計師比較頭疼的問題,從Java 8之後,Java裡面添加了許多的新特性,其中一個最常見也是最實用的便是日期處理的類——LocalDate。LocalDate是一種更為高效的日期類,比起Date的複雜具有相當高的簡潔性,吸取了企業級別的joda.time時間處理的優點,避免了傳統的Date和Calendar複合起來計算的難處。

新增的日期常用的用這三個:

  • java.time.LocalDate:只對年月日做出處理
  • java.time.LocalTime:只對時分秒納秒做出處理
  • java.time.LocalDateTime :同時可以處理年月日和時分秒

2、LocalDate、LocalTime、LocalDateTime

LocalDate:代表IOS格式(yyyy-MM-hh)的日期,不包含具體時間的日期,比如2014-01-14。它可以用來儲存生日,週年紀念日,入職日期等。

LocalTime:它代表的是不含日期的時間;

LocalDateTime:它包含了日期及時間,不過還是沒有偏移資訊或者說時區,比較常用;

它們三者共同特點:

  • 相比於前面的Date和Calendar,他們是執行緒安全的;
  • 它們是不可變的日期時間物件;

常用方法:

  • now() 、 now(Zoneld zone):靜態方法,根據當前時間建立物件 、 指定時區的物件
  • of() :靜態方法,根據指定日期,時間建立物件
  • getDayOfMonth():獲得月份天數(1-31) 
  • getDayOfYear():獲取年份天數(1-366)
  • getDayOfWeek():獲得星期幾
  • getYear():獲得年份
  • getMonth() 、 getMonthValue(): 獲得月份(返回列舉值如:January) 、 返回數字(1-12)
  • getHour()、getMinute()、getSecond():獲得當前物件的時、分、秒
  • withDayOfMonth()、withDayOfYear()、withMonth()、withYear():將月份天數、年份天數、月份、年份修改為指定的值並且返回新的物件,因為LocalDate等是不變性的
  • plusDays()、plusWeeks()、plusMonths()、plusYears()、plusHours():向當前物件新增幾天、幾周、幾個月、幾年,幾小時
  • minusDays()、minusWeeks()、minusMonths()、minusYears()、minusHours():從當前物件減去幾月、幾周、幾個月、幾年、幾小時
  • isLeapYear():判斷是否為閏年
  • isBefore、isEqual、isAfter:檢查日期是否在指定日期前面,相等,後面

由於LocalDate的API與LocalTime、LocalDateTime大都是通用的,所有後面兩個的就不展示了。

方法使用舉例:

 1 //now():獲取當前日期
 2 LocalDate localDate=LocalDate.now();
 3 LocalTime localTime=LocalTime.now();
 4 LocalTime localTime1= LocalTime.now().withNano(0); // 這個是不帶毫秒的
 5 LocalDateTime localDateTime=LocalDateTime.now();
 6 System.out.println("日期:"+localDate);
 7 System.out.println("時間:"+localTime);
 8 System.out.println("時間不帶毫秒:"+localTime1);
 9 System.out.println("日期時間:"+localDateTime);
10  
11 //of():設定指定的年月日時分秒,沒有偏移量
12 System.out.println("-----------");
13 LocalDateTime localDateTime2=LocalDateTime.of(2020, 04, 04, 18, 48, 56);
14 System.out.println("設定的時間為:"+localDateTime2);
15  
16 //getXXX:獲取相關的屬性
17 System.out.println("-----------");
18 System.out.println("這年的第幾天:"+localDateTime.getDayOfYear());
19 System.out.println("這月的第幾天:"+localDateTime.getDayOfMonth());
20 System.out.println("這月的第幾天:"+localDateTime.getDayOfWeek());
21 System.out.println("月份為:"+localDateTime.getMonth());
22 System.out.println("月份為:"+localDateTime.getMonthValue());
23 System.out.println("小時為:"+localDateTime.getHour());
24  
25 //withXXX:設定相關的屬性,體現了不可變性,修改後返回了新的物件
26 LocalDateTime localDateTime3=localDateTime.withDayOfMonth(22);
27 System.out.println("當前的時間:"+localDateTime);
28 System.out.println("修改月份後:"+localDateTime3);
29  
30 LocalDateTime localDateTime4=localDateTime.withHour(14);
31 System.out.println("當前的時間:"+localDateTime);
32 System.out.println("修改小時後:"+localDateTime4);
33  
34 //plusXXX:增加相關屬性
35 LocalDateTime localDateTime5=localDateTime.plusDays(10);
36 System.out.println("當前時間:"+localDateTime);
37 System.out.println("相加之後:"+localDateTime5);
38  
39 //minusXXX:減少相關屬性
40 LocalDateTime localDateTime6=localDateTime.minusDays(10);
41 System.out.println("當前時間:"+localDateTime);
42 System.out.println("相減之後:"+localDateTime6);

LocalDate ,LocalTime ,LocalDateTime 它們之間的互相轉換: 

 1 /**
 2  * LocalDate ,LocalTime,LocalDateTime 互相轉換
 3  */
 4 @Test
 5 public void test5(){
 6     String date = "2020-7-12";
 7     String time = "15:51:30";
 8     LocalDate localDate = LocalDate.parse(date);
 9     LocalTime localTime = LocalTime.parse(time);
10  
11     LocalDateTime localDateTime = LocalDateTime.of(2020, 7, 13, 16, 01, 30, 888);
12     LocalDateTime localDateTime1 = LocalDateTime.of(localDate, localTime);
13  
14     //localDateTime-->LocalDate,LocalTime
15     LocalDate localDate1 = localDateTime.toLocalDate();
16     LocalTime localTime1 = localDateTime.toLocalTime();
17  
18     // LocalDate,LocalTime --> LocalDateTime
19     LocalDateTime localDateTime2 = localDate.atTime(16, 02, 30);
20     LocalDateTime localDateTime3 = localTime.atDate(localDate);
21  
22 }

3、瞬時(Instant)

Instant類:時間線上的一個瞬時點,設計初衷是為了便於機器使用,不提供人類意義上的時間單位,獲取當前時刻的時間戳;它只是簡單的從1970年1月1日0時0分0秒(UTC)開始的秒數。

常用方法:

  • now():靜態方法,返回預設的UTC時區的Instant類的物件
  • atOffset(ZoneOffset offset):將此瞬間與偏移組合起來建立一個OffsetDateTime
  • toEpochMilli():返回1970-01-01 00:00:00到當前的毫秒數,即時間戳
  • ofEpochMilli(long epochMilli):靜態方法,返回在1970-01-01 00:00:00基礎加上指定毫秒數之後的Instant類的物件
  • ofEpochSecond(long epochSecond):靜態方法,返回在1970-01-01 00:00:00基礎加上指定秒數之後的Instant類的物件

方法使用舉例:

 1 @Test
 2 public void testInstant() {
 3     //now():獲取標準時間,即本初子午線的時間,沒有偏移量
 4     Instant instant = Instant.now();
 5     System.out.println(instant);
 6         
 7     //atOffset:新增偏移量,北京在東八區,時區加八即為北京時間
 8     OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.ofHours(8));
 9     System.out.println(offsetDateTime);
10        
11     //toEpochMilli:獲取1970-01-01 00:00:00 開始的毫秒;類似Date的getTime
12     long epochMilli = instant.toEpochMilli();
13     System.out.println(epochMilli);
14         
15     //ofEpochMilli:通過給定的毫秒數,獲取Instant例項;類似Date(long millis)
16     Instant ofEpochMilli = Instant.ofEpochMilli(1562384592201L);
17     System.out.println(ofEpochMilli);
18 }

4、日期間隔,持續時間 (Period 和 Duration)

Java 8 中還引入的兩個與日期相關的新類:Period 和 Duration。兩個類分別表示時間量或兩個日期之間的差,兩者之間的差異為:Period基於日期值,而Duration基於時間值。

例項:

 1     @Test
 2     public void testDurationAndPeriod(){
 3         //Duration
 4         LocalDate date1 = LocalDate.of(2020, 7, 6);
 5         LocalDate date2 = LocalDate.of(2025, 9, 10);
 6         LocalTime time1 = LocalTime.of(15, 7, 50);
 7         LocalTime time2 = LocalTime.of(17, 8, 53);
 8         LocalDateTime dateTime1 = LocalDateTime.of(2020, 5, 12, 14, 22, 28);
 9         LocalDateTime dateTime2 = LocalDateTime.of(2024, 5, 12, 14, 22, 28);
10         Instant instant1 = Instant.ofEpochSecond(1);
11         Instant instant2 = Instant.now();
12         Duration d1 = Duration.between(time1, time2);
13         Duration d2 = Duration.between(dateTime1, dateTime2);
14         Duration d3 = Duration.between(instant1, instant2);
15         // 這裡會拋異常java.time.temporal.UnsupportedTemporalTypeException: Unsupported unit: Seconds
16         //需要使用Period類進行操作日期
17         //Duration d4 = Duration.between(date1, date2);
18         System.out.println("LocalTime持續秒數:" + d1.getSeconds());
19         System.out.println("LocalDateTime持續秒數:" + d2.getSeconds());
20         System.out.println("Instant持續秒數" + d3.getSeconds());
21         
22         //Period
23         Period period=Period.between(date1, date2);
24         System.out.println(period.getYears());
25         System.out.println(period.getMonths());
26         System.out.println(period.getDays());
27         System.out.println(period.toTotalMonths());
28     }

5、日期校正器TemporalAdjusters

到現在你所看到的所有日期操作都是相對比較直接的。有的時候,你需要進行一些更加 複雜的操作,比如,將日期調整到下個週日、下個工作日,或者是本月的最後一天。這時,你可以使用過載版本的with方法,向其傳遞一個提供了更多定製化選擇的TemporalAdjusters物件, 更加靈活地處理日期。對於最常見的用例,日期和時間API已經提供了大量預定義的 TemporalAdjusters。你可以通過TemporalAdjusters類的靜態工廠方法訪問它們,如下所示:

下面是TemporalAdjusters類中的方法:

  • dayOfWeekInMonth(int ordinal,DayOfWeek dayOfWeek):返回一個新的日期,它的值為同一個月中每一週的第幾天
  • firstDayOfMonth():返回一個新的日期,它的值為當月的第一天
  • firstDayOfNextMonth():返回一個新的日期,它的值為下月的第一天
  • firstDayOfNextYear():返回一個新的日期,它的值為明年的第一天
  • firstDayOfYear():返回一個新的日期,它的值為當年的第一天
  • firstInMonth(DayOfWeek dayOfWeek):返回一個新的日期,它的值為同一個月中,第一個符合星期幾要求的值
  • lastDayOfMonth():返回一個新的日期,它的值為當月的最後一天
  • lastDayOfNextMonth():返回一個新的日期,它的值為下月的最後一天
  • lastDayOfNextYear():返回一個新的日期,它的值為明年的最後一天
  • lastDayOfYear():返回一個新的日期,它的值為今年的最後一天
  • lastInMonth(DayOfWeek dayOfWeek):返回一個新的日期,它的值為同一個月中,最後一個符合星期幾要求的值
  • next(DayOfWeek dayOfWeek)、previous(DayOfWeek dayOfWeek):返回一個新的日期,並將其值設定為日期調整後或者調整前,第一個符合指定星期幾要求的日期
  • nextOrSame(DayOfWeek dayOfWeek)、previousOrSame(DayOfWeek dayOfWeek):返回一個新的日期,並將其值設定為日期調整後或者調整前,第一個符合指定星期幾要求的日期,如果該日期已經符合要求,直接返回該物件

方法使用舉例:

 1 @Test
 2 public void testTemporalAdjusters(){
 3     //dayOfWeekInMonth:返回這個月第二週星期二的日期
 4     LocalDate localDate1=LocalDate.of(2020,9,15);
 5     LocalDate localDate2 = localDate1.with(TemporalAdjusters.dayOfWeekInMonth(2, DayOfWeek.TUESDAY));
 6     System.out.println("預設時間:"+localDate1);
 7     System.out.println("更改時間:"+localDate2);
 8     
 9     //firstDayOfMonth():這個月第一天
10     System.out.println("---------");
11     LocalDate localDate3=localDate1.with(TemporalAdjusters.firstDayOfMonth());
12     System.out.println("預設時間:"+localDate1);
13     System.out.println("更改時間:"+localDate3);
14     
15     //lastDayOfMonth():這個月最後一天
16     System.out.println("---------");
17     LocalDate localDate4=localDate1.with(TemporalAdjusters.lastDayOfMonth());
18     System.out.println("預設時間:"+localDate1);
19     System.out.println("更改時間:"+localDate4);
20     
21     //nextOrSame():獲取周2時間,如果當前時間剛好是星期2,那麼就返回當前時間
22     System.out.println("---------");
23     LocalDate localDate5 = localDate1.with(TemporalAdjusters.nextOrSame(DayOfWeek.TUESDAY));
24     System.out.println("預設時間:"+localDate1);
25     System.out.println("更改時間:"+localDate5);
26 }

執行結果:

6、Java 8日期解析和格式化(DateTimeFormatter)

之前格式化有SimpleDateFormat和DateFormat,但是它們兩者都是執行緒不安全的!啥情況下會有這樣的問題呢?如果我們為了實現日期轉換這樣的工具,每次都new一個物件,但是用完了就不用了,就造成了浪費,為此我們會將它寫成單例的,但是單例的同時,一個物件供多個執行緒使用的時候,就會出現執行緒安全的問題。這個時候就需要這個新的jdk8出的DateTimeformatter這個類。
由字串轉為日期的方法:

如果是預設的格式,yyyy-MM-dd 這種日期格式字串,直接用LocalDate.parse()進行轉換就行了,相對應的時間也是。既有時間又有日期的用DateTimeformatte這個類就行。 

1 String time="2019-02-16";
2 LocalDate localDate=LocalDate.parse(time);
3 System.out.println(localDate);

有時間有日期:

 1 String datetime1="2019-05-24 18:15:56";
 2 DateTimeFormatter formatter1=DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
 3 LocalDateTime localDateTime1=LocalDateTime.parse(datetime1,formatter1);
 4 System.out.println(localDateTime1);
 5  
 6 或者:
 7 String datetime2="2019-05-24 18:15:56";
 8 DateTimeFormatter formatter2=DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
 9 TemporalAccessor parse = formatter2.parse(datetime2);
10 LocalDateTime localDateTime=LocalDateTime.from(parse);
11 System.out.println(localDateTime);

由日期轉為字串的方法:

  • 如果是LocalDate這種標準格式的,直接toString就可以了,
  • 如果是LocalTime這種格式的,toString會附帶納秒值21:06:30.760163, 這個時候你可以使用日期格式器,或者這樣 LocalTime time = LocalTime.now().withNano(0),把納秒直接清0.
  • 如果是LocalDateTime,這個時候是需要一個日期轉換器的。才能由時間+日期->想要的時間,
1 LocalDate localDate=LocalDate.now();
2 System.out.println(localDate.toString());
3         
4 DateTimeFormatter formatter=DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
5 LocalDateTime localDateTime=LocalDateTime.now();
6 String result=localDateTime.format(formatter);
7 System.out.println(result);

7、JDBC中對應的日期

最新JDBC對映將把資料庫的日期型別和Java 8的新型別關聯起來:

SQL -> Java

---------------------

date -> LocalDate

time -> LocalTime

timestamp -> LocalDateTime

8、小結

這次主要學習了Java8中新的日期處理類

  1. LocalDate、LocalTime、LocalDateTime處理日期時間都非常的方便,而且它們是執行緒安全的,
  2. 新版的日期和時間API中,日期和時間物件是不可變的。
  3. LocalDate日期是一個便於使用的日期類,執行緒安全,Date類比較複雜,時間計算麻煩。
  4. DateTimeFormatter的使用也安全,方便。以後用它來代替SimpleDateFormat
  5. TemporalAdjuster 讓你能夠用更精細的方式操縱日期,不再侷限於一次只能改變它的 一個值,並且你還可按照需求定義自己的日期轉換器
  6. JDBC的TimeStamp類和LocalDateTime的轉換也很方便,提供了相應的方法。
  7. 使用的時候,日期必須是標準的yyyy-MM-dd格式,比如1月必須寫成01,不然會報錯。

更多用例檢視此文: https://www.cnblogs.com/comeboo/p/5378922.