计算两个日期之间的工作日数的最快算法?

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 个工作日。