Search code examples
swiftdatecalendarnsdatenscalendar

Calculate business days and weekend days between 2 NSDates


I'm trying to calculate the amount of workdays + business days between 2 NSDates but I can't seem to find a proper solution. I can currently find the amount of Days between 2 NSDates like so:

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: "
}

Can anyone point me in the right direction?


Solution

  • First, if you are using Swift 2 you should make NSDate conform to Comparable protocol:

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

    Second, You can use Calendar isDateInWeekend to check if any date it is a weekend day or not, and you can use dateByAddingUnit to get add a day to the start date until the end date:

    Create those extensions to help you:

    edit/update: 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)!
        }
    }
    

    and a method to count the days:

    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)
    }
    

    Testing:

    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
        }
    }