日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

上半年春招的時候,作為面試官,對于面試表現的不錯的同學會要求其寫一小段代碼看看。題目很簡單:

給定一個日期,然后計算下距離今天相差的天數。

本以為這么個問題就是用來活躍面試氛圍的,但是結果卻讓人大跌眼鏡,真正能寫出來的人竟然寥寥無幾,很多人寫了一整張A4紙都寫不下,最后還是沒寫完...他們在做什么?先取出今天的日期,然后分別計算得出年、月、日的值,然后將給定的字符串進行切割,得到目標的年、月、日,然后再判斷是否閏年之類的邏輯,決定每月應該是加28天還是29天還是30或者31天,最后得出一個天數!

JAVA中計算兩個日期時間的差值竟然也有這么多門道

 

想想都令人窒息的操作...

日期時間的處理,是軟件開發中極其常見的場景,JAVA中與日期、時間相關的一些類與API方法也很多,這里結合平時的編碼實踐全面的整理了下,希望可以幫助大家厘清其中的門道,更加游刃有余的面對此方面的處理~

JAVA中與日期時間相關的類

java.util包中

類名

具體描述

Date

Date對象算是JAVA中歷史比較悠久的用于處理日期、時間相關的類了,但是隨著版本的迭代演進,其中的眾多方法都已經被棄用,所以Date更多的時候僅被用來做一個數據類型使用,用于記錄對應的日期與時間信息

Calender

為了彌補Date對象在日期時間處理方法上的一些缺陷,JAVA提供了Calender抽象類來輔助實現Date相關的一些日歷日期時間的處理與計算。

TimeZone

Timezone類提供了一些有用的方法用于獲取時區的相關信息


JAVA中計算兩個日期時間的差值竟然也有這么多門道

 

java.time包中

JAVA8之后新增了java.time包,提供了一些與日期時間有關的新實現類:

JAVA中計算兩個日期時間的差值竟然也有這么多門道

 

具體每個類對應的含義梳理如下表:

類名

含義說明

LocalDate

獲取當前的日期信息,僅有簡單的日期信息,不包含具體時間、不包含時區信息。

LocalTime

獲取當前的時間信息,僅有簡單的時間信息,不含具體的日期、時區信息。

LocalDateTime

可以看做是LocalDate和LocalTime的組合體,其同時含有日期信息與時間信息,但是依舊不包含任何時區信息。

OffsetDateTime

在LocalDateTime基礎上增加了時區偏移量信息

ZonedDateTime

在OffsetDateTime基礎上,增加了時區信息

ZoneOffset

時區偏移量信息, 比如+8:00或者-5:00等

ZoneId

具體的時區信息,比如Asia/Shanghai或者America/Chicago


JAVA中計算兩個日期時間的差值竟然也有這么多門道

 

時間間隔計算

Period與Duration類

JAVA8開始新增的java.time包中有提供Duration和Period兩個類,用于處理日期時間間隔相關的場景,兩個類的區別點如下:

描述

Duration

時間間隔,用于秒級的時間間隔計算

Period

日期間隔,用于天級別的時間間隔計算,比如年月日維度的

Duration與Period具體使用的時候還需要有一定的甄別,因為部分的方法很容易使用中被混淆,下面分別說明下。

  • Duration

Duration的最小計數單位為納秒,其內部使用seconds和nanos兩個字段來進行組合計數表示duration總長度。

JAVA中計算兩個日期時間的差值竟然也有這么多門道

 

Duration的常用API方法梳理如下:

方法

描述

between

計算兩個時間的間隔,默認是秒

ofXxx

以of開頭的一系列方法,表示基于給定的值創建一個Duration實例。比如ofHours(2L),則表示創建一個Duration對象,其值為間隔2小時

plusXxx

以plus開頭的一系列方法,用于在現有的Duration值基礎上增加對應的時間長度,比如plusDays()表示追加多少天,或者plusMinutes()表示追加多少分鐘

minusXxx

以minus開頭的一系列方法,用于在現有的Duration值基礎上扣減對應的時間長度,與plusXxx相反

toXxxx

以to開頭的一系列方法,用于將當前Duration對象轉換為對應單位的long型數據,比如toDays()表示將當前的時間間隔的值,轉換為相差多少天,而toHours()則標識轉換為相差多少小時。

getSeconds

獲取當前Duration對象對應的秒數, 與toXxx方法類似,只是因為Duration使用秒作為計數單位,所以直接通過get方法即可獲取到值,而toDays()是需要通過將秒數轉為天數換算之后返回結果,所以提供的方法命名上會有些許差異。

getNano

獲取當前Duration對應的納秒數“零頭”。注意這里與toNanos()不一樣,toNanos是Duration值的納秒單位總長度,getNano()只是獲取不滿1s剩余的那個零頭,以納秒表示。

isNegative

檢查Duration實例是否小于0,若小于0返回true, 若大于等于0返回false

isZero

用于判斷當前的時間間隔值是否為0 ,比如比較兩個時間是否一致,可以通過between計算出Duration值,然后通過isZero判斷是否沒有差值。

withSeconds

對現有的Duration對象的nanos零頭值不變的情況下,變更seconds部分的值,然后返回一個新的Duration對象

withNanos

對現有的Duration對象的seconds值不變的情況下,變更nanos部分的值,然后返回一個新的Duration對象

關于Duration的主要API的使用,參見如下示意:

public void testDuration() {
    LocalTime target = LocalTime.parse("00:02:35.700");
    // 獲取當前日期,此處為了保證后續結果固定,注掉自動獲取當前日期,指定固定日期
    // LocalDate today = LocalDate.now();
    LocalTime today = LocalTime.parse("12:12:25.600");
    // 輸出:12:12:25.600
    System.out.println(today);
    // 輸出:00:02:35.700
    System.out.println(target);
    Duration duration = Duration.between(target, today);
    // 輸出:PT12H9M49.9S
    System.out.println(duration);
    // 輸出:43789
    System.out.println(duration.getSeconds());
    // 輸出:900000000
    System.out.println(duration.getNano());
    // 輸出:729
    System.out.println(duration.toMinutes());
    // 輸出:PT42H9M49.9S
    System.out.println(duration.plusHours(30L));
    // 輸出:PT15.9S
    System.out.println(duration.withSeconds(15L));
}
JAVA中計算兩個日期時間的差值竟然也有這么多門道

 

  • Period

Period相關接口與Duration類似,其計數的最小單位是天,看下Period內部時間段記錄采用了年、月、日三個field來記錄:

JAVA中計算兩個日期時間的差值竟然也有這么多門道

 

常用的API方法列舉如下:

方法

描述

between

計算兩個日期之間的時間間隔。注意,這里只能計算出相差幾年幾個月幾天。

ofXxx

of()或者以of開頭的一系列static方法,用于基于傳入的參數構造出一個新的Period對象

withXxx

以with開頭的方法,比如withYears、withMonths、withDays等方法,用于對現有的Period對象中對應的年、月、日等字段值進行修改(只修改對應的字段,比如withYears方法,只修改year,保留month和day不變),并生成一個新的Period對象

getXxx

讀取Period中對應的year、month、day字段的值。注意下,這里是僅get其中的一個字段值,而非整改Period的不同單位維度的總值。

plusXxx

對指定的字段進行追加數值操作

minusXxx

對指定的字段進行扣減數值操作

isNegative

檢查Period實例是否小于0,若小于0返回true, 若大于等于0返回false

isZero

用于判斷當前的時間間隔值是否為0 ,比如比較兩個時間是否一致,可以通過between計算出Period值,然后通過isZero判斷是否沒有差值。

關于Period的主要API的使用,參見如下示意:

public void calculateDurationDays() {
    LocalDate target = LocalDate.parse("2021-07-11");
    // 獲取當前日期,此處為了保證后續結果固定,注掉自動獲取當前日期,指定固定日期
    // LocalDate today = LocalDate.now();
    LocalDate today = LocalDate.parse("2022-07-08");
    // 輸出:2022-07-08
    System.out.println(today);
    // 輸出:2021-07-11
    System.out.println(target);
    Period period = Period.between(target, today);
    // 輸出:P11M27D, 表示11個月27天
    System.out.println(period);
    // 輸出:0, 因為period值為11月27天,即year字段為0
    System.out.println(period.getYears());
    // 輸出:11, 因為period值為11月27天,即month字段為11
    System.out.println(period.getMonths());
    // 輸出:27, 因為period值為11月27天,即days字段為27
    System.out.println(period.getDays());
    // 輸出:P14M27D, 因為period為11月27天,加上3月,變成14月27天
    System.out.println(period.plusMonths(3L));
    // 輸出:P11M15D,因為period為11月27天,僅將days值設置為15,則變為11月15天
    System.out.println(period.withDays(15));
    // 輸出:P2Y3M44D
    System.out.println(Period.of(2, 3, 44));
}

JAVA中計算兩個日期時間的差值竟然也有這么多門道

 

Duration與Period踩坑記

Duration與Period都是用于日期之間的計算操作。Duration主要用于秒、納秒等維度的數據處理與計算。Period主要用于計算年、月、日等維度的數據處理與計算。

先看個例子,計算兩個日期相差的天數,使用Duration的時候:

public void calculateDurationDays(String targetDate) {
    LocalDate target = LocalDate.parse(targetDate);
    LocalDate today = LocalDate.now();
    System.out.println("today : " + today);
    System.out.println("target: " + target);
    long days = Duration.between(target, today).abs().toDays();
    System.out.println("相差:"  + days + "天");
}

運行后會報錯:

today : 2022-07-07
target: 2022-07-11
Exception in thread "main" java.time.temporal.UnsupportedTemporalTypeException: Unsupported unit: Seconds
	at java.time.LocalDate.until(LocalDate.java:1614)
	at java.time.Duration.between(Duration.java:475)
	at com.veezean.demo5.DateService.calculateDurationDays(DateService.java:24)

點擊看下Duration.between源碼,可以看到注釋上明確有標注著,這個方法是用于秒級的時間段間隔計算,而我們這里傳入的是兩個天級別的數據,所以就不支持此類型運算,然后拋異常了。

JAVA中計算兩個日期時間的差值竟然也有這么多門道

 


JAVA中計算兩個日期時間的差值竟然也有這么多門道

 

再看下使用Period的實現:

public void calculateDurationDays(String targetDate) {
    LocalDate target = LocalDate.parse(targetDate);
    LocalDate today = LocalDate.now();
    System.out.println("today : " + today);
    System.out.println("target: " + target);
    // 注意,此處寫法錯誤!這里容易踩坑:
    long days = Math.abs(Period.between(target, today).getDays());
    System.out.println("相差:"  + days + "天");
}

執行結果:

today : 2022-07-07
target: 2021-07-07
相差:0天

執行是不報錯,但是結果明顯是錯誤的。這是因為getDays()并不會將Period值換算為天數,而是單獨計算年、月、日,此處只是返回天數這個單獨的值。

JAVA中計算兩個日期時間的差值竟然也有這么多門道

 

再看下面的寫法:

public void calculateDurationDays(String targetDate) {
    LocalDate target = LocalDate.parse(targetDate);
    LocalDate today = LocalDate.now();
    System.out.println("today : " + today);
    System.out.println("target: " + target);
    Period between = Period.between(target, today);
    System.out.println("相差:"
            + Math.abs(between.getYears()) + "年"
            + Math.abs(between.getMonths()) + "月"
            + Math.abs(between.getDays()) + "天");
}

結果為:

today : 2022-07-07
target: 2021-07-11
相差:0年11月26天

所以說,如果想要計算兩個日期之間相差的絕對天數,用Period不是一個好的思路。

JAVA中計算兩個日期時間的差值竟然也有這么多門道

 

計算日期差

  • 通過LocalDate來計算

LocalDate中的toEpocDay可返回當前時間距離原點時間之間的天數,可以基于這一點,來實現計算兩個日期之間相差的天數:

JAVA中計算兩個日期時間的差值竟然也有這么多門道

 

代碼如下:

public void calculateDurationDays(String targetDate) {
    LocalDate target = LocalDate.parse(targetDate);
    LocalDate today = LocalDate.now();
    System.out.println("today : " + today);
    System.out.println("target: " + target);
    long days = Math.abs(target.toEpochDay() - today.toEpochDay());
    System.out.println("相差:" + days + "天");
}

結果為:

today : 2022-07-07
target: 2021-07-11
相差:361天

JAVA中計算兩個日期時間的差值竟然也有這么多門道

 

  • 通過時間戳來計算

如果是使用的Date對象,則可以通過將Date日期轉換為毫秒時間戳的方式相減然后將毫秒數轉為天數的方式來得到結果。需要注意的是通過毫秒數計算日期天數的差值時,需要屏蔽掉時分秒帶來的誤差影響。

public void calculateDaysGap(Date start, Date end) {
    final long ONE_DAY_MILLIS = 1000L * 60 * 60 * 24;
    // 此處要注意,去掉時分秒的差值影響,此處采用先換算為天再相減的方式
    long gapDays = Math.abs(end.getTime()/ONE_DAY_MILLIS - start.getTime()/ONE_DAY_MILLIS);
    System.out.println(gapDays);
}

輸出結果:

today : 2022-07-08
target: 2021-07-11
相差:362天

JAVA中計算兩個日期時間的差值竟然也有這么多門道

 

  • 數學邏輯計算

分別算出年、月、日差值,然后根據是否閏年、每月是30還是31天等計數邏輯,純數學硬懟方式計算。

不推薦、代碼略...

JAVA中計算兩個日期時間的差值竟然也有這么多門道

 

計算接口處理耗時

在一些性能優化的場景中,我們需要獲取到方法處理的執行耗時,很多人都是這么寫的:

public void doSomething() {
    // 記錄開始時間戳
    long startMillis = System.currentTimeMillis();
    // do something ...
    
    // 計算結束時間戳
    long endMillis = System.currentTimeMillis();
    
    // 計算相差的毫秒數
    System.out.println(endMillis - startMillis);
}

JAVA中計算兩個日期時間的差值竟然也有這么多門道

 

當然啦,如果你使用的是JDK8+的版本,你還可以這么寫:

public void doSomething() {
    // 記錄開始時間戳
    Instant start = Instant.now();
    // do something ...

    // 計算結束時間戳
    Instant end = Instant.now();

    // 計算相差的毫秒數
    System.out.println(Duration.between(start, end).toMillis());
}

JAVA中計算兩個日期時間的差值竟然也有這么多門道

 

時間格式轉換

項目中,時間格式轉換是一個非常典型的日期處理操作,可能會涉及到將一個字符串日期轉換為JAVA對象,或者是將一個JAVA日期對象轉換為指定格式的字符串日期時間。

SimpleDataFormat實現

在JAVA8之前,通常會使用SimpleDateFormat類來處理日期與字符串之間的相互轉換:

public void testDateFormatter() {
    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    // 日期轉字符串
    String format = simpleDateFormat.format(new Date());
    System.out.println("當前時間:" + format);
   
    try {
        // 字符串轉日期
        Date parseDate = simpleDateFormat.parse("2022-07-08 06:19:27");
        System.out.println("轉換后Date對象: " + parseDate);
        // 按照指定的時區進行轉換,可以對比下前面轉換后的結果,會發現不一樣
        simpleDateFormat.setTimeZone(TimeZone.getTimeZone("GMT+5:00"));
        parseDate = simpleDateFormat.parse("2022-07-08 06:19:27");
        System.out.println("指定時區轉換后Date對象: " + parseDate);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

輸出結果如下:

當前時間:2022-07-08 06:25:31
轉換后Date對象: Fri Jul 08 06:19:27 CST 2022
指定時區轉換后Date對象: Fri Jul 08 09:19:27 CST 2022

補充說明:

SimpleDateFormat對象是非線程安全的,所以項目中在封裝為工具方法使用的時候需要特別留意,最好結合ThreadLocal來適應在多線程場景的正確使用。
JAVA8之后,推薦使用DateTimeFormat替代SimpleDateFormat。

JAVA中計算兩個日期時間的差值竟然也有這么多門道

 

DataTimeFormatter實現

JAVA8開始提供的新的用于日期與字符串之間轉換的類,它很好的解決了SimpleDateFormat多線程的弊端,也可以更方便的與java.time中心的日期時間相關類的集成調用。

public void testDateFormatter() {
    DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    LocalDateTime localDateTime = LocalDateTime.now();
    // 格式化為字符串
    String format = localDateTime.format(dateTimeFormatter);
    System.out.println("當前時間:" + format);
    // 字符串轉Date
    LocalDateTime parse = LocalDateTime.parse("2022-07-08 06:19:27", dateTimeFormatter);
    Date date = Date.from(parse.atZone(ZoneId.systemDefault()).toInstant());
    System.out.println("轉換后Date對象: " + date);
}


輸出結果:

當前時間:2022-07-08 18:37:46
轉換后Date對象: Fri Jul 08 06:19:27 CST 2022

JAVA中計算兩個日期時間的差值竟然也有這么多門道

 

日期時間格式模板

對于計算機而言,時間處理的時候按照基于時間原點的數字進行處理即可,但是轉為人類方便識別的場景顯示時,經常會需要轉換為不同的日期時間顯示格式,比如:

2022-07-08 12:02:34
2022/07/08 12:02:34.238
2022年07月08日 12點03分48秒

在JAVA中,為了方便各種格式轉換,提供了基于時間模板進行轉換的實現能力:

JAVA中計算兩個日期時間的差值竟然也有這么多門道

 

時間格式模板中的字幕含義說明如下:

字母

使用說明

yyyy

4位數的年份

yy

顯示2位數的年份,比如2022年,則顯示為22年

MM

顯示2位數的月份,不滿2位數的,前面補0,比如7月份顯示07月

M

月份,不滿2位的月份不會補0

dd

天, 如果1位數的天數,則補0

d

天,不滿2位數字的,不補0

HH

24小時制的時間顯示,小時數,兩位數,不滿2位數字的前面補0

H

24小時制的時間顯示,小時數,不滿2位數字的不補0

hh

12小時制的時間顯示,小時數,兩位數,不滿2位數字的前面補0

ss

秒數,不滿2位的前面補0

s

秒數,不滿2位的不補0

SSS

毫秒數

z

時區名稱,比如北京時間東八區,則顯示CST

Z

時區偏移信息,比如北京時間東八區,則顯示+0800


JAVA中計算兩個日期時間的差值竟然也有這么多門道

 

消失的8小時問題

日期字符串存入DB后差8小時

在后端與數據庫交互的時候,可能會遇到一個問題,就是往DB中存儲了一個時間字段之后,后面再查詢的時候,就會發現時間數值差了8個小時,這個需要在DB的連接信息中指定下時區信息:

spring.datasource.druid.url=jdbc:MySQL://127.0.0.1:3306/test?serverTimezone=Asia/Shanghai

JAVA中計算兩個日期時間的差值竟然也有這么多門道

 

界面時間與后臺時間差8小時

在有一些前后端交互的項目中,可能會遇到一個問題,就是前端選擇并保存了一個時間信息,再查詢的時候就會發現與設置的時間差了8個小時,這個其實就是后端時區轉換設置的問題。

SpringBoot的配置文件中,需要指定時間字符串轉換的時區信息:

spring.jackson.time-zone=GMT+8

這樣從接口json中傳遞過來的時間信息,jackson框架可以根據對應時區轉換為正確的Date數據進行處理。

JAVA中計算兩個日期時間的差值竟然也有這么多門道

 


我是悟道,聊技術、又不僅僅聊技術~

如果覺得有用,請點個關注,也可以關注下我的公眾號【架構悟道】,獲取更及時的更新。

期待與你一起探討,一起成長為更好的自己。

分享到:
標簽:JAVA
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定