Skip to content

Commit

Permalink
Two calendars are better than one.
Browse files Browse the repository at this point in the history
Previous 5× speed-up required assistance from the test program (setting the default output time zone to the time zone returned from an initial parse). Now it's official: ISO8601DateFormatter gets its 5× speed-up from calendar-caching without assistance from the test app.
  • Loading branch information
Peter Hosey committed Oct 15, 2011
1 parent 31069a8 commit 75964c2
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 16 deletions.
3 changes: 2 additions & 1 deletion ISO8601DateFormatter.h
Expand Up @@ -39,7 +39,8 @@ extern unichar ISO8601DefaultTimeSeparatorCharacter;
NSString *lastUsedFormatString;
NSDateFormatter *unparsingFormatter;

NSCalendar *calendar;
NSCalendar *parsingCalendar, *unparsingCalendar;

NSTimeZone *defaultTimeZone;
ISO8601DateFormat format;
unichar timeSeparator;
Expand Down
37 changes: 22 additions & 15 deletions ISO8601DateFormatter.m
Expand Up @@ -33,11 +33,17 @@ - (NSString *) weekDateStringForDate:(NSDate *)date timeZone:(NSTimeZone *)timeZ

@implementation ISO8601DateFormatter

- (NSCalendar *) makeCalendarWithDesiredConfiguration {
NSCalendar *calendar = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];
calendar.firstWeekday = 2; //Monday
calendar.timeZone = [NSTimeZone defaultTimeZone];
return calendar;
}

- (id) init {
if ((self = [super init])) {
calendar = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];
calendar.firstWeekday = 2; //Monday
calendar.timeZone = [NSTimeZone defaultTimeZone];
parsingCalendar = [[self makeCalendarWithDesiredConfiguration] retain];
unparsingCalendar = [[self makeCalendarWithDesiredConfiguration] retain];

format = ISO8601DateFormatCalendar;
timeSeparator = ISO8601DefaultTimeSeparatorCharacter;
Expand All @@ -51,7 +57,8 @@ - (void) dealloc {

[unparsingFormatter release];
[lastUsedFormatString release];
[calendar release];
[parsingCalendar release];
[unparsingCalendar release];

[super dealloc];
}
Expand All @@ -62,7 +69,7 @@ - (void) setDefaultTimeZone:(NSTimeZone *)tz {
[defaultTimeZone release];
defaultTimeZone = [tz retain];

calendar.timeZone = defaultTimeZone;
unparsingCalendar.timeZone = defaultTimeZone;
}
}

Expand Down Expand Up @@ -136,7 +143,7 @@ - (NSDateComponents *) dateComponentsFromString:(NSString *)string timeZone:(out
NSDate *now = [NSDate date];

NSDateComponents *components = [[[NSDateComponents alloc] init] autorelease];
NSDateComponents *nowComponents = [calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) fromDate:now];
NSDateComponents *nowComponents = [parsingCalendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) fromDate:now];

NSUInteger
//Date
Expand Down Expand Up @@ -594,9 +601,9 @@ - (NSDate *) dateFromString:(NSString *)string timeZone:(out NSTimeZone **)outTi
NSDateComponents *components = [self dateComponentsFromString:string timeZone:&timeZone range:outRange];
if (outTimeZone)
*outTimeZone = timeZone;
calendar.timeZone = timeZone;
parsingCalendar.timeZone = timeZone;

return [calendar dateFromComponents:components];
return [parsingCalendar dateFromComponents:components];
}

- (BOOL)getObjectValue:(id *)outValue forString:(NSString *)string errorDescription:(NSString **)error {
Expand Down Expand Up @@ -648,7 +655,7 @@ - (NSString *) stringFromDate:(NSDate *)date formatString:(NSString *)dateFormat
if (includeTime)
dateFormat = [dateFormat stringByAppendingFormat:@"'T'%@", [self replaceColonsInString:ISO_TIME_FORMAT withTimeSeparator:self.timeSeparator]];

calendar.timeZone = timeZone;
unparsingCalendar.timeZone = timeZone;

if (dateFormat != lastUsedFormatString) {
[unparsingFormatter release];
Expand All @@ -662,7 +669,7 @@ - (NSString *) stringFromDate:(NSDate *)date formatString:(NSString *)dateFormat
unparsingFormatter = [[NSDateFormatter alloc] init];
unparsingFormatter.formatterBehavior = NSDateFormatterBehavior10_4;
unparsingFormatter.dateFormat = dateFormat;
unparsingFormatter.calendar = calendar;
unparsingFormatter.calendar = unparsingCalendar;
}

NSString *str = [unparsingFormatter stringForObjectValue:date];
Expand All @@ -677,7 +684,7 @@ - (NSString *) stringFromDate:(NSDate *)date formatString:(NSString *)dateFormat
}

//Undo the change we made earlier
calendar.timeZone = self.defaultTimeZone;
unparsingCalendar.timeZone = self.defaultTimeZone;

return str;
}
Expand All @@ -694,14 +701,14 @@ - (NSString *) stringForObjectValue:(id)value {
* http://personal.ecu.edu/mccartyr/ISOwdALG.txt
*/
- (NSString *) weekDateStringForDate:(NSDate *)date timeZone:(NSTimeZone *)timeZone {
calendar.timeZone = timeZone;
NSDateComponents *components = [calendar components:NSYearCalendarUnit | NSWeekdayCalendarUnit | NSDayCalendarUnit fromDate:date];
unparsingCalendar.timeZone = timeZone;
NSDateComponents *components = [unparsingCalendar components:NSYearCalendarUnit | NSWeekdayCalendarUnit | NSDayCalendarUnit fromDate:date];

//Determine the ordinal date.
NSDateComponents *startOfYearComponents = [calendar components:NSYearCalendarUnit fromDate:date];
NSDateComponents *startOfYearComponents = [unparsingCalendar components:NSYearCalendarUnit fromDate:date];
startOfYearComponents.month = 1;
startOfYearComponents.day = 1;
NSDateComponents *ordinalComponents = [calendar components:NSDayCalendarUnit fromDate:[calendar dateFromComponents:startOfYearComponents] toDate:date options:0];
NSDateComponents *ordinalComponents = [unparsingCalendar components:NSDayCalendarUnit fromDate:[unparsingCalendar dateFromComponents:startOfYearComponents] toDate:date options:0];
ordinalComponents.day += 1;

enum {
Expand Down

0 comments on commit 75964c2

Please sign in to comment.