Apollo
Apollo

Reputation: 9064

Generate consecutive sequence of NSDates

Given some startDate, I would like to degenerate x number of consecutive days after this startDate. I'm attempting to use the following code:

// Generate dates
self.days = [[NSMutableArray alloc] init];
NSDate *startDate = [NSDate date];

NSCalendar *theCalendar = [NSCalendar currentCalendar];
NSDateComponents *dayComponent = [[NSDateComponents alloc] init];
dayComponent.day = 1;

for (int i = 1; i < self.mygoal.goalDays; i++) {
    [self.days addObject:startDate];
    startDate = [theCalendar dateByAddingComponents:dayComponent toDate:startDate options:0];
}

Question: Is the reassignment of startDate ok, given that I'm adding the same object to self.days?

Upvotes: 0

Views: 80

Answers (2)

vikingosegundo
vikingosegundo

Reputation: 52227

Creating a sequence of dates is not as trivial as it sounds. Actually it is covered in the great WWDC2011 video «Performing Calendar Calculations».

You are adding in every loop a day to the last date. But actually this will fail in timezones with DST if the time is in the hour that is changed for the day of switching and for any following days as the dates will be nil.

If you instead change the date components i the loop and add it to the original satrtdate, it will only effect the day of DST-switching.

To also handle that you can set the hour of the start date to something safe — as noon — as all switches are performed at night hours.

With all this in mind I would use something like this to create a sequence of days with times set to start of day:

NSUInteger numberOfDays = 10;
NSCalendar *cal = [NSCalendar currentCalendar];
NSDate *startDate = [cal dateFromComponents:({
    NSDateComponents *comps = [[NSDateComponents alloc] init];
    comps.year = 2015;
    comps.month = 1;
    comps.day = 2;
    comps.hour = 12; // for DST-safety
    comps;
})];


NSMutableArray *dates = [@[] mutableCopy];

for (NSUInteger i =0 ; i < numberOfDays; ++i) {
    NSDateComponents *comps = [[NSDateComponents alloc] init];
    comps.day = i;
    NSDate *date = [cal dateByAddingComponents:comps
                                        toDate:startDate
                                       options:0];

    // set date to beginning of day
    [cal rangeOfUnit:NSCalendarUnitDay
           startDate:&date
            interval:NULL
             forDate:date];

    [dates addObject:date];
}

So, yes, reassignment is technically OK, but in this particular case it is might cause unexpected trouble.

Upvotes: 3

Fabio Ritrovato
Fabio Ritrovato

Reputation: 2616

It's fine because you're not actually adding the same object. dateByAddingComponents: returns a new object, so when you assign it to startDate you are replacing the reference to your old object to a reference to the new one

Upvotes: 0

Related Questions