IOS6 Incorrect TimeZone while converting date from string to NSDate - objective-c

My date is in the format
2013-07-16T07:40:36.939-04:00
When I convert it into a NSDate
the date is in the format IST or GMT +5:30 as I am in India. How should I make it use -4:00 as the timezone and display EST or PDT as per the number. if I use zzz, it returns GTM+5:30 and zzzz returns Indian Standard Time. This is my way
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd'T'HH:mm:ss.SSSzzz"];
NSDate *date = [dateFormatter dateFromString:strDate];

You need to set the formatted locale to en_US_POSIX to force it to use the supplied timezone instead of the system timezone:
[dateFormatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"]];

You're parsing the date string correctly (in iOS 6 and later; this is not date format recognized in iOS 5 which recognizes -0400 or GMT-04:00, but not -04:00). Unfortunately, NSDate objects do not have a "time zone", so that information is not captured by the NSDateFormatter.
If you really want to capture the original timezone, I think you may have to manually parse the string for those last few characters (the -04:00), determine the timezone offset from that, and store this in a separate field and when outputting the date, use this separate time zone offset to set the timeZone property of your date formatter accordingly. Or if you really want to represent the original date, you could reformat this ISO8601 date string as human-friendly string and keep this pretty string (as well as the NSDate object, presumably).
BTW, splitting hairs, but you might want to be wary about assuming that -04:00 will represent EDT because (a) it depends upon the time of the year; and (b) there are other timezones that are also -04:00 (e.g. there are a bunch of South American timezones that are also -04:00).
Generally apps avoid this problem altogether by (a) converting the date strings to NSDate objects; and (b) output these NSDate objects using the timezone and locale of the device that the app is running on.

Related

DateTime conversion in iOS when device's timezone change

I get time in EDT from my server in format yyyy-MM-ddTHH:mm:ss for instance 2014-05-21T09:30:00. I convert these to NSDate and save in sqlite on iphone using code below
NSString *strDate = #"2014-05-21T09:30:00";
NSDateFormatter *df = [[NSDateFormatter alloc] init];
[df setTimeZone:[NSTimeZone timeZoneWithName:#"EDT"]];
[df setDateFormat:#"yyyy-MM-dd'T'HH:mm:ss"];
NSDate *date = [df dateFromString:strDate];
It works fine until I change the timezone on the device. If I change time on device time gets messed up. Any idea what am I doing wrong here?
Device's timezone is Eastern and I save 8:00AM
I change device's timezone to Pacific and time changes to 5:00AM
I have an update process that updates all datetime values again and it goes back to 8AM
I now change device's timezone to Eastern and time goes to 11AM
I run the update process again and time goes back to 8AM
How can I save these times so no matter which timezone users is in, they always see eastern time.
Thanks,
D.
NSDate itself doesn't know about timezone; it's just a simple wrapper around a double value, which represents the number of seconds since some fixed time (I think Jan 1 2001 or something) UTC.
What you need is a NSDateFormatter, similar to the one you use to parse the date, to transform the NSDate into an NSString using the EDT timezone.

NSDateFormatter dateFromString returns incorrect date [duplicate]

This question already has answers here:
Get NSDate from NSDate adjusted with timezone
(2 answers)
Closed 9 years ago.
I am trying to use NSDateFormatter in my app which takes a date string and formats it to an NSDate so that I can do Date Comparisons, however I am finding when I use dateFromString and format it the date is losing one day.
NSString *dateString = #"02-06-2012";
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"dd-MM-yyyy"];
NSDate *dateFromString = [[NSDate alloc] init];
dateFromString = [dateFormatter dateFromString:dateString];
NSLog(#"My Date = %#", dateFromString);
[dateFormatter release];
This outputs to the console:
My Date = 2012-06-01 23:00:00 +0000
Try adding this lines to your code,
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"GMT+0:00"]];
or
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:#"GMT"]];
SWIFT update :
Code from quetion,
let dateString = "02-06-2012"
var dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "dd-MM-yyyy"
var dateFromString : NSDate = dateFormatter.dateFromString(dateString)!
println("My Date \(dateFromString)")
And Solution ,
dateFormatter.timeZone = NSTimeZone(name: "GMT")
OR
dateFormatter.timeZone = NSTimeZone(abbreviation: "GMT+0:00")
I don't believe that Dhruv's answer is correct. In fact, it's not clear there's any problem at all. You just seem to have an incorrect expectation of what should happen and/or interpretation of what's happening.
NSDate represents a moment in time. This moment does not have one unique name. It will be known by different names in different places and under different naming systems (time zones, calendars). NSDate doesn't deal with any of this, except lamely in its -description method, where it has to produce a string representation of that moment.
Second, a string like "02-06-2012" doesn't specify a precise moment in time. First of all, it's just a date with no time information, so NSDateFormatter just defaults to the first moment for that date. Second, it doesn't specify the time zone. The first moment of the calendar day is a different moment in each time zone. Unless you specify a time zone with -setTimeZone: or the string itself carries time zone information, NSDateFormatter assumes that any date strings you ask it to parse are in the current time zone.
So, your dateFromString object represents the first moment of the specified date, 02-06-2012, in your time zone. I expect this is what you wanted. However, you then got confused by the way that NSDate describes itself when logged. As I said, NSDate has to pick some "name" (string representation) for the moment it represents and which name it picks is fairly arbitrary. These days it is picking the name that the moment is known by in UTC. I gather from the log output shown in your question that you are located at UTC+0100. So, the date may look like it's one day earlier but it really is the same moment you specified. In other words, "2012-06-01 23:00:00 +0000" and "2012-06-02 00:00:00 +0100" are two equivalent names for exactly the same moment in time. You just aren't used to seeing the first one and misinterpreted it.
The lesson is that you have to stop relying on NSDate's self-description to be in any particular time zone. Really, you have to not rely on anything about it, since it's not documented. In fact, the docs for -[NSDate description] state, "The representation is not guaranteed to remain constant across different releases of the operating system."
Dhruv's solution seems to help merely because it causes NSDateFormatter and -[NSDate description] to agree on the time zone. But that's unreliable. It wouldn't work on Snow Leopard, for example, because -[NSDate description] used the local time zone instead of UTC in that version of the frameworks.
More importantly, though, it alters the actual moment represented by the NSDate object you get from NSDateFormatter's interpretation of your date string. I suspect you really want that to have a specific meaning – you want the string to be interpreted as being in the local time zone – and his solution thwarts your intent.
tl;dr: you were getting the date you wanted all along; don't rely on -[NSDate description]; don't use Dhruv's solution

6 hours being added to NSDate object when using NSDateFormatter

I am trying to format a date object and I am noticing on the string I am passing in; 6 hours is being added to my time. This seems to be associating my date time object to GMT.
My code:
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"yyyy-MM-dd h:mm:ss a"];
[formatter setTimeZone:[NSTimeZone systemTimeZone]];
NSDate *date = [formatter dateFromString:#"2012-02-01 03:38:12 AM"];
NSLog(#"%#", date);
The result is:
2012-02-01 09:38:12 +0000
I have tried this with and without the setTimeZone and it does not matter. Any ideas on why this is displaying as GMT time?
Thanks,
Flea
The date that your formatter creates is not associated with any timezone, but the description method of NSDate (which is what NSLog uses for the output) converts any date to UTC. You would have to use another (or the same) date formatter's stringFromDate: method to print it with a different time zone.
All NSDates are absolute times, meaning that 3:00 AM central time in the United States is 9 AM UTC. I suspect that your systemTimeZone is central time in the United States.
NSLog always shows times in UTC.
If you want to see, as a string, what the time is in your time zone, then you can use the same date formatter stringFromDate: method, and make the you set the time zone of the date formatter to that time zone.
NSLog date formatting is an annoyance because it leads to the kind of confusion you are experiencing.

Date/Time parsing in iOS: how to deal (or not deal) with timezones?

I have an ASP.NET MVC 3 website that communicates with my iOS app via JSON. As part of the objects sent in the JSON response, I have dates in the format of yyyy-MM-dd HH:mm:ss ZZZ which outputs 2011-04-05 16:28:22 -07:00. How do I parse that in iOS?
This is the code I'm messing around with right now:
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd'T'HH:mm:ssZZZ"];
[dateFormatter setTimeZone:[NSTimeZone localTimeZone]];
NSDate *date = [dateFormatter dateFromString:#"2011-04-05T16:28:22-0700"];
NSLog(#"%#; %#; %#", dateFormatter, date, [NSTimeZone localTimeZone]);
First thing to note is that 2011-04-05 16:28:22 -07:00 has to look like 2011-04-05T16:28:22-0700, where a T replaces the first space (assuming that stands for time, or where the time part of the string starts from?), the second space is removed and the colon in the time zone is removed. I figure I'll find a way to format the string that .NET is sending back to conform to the string iOS will parse.
The real issue is that the date that is outputted is 7 hours ahead of what I've sent in the JSON response. So, iOS outputs 2011-04-05 16:28:22 -07:00 as 2011-04-05 23:28:22 +0000, and that is wrong as far as my app is concerned.
The only solution I've found so far is to send the date in the JSON as 2011-04-05 16:28:22 +00:00, but that again is wrong because I'm altering what the real date should be.
Anyway, I'd appreciate someone taking a look and letting me know how I can parse the date string .NET is outputting via the format yyyy-MM-dd HH:mm:ss ZZZ (which I suppose can be re-written to yyyy-MM-ddTHH:mm:ssZZZ) to an NSDate object I can use in iOS.
I don't know how right this is, but I ultimately found that in .NET I have to do DateTime.ToUniversalTime().ToString("yyyy-MM-ddHH:mm:ss") and on the iOS side I have to do this:
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:#"UTC"]];
[dateFormatter setDateFormat:#"yyyy-MM-ddHH:mm:ss"];
NSDate *date = [dateFormatter dateFromString:#"2011-04-0600:28:27"];
Only then is the date correct when NSLog outputs, so I'm assuming that I've finally got a proper date/time.
Your iOS date parsing code is correct: 2011-04-05 16:28:22 -07:00 and 2011-04-05 23:28:22 +0000 represent the same time, just in different time zones. Your only problem is that NSDate doesn't actually store the time zone, and so [date description] outputs using UTC.
You're almost certainly better off just using UTC time everywhere for interchange and not bothering with time zones. I'm sure you can get that your ASP.NET code to do that, and it's easier to parse on the receiving end as well. NSDateFormatter uses standard Unicode date formatting syntax, which you can read about here.

Keep original time zone with NSDateFormatter

I have strings like 2011-01-19T20:30:00-5:00 and I'd like to parse them into an NSDate but I want to keep the original time zone.
NSDateFormatter *dateFormatter = [NSDateFormatter new];
[dateFormatter setDateFormat: #"yyyy-MM-dd'T'HH:mm:ssZ"];
NSLog(#"%#", [dateFormatter dateFromString: dateString]);
[dateFormatter release];
That snippet gives me 2011-01-20 02:30:00 +0100 which is also correct but I wish to keep the original time zone -0500 instead of my local time zone +0100 in the NSDate.
First of all, you should be aware that NSDate objects don't store anything related to their locales or timezones, and internally they're essentially represented as a number of seconds since the first instant of 1 January 2001, GMT.
If you are able to the timezone for the string in an NSTimezone object, just do the following before doing dateFromString:
[dateFormatter setTimeZone:timezoneForString];
and you'll be set.
If you're unable to get an NSTimezone and all you have is a string "2011-01-19T20:30:00-5:00", there isn't a very good way to get to an NSTimezone from the -5:00, since there isn't always an unambiguous way to get a timezone ID (e.g., "America/Los_Angeles") or timezone name (e.g., "Pacific Daylight Time") from an UTC offset. So you'd have to write your own code to manually extract the offset, store it, and add it to the time before displaying it.