8

Let's suppose that today is Wednesday. I can break an NSDate down into NSDateComponents, but I need to find the NSDate with the next upcoming Monday. If today is Monday, then the next upcoming Monday is today. What's the right way to achieve this?

jscs
  • 63,694
  • 13
  • 151
  • 195
Bartłomiej Semańczyk
  • 59,234
  • 49
  • 233
  • 358

3 Answers3

27

You can use nextDateAfterDate: method on NSCalendar object to achieve this,

let now = Date() // today

var matchingComponents = DateComponents()
matchingComponents.weekday = 2 // Monday

let comingMonday =  Calendar.current.nextDate(after: now,
                                              matching: matchingComponents,
                                              matchingPolicy:.nextTime)

Here, is a simple method to find next monday. If today is Monday the following function returns today or else the closest next Monday. Note that it uses en_POSIX_US such that the days can be matched. When the locale is en_POSIX_US, weekdays symbols become,

["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]

And, here is how this days could be used,

func findNext(_ day: String, afterDate date: Date) -> Date? {

    var calendar = Calendar.current
    calendar.locale = Locale(identifier: "en_US_POSIX")

    let weekDaySymbols = calendar.weekdaySymbols
    let indexOfDay = weekDaySymbols.index(of: day)

    assert(indexOfDay != nil, "day passed should be one of \(weekDaySymbols), invalid day: \(day)")

    let weekDay = indexOfDay! + 1

    let components = calendar.component(.weekday, from: date)

    if components == weekDay {
        return date
    }

    var matchingComponents = DateComponents()
    matchingComponents.weekday = weekDay // Monday

    let nextDay = calendar.nextDate(after: date,
                                    matching: matchingComponents,
                                    matchingPolicy:.nextTime)
    return nextDay!
}


let nextMonday = findNext("Monday", afterDate: Date())
let mondayAfterThat = findNext("Monday", afterDate: nextMonday!)

let thursday = findNext("Thursday", afterDate: mondayAfterThat!)
Sandeep
  • 20,908
  • 7
  • 66
  • 106
2

for target iOS >= 8 use GeneratorOfOne's solution

else you can use this

let now = NSDate()
var lastMonday:NSDate?
var nextMonday:NSDate?
var start:NSDate?        

var interval:NSTimeInterval = 0   // holds the length of a week. can differ for Daylight Saving Time
let cal = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)! // have a own calendar object for this calculation to guarantee that the next line does not influence other calculations 
cal.firstWeekday = 2              // make sure first day of week is Monday. 


cal.rangeOfUnit(NSCalendarUnit.CalendarUnitWeekOfMonth, startDate: &lastMonday, interval:&interval, forDate: now)      // monday of current week
nextMonday = lastMonday?.dateByAddingTimeInterval(interval)  // add a weeks length to the last weeks's monday
println(nextMonday)
vikingosegundo
  • 52,040
  • 14
  • 137
  • 178
-4

You can get the week day by using NSDateComponents and calculate the interval days, then use dateByAddingTimeInterval from NSDate like so:

let now = NSDate()
let calendar: NSDateComponents = NSCalendar.currentCalendar().components(NSCalendarUnit.CalendarUnitWeekday, fromDate: now)
let weekday = calendar.weekday  // 1 = Sunday, 2 = Monday

// You get input the weekday here and calculate the interval

// exmaple for moving to the next day
let expectedDate = now.dateByAddingTimeInterval(1 * 24 * 60 * 60)

// exmaple for moving to yesterday
let yesterday = now.dateByAddingTimeInterval(-1 * 24 * 60 * 60)
Lucas Huang
  • 3,998
  • 3
  • 20
  • 29