Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Find NSDate for the next closest specific day of week for any date

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?

like image 997
Bartłomiej Semańczyk Avatar asked Jul 31 '15 07:07

Bartłomiej Semańczyk


2 Answers

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!)
like image 53
Sandeep Avatar answered Nov 15 '22 12:11

Sandeep


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)
like image 2
vikingosegundo Avatar answered Nov 15 '22 12:11

vikingosegundo