计算两个NSDate之间的工作日和周末天数

6
我将尝试计算两个NSDate之间的工作日和营业日,但似乎找不到合适的解决方案。我目前可以像这样找到两个NSDate之间的天数:
func reloadData(){
    let cal = NSCalendar.currentCalendar()

    var daysInt = 0

    let days = cal.components(.Day, fromDate: selectedDateTimePointTwo, toDate: selectedDateTimePointOne, options: [])
    daysInt = days.day

    workDaysLabel.text = "work days: \(daysInt)"
    weekendDaysLabel.text = "weekend days: "
}

有人能指引我正确的方向吗?


你可能会在这里找到一些有用的信息:http://nshipster.com/nscalendar-additions/ - jtbandes
公共假期如果落在工作日,是否算作工作日? - Code Different
不需要区分公共假期,只想计算两个日期之间的周末和工作日数量。 - Rutger Huijsmans
2个回答

9
首先,如果您使用的是Swift 2,则应使NSDate符合Comparable协议:
extension NSDate: Comparable { }

public func <(lhs: NSDate, rhs: NSDate) -> Bool {
    return lhs.compare(rhs) == .OrderedAscending
}

其次,您可以使用日历的isDateInWeekend函数来检查任何日期是否为周末,您还可以使用dateByAddingUnit函数将一天添加到开始日期直到结束日期:

创建这些扩展以帮助您:

编辑/更新:Swift 4

extension Calendar {
    static let iso8601 = Calendar(identifier: .iso8601)
}


extension Date {
    var isDateInWeekend: Bool {
        return Calendar.iso8601.isDateInWeekend(self)
    }
    var tomorrow: Date {
        return Calendar.iso8601.date(byAdding: .day, value: 1, to: noon)!
    }
    var noon: Date {
        return Calendar.iso8601.date(bySettingHour: 12, minute: 0, second: 0, of: self)!
    }
}

还有一种计算天数的方法:

func coutDays(from start: Date, to end: Date) -> (weekendDays: Int, workingDays: Int) {
    guard start < end else { return (0,0) }
    var weekendDays = 0
    var workingDays = 0
    var date = start.noon
    repeat {
        if date.isDateInWeekend {
            weekendDays +=  1
        } else {
            workingDays += 1
        }
        date = date.tomorrow
    } while date < end
    return (weekendDays, workingDays)
}

测试:

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let start = DateComponents(calendar: .iso8601, year: 2016).date!  // "Jan 1, 2016, 12:00 AM"
        let end = DateComponents(calendar: .iso8601, year: 2017).date!  // "Jan 1, 2017, 12:00 AM"
        print(coutDays(from: start, to: end))  // 105, 261
    }
}

⚠️ 注意:这个解决方案存在性能问题。在“tomorrow”函数中使用“noon”会显著降低性能。在我的情况下,将“noon”替换为“self”后,运行性能测试的时间从5秒缩短到了0.2秒。 - jcislinsky
我有成千上万的计算。 - jcislinsky

6

这是Swift 5版本。我还使用了当前设备的日历,而不是ISO标准日历。

func nextDay(in calendar: Calendar) -> Date? {
    return calendar.date(byAdding: .day, value: 1, to: self)
}

func daysCount(until endDate: Date) -> (workingDays: Int, weekends: Int) {
    let calendar = Calendar.current
    var weekends = 0
    var workingDays = 0
    var date = self
    while date < endDate {
        if calendar.isDateInWeekend(date) {
            weekends += 1
        } else {
            workingDays += 1
        }

        guard let nextDay = date.nextDay(in: calendar) else {
            fatalError("Failed to instantiate a next day")
        }

        date = nextDay
    }

    return (workingDays, weekends)
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接