views:

1346

answers:

3

I've been trying to find a sensible way of storing daily data using Core Data on the iPhone.

My app receives data in csv format, with a date but no time:

date, cycles
2009-08-01, 123
2009-08-02, 234
2009-08-03, 345
2009-08-04, 456

When this data is stored, there should only be one record per day. I figured the best thing to do was create an NSDate to be stored, but strip out the time & time zone data.

I can easily create an NSDate without hours, minutes or seconds using either NSDateComponents or an NSDateFormatter. However even when I set the time zone explicitly to UTC or to zero seconds from GMT, outputting a created date with NSLog() always has my local timezone like:

2009-07-29 00:00:00 +0100

Does anyone know of a better way to make NSDates without time components? Or perhaps a better way of storing the dates?

+2  A: 

The NSDate object will always incorporate time date - to quote the docs it "represent[s] a single point in time" and does so by storing a time value since its reference date (the start of 1 January 2001 at GMT, again according to the docs). Therefore you cannot have an NSDate that is unaware of time of day.

Rather than try and store dates your own way, I would still use NSDate in your model and consider adding a pair of methods to your entity class, one of which will do what you described above, setting the NSDate to 00:00:00 on a given day. The other could return just the date from an NSDate in your preferred format. These would then use the Core Data-generated getter and setter to access the NSDate property.

By still using NSDate you are using a class that Core Data can work with natively, meaning you can still use predicates easily for filtering, or sort your fetched results by date without having to think too hard about it.

marramgrass
Thanks for the reply. This does still leave the problem of time zones. For example: I save my data in July London (GMT+0100) and someone else saves it in Cupertino (GMT-0700). There is now an 8 hour difference in the stored date. I think it's probably more efficient just to drop back to raw SQLite.
Ben
I don't quite understand the problem: the date in an NSDate is stored as an absolute date, seconds since 00:00:00 1/1/2001 *GMT*. So if two people in different timezones store the 'current' date at exactly the same instant, their NSDate's are identical.Timezone is only worked with on retrieval/display, and unless you tell NSDate otherwise it will go with the system locale timezone.In other words, if your two sets of data are stored at the same moment in London and Cupertino, the stored dates are the same, with no difference.
marramgrass
+3  A: 

A good programming rule of thumb is to always store dates in UTC. It doesn't matter whether you use Core Data or not; you'll still have to do some work because Apple's date classes pretty much suck.

Dates are represented internally as a number of seconds since a reference date which is, I believe, 1 January 2001 00:00:00 (although the actual reference date isn't very important). Point is, NSDate objects are always natively in UTC. If the dates you're getting in your CSV file are local, you'll need to do something like this to get the UTC time:

NSDate *UTCDate = [localDate addTimeInterval:-[[NSTimeZone localTimeZone] secondsFromGMT]];

Then, I'd set the time to 00:00:00. Now you're saving the date, at midnight, in UTC. For presentation purposes, you will use an NSDateFormatter configured with the time zone of your choice (the system time zone is the default if you don't specify one) to display those dates.

Time zones don't really matter when you're just dealing with dates, though. As long as you make sure to set the time zone on your NSDateFormatter to UTC, you'll always show the same date, no matter what time zone the user has selected on her device.

If you don't like this solution, you can always store your dates in an alternative format. You could use a double or int to store the date in some custom format (e.g. the number of days since some reference date), or you could even roll your own class to model the date exactly the way you want and store it as an NSData object. As long as the class implements NSCoding, you can serialize it to an NSData object in Core Data. You just need to set the attribute type in Core Data to "Transformable".

You have a ton of options here, and none of them involve the effort of writing your own SQLite queries and databases.

Alex
Thanks very much. I've got it sorted now. Your answer makes the conversions make more sense and Peter Hosey's below explains the NSLog output.
Ben
+2  A: 

An NSDate doesn't have a time zone. NSLog uses your local time zone; it says +0100 because that's where you are.

Peter Hosey
Ben
I did not understand the +0100. What is it exactly representing ?
srikanth rongali
srikanth rongali: Time zone offset. The questioner was one hour ahead of GMT: GMT+0100. (The latter pair of digits are minutes, so a time zone five and a half hours ahead of GMT would be +0530.)
Peter Hosey