2 回答

TA貢獻1815條經驗 獲得超10個贊
另外不要忘記在添加累積的額外天數(shù)(周末和假期)時,這些天數(shù)可能會涵蓋新的周末和假期,因此您必須“遞歸”執(zhí)行此操作。
最簡單的解決方案
最簡單的解決方案可以從初始日期開始,將其增加一天,然后檢查每一天是否是可跳過的(周末或假期)。如果不是,請減少天數(shù),然后重復直到添加所需的天數(shù)。
這就是它的樣子:
func addDays(start time.Time, days int) (end time.Time) {
for end = start; days > 0; {
end = end.AddDate(0, 0, 1)
if !skippable(end) {
days--
}
}
return end
}
func skippable(day time.Time) bool {
if wd := day.Weekday(); wd == time.Saturday || wd == time.Sunday {
return true
}
if isHoliday(day) {
return true
}
return false
}
func isHoliday(day time.Time) bool {
return false // TODO
}
測試它:
d := time.Date(2022, time.April, 14, 0, 0, 0, 0, time.UTC)
fmt.Println(addDays(d, 0))
fmt.Println(addDays(d, 1))
fmt.Println(addDays(d, 10))
哪些輸出(在Go Playground上嘗試):
2022-04-14 00:00:00 +0000 UTC
2022-04-15 00:00:00 +0000 UTC
2022-04-28 00:00:00 +0000 UTC
更快的解決方案
更快的解決方案可以避免循環(huán)日復一日。
計算周末天數(shù):知道初始日期是哪一天,知道你要步進多少天,我們就可以計算出中間的周末天數(shù)。例如,如果我們必須步進 14 天,即整整 2 周,那肯定正好包括 4 個周末。如果我們必須多走一步,例如 16 天,那也包括 2 個完整的星期(4 個周末),以及可選的 1 或 2 天,我們可以輕松檢查。
計算假期:我們可能會使用一個技巧來在排序切片(按日期排序)中列出假期,因此我們可以輕松/快速地找到 2 個日期之間的天數(shù)。我們可以在一個排序的切片中對某個時間段的開始和結束日期進行二分查找,一個時間段中的假期數(shù)就是這兩個索引之間的元素數(shù)。注意:周末假期不得包含在此切片中(否則會被計算兩次)。
讓我們看看這個實現(xiàn)的樣子:
// holidays is a sorted list of holidays
var holidays = []time.Time{
time.Date(2022, time.April, 15, 0, 0, 0, 0, time.UTC),
}
func addDaysFast(start time.Time, days int) (end time.Time) {
weekendDays := days / 7 * 2 // Full weeks
// Account for weekends if there's fraction week:
for day, fraction := start.AddDate(0, 0, 1), days%7; fraction > 0; day, fraction = day.AddDate(0, 0, 1), fraction-1 {
if wd := day.Weekday(); wd == time.Saturday || wd == time.Sunday {
weekendDays++
}
}
end = start.AddDate(0, 0, days+weekendDays)
first := sort.Search(len(holidays), func(i int) bool {
return !holidays[i].Before(start)
})
last := sort.Search(len(holidays), func(i int) bool {
return !holidays[i].Before(end)
})
// There are last - first holidays in the range [start..end]
numHolidays := last - first
if last < len(holidays) && holidays[last].Equal(end) {
numHolidays++ // end is exactly a holiday
}
if numHolidays == 0 {
return end // We're done
}
// We have to add numHolidays, using the same "rules" above:
return addDaysFast(end, numHolidays)
}
測試它:
d := time.Date(2022, time.April, 14, 0, 0, 0, 0, time.UTC)
fmt.Println(addDaysFast(d, 0))
fmt.Println(addDaysFast(d, 1))
fmt.Println(addDaysFast(d, 10))
輸出(在Go Playground上嘗試):
2022-04-14 00:00:00 +0000 UTC
2022-04-18 00:00:00 +0000 UTC
2022-04-29 00:00:00 +0000 UTC
改善addDaysFast()
仍然有改進的方法addDaysFast()
:
檢查小數(shù)周中周末天數(shù)的初始循環(huán)可以用算術計算代替(參見示例)
遞歸可以用迭代解決方案代替
另一種解決方案可以將周末列為假期,因此可以消除計算周末的第一部分(不得包括重復項)

TA貢獻1856條經驗 獲得超5個贊
我會像這樣計算工作日。除了假日查找之外,它沒有循環(huán)并且具有 O(1) 時間和空間復雜度:
計算范圍的開始日期和結束日期之間的天數(shù)
將其除以 7。商是范圍內的周數(shù);余下的是整日剩余的小數(shù)周。
范圍內的基本工作日數(shù)是范圍內的周數(shù)乘以 5,因為每 7 天的時間段,無論何時開始,都包含 2 個周末。
末尾的小數(shù)周,在整天中,必須進行調整以刪除任何周末。這是小數(shù)周中的整數(shù)天數(shù)和范圍結束日期的星期幾的函數(shù)。
假期查詢留給讀者作為練習,因為這太過依賴于文化、地區(qū)和業(yè)務而無法解決。應該注意,這里的邏輯中有一個內置的假設,即“假期”不會出現(xiàn)在周六或周日。
func BusinessDays(start time.Time, end time.Time) int {
from := toDate(start)
thru := toDate(end)
weeks, days := delta(from, thru)
adjustedDays := adjustDays(days, thru.Weekday())
businessDays := ( ( weeks * 5) + adjustedDays ) - holidaysInRange(from, thru)
return businessDays
}
func toDate(t time.Time) time.Time {
y, m, d := t.Date()
adjusted := time.Date(y, m, d, 0, 0, 0, 0, t.Location())
return adjusted
}
func holidaysInRange(from, thru time.Time) (cnt int) {
// TODO: Actual implementation left as an exercise for the reader
return cnt
}
func delta(from, thru time.Time) (weeks, days int) {
const seconds_per_day = 86400
totalDays := (thru.Unix() - from.Unix()) / seconds_per_day
weeks = int(totalDays / 7)
days = int(totalDays % 7)
return weeks, days
}
func adjustDays(days int, lastDay time.Weekday) int {
adjusted := days
switch days {
case 1:
switch lastDay {
case time.Saturday:
case time.Sunday:
adjusted -= 1
}
case 2:
switch lastDay {
case time.Sunday:
adjusted -= 2
case time.Saturday:
case time.Monday:
adjusted -= 1
}
case 3:
switch lastDay {
case time.Sunday:
case time.Monday:
adjusted -= 2
case time.Tuesday:
case time.Saturday:
adjusted -= 1
}
case 4:
switch lastDay {
case time.Sunday:
case time.Monday:
case time.Tuesday:
adjusted -= 2
case time.Wednesday:
case time.Saturday:
adjusted -= 1
}
case 5:
switch lastDay {
case time.Sunday:
case time.Monday:
case time.Tuesday:
case time.Wednesday:
adjusted -= 2
case time.Thursday:
case time.Saturday:
adjusted -= 1
}
case 6:
switch lastDay {
case time.Sunday:
case time.Monday:
case time.Tuesday:
case time.Wednesday:
case time.Thursday:
adjusted -= 2
case time.Friday:
case time.Saturday:
adjusted -= 1
}
}
return adjusted
}
- 2 回答
- 0 關注
- 155 瀏覽
添加回答
舉報