How do I find the beginning of the week from an NSDate?

I’m implementing a calendar view, and I’d like it to start at the beginning of the week containing a particular date. Eg. If the target date is Monday, Feb 29, 2016, and the current calendar is set to start on Sunday, I’d like my view to start with Sunday, February 28.

This seems like it should be straightforward:

  • How to get previous and next month in calendar
  • How to get the number of weeks from given year
  • How to get Date from String in swift 3?
  • Comparing time and date in objective C
  • setting date format for NSDateFormatter
  • NSDate() or Date() shows the wrong time
  • let calendar = NSCalendar.currentCalendar()
    let firstDate = calendar.nextDateAfterDate(targetDate, 
                        matchingUnit: .Weekday,
                               value: calendar.firstWeekday,
                             options: .SearchBackwards)
    

    But this fails with:

    Terminating app due to uncaught exception ‘NSInvalidArgumentException’, reason: ‘Exactly one option from the set {NSCalendarMatchPreviousTimePreservingSmallerUnits, NSCalendarMatchNextTimePreservingSmallerUnits, NSCalendarMatchNextTime} must be specified.’

    I can get basically what I want with:

    let firstDate = calendar.nextDateAfterDate(firstDate, 
                        matchingUnit: .Weekday,
                               value: calendar.firstWeekday,
                            options: .MatchPreviousTimePreservingSmallerUnits)?
                        .dateByAddingTimeInterval(-7 * 84600)
    

    But it seems like a bad practice, since sometimes the number of seconds in a day isn’t 86400.

    Is there a better way?

    3 Solutions Collect From Internet About “How do I find the beginning of the week from an NSDate?”

    you can use NSCalendar method dateFromComponents passing .YearForWeekOfYear, .WeekOfYear components from any date it will return the first day of the week from the calendar used. So if you would like to get Sunday just use Gregorian calendar. if you would like to get the Monday as the first day of the week you can use NSCalendar iso8601 as you can see in this answer

    Xcode 8.3.2 • Swift 3.1 or later

    extension Calendar {
        static let gregorian = Calendar(identifier: .gregorian)
    }
    extension Date {
        var startOfWeek: Date? {
            return Calendar.gregorian.date(from: Calendar.gregorian.dateComponents([.yearForWeekOfYear, .weekOfYear], from: self))
        }
    }
    

    usage:

    Date().startOfWeek   // "Oct 15, 2017 at 1:00 AM" (note that daylight savings took effect last Sunday, thats why it shows 1am)
    

    Basically use

    NSCalender

    and

    dateByAddingComponents

    . For solving of you’re problem try to use this code sample:

    let cal = NSCalendar.currentCalendar()
    
    let components = NSDateComponents()
    components.weekOfYear -= 1
    
    if let date = cal.dateByAddingComponents(components, toDate: NSDate(), options: NSCalendarOptions(0)) {
        var beginningOfWeek: NSDate?
        var weekDuration = NSTimeInterval()
        if cal.rangeOfUnit(.CalendarUnitWeekOfYear, startDate: &beginningOfWeek, interval: &weekDuration, forDate: date) {
             print(beginningOfWeek) 
        }
    }
    

    The Calendar has a mechanism for finding date at the start of a given time interval (say week of year, or month) that contains a given date:

    let dateFormatter = DateFormatter()
    dateFormatter.dateFormat = "yyyy-MM-dd"
    let date = dateFormatter.date(from: "2017-01-07")
    
    if let date = date {
        let calendar = Calendar(identifier: .gregorian)
    
        var startDate : Date = Date()
        var interval : TimeInterval = 0
    
        if calendar.dateInterval(of: .weekOfYear, start: &startDate, interval: &interval, for: date) {
            print("Start of week is \(startDate)")
            // prints "Start of week is 2017-01-01 06:00:00 +0000"
        }
    }