在 Java 中計算兩個日期之間的工作天數
1. 概述
在本教程中,我們將了解 Java 中計算兩個日期之間的工作日數的兩種不同方法。我們將看看使用Stream
的可讀版本和一個可讀性較差但更有效的選項,該選項根本不循環。
2. 使用Stream
進行全搜尋
首先,讓我們看看如何使用Stream
來做到這一點。該計劃是循環兩個日期之間的每一天併計算工作日:
long getWorkingDaysWithStream(LocalDate start, LocalDate end){
return start.datesUntil(end)
.map(LocalDate::getDayOfWeek)
.filter(day -> !Arrays.asList(DayOfWeek.SATURDAY, DayOfWeek.SUNDAY).contains(day))
.count();
}
首先,我們使用LocalDate
的datesUntil()
方法。此方法傳回從開始日期(包括)到結束日期(不包括)的所有日期的Stream
。
接下來,我們使用map()
和LocalDate
的getDayOfWeek()
將每個日期轉換為一天。例如,這會將 10-01-2023 更改為星期三。
接下來,我們透過對照DaysOfWeek
枚舉檢查所有週末,從而過濾掉所有週末。最後,我們可以計算剩下的天數,因為我們知道這些都是工作日。
這種方法不是最快的,因為我們必須每天查看它。然而,它很容易理解,並且提供了在需要時輕鬆進行額外檢查或處理的機會。
3. 高效搜索,無需循環
我們的另一個選擇是不循環所有的日子,而是應用我們知道的關於一周中的日子的規則。這裡我們需要幾個步驟,以及一些需要處理的邊緣情況。
3.1.設定初始日期
首先,我們將定義我們的方法簽名,它與之前的方法非常相似:
long getWorkingDaysWithoutStream(LocalDate start, LocalDate end)
處理這些日期的第一步是排除開始和結束時的任何週末。因此,對於開始日期,如果是週末,我們將選擇下週一。我們還將追蹤我們使用boolean
執行此操作的事實:
boolean startOnWeekend = false;
if(start.getDayOfWeek().getValue() > 5){
start = start.with(TemporalAdjusters.next(DayOfWeek.MONDAY));
startOnWeekend = true;
}
我們在這裡使用了TemporalAdjusters
類,特別是它的next()
方法,它允許我們跳到下一個指定的日期。
然後,我們可以對結束日期執行相同的操作 - 如果是週末,我們就採用前一個星期五。這次我們將使用TemporalAdjusters.previous()
將我們帶到給定日期之前我們想要的第一天:
boolean endOnWeekend = false;
if(end.getDayOfWeek().getValue() > 5){
end = end.with(TemporalAdjusters.previous(DayOfWeek.FRIDAY));
endOnWeekend = true;
}
3.2.考慮邊緣情況
如果我們從週六開始並在周日結束,這已經為我們帶來了潛在的邊緣情況。在這種情況下,我們的開始日期將是星期一,結束日期是之前的星期五。開始在結束之後是沒有意義的,因此我們可以透過快速檢查來涵蓋這個潛在的用例:
if(start.isAfter(end)){
return 0;
}
我們還需要涵蓋另一個邊緣情況,這就是我們追蹤週末開始和結束的原因。這是可選的,取決於我們想要如何計算天數。例如,如果我們計算同一周的星期二和星期五,我們會說它們之間有三天。
我們還可以說星期六和下一個星期六之間有五個工作日。但是,如果我們像這裡所做的那樣將開始日和結束日移至星期一和星期五,現在將算作四天。因此,為了解決這個問題,我們可以根據需要簡單地添加一天:
long addValue = startOnWeekend || endOnWeekend ? 1 : 0;
3.3.最終計算
我們現在可以計算開始和結束之間的總週數。為此,我們將使用ChronoUnit'
的between()
方法。此方法計算兩個Temporal
物件之間的時間,以指定的單位(在我們的例子中為WEEKS
) :
long weeks = ChronoUnit.WEEKS.between(start, end);
最後,我們可以使用迄今為止收集到的所有資訊來獲得工作日數的最終值:
return ( weeks * 5 ) + ( end.getDayOfWeek().getValue() - start.getDayOfWeek().getValue() ) + addValue;
這裡的步驟首先是將週數乘以每週的工作天數。我們還沒有考慮非整週,因此我們添加了一周開始日和一周結束日之間的額外天數。最後,我們加入了在週末開始或結束的調整。
4。結論
在本文中,我們研究了計算兩個日期之間工作日數的兩種選項。
首先,我們了解如何使用Stream
並單獨檢查每一天。這種方法提供了簡單性和可讀性,但犧牲了效率。
第二個選擇是應用我們所知道的關於一周中的幾天的規則來計算,而不需要循環。這提供了效率,但犧牲了可讀性和可維護性。
與往常一樣,範例的完整程式碼可在 GitHub 上取得。