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

时间:2017-04-21 11:47:36

标签: algorithm scala jodatime

我之前偶然发现了这个问题并且有一些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()

我的问题不仅是如何计算两个日期之间的工作日数,还有最快的解决方案。请注意,我只需要知道工作日的数量,而不是实际的日期。

2 个答案:

答案 0 :(得分:1)

在我看来,这是一个稍微更具可读性的版本,具有相同的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个工作日。

答案 1 :(得分:0)

这是我认为最快的解决方案,只需要考虑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
}