I see that NSTimeZone has these methods :
defaultTimeZone
localTimeZone
systemTimeZone
Can someone explain to me, in simple terms, what the differences are beetween those calls, and when one should be used instead of the other? I don't understand anything inside the Apple docs about this.
The language in the docs is a bit on the dry side, to be sure, and the similarity of the names is potentially confusing. I'll quote the NSTimeZone docs here and try to explain them:
systemTimeZone
The time zone currently used by the system. If the current time zone cannot be determined, returns the GMT time zone.
This is the time zone which the device believes it is in; it is often set automatically, and would then correspond to the device's physical location, but if the user has explicitly set a particular time zone in the Settings App, that's what you'll get.
defaultTimeZone
The default time zone for the current application. If no default time zone has been set, this method invokes systemTimeZone and returns the system time zone.
Your application is allowed to set its own time zone, so that you can perform actions as if the device were in another zone, but without affecting the system time zone (and thereby other apps). The setting is performed with a call to setDefaultTimeZone:. If you haven't done that, this call is identical to calling systemTimeZone.
localTimeZone
An object that forwards all messages to the default time zone for the current application. The local time zone represents the current state of the default time zone at all times.
This is where it gets a little bit tricky. localTimeZone gives you nearly the same result as defaultTimeZone. The difference is that the specific NSTimeZone instance you get from localTimeZone will always reflect the setting you've made to the time zone within your app. You can call it once, save the result, and always get the current simulated time zone through that object, no matter the changes made. It is as if, when you use this NSTimeZone instance, the framework is calling defaultTimeZone for you, to be sure that you always get the current value.
Here's a couple of brief illustrations of the above. The NSTimeZone object that you get back from systemTimeZone represents the system time zone at the time you make the call. If you call systemTimeZone again, even if the user has since changed the time zone, you will get the same one. Your app caches that value, and you have to ask the system to clear it with resetSystemTimeZone to get the update.
// Say that device is in GMT originally
NSLog(#"%#", [NSTimeZone systemTimeZone]); // GMT
// User flies into Rome and iPhone changes the zone automatically
NSLog(#"%#", [NSTimeZone systemTimeZone]); // Still GMT
[NSTimeZone resetSystemTimeZone]; // Clear app's cache
NSLog(#"%#", [NSTimeZone systemTimeZone]); // Now GMT+2
A similar thing happens with defaultTimeZone. When you call that method, you get an object that will always represent the same time zone, even if you later call setDefaultTimeZone:. However, if you use the object you get from localTimeZone, it will follow the change you make to the default time zone*.
// Say that defaultTimeZone is originally GMT
NSTimeZone * myDefaultTZ = [NSTimeZone defaultTimeZone];
NSTimeZone * myLocalTZ = [NSTimeZone localTimeZone];
[NSTimeZone setDefaultTimeZone:[NSTimeZone timeZoneWithName:#"Etc/GMT-4"]];
NSLog(#"%#", myDefaultTZ); // Still gives GMT
NSLog(#"%#", [NSTimeZone defaultTimeZone]); // GMT-4, the new value
NSLog(#"%#", myLocalTZ); // Also the new value!
Apple seems to recommend using localTimeZone:
with the localTimeZone class method, you can get a relative time zone object that decodes itself to become the default time zone on any computer on which it finds itself.
*Note that localTimeZone is still subject to the app-level cache of the system time zone. It only changes to follow your setting of the default time zone.
Related
I'm returning an NSDate from my server (running on GMT+2)
I'm calculating few things with the server's date and the device current date.
The problem (obviously) is when the device is running on different timezone then my server.
How can I apply and change the server's NSDate to return current device NSDate for my calculation will be exact for every time zone.
I simply need a function that will get my server NSDate with my server's timezone (gmt+2) and will return the correct device NSDate.
hope someone can help me on that
Server returns Ticks (running on c#) and manipulating to nsdate with this code
double tickFactor = 10000000;
double ticksDoubleValue = [ticks doubleValue];
double seconds = ((ticksDoubleValue - 621355968000000000)/ tickFactor);
NSDate *returnDate = [NSDate dateWithTimeIntervalSince1970:seconds];
return returnDate;
The NSDate class stores an absolute time. To facilitate this, it represents time in UTC, which is time-zone-agnostic. However you create an NSDate, it is assumed the time is in UTC. Even when you use NSDateFormatter to "read" a date from a string, it's just doing the math on your behalf, before creating the NSDate.
If you have a time representation that includes a time zone offset, you need to account for that when you do the conversion. As mentioned above, given a proper format string, NSDateFormatter will do that for you. If your representation is numeric (typically number of seconds from some date), you need to add or subtract the time zone offset. Add if the offset is negative, subtract if it's positive.
To adjust a server date provided in the server's local time, adjust based on the server's time zone. For GMT+2, subtract 3600 * 2 (number of seconds per hour * offset). This gives the seconds in UTC. When you create the NSDate using `[NSDate dateWithTimeIntervalSince1970:]. it will be the expected time.
Checking -[NSTimeZone isDaylightSavingTime] is giving me NO, and I don't know why. On my system I have the correct time displayed, and my time zone is Eastern US -- New York, which observes DST.
NSTimeZone *sZone = [NSTimeZone systemTimeZone];
BOOL isDST = [sZone isDaylightSavingTime];
if (isDST)
NSLog(#"\n Daylight saving");
else
NSLog(#"\n Not in Daylight saving"); // This prints
Can anyone please explain why this would be happening, and a possible remedy?
isDaylightSavingTime is date-based; the answer depends on the current date. Today is January 6, and on January 6 in your time zone, daylight saving time is not in use. Thus, the result you are seeing is correct.
I have a class which must have a property of some kind of timestamp, representing the moment of time when the instance of this class was created. And then when having multiple objects of this class I need to find the time interval between the creation of these objects.
And the usual interval is going to be up to 10 seconds, so I need precision of at least 1 second, but something like 0.1-0.001 second would be much better.
What is the best option to use for this property?
As far as I know, NSDate has precision up to 1 second.
I believe that I need something related to CFTimeInterval. I've used it for view animation with CADisplayLink. It provided the CFTimeInterval value for each moment of screen update and I could calculate the time interval between two CFTimeInterval's very easily.
But how do I assign the value to this CFTimeInterval at any moment of time?
NSDate will work, as Matthias Bauch's comment indicates. You can also just use CFTimeIntervals though:
CFTimeInterval currentTime = CFAbsoluteTimeGetCurrent();
Do note that this function and NSDate are both based on an absolute reference date (Jan 1, 2000 in this case). This means that if the system's clock is changed while your app is running, values obtained before the clock change won't correctly compare to values obtained afterward.
I am trying to use RestKit to import and map data to CoreData.
Here is the data from the API.
active": false,
"date": "2012-09-09",
"desc": "",
"end": "18:30",
"location": "",
"simStatus": "Accepted",
"start": "17:00",
"title": "The title"
When I try to map these to Core Data the times and sometimes the dates get altered. For instance, the above data stored in Core Data will end up with a start = 1970-1-1 23:00 and end = 1970-1-1 00:30?
The times the API sends over are local times, the API knows when and where the app is used. Think sporting event, we know where/when the away game is.
I need to get these times and dates stored in Core Data, the exact time hh:mm that the API hands them over. Not sure why Core Data or Restkit decides to change them? I understand the 1970 part as the start and end don't have dates, but why change the hour?
Does anyone know of a solution?
Below is the RestKit mapping code, which I have tried with timeZone, no timeZone, local timeZone, UTC timezone, etc... I have also tried with and without en_US_POSIX.
NSDateFormatter* timeFormatter = [NSDateFormatter new];
[timeFormatter setDateFormat:#"HH:mm"];
timeFormatter.timeZone = [NSTimeZone localTimeZone];
timeFormatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"];
NSDateFormatter* dateFormatter = [NSDateFormatter new];
[dateFormatter setDateFormat:#"yyyy-MM-dd"];
dateFormatter.timeZone = [NSTimeZone localTimeZone];
dateFormatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"];
gameMapping.dateFormatters = [NSArray arrayWithObjects:dateFormatter, timeFormatter, nil ];
[gameMapping mapKeyPath:#"start" toAttribute:#"start"];
[gameMapping mapKeyPath:#"end" toAttribute:#"end"];
.......
As Hot Licks points out in his comment, all NSDate objects are UTC, so that's what you're seeing when you print those out. Because you're explicitly parsing the values in the device's time zone, you'll see a shift when you look at the resulting UTC values.
Normally, I'd strongly recommend sending things as full date & time values, with the time zone offset included. (For example, "2012-09-09T18:30:00-05:00".) There are just too many variables involved not to be explicit about everything. Or at least passing the time zone as a separate (but still explicit) value.
If you don't have any control over the server side (as you say you don't), then your workaround of parsing the values as though they were UTC, and then hoping that things match up--while risky and brittle--sounds like it might be the best option you've got.
Does anyone know how to convert a JSON date(ticks) to an NSDate in Objective-C? Can someone post some code?
I'm guessing here but your JSON value is the number of milliseconds since 1970, right? You can use NSDate's dateWithTimeIntervalSince1970: method to return an NSDate object with the correct time. Just make sure to convert the JSON milliseconds number to seconds before passing it to NSDate-- Cocoa uses NSTimeInterval in most places, which represents an interval in seconds.
It goes roughly like this:
// Input string is something like: "/Date(1292851800000+0100)/" where
// 1292851800000 is milliseconds since 1970 and +0100 is the timezone
NSString *inputString = [item objectForKey:#"DateTimeSession"];
// This will tell number of seconds to add according to your default timezone
// Note: if you don't care about timezone changes, just delete/comment it out
NSInteger offset = [[NSTimeZone defaultTimeZone] secondsFromGMT];
// A range of NSMakeRange(6, 10) will generate "1292851800" from "/Date(1292851800000+0100)/"
// as in example above. We crop additional three zeros, because "dateWithTimeIntervalSince1970:"
// wants seconds, not milliseconds; since 1 second is equal to 1000 milliseconds, this will work.
// Note: if you don't care about timezone changes, just chop out "dateByAddingTimeInterval:offset" part
NSDate *date = [[NSDate dateWithTimeIntervalSince1970:
[[inputString substringWithRange:NSMakeRange(6, 10)] intValue]]
dateByAddingTimeInterval:offset];
(from https://gist.github.com/726910)
You'd have to detect the client's locale in order to be able to do that, and unless your client knows how to do that, there's probably not much point.
NSDate's descriptionWithLocale: would be the way you format it for another locale. And timeIntervalSince1970 will go back to the (seconds) since 1970, which you could multiply by 1000 to get ms to return to the client. It's all in the NSDate documentation.
http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSDate_Class/Reference/Reference.html
According to this page: http://msdn.microsoft.com/en-us/library/system.datetime.ticks.aspx ticks begin on Jan 1, 0001 so dateWithTimeIntervalSince1970: is not automatically setup to work with ticks. You can still use this method but should adjust for the difference.