views:

946

answers:

2

How do I parse "2010-04-30T00:45:48.711127" into an NSDate? (and maintain all precision)

A: 

It seems the NSDate only has millisecond precision.

#import <Foundation/Foundation.h>

int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setDateFormat:@"yyyy-MM-dd'T'hh:mm:ss.SSSSSS"];

    NSDate *date = [dateFormatter dateFromString:@"2010-04-30T00:45:48.711127"];

    NSLog(@"%@", date);

    NSString *string = [dateFormatter stringFromDate:date];

    NSLog(@"%@", string);

    [pool drain];
    return 0;
}

That code yields the following console output:

Program loaded.
run
[Switching to process 27202]
Running…
2010-05-08 20:02:46.342 TestNSDate[27202:a0f] 2010-04-30 00:45:48 -0700
2010-05-08 20:02:46.344 TestNSDate[27202:a0f] 2010-04-30T12:45:48.711000

Debugger stopped.
Program exited with status value:0.

So "2010-04-30T00:45:48.711127" turning into "2010-04-30T00:45:48.711000" is probably not what you have in mind.

WineSoaked
It seems we are both stuck at the same point. I think the problem is with NSDateFormatter though, since in many places it is documented that NSDate supports microsecond precision.
bradley.ayers
There's NSTimeInterval that possesses that ability. Perhaps a composite pattern is in order...
WineSoaked
Perhaps I should be more specific: How important is it that you're storing these sub-millisecond resolution timestamps (for want of a better description) in NSDate itself? Couldn't a subclass that handles the microsecond resolution make up the difference for maintaining the additional precision you're needing?
WineSoaked
Your code has a small bug. You should change the format to yyyy-MM-dd'T'HH:mm:ss.SSSSSS (note the HH instead of hh) as the time in iso fromat uses uses 24h clock instead of 12h.
Piotr Czapla
+1  A: 

You have your work cut out for you.

NSDate will throw out any values past 3 decimal places for seconds. You can create a subclass of NSDate to hold on to that precision but you'll also need to implement your own parsing and custom formatters to input and display it since NSDateFormatter and CFDateFormatter, which it is built on, will also truncate precision after 3 decimal places. Depending on what you're doing though that shouldn't be all that hard.

This is a simple subclass (not implementing NSCoding or NSCopying) that will hold on to all the precision you give it.

@interface RMPreciseDate : NSDate {
    double secondsFromAbsoluteTime;
}

@end

@implementation RMPreciseDate

- (NSTimeInterval)timeIntervalSinceReferenceDate {
    return secondsFromAbsoluteTime;
}

- (id)initWithTimeIntervalSinceReferenceDate:(NSTimeInterval)secsToBeAdded {
    if (!(self = [super init]))
        return nil;

    secondsFromAbsoluteTime = secsToBeAdded;

    return self;
}

@end

You can then ask for the -timeIntervalSince1970 to get UNIX epoch time.

There is an ISO8601 date/time parser class already out there, but since it's using NSDateComponents to generate its date it's limited to full-second precision currently, but you could use it as a starting point perhaps to create more precise representations.

Ashley Clark