Reputation: 1538
I have a situation where I need the monday before a certain date (certain date here being localtournament.entryDeadline). I tried the below, but it gives me back the same date. I found a few similar questions but none that can do this on iOS. It seems it should be easy, I actually like the Cocoa date framework, but I'm stumped for the moment on this.
What am I doing wrong? The result (which should always be a monday and isn't) is in localTournament.entryOpen.
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *comps = [calendar components:(NSYearCalendarUnit | NSWeekdayCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) fromDate:localTournament.entryDeadline]; //1=sunday, 2=monday, etc
if(comps.weekday > 2) {
//later in same week
[comps setWeekday:2];
[comps setHour:12];
localTournament.entryOpen = [calendar dateFromComponents:comps];
} else if(comps.weekday == 1) {
//sunday, go back a week
[comps setWeek:-1];
[comps setWeekday:2];
[comps setHour:12];
localTournament.entryOpen = [calendar dateByAddingComponents:comps toDate:localTournament.entryDeadline options:0];
} else {
//already monday, use previous week
[comps setWeek:-1];
[comps setHour:12];
localTournament.entryOpen = [calendar dateByAddingComponents:comps toDate:localTournament.entryDeadline options:0];
}
[calendar release];
Upvotes: 2
Views: 1194
Reputation:
To extrapolate Justin's answer, if you are wanting to work with weeks and weekdays, you should be creating a new NSDateComponent
object, that contains weekday
and weekOfYear
elements INSTEAD of day
and month
components. You may need a new temporary object for this.
Here is some code from my project, which finds next Friday but it's a similar idea: (calGergorian
and dcNow
are properties of my class, but should be self explanatory)
_dcNextWeekReminderTime = [[NSDateComponents alloc] init];
_dcNextWeekReminderTime.weekday = 6;
_dcNextWeekReminderTime.weekOfYear = self.dcNow.weekOfYear;
_dcNextWeekReminderTime.year = self.dcNow.year;
_dcNextWeekReminderTime.calendar = self.calGregorian;
//if the date we've just created is earlier than today...
if ([[self.calGregorian dateFromComponents:_dcNextWeekReminderTime] timeIntervalSinceDate:[self.calGregorian dateFromComponents:self.dcNow]] < 0) {
//...make it next week
_dcNextWeekReminderTime.weekOfYear +=1;
}
(Pardon my Hungarian notation)
To solve your problem, you'd basically change the >
to a <
in the if statement, and change +=1
to -=1
, and the number 6 (Friday) to 2 (Monday).
Also, unless you are working with an old iOS version, week
seems to be deprecated in favor of weekOfYear
.
Upvotes: 0
Reputation: 1538
The solution (below) was to just determine how many days back I needed to go and subtract.
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *comps = [calendar components:(NSYearCalendarUnit | NSWeekdayCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) fromDate:localTournament.entryDeadline]; //1=sunday, 2=monday, etc
if(comps.weekday > 2) {
//later in same week
[comps setHour:12];
localTournament.entryOpen = [calendar dateFromComponents:comps];
NSDateComponents *sparseComps = [[[NSDateComponents alloc] init] autorelease];
[sparseComps setDay:0-(comps.weekday-2)];
localTournament.entryOpen = [calendar dateByAddingComponents:sparseComps toDate:localTournament.entryOpen options:0];
} else if(comps.weekday == 1) {
//sunday, go back a week and add a day
[comps setHour:12];
localTournament.entryOpen = [calendar dateFromComponents:comps];
NSDateComponents *sparseComps = [[[NSDateComponents alloc] init] autorelease];
[sparseComps setWeek:-1];
[sparseComps setWeekday:1];
localTournament.entryOpen = [calendar dateByAddingComponents:sparseComps toDate:localTournament.entryOpen options:0];
} else {
//already monday, use previous week
[comps setHour:12];
localTournament.entryOpen = [calendar dateFromComponents:comps];
NSDateComponents *sparseComps = [[[NSDateComponents alloc] init] autorelease];
[sparseComps setWeek:-1];
localTournament.entryOpen = [calendar dateByAddingComponents:sparseComps toDate:localTournament.entryOpen options:0];
}
[calendar release];
Upvotes: 1
Reputation: 16973
If you specify both NSWeekdayCalendarUnit
and NSDayCalendarUnit
components, the NSCalendar
methods will prefer day information (which isn't being updated) over weekday information (which is). I would either remove NSDayCalendarUnit
entirely and replace it with NSWeekCalendarUnit
, or update the day instead of the weekday.
See the documentation for dateFromComponents: for more information.
Upvotes: 1