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?
Asked
Active
Viewed 2,151 times
8

jscs
- 63,694
- 13
- 151
- 195

Bartłomiej Semańczyk
- 59,234
- 49
- 233
- 358
-
You could take a look at https://github.com/mysterioustrousers/MTDates , and it has a `mt_startOfNextWeek;` method. – Dániel Nagy Jul 31 '15 at 07:38
-
I need a solution without any third part libraries – Bartłomiej Semańczyk Jul 31 '15 at 07:46
-
2Do you mean the next *upcoming* Monday, or just the *closest* (which could be in the past or in the future) ? – Martin R Jul 31 '15 at 08:05
-
I updated the question. – Bartłomiej Semańczyk Jul 31 '15 at 08:20
3 Answers
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
-
-
2It's amazing that `NSCalendar`'s iOS 8 methods are still undocumented on the reference library. – Desdenova Jul 31 '15 at 08:35
-
Yes, they seem to have added many new apis to NSCalendar and siblings. It would be really good to have them documented. – Sandeep Jul 31 '15 at 08:57
-
"Monday" will not work for other languages, `Monday` in polish is `Poniedziałek` for instance. I think that searching by name is not the best solution since calendars in devices are automatically localised. – Bartłomiej Semańczyk Jul 31 '15 at 13:45
-
That is the reason that locale is used for the calendar with en_US_POSIX, see that it uses the system calendar but sets locale to en_US_POSIX, just to extract english name. – Sandeep Jul 31 '15 at 13:46
-
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
-
1**Don't** use 24*60*60 seconds as the duration of a day (think of daylight saving time transitions). – Martin R Jul 31 '15 at 08:10
-
-
days can be 23, 24, 25 hours long, due to Daylight Saving Times – vikingosegundo Jul 31 '15 at 08:14