1

Given an arbitrary date, I need to find the date of the first day of the next week of the month. Note that it is not as simple as adding 7 days to the current date because the last week of the month may be less than 7 days. Here is the code I'm using now:

    NSCalendar* calendar = [NSCalendar currentCalendar];
    NSDateComponents* components = [calendar components:NSWeekOfMonthCalendarUnit|NSYearCalendarUnit|NSMonthCalendarUnit|NSWeekCalendarUnit|NSDayCalendarUnit fromDate:currentDate];

    NSLog(@"week of month: %ld", [components weekOfMonth]);

    [components setWeekOfMonth:[components weekOfMonth] + 1];
    NSLog(@"new week of month: %ld", [components weekOfMonth]); //week of month is now 2

    [components setWeekday:1];
    NSDate *nextWeek = [calendar dateFromComponents:components];

As an example, currentDate is set to 2012-10-01. In this example nextWeek is always 2012-10-01. It appears that sending setWeekOfMonth: does not increment the other date components in the NSDateComponents object. Do I have the wrong date components configured, or is setWeekOfMonth: not supposed to work like that?

Mike T
  • 1,163
  • 1
  • 11
  • 27
  • Assume your week starts from Monday, today is 27 dec, so you want 31Dec as your answer? – Anoop Vaidya Dec 27 '12 at 06:58
  • Yes, that's right, assuming the currentCalenar is is set to use Monday as the first day of the week. If it is set to use Sunday as the first day of the week, then nextWeek would be 30 Dec. – Mike T Dec 27 '12 at 07:03
  • StackOverflow: [NSCalendar first day of week](http://stackoverflow.com/questions/1106943/nscalendar-first-day-of-week) – Jay Dec 27 '12 at 07:33
  • @MikeT : I have posted another answer, kindly let me know, if this is again correct or not? – Anoop Vaidya Dec 28 '12 at 07:10

2 Answers2

8

So.... Let's start with an NSDate and an NSCalendar:

NSDate *date = ...;
NSCalendar *cal = [NSCalendar currentCalendar];

Figure out what day of the week that date is:

NSInteger weekdayOfDate = [cal ordinalityOfUnit:NSWeekdayCalendarUnit inUnit:NSWeekCalendarUnit forDate:date];
NSInteger numberOfDaysToStartOfCurrentWeek = weekdayOfDate - 1;

Let's move that date into the next week:

NSDateComponents *oneWeek = [[NSDateComponents alloc] init];
[oneWeek setWeek:1]; // add one week
[oneWeek setDay:-numberOfDaysToStartOfCurrentWeek]; // ... and subtract a couple of days to get the first day of the week
NSDate *startOfNextWeek = [cal dateByAddingComponents:oneWeek toDate:date options:0];

At this point, you have a date that points to the first day of the next week. Now we should verify that it's still in the same month:

NSDateComponents *monthOfNextWeek = [cal components:NSMonthCalendarUnit fromDate:startOfNextWeek];
NSDateComponents *monthOfThisWeek = [cal components:NSMonthCalendarUnit fromDate:date];
if ([monthOfNextWeek month] != [monthOfThisWeek month]) {
  // the first day of the next week is not in the same month as the start date
}

When I run this, I get that the start of next week is 30 Dec 2012 (a Sunday, because my calendar's weeks start on Sunday).

If, however, I want the first day of the week to start on Monday, I can preface this code with:

[cal setFirstWeekday:2]; // the first day of the week is the second day (ie, Monday, because Sunday = 1)

If I do this, then the startOfNextWeek results in 31 Dec 2012.

Dave DeLong
  • 242,470
  • 58
  • 448
  • 498
  • Could you explain why you subtract 1 from weekdayOfDate? I don't see how that gets you the number of days to the start of the current week. The rest I follow and I'll implement it asap and see how it works. – Mike T Dec 27 '12 at 17:26
  • @MikeT basically, because weekdays are 1-based, not 0-based. What the code does is two calculations in a single step: first add a week, and then subtract enough days to get to the start of the next week. `NSDateComponents` conveniently lets us do that in one step. – Dave DeLong Dec 27 '12 at 17:31
  • So if `date` corresponds to a Sunday (weekday 1), then `numberOfDaysToStartOfCurrentWeek` is `1 - 1`, or `0` (because it already is the start of the current week). So then add one week and subtract 0 days to get to the start of the next week. – Dave DeLong Dec 27 '12 at 17:33
  • This works except that I used [oneWeek setDay: [oneWeek day] - numberOfDaysToStartOfCurrentWeek]; so that day will never be set to 0 – Mike T Dec 29 '12 at 07:33
  • @MikeT it's just fine to set it to 0. If you don't want to set it to 0 however, you should do `if (numberOfDaysToStartOfCurrentWeek > 0) { ... }` – Dave DeLong Dec 29 '12 at 15:39
0

Will this be a valid answer :

NSDateFormatter *dateFormatter=[NSDateFormatter new];
[dateFormatter setLocale:[[NSLocale alloc]initWithLocaleIdentifier:@"en_US_POSIX"]];
[dateFormatter setDateFormat:@"EEE"];

NSDate *date=[NSDate date];
NSString *dateString=[dateFormatter stringFromDate:date];

NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier: NSGregorianCalendar];
NSDateComponents *components = [NSDateComponents new];

[calendar setFirstWeekday:1];//1 for Mon

NSDate *newDate=date;

while (![dateString isEqualToString:@"Mon"]) {
    components.day = 1;
    newDate = [calendar dateByAddingComponents:components toDate:newDate options:0];
    dateString=[dateFormatter stringFromDate:newDate];
}
NSLog(@"Upcoming week Date=%@",newDate);
Anoop Vaidya
  • 46,283
  • 15
  • 111
  • 140
  • If you go this route, you must also set the locale of the dateFormatter to `en_US_POSIX`, because this code will break depending on the system's locale. (For example, if this is run on a spanish-speaker's system, `@"EEE"` gets rendered as `@"Lun"`, not `@"Mon"`) – Dave DeLong Dec 29 '12 at 15:41
  • @DaveDeLong : OMG... I am really happy to learn a lot from SO and also from you. Thanks sir. i will update the answer. – Anoop Vaidya Dec 29 '12 at 15:45