What's the optimum way of storing an NSDate in NSUserDefaults?

CocoaDatetimeNsdateNsuserdefaultsNstimeinterval

Cocoa Problem Overview


There's two ways of storing an NSDate in NSUserDefaults that I've come across.

Option 1 - setObject:forKey:

// Set
NSDate *myDate = [NSDate date];
[[NSUserDefaults standardUserDefaults] setObject:myDate forKey:@"myDateKey"];

// Get
NSDate *myDate = (NSDate *)[[NSUserDefaults standardUserDefaults] objectForKey:@"myDateKey"];

Option 2 - timeIntervalSince1970

// Set
NSDate *myDate = [NSDate date];
NSTimeInterval myDateTimeInterval = [myDate timeIntervalSince1970];
[[NSUserDefaults standardUserDefaults] setFloat:myDateTimeInterval forKey:@"myDateKey"];

// Get
NSTimeInterval myDateTimeInterval = [[NSUserDefaults standardUserDefaults] floatForKey:@"myDateKey"];
NSDate *myDate = [NSDate dateWithTimeIntervalSince1970:myDateTimeInterval];

Pros and Cons

Option 1

This seems to be compact and logical. However, I've got worries about this going wrong because of Date Formatter bugs.

Option 2

This seems to be clumsy. I'm also unsure of the accuracy of it - in one test I did, when I retrieved the date back it was out by 48 seconds, despite the Apple Docs saying that NSTimeInterval has "subsecond accuracy".

Requirements

Whatever method I choose, it must be:

  1. Precise to within a second.

  2. Readable and reliable.

My Question

Is the inaccuracy with Option 2 because I'm doing something wrong?

Which out of these two options would you use?

Is there another option that I'm not aware of?

Thanks!

Cocoa Solutions


Solution 1 - Cocoa

You are needlessly complicating things. Why are you converting the date to a time interval (then the time interval to a different primitive)? Just [sharedDefaults setObject:theDate forKey:@"theDateKey"] and be done with it. NSDate is one of the "main types" supported by the PLIST format (dates, numbers, strings, data, dictionaries, and arrays), so you can just store it directly.

See the documentation for proof.

Just store and retrieve the date directly and watch it Do The Right Thing (including time zones, precision, etc). There is no formatter involved, as others have said.

Solution 2 - Cocoa

For option #1, I don't believe a date formatter is involved. Possibly under the hood, but I imagine it's not broken. The date is stored in ISO 8601 form.

For option #2, use -setDouble:forKey: and -doubleForKey instead of the float-based versions. That might be the cause of your precision errors.

Solution 3 - Cocoa

Use NSUserDefaults; dates are stored in Zulu time, so there are no time zone issues to worry about. Store it in your time zone, pull it out in another time zone, you'll be fine, the system handles the conversion (no date formatter to worry about).

Solution 4 - Cocoa

If you are saving the expiration date from the Facebook Graph API, I would use Option 2.

Option two can be easily converted to a string (using stringWithFormat). Most importantly, it works for the Graph API.

Plus, you don't have to worry about the format of your date. Not dealing with NSDateFormatter is worth the possibility of a 48 second error.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJohn GallagherView Question on Stackoverflow
Solution 1 - CocoaJoshua NozziView Answer on Stackoverflow
Solution 2 - CocoaJohn CalsbeekView Answer on Stackoverflow
Solution 3 - CocoaBen GottliebView Answer on Stackoverflow
Solution 4 - CocoaNate SymerView Answer on Stackoverflow