What's the simplest way to loop from one date to another?
What I want conceptually is something like this:
for (NSDate *date = [[startDate copy] autorelease]; [date compare: endDate] < 0;
date = [date dateByAddingDays: 1]) {
// do stuff here
}
This doesn't work, of course: there's no dateByAddingDays:
. And even if it did, it would leave a wide trail of autoreleased objects waiting for their destruction.
Here's what I've thought of:
- I can't just add an
NSTimeInterval
, since the number of seconds in a day can vary. - I could break it down into
NSDateComponents
and add one day to the components, then reassemble it. But that's long and ugly code.
So I'm hoping someone has tried a few options for this, and found 开发者_运维技巧a good one. Any ideas?
Set up a oneDay date component constant and repeatedly add it:
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *oneDay = [[NSDateComponents alloc] init];
[oneDay setDay: 1];
for (id date = [[startDate copy] autorelease]; [date compare: endDate] <= 0;
date = [calendar dateByAddingComponents: oneDay
toDate: date
options: 0] ) {
NSLog( @"%@ in [%@,%@]", date, startDate, endDate );
}
This still leaves the trail of autoreleased objects, but dateByAddingComponents:toDate:options:
is responsible. Not sure anything can be done about that.
How about using date = [date dateByAddingTimeInterval:24 * 60 * 60] instead?
for (NSDate *date = [[startDate copy] autorelease]; [date compare: endDate] < 0;
date = [date dateByAddingTimeInterval:24 * 60 * 60] ) {
NSLog( @"%@ in [%@,%@]", date, startDate, endDate );
}
Add fast enumeration to a DateRange class:
- (NSUInteger)countByEnumeratingWithState: (NSFastEnumerationState *)state
objects: (id *)stackbuf
count: (NSUInteger)len;
{
NSInteger days = 0;
id current = nil;
id components = nil;
if (state->state == 0)
{
current = [NSCalendar currentCalendar];
state->mutationsPtr = &state->extra[0];
components = [current components: NSDayCalendarUnit
fromDate: startDate
toDate: endDate
options: 0];
days = [components day];
state->extra[0] = days;
state->extra[1] = (uintptr_t)current;
state->extra[2] = (uintptr_t)components;
} else {
days = state->extra[0];
current = (NSCalendar *)(state->extra[1]);
components = (NSDateComponents *)(state->extra[2]);
}
NSUInteger count = 0;
if (state->state <= days) {
state->itemsPtr = stackbuf;
while ( (state->state <= days) && (count < len) ) {
[components setDay: state->state];
stackbuf[count] = [current dateByAddingComponents: components
toDate: startDate
options: 0];
state->state++;
count++;
}
}
return count;
}
This is ugly, but the ugliness is confined to my date range class. My client code is just:
for (id date in dateRange) {
NSLog( @"%@ in [%@,%@]", date, startDate, endDate );
}
I think this is probably a good enough reason to create a DateRange class if you don't have one already.
精彩评论