MatterGoal
MatterGoal

Reputation: 16430

Get the first and last Weekdays. Strange behaviour for first and last Weeks of the Year

I want to obtain the first and the last day of a given week (number) for a given year. The function that I wrote works except for the last and the first week of the year.

For example, if I ask for the weekday 1 and 7 of the week 1 for the year 2014 I get the first week of the 2015!!!

2014-12-28 // weekday 1
2015-01-03 // weekday 7 

But the right result should be!

2013-12-29 // weekday 1  
2014-01-04 // weekday 7 

If I ask for week 51 of 2013 I correctly receive:

2013-12-15 // weekday 1
2013-12-21 // weekday 7

Here my function, how can I fix this strange behaviour?!

// Return the date which is the weekday for a given week number and year
+ (NSDate*)weekDay:(NSInteger)weekday forWeekOfYear:(NSInteger)week year:(NSInteger)year{

    // Date component
    NSDateComponents *comp = [[NSDateComponents alloc]init];
    [comp setWeekOfYear:week];
    [comp setWeekday:weekday];
    [comp setYear:year];

    NSCalendar *calendar = [NSCalendar currentCalendar];
    NSDate *date = [calendar dateFromComponents:comp];

    NSLog(@"week %d year %d weekday %d\n%@", week, year, weekday, date);
    return date;
}

EDIT -------------

Following @Guillaume answer I've modified my code using setWeekOfYear instead of setYear. It partially worked, I correctly get the last day of the week, but as first weekday I get the first day of the next week. Now I get this error with any weeks number, not only the first or the last of the year.

Here the new result for week 1 of 2014:

2014-01-05 // weekday1... it should be 2013-12-29. damn!
2014-01-04 // weekday7... it should be 2014-01-04. great! 

Just as information I call my Category function with this code:

self.fromDate = [NSDate weekDay:1 forWeekOfYear:self.selectedWeek year:self.selectedYear];
self.toDate = [NSDate weekDay:7 forWeekOfYear:self.selectedWeek year:self.selectedYear];

Upvotes: 0

Views: 291

Answers (4)

vikingosegundo
vikingosegundo

Reputation: 52227

I get this result

2013-12-18 14:57:48.090 datecal[20740:303] week 1 year 2014 weekday 1 29/12/2013 00:00:00
2013-12-18 14:57:48.091 datecal[20740:303] week 1 year 2014 weekday 7 04/01/2014 00:00:00

for this code (Sunday first day of the week):

#import <Foundation/Foundation.h>

@interface NSDate (WeekBoundries)
+ (NSDate*)weekDay:(NSInteger)weekday forWeekOfYear:(NSInteger)week year:(NSInteger)year;
@end

@implementation NSDate (WeekBoundries)
static NSUInteger SUNDAY = 1;
static NSUInteger MONDAY = 2;
static NSUInteger SATURDAY = 7;

+ (NSDate*)weekDay:(NSInteger)weekday forWeekOfYear:(NSInteger)week year:(NSInteger)year{

    // Date component
    NSDateComponents *comp = [[NSDateComponents alloc]init];
    [comp setWeekOfYear:week];
    [comp setWeekday:weekday];
    [comp setYearForWeekOfYear:year];

    NSCalendar *calendar = [NSCalendar currentCalendar];

    calendar.locale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"];
    calendar.firstWeekday = SUNDAY;
    NSDate *date = [calendar dateFromComponents:comp];

    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    [formatter setDateFormat:[NSDateFormatter dateFormatFromTemplate:@"yyyy-MM-dd HH:mm:ss"
                                                             options:0
                                                              locale:[NSLocale currentLocale]]];
    NSLog(@"week %ld year %ld weekday %ld %@", (long)week, (long)year, (long)weekday, [formatter stringFromDate:date]);
    return date;
}

@end


int main(int argc, const char * argv[])
{

    @autoreleasepool {

        NSDate *fromDate = [NSDate weekDay:SUNDAY forWeekOfYear:1 year:2014];
        NSDate *toDate = [NSDate weekDay:SATURDAY forWeekOfYear:1 year:2014];

    }
    return 0;
}

if you want Monday be first day of the week, change:

calendar.firstWeekday = SUNDAY;

to

calendar.firstWeekday = MONDAY;

and

NSDate *fromDate = [NSDate weekDay:SUNDAY forWeekOfYear:1 year:2014];
NSDate *toDate = [NSDate weekDay:SATURDAY forWeekOfYear:1 year:2014];

to

NSDate *fromDate = [NSDate weekDay:MONDAY forWeekOfYear:1 year:2014];
NSDate *toDate = [NSDate weekDay:SUNDAY forWeekOfYear:1 year:2014];

if you mix it up like

calendar.firstWeekday = MONDAY;
NSDate *fromDate = [NSDate weekDay:SUNDAY forWeekOfYear:1 year:2014];
NSDate *toDate = [NSDate weekDay:SATURDAY forWeekOfYear:1 year:2014];

you'll get the behaviour you describe in your edit, there-for it is apparent, that your calendar has Monday as start of the week, will you fill in a sunday and a saturday.


If you want to respect the users locale, you can do this:

@interface NSDate (WeekBoundries)
+ (NSDate*)weekDay:(NSInteger)weekday forWeekOfYear:(NSInteger)week year:(NSInteger)year;
@end

@implementation NSDate (WeekBoundries)


+ (NSDate*)weekDay:(NSInteger)weekday forWeekOfYear:(NSInteger)week year:(NSInteger)year{

    NSDateComponents *comp = [[NSDateComponents alloc]init];
    [comp setWeekOfYear:week];
    [comp setWeekday:weekday];
    [comp setYearForWeekOfYear:year];

    NSCalendar *calendar = [NSCalendar currentCalendar];

    NSDate *date = [calendar dateFromComponents:comp];

    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    [formatter setDateFormat:[NSDateFormatter dateFormatFromTemplate:@"yyyy-MM-dd HH:mm:ss"
                                                             options:0
                                                              locale:[NSLocale currentLocale]]];
    NSLog(@"week %ld year %ld weekday %ld %@", (long)week, (long)year, (long)weekday, [formatter stringFromDate:date]);
    return date;
}

@end

-(void)method
{
        static NSUInteger SUNDAY = 1;
        static NSUInteger MONDAY = 2;
        static NSUInteger SATURDAY = 7;

        NSCalendar *calendar = [NSCalendar currentCalendar];

        NSDate *fromDate = [NSDate weekDay:(calendar.firstWeekday == MONDAY)? MONDAY : SUNDAY forWeekOfYear:1 year:2014];
        NSDate *toDate = [NSDate weekDay:(calendar.firstWeekday == MONDAY)? SUNDAY : SATURDAY forWeekOfYear:1 year:2014];
}

Upvotes: 1

Andy Kaminski
Andy Kaminski

Reputation: 142

Have you worked it out yet?

Try:

int week = 0;
int weekday = 0; 
int year = 2014;
[comp setWeekOfYear:week];
[comp setWeekday:weekday];
[comp setYear:year];

NSCalendar *calendar = [NSCalendar currentCalendar];
NSDate *date = [calendar dateFromComponents:comp];

NSLog(@"week %d year %d weekday %d\n%@", week, year, weekday, date);

Upvotes: -1

Guillaume
Guillaume

Reputation: 4361

Did you try setYearForWeekOfYear: instead of setYear:?

In NSCalendar there is also a property minimumDaysInFirstWeek that might be worth looking at...

Upvotes: 2

Apurv
Apurv

Reputation: 17186

You are creating the wrong object of calendar.

Create it by below way:

NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar];

Upvotes: 0

Related Questions