最快的算法来计算两个日期之间的营业日数?
问题描述:
我偶然发现过几次这个问题,并且有一些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()
我的问题不仅是如何计算两个日期之间的工作日数,而且是最快的解决方案。请注意,我只需要知道工作日数而不是实际日期。
答
这里有一个稍微更可读的版本,在我看来,与同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
}
我认为本周周一(对于乔达默认)开始。
我也认为在周六和下周五之间有5个工作日,而在周一和下周五之间只有4个工作日。
答
而这是我认为最快的解决方案,只需要考虑一周中的哪一天是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
}
根据您的使用情况,预先计算并查找它(我们实际上是在一家公司中为一年剩余的日子做了这些工作 - 我们使用的是Lotus Notes,并且考虑在飞行中做这件事实在太痛苦) –
为什么要预先计算并缓存一些可以在固定时间内完成的事情? –
因为,根据您的使用情况,可能会更快。特别是如果你的实现语言在计算时很慢。 –