Skip to content

Instantly share code, notes, and snippets.

@AnuragMishra
Created September 8, 2013 05:45
Show Gist options
  • Save AnuragMishra/6482177 to your computer and use it in GitHub Desktop.
Save AnuragMishra/6482177 to your computer and use it in GitHub Desktop.
Date parsing performance comparison
#import <Foundation/Foundation.h>
#include <time.h>
#include <xlocale.h>
#import "sqlite3.h"
#import "ISO8601DateFormatter.h"
#define LOG_DATE 0
static NSUInteger count = 1000000;
typedef int64_t timestamp;
NSUInteger randomNumberInRange(NSUInteger start, NSUInteger end);
// Create a sample date using the ISO-8601 format.
// 2013-04-23T16:29:05Z
NSString* generateSampleDate();
// Create an array of <count> dates in the ISO-8601 format.
NSArray *generateSampleDates(NSUInteger count);
// Parse all given dates using SQLite's strftime function
void parseDatesUsingSQLite(NSArray *dates);
// Parse all given dates using NSDateFormatter
void parseDatesUsingNSDateFormatter(NSArray *dates);
// Use SQLite implementation directly
void parseDatesUsingSQLiteImpl(NSArray *dates);
// Use the library IS08601 written by Peter Hosey
void parseDatesUsingISO8601Parser(NSArray *dates);
// Use strptime and gmtime from time.h
void parseDatesUsingGMTime(NSArray *dates);
timestamp unixDate(int year, int month, int day, int hour, int minute, int second);
static NSDateFormatter *dateFormatter = nil;
static ISO8601DateFormatter *isoDateFormatter = nil;
int main()
{
@autoreleasepool
{
printf("Generating sample data with %lu dates\n", count);
NSArray *dates = generateSampleDates(count);
printf("Sample data generation complete. Commencing tests...\n\n");
NSDate *start = nil;
NSDate *end = nil;
start = [NSDate date];
parseDatesUsingSQLite(dates);
end = [NSDate date];
printf("sqlite3 took %4.3f seconds\n", [end timeIntervalSinceDate:start]);
start = [NSDate date];
parseDatesUsingNSDateFormatter(dates);
end = [NSDate date];
printf("NSDateFormatter took %4.3f seconds\n", [end timeIntervalSinceDate:start]);
start = [NSDate date];
parseDatesUsingSQLiteImpl(dates);
end = [NSDate date];
printf("SQLite's implementation in C took %4.3f seconds\n", [end timeIntervalSinceDate:start]);
start = [NSDate date];
parseDatesUsingISO8601Parser(dates);
end = [NSDate date];
printf("ISO8601DateFormatter took %4.3f seconds\n", [end timeIntervalSinceDate:start]);
start = [NSDate date];
parseDatesUsingGMTime(dates);
end = [NSDate date];
printf("strptime/gmtime took %4.3f seconds\n", [end timeIntervalSinceDate:start]);
}
return 0;
}
NSArray *generateSampleDates(NSUInteger count)
{
NSMutableArray *dates = [NSMutableArray array];
for (int i = 0; i < count; i++)
{
[dates addObject:generateSampleDate()];
}
return dates;
}
NSString* generateSampleDate()
{
NSUInteger year = randomNumberInRange(1980, 2013);
NSUInteger month = randomNumberInRange(1, 12);
NSUInteger date = randomNumberInRange(1, 28);
NSUInteger hour = randomNumberInRange(0, 23);
NSUInteger minute = randomNumberInRange(0, 59);
NSUInteger second = randomNumberInRange(0, 59);
NSString *dateString = [NSString stringWithFormat:@"%lu-%02lu-%02luT%02lu:%02lu:%02luZ",
year,
month,
date,
hour,
minute,
second
];
return dateString;
}
void parseDatesUsingSQLiteImpl(NSArray *dates)
{
static const char *scanFormat = "%d-%d-%dT%d:%d:%d";
int year, month, date, hour, minute, second;
for (NSString *dateString in dates)
{
sscanf(dateString.UTF8String, scanFormat, &year, &month, &date, &hour, &minute, &second);
timestamp interval = unixDate(year, month, date, hour, minute, second);
NSDate *date = [NSDate dateWithTimeIntervalSince1970:interval];
#if LOG_DATE
NSLog(@"%@", date);
#endif
}
}
void parseDatesUsingSQLite(NSArray *dates)
{
sqlite3 *db = NULL;
sqlite3_open(":memory:", &db);
sqlite3_stmt *statement = NULL;
sqlite3_prepare_v2(db, "SELECT strftime('%s', ?);", -1, &statement, NULL);
for (NSString *dateString in dates)
{
sqlite3_bind_text(statement, 1, [dateString UTF8String], -1, SQLITE_STATIC);
sqlite3_step(statement);
timestamp value = sqlite3_column_int64(statement, 0);
NSDate *date = [NSDate dateWithTimeIntervalSince1970:value];
#if LOG_DATE
NSLog(@"%@", date);
#endif
sqlite3_clear_bindings(statement);
sqlite3_reset(statement);
}
}
void parseDatesUsingNSDateFormatter(NSArray *dates)
{
if (dateFormatter == nil)
{
dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss'Z'"];
[dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
}
for (NSString *dateString in dates)
{
NSDate *date = [dateFormatter dateFromString:dateString];
#if LOG_DATE
NSLog(@"%@", date);
#endif
}
}
NSUInteger randomNumberInRange(NSUInteger start, NSUInteger end)
{
NSUInteger span = end - start;
return start + arc4random_uniform(span);
}
timestamp unixDate(int year, int month, int day, int hour, int minute, int second)
{
int century, b, x1, x2;
int64_t julianDay;
if (month <= 2)
{
year--;
month += 12;
}
century = year / 100;
b = 2 - century + (century / 4);
x1 = 36525 * (year + 4716) / 100;
x2 = 306001 * (month + 1) / 10000;
julianDay = (int64_t)((x1 + x2 + day + b - 1524.5 ) * 86400000);
julianDay += (hour * 3600000) + (minute * 60000) + (int64_t)(second * 1000);
int64_t unixTime = (julianDay / 1000) - (21086676 * (int64_t)10000);
return unixTime;
}
void parseDatesUsingISO8601Parser(NSArray *dates)
{
[NSTimeZone setDefaultTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:+0]];
if (isoDateFormatter == nil)
{
isoDateFormatter = [[ISO8601DateFormatter alloc] init];
isoDateFormatter.parsesStrictly = YES;
}
for (NSString *dateString in dates)
{
NSDate *date = [isoDateFormatter dateFromString:dateString];
#if LOG_DATE
NSLog(@"%@", date);
#endif
}
}
void parseDatesUsingGMTime(NSArray *dates)
{
struct tm sometime;
const char *formatString = "%Y-%m-%dT%H:%M:%SZ";
for (NSString *date in dates)
{
strptime_l([date UTF8String], formatString, &sometime, NULL);
NSDate *date = [NSDate dateWithTimeIntervalSince1970: timegm(&sometime)];
#if LOG_DATE
NSLog(@"%@", date);
#endif
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment