计算两个日期之间的工作日数的最快算法?
Fastest algorithm to calculate the number of business days between two dates?
我之前曾几次偶然发现这个问题,周围有一些 SO 答案,但它们非常慢,例如
def businessDaysBetween(startDate: DateTime, endDate: DateTime): Seq[DateTime] = {
1 to daysBetween(startDate, endDate) map {
startDate.withFieldAdded(DurationFieldType.days(), _)
} diff holidays filter {
_.getDayOfWeek() match {
case DateTimeConstants.SUNDAY | DateTimeConstants.SATURDAY => false
case _ => true
}
}
}
def daysBetween(startDate: DateTime, endDate: DateTime) =
Days.daysBetween(startDate.toDateMidnight(), endDate.toDateMidnight()).getDays()
我的问题不仅是如何计算两个日期之间的工作日数,而且是最快的解决方案。请注意,我只需要知道工作日数,而不是实际日期。
这是我认为最快的解决方案,只需要考虑startDate
代表一周中的哪一天。复杂度为 O(C)
:
def businessDaysBetween(startDate: DateTime, endDate: DateTime): Int = {
val numDays = daysBetween(startDate, endDate)
val numHolidays: Int = startDate.getDayOfWeek match {
case DateTimeConstants.MONDAY => (numDays / 7)*2 + (if (numDays % 7 > 4) min(numDays % 7 - 4, 2) else 0)
case DateTimeConstants.TUESDAY => (numDays / 7)*2 + (if (numDays % 7 > 3) min(numDays % 7 - 3, 2) else 0)
case DateTimeConstants.WEDNESDAY => (numDays / 7)*2 + (if (numDays % 7 > 2) min(numDays % 7 - 2, 2) else 0)
case DateTimeConstants.THURSDAY => (numDays / 7)*2 + (if (numDays % 7 > 1) min(numDays % 7 - 1, 2) else 0)
case DateTimeConstants.FRIDAY => (numDays / 7)*2 + (if (numDays % 7 > 0) min(numDays % 7, 2) else 0)
case DateTimeConstants.SATURDAY => 1 + (numDays / 7)*2 + (if (numDays % 7 > 0) 1 else 0)
case DateTimeConstants.SUNDAY => 1 + (numDays / 7)*2 + (if (numDays % 7 > 5) 1 else 0)
}
numDays - numHolidays
}
在我看来,这是一个更易读的版本,具有相同的 O(C)
复杂性:
def getPreviousWorkDay(d: DateTime): DateTime = {
d.withDayOfWeek(Math.min(d.getDayOfWeek, DateTimeConstants.FRIDAY)).withTimeAtStartOfDay()
}
def businessDaysBetween(startDate: DateTime, endDate: DateTime): Int = {
val workDayStart = getPreviousWorkDay(startDate)
val workDayEnd = getPreviousWorkDay(endDate)
val daysBetween = Days.daysBetween(workDayStart, workDayEnd).getDays
val weekendDaysBetween = daysBetween / 7 * 2
val additionalWeekend = if(workDayStart.getDayOfWeek > workDayEnd.getDayOfWeek) 2 else 0
daysBetween - weekendDaysBetween - additionalWeekend
}
我认为一周从星期一开始(Joda 的默认设置)。
我还认为周六和下周五之间有 5 个工作日,而周一和下周五之间只有 4 个工作日。
我之前曾几次偶然发现这个问题,周围有一些 SO 答案,但它们非常慢,例如
def businessDaysBetween(startDate: DateTime, endDate: DateTime): Seq[DateTime] = {
1 to daysBetween(startDate, endDate) map {
startDate.withFieldAdded(DurationFieldType.days(), _)
} diff holidays filter {
_.getDayOfWeek() match {
case DateTimeConstants.SUNDAY | DateTimeConstants.SATURDAY => false
case _ => true
}
}
}
def daysBetween(startDate: DateTime, endDate: DateTime) =
Days.daysBetween(startDate.toDateMidnight(), endDate.toDateMidnight()).getDays()
我的问题不仅是如何计算两个日期之间的工作日数,而且是最快的解决方案。请注意,我只需要知道工作日数,而不是实际日期。
这是我认为最快的解决方案,只需要考虑startDate
代表一周中的哪一天。复杂度为 O(C)
:
def businessDaysBetween(startDate: DateTime, endDate: DateTime): Int = {
val numDays = daysBetween(startDate, endDate)
val numHolidays: Int = startDate.getDayOfWeek match {
case DateTimeConstants.MONDAY => (numDays / 7)*2 + (if (numDays % 7 > 4) min(numDays % 7 - 4, 2) else 0)
case DateTimeConstants.TUESDAY => (numDays / 7)*2 + (if (numDays % 7 > 3) min(numDays % 7 - 3, 2) else 0)
case DateTimeConstants.WEDNESDAY => (numDays / 7)*2 + (if (numDays % 7 > 2) min(numDays % 7 - 2, 2) else 0)
case DateTimeConstants.THURSDAY => (numDays / 7)*2 + (if (numDays % 7 > 1) min(numDays % 7 - 1, 2) else 0)
case DateTimeConstants.FRIDAY => (numDays / 7)*2 + (if (numDays % 7 > 0) min(numDays % 7, 2) else 0)
case DateTimeConstants.SATURDAY => 1 + (numDays / 7)*2 + (if (numDays % 7 > 0) 1 else 0)
case DateTimeConstants.SUNDAY => 1 + (numDays / 7)*2 + (if (numDays % 7 > 5) 1 else 0)
}
numDays - numHolidays
}
在我看来,这是一个更易读的版本,具有相同的 O(C)
复杂性:
def getPreviousWorkDay(d: DateTime): DateTime = {
d.withDayOfWeek(Math.min(d.getDayOfWeek, DateTimeConstants.FRIDAY)).withTimeAtStartOfDay()
}
def businessDaysBetween(startDate: DateTime, endDate: DateTime): Int = {
val workDayStart = getPreviousWorkDay(startDate)
val workDayEnd = getPreviousWorkDay(endDate)
val daysBetween = Days.daysBetween(workDayStart, workDayEnd).getDays
val weekendDaysBetween = daysBetween / 7 * 2
val additionalWeekend = if(workDayStart.getDayOfWeek > workDayEnd.getDayOfWeek) 2 else 0
daysBetween - weekendDaysBetween - additionalWeekend
}
我认为一周从星期一开始(Joda 的默认设置)。
我还认为周六和下周五之间有 5 个工作日,而周一和下周五之间只有 4 个工作日。