Skip to content

Commit

Permalink
[Issue #39] Adding RFC 2822 timestamp transformer
Browse files Browse the repository at this point in the history
  • Loading branch information
mattt committed Jun 22, 2014
1 parent e6fbaa3 commit ff4a698
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 1 deletion.
2 changes: 1 addition & 1 deletion Example/main.m
Expand Up @@ -57,7 +57,7 @@ int main(int __unused argc, const char __unused *argv[]) {
NSLog(@"%@ (Reversed): %@", value, [[NSValueTransformer valueTransformerForName:name] reverseTransformedValue:value]);
}];

[@[TTTISO8601DateTransformerName] enumerateObjectsUsingBlock:^(id name, __unused NSUInteger idx, __unused BOOL *stop) {
[@[TTTISO8601DateTransformerName, TTTRFC2822DateTransformerName] enumerateObjectsUsingBlock:^(id name, __unused NSUInteger idx, __unused BOOL *stop) {
NSValueTransformer *transformer = [NSValueTransformer valueTransformerForName:name];
NSLog(@"%@ (Timestamp): %@", name, [transformer transformedValue:[NSDate date]]);
NSLog(@"%@ (Date): %@", name, [transformer reverseTransformedValue:[transformer transformedValue:[NSDate date]]]);
Expand Down
5 changes: 5 additions & 0 deletions TransformerKit/TTTDateTransformers.h
Expand Up @@ -27,6 +27,11 @@
*/
extern NSString * const TTTISO8601DateTransformerName;

/**
@warning Because `time.h` represents timestamps as 32-bit integers, times before 00:00::00 UTC on Thursday, January 1, 1970 and after 03:14:07 UTC on Tuesday, 19 January 2038 cannot be represented.
*/
extern NSString * const TTTRFC2822DateTransformerName;

@interface TTTDateTransformers : NSObject

@end
91 changes: 91 additions & 0 deletions TransformerKit/TTTDateTransformers.m
Expand Up @@ -28,6 +28,7 @@
#include <xlocale.h>

NSString * const TTTISO8601DateTransformerName = @"TTTISO8601DateTransformerName";
NSString * const TTTRFC2822DateTransformerName = @"TTTRFC2822DateTransformerName";

static NSString * TTTISO8601TimestampFromDate(NSDate *date) {
static NSDateFormatter *_iso8601DateFormatter = nil;
Expand Down Expand Up @@ -85,6 +86,90 @@
return [NSDate dateWithTimeIntervalSince1970:mktime(&time) + milliseconds];
}

static NSString * TTTRFC2822TimestampFromDate(NSDate *date) {
static NSDateFormatter *_rfc2822DateFormatter = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_rfc2822DateFormatter = [[NSDateFormatter alloc] init];
[_rfc2822DateFormatter setDateFormat:@"EEE, d MMM yyyy HH:mm:ss zzz"];
[_rfc2822DateFormatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]];
});

return [_rfc2822DateFormatter stringFromDate:date];
}

static inline const char * TTTFormatForRFC2822Timestamp(const char *timestamp) {
NSCParameterAssert(timestamp);

size_t length = strlen(timestamp);
switch (length) {
case 11:
return "%d %b %Y";
case 15:
return "%a %d %b %Y";
case 16:
if (timestamp[3] == ',') {
return "%a, %d %b %Y";
} else if (timestamp[14] == ':') {
return "%d %b %Y %H:%M";
}
break;
case 18:
return "%d %b %Y %H:%M:%S";
case 21:
return "%a %d %b %Y %H:%M";
case 22:
return "%a, %d %b %Y %H:%M";
case 24:
return "%d %b %Y %H:%M:%S";
case 25:
return "%a, %d %b %Y %H:%M:%S";
case 26:
return "%d %b %Y %H:%M:%S %z";
case 28:
case 29:
if (timestamp[3] == ',') {
return "%a, %d %b %Y %H:%M:%S %Z";
} else {
return "%a %d %b %Y %H:%M:%S %Z";
}
break;
case 30:
case 31:
if (timestamp[3] == ',') {
return "%a, %d %b %Y %H:%M:%S %z";
} else {
return "%a %d %b %Y %H:%M:%S %z";
}
break;
default:
break;
}

return NULL;
}

static NSDate * TTTDateFromRFC2822Timestamp(NSString *timestamp) {
if (!timestamp) {
return nil;
}

const char *source = [timestamp cStringUsingEncoding:NSUTF8StringEncoding];
const char *format = TTTFormatForRFC2822Timestamp(source);

if (format == NULL) {
return nil;
}

struct tm time = {
.tm_isdst = -1,
};

strptime_l(source, format, &time, NULL);

return [NSDate dateWithTimeIntervalSince1970:mktime(&time)];
}

@implementation TTTDateTransformers

+ (void)load {
Expand All @@ -94,6 +179,12 @@ + (void)load {
} allowingReverseTransformationWithBlock:^id(id value) {
return TTTDateFromISO8601Timestamp(value);
}];

[NSValueTransformer registerValueTransformerWithName:TTTRFC2822DateTransformerName transformedValueClass:[NSDate class] returningTransformedValueWithBlock:^id(id value) {
return TTTRFC2822TimestampFromDate(value);
} allowingReverseTransformationWithBlock:^id(id value) {
return TTTDateFromRFC2822Timestamp(value);
}];
}
}

Expand Down

0 comments on commit ff4a698

Please sign in to comment.