John
John

Reputation: 1538

Finding Monday previous to current day on iOS

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

Answers (3)

user1285464
user1285464

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

John
John

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

Justin Spahr-Summers
Justin Spahr-Summers

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

Related Questions