We have those convenient functions in calendar:
let calendar = NSCalendar.currentCalendar()
calendar.isDateInToday(date)
calendar.isDateInTomorrow(date)
But I am missing those two:
calendar.isDateInNextWeek(date)
calendar.isDateInNextMonth(date)
As @Rob mentioned, the meaning is: "in the calendar week starting this coming Sunday, going through the following Saturday"
I having a hard time figuring out how to implement those functions in a robust way that covers all the corner cases.
Can someone provide an assistant?
The algorithm is not very spectacular:
NSCalendar does most of the work for us. But it looks still a bit intimidating, at least if you don't use these date methods often. You should read the documentation of all of these methods to understand them.
let calendar = NSCalendar.currentCalendar()
let date = NSDate()
var startOfThisWeek: NSDate?
if !calendar.rangeOfUnit(.CalendarUnitWeekOfMonth, startDate: &startOfThisWeek, interval: nil, forDate: date) {
fatalError("Can't calculate start of this week")
}
let startOfNextWeek = calendar.dateByAddingUnit(.CalendarUnitWeekOfMonth, value: 1, toDate: startOfThisWeek!, options: nil)!
let startOfNextNextWeek = calendar.dateByAddingUnit(.CalendarUnitWeekOfMonth, value: 1, toDate: startOfNextWeek, options: nil)!
Just switch .CalendarUnitWeekOfMonth
with .CalendarUnitMonth
and you get the calculation for this, next and the following month.
var startOfThisMonth: NSDate?
if !calendar.rangeOfUnit(.CalendarUnitMonth, startDate: &startOfThisMonth, interval: nil, forDate: date) {
fatalError("Can't calculate start of this month")
}
let startOfNextMonth = calendar.dateByAddingUnit(.CalendarUnitMonth, value: 1, toDate: startOfThisMonth!, options: nil)!
let startOfNextNextMonth = calendar.dateByAddingUnit(.CalendarUnitMonth, value: 1, toDate: startOfNextMonth, options: nil)!
And the test:
let testDate = NSDate(timeIntervalSinceNow: 7*24*60*60)
if startOfThisWeek <= testDate && testDate < startOfNextWeek {
println("\(testDate) is this week")
}
if startOfNextWeek <= testDate && testDate < startOfNextNextWeek {
println("\(testDate) is next week")
}
if startOfThisMonth <= testDate && testDate < startOfNextMonth {
println("\(testDate) is this month")
}
if startOfNextMonth <= testDate && testDate < startOfNextNextMonth {
println("\(testDate) is next month")
}
Result:
"2015-03-22 02:55:19 +0000 is next week"
"2015-03-22 02:55:19 +0000 is this month"
Sounds right.
And if you want to use <=
, ==
, <
etc. instead of the ugly (and confusing) NSComparisonResult
you need this as well:
public func ==(lhs: NSDate, rhs: NSDate) -> Bool {
return lhs === rhs || lhs.compare(rhs) == .OrderedSame
}
public func <(lhs: NSDate, rhs: NSDate) -> Bool {
return lhs.compare(rhs) == .OrderedAscending
}
extension NSDate: Comparable { }
This is iOS8 code. If you want to write code that works on older versions you have to replace dateByAddingUnit:value::toDate:options:
by good old NSDateComponents. i.e:
let offSetComponents = NSDateComponents()
offSetComponents.weekOfMonth = 1
let startOfNextWeek = calendar.dateByAddingComponents(offSetComponents, toDate: startOfThisWeek, options: nil)