0

I'm trying to find the first day of weeks using DateTools like so:

for (NSInteger week = 46; week <= 53; week++) {
    NSDate *tempDate = [NSDate dateWithString:[NSString stringWithFormat:@"2015-%d", (int)week] formatString:@"Y-w"];

    NSLog(@"INFO: tempDate: %@, day: %.2d, week: %d", tempDate, (int)[tempDate day], (int)week);
}

for (NSInteger week = 1; week <= 5; week++) {
    NSDate *tempDate = [NSDate dateWithString:[NSString stringWithFormat:@"2016-%d", (int)week] formatString:@"Y-w"];

    NSLog(@"INFO: tempDate: %@, day: %.2d, week: %d", tempDate, (int)[tempDate day], (int)week);
}

and I get this output:

INFO: tempDate: 2015-11-07 22:00:00 +0000, day: 08, week: 46
INFO: tempDate: 2015-11-14 22:00:00 +0000, day: 15, week: 47
INFO: tempDate: 2015-11-21 22:00:00 +0000, day: 22, week: 48
INFO: tempDate: 2015-11-28 22:00:00 +0000, day: 29, week: 49
INFO: tempDate: 2015-12-05 22:00:00 +0000, day: 06, week: 50
INFO: tempDate: 2015-12-12 22:00:00 +0000, day: 13, week: 51
INFO: tempDate: 2015-12-19 22:00:00 +0000, day: 20, week: 52
INFO: tempDate: 2015-12-26 22:00:00 +0000, day: 27, week: 53
INFO: tempDate: 2015-12-26 22:00:00 +0000, day: 27, week: 1
INFO: tempDate: 2016-01-02 22:00:00 +0000, day: 03, week: 2
INFO: tempDate: 2016-01-09 22:00:00 +0000, day: 10, week: 3
INFO: tempDate: 2016-01-16 22:00:00 +0000, day: 17, week: 4
INFO: tempDate: 2016-01-23 22:00:00 +0000, day: 24, week: 5

and as you can see, the week 53 from 2015 has the same day as the week 1 from 2016 (This site tells me that there are 53 weeks in 2015).

Actually, the week 1 from 2016 starts from 04.01.2016.

Also, notice the dateWithString:formatString: gives me the previous day of the first day of the week. Why is that? I can simply use dateByAddingDays:1 but I don't know if it's hackish and the problem should be solved somewhere else.

I tried using NSDateComponents as @DarkDust mentioned, to no avail. So this:

for (NSInteger week = 1; week <= 5; week++) {
    NSDate *tempDate = [NSDate dateWithString:[NSString stringWithFormat:@"2016-%d", (int)week] formatString:@"Y-w"];

    NSDateComponents *dateComponents = [NSDateComponents new];

    dateComponents.year = 2016;
    dateComponents.weekOfYear = week;

    NSLog(@"INFO: tempDate: %@, day: %.2d, week: %d = %@", tempDate, (int)[tempDate day], (int)week, [calendar dateFromComponents:dateComponents]);
}

gives me this:

INFO: tempDate: 2015-12-26 22:00:00 +0000, day: 27, week: 1 = 2015-12-31 22:00:00 +0000
INFO: tempDate: 2016-01-02 22:00:00 +0000, day: 03, week: 2 = 2015-12-31 22:00:00 +0000
INFO: tempDate: 2016-01-09 22:00:00 +0000, day: 10, week: 3 = 2015-12-31 22:00:00 +0000
INFO: tempDate: 2016-01-16 22:00:00 +0000, day: 17, week: 4 = 2015-12-31 22:00:00 +0000
INFO: tempDate: 2016-01-23 22:00:00 +0000, day: 24, week: 5 = 2015-12-31 22:00:00 +0000

Here is the DateTools' dateWithString:formatString: implementation:

+ (NSDate *)dateWithString:(NSString *)dateString formatString:(NSString *)formatString {

    return [self dateWithString:dateString formatString:formatString timeZone:[NSTimeZone systemTimeZone]];
}

+ (NSDate *)dateWithString:(NSString *)dateString formatString:(NSString *)formatString timeZone:(NSTimeZone *)timeZone {

    static NSDateFormatter *parser = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        parser = [[NSDateFormatter alloc] init];
    });

    parser.dateStyle = NSDateFormatterNoStyle;
    parser.timeStyle = NSDateFormatterNoStyle;
    parser.timeZone = timeZone;
    parser.dateFormat = formatString;

    return [parser dateFromString:dateString];
}

As for the duplicate report:

The top 3 are wrong, 2 of them with downvotes, and they don't even do what I need at all.

Iulian Onofrei
  • 9,188
  • 10
  • 67
  • 113
  • Yikes. I suggest you look into `NSDateComponents` instead of doing string parsing for dates. – DarkDust Dec 04 '15 at 13:23
  • @DarkDust, What do you mean? I have week of year dates in `NSString` format like `@"2015-52"`, `@"2015-53"`, `@"2016-1"`, `@"2016-2"` and I need `NSDate`s representing the first day of each week. – Iulian Onofrei Dec 04 '15 at 13:25
  • 1
    this link may help you [stackOverFlow](http://stackoverflow.com/questions/1889164/get-nsdate-today-yesterday-this-week-last-week-this-month-last-month-var) – Alexandr Kolesnik Dec 04 '15 at 13:38
  • @АлександрКолесник, That question is from 2009, and so are the most answer. – Iulian Onofrei Dec 04 '15 at 13:41
  • So? That answer can still help you. Nothing drastic has changed since thing. – Robert J. Clegg Dec 04 '15 at 13:46
  • @Tander, What answer? The top 3 are wrong, 2 of them with downvotes, and they don't even do what I need at all. – Iulian Onofrei Dec 04 '15 at 13:57
  • What I meant was that parsing date strings is very slow. Using `NSDateComponents` and `-[NSCalendar dateFromComponents:]` is faster and more reliable for these things. Create a component, set the year and week, call `dateFromComponents:`. That doesn't solve your problem (haven't got the time right now to help you, sorry) but you're getting rid of the slow and *thread-unsafe* `NSDateFormatter`. – DarkDust Dec 04 '15 at 14:08
  • And isn't NSDateComponent's `weekOfYear` what you need for your problem, BTW? I mean, set `year` to 2016 and `weekOfYear` to 1, then get `dateFromComponents:`. – DarkDust Dec 04 '15 at 14:15
  • @DarkDust, I guess it is, I'll make some tests when I have some time, thanks for the help. – Iulian Onofrei Dec 04 '15 at 14:16
  • @DarkDust, I have updated my question. – Iulian Onofrei Dec 04 '15 at 15:23

2 Answers2

0

This is a bad idea what you are doing. You must understand a date is a time stamp which can be interpreted differently depending on the time zone and the calendar you are using. As it was already mentioned in comments you should use date components for your solution. Note that printing out the date may use a different format and the result may not be expected.

Next a first weekday in a year depends on definition. If I remember correctly some standards (or all) will treat the first week of the year depending on what day of week is the first day. In other words if 1.1 is sunday then the first week of the year is in december but if it is tuesday then it is in january.

So if you want to find the beginning of the first monday of the given year the code should look something like this (I did not test it):

+ (NSDate *)firstWeekInYear:(NSInteger)year {

        NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar];

        NSDate *toReturn = nil;
        NSDateComponents *components = [[NSDateComponents alloc] init];
        components.year = year;
        NSDate *beginningOfTheYear = [calendar dateFromComponents:components];
        NSInteger day = [calendar component:NSCalendarUnitWeekday fromDate:beginningOfTheYear];
        NSInteger daysToAdd = (8-day)%7;

        toReturn = [calendar dateByAddingUnit:NSCalendarUnitDay value:daysToAdd toDate:beginningOfTheYear options:kNilOptions];

        return toReturn;
    }

So you need to choose the calendar, create date components with a target year, get the date from those components with the calendar to get the beginning of the year. Then find out what weekday that is and increase such a number of days so the result is the beginning of the first monday in a year.

Iulian Onofrei
  • 9,188
  • 10
  • 67
  • 113
Matic Oblak
  • 16,318
  • 3
  • 24
  • 43
  • Also, I need the first day of each week, not just the first one in the year. – Iulian Onofrei Dec 04 '15 at 15:07
  • 1
    Using Matic's solution you get the first week day of the year (also pay attention to whether the calendar considers Sunday or Monday as start of the week; `firstWeekday`!). You can then get the date of week X by adding the number of weeks using `- dateByAddingUnit:value:toDate:options:`. – DarkDust Dec 04 '15 at 15:35
  • I think about everyone agrees that the first week of a year is the one where at least four days fall into the year. Where they don't agree is which one is the first day of the week, for example that is different between USA and Europe. – gnasher729 Dec 17 '15 at 17:01
0

I finally figured it out. @Matic's solution doesn't work in iOS 7 and it's hard to understand, so I managed to find a simpler solution that works on iOS 7 too:

+ (NSDate *)getFirstDayInWeek:(NSInteger)week ofYear:(NSInteger)year {

    /* create the calendar only once */

    static NSCalendar *calendar = nil;
    static dispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{
        calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];

        calendar.firstWeekday = 2;
        calendar.minimumDaysInFirstWeek = 4;
    });

    NSDateComponents *components = [NSDateComponents new]; // create an empty date components object

    components.year = year;
    components.weekOfYear = week; // set the number of the week in the year
    components.weekday = calendar.firstWeekday; // important! set the result date's day of week

    return [calendar dateFromComponents:components];
}
Iulian Onofrei
  • 9,188
  • 10
  • 67
  • 113