Converting ISO8601 Date Format to local time (iOS) - ios

So there is a section on web application that users can enter events into and the web service sends those events to the mobile app in the following format:
"yyyy-MM-dd'T'HH:mm:ssZZZZZ"
I'm having issues trying to convert the string into a date so I can get just the time from the event (formatted in the correct timezone as well), So for example here's one that comes over "2015-03-20T20:00:00-07:00", which when I pull the time should be 1PM Pacific Time. But instead I either get 8PM or 3AM (depending on whether I add UTC abbreviation to the date formatter).
Here's what I have so far, I know I'm missing something here & maybe there's another date formatter that needs to be used but so far I can't figure out where I'm going wrong.
NSString *datePattern = #"yyyy-MM-dd'T'HH:mm:ssZZZZZ";
NSDateFormatter *dateFormatter = [NSDateFormatter new];
[dateFormatter setDateFormat:datePattern];
NSString *sString = [valueDict valueForKey:#"start_date"];
NSDate *startDate = [dateFormatter dateFromString:sString];
NSDateFormatter *timeFormatter = [NSDateFormatter new];
[timeFormatter setDateFormat:#"hh:mm a"];
[timeFormatter setLocale:[NSLocale systemLocale]];
NSString *timeString = [timeFormatter stringFromDate:startDate];

2015-03-20T20:00:00-07:00 is 8pm Pacific Daylight Time.
If you're representing 1pm PDT, that's either
2015-03-20T13:00:00-07:00
or represent that in "Zulu" (i.e. GMT/UTC)
2015-03-20T20:00:00Z
When working with a web service, the latter is the common convention for ISO 8601 dates. Then, when you present it to the user, you present it to them in their local timezone (using a NSDateFormatter with its default timeZone setting.
Note, when using NSDateFormatter to prepare ISO 8601 dates, you will want to ensure that you specify a locale of en_US_POSIX as outlined in Technical Q&A QA1480. When designing app for US audience this isn't critical, but it's best practice in case the user is not using a gregorian calendar on their device.

Related

when to set the NSLocale for the NSDateFormatter ?

In my app , Im using following code to convert string to date before inserting the date into the database.
However this code fails for the users in UK, they have the Region set to UK, and Timezone set to London.
This works for the users in the US as their locale is en_US. So that says, this code works fine for en_US locale but not en_GB locale.
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
[dateFormatter setLocale:[NSLocale currentLocale]];
[dateFormatter setDateFormat:#"yyyy-MM-dd'T1'HH-mm-ss-SSS"];
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:#"UTC"]]; //doing this as timestamp stored in server is based on UTC, hence I'm using UTC instead of systemTimeZone
date = [dateFormatter dateFromString:theDate];
The passed string is : 2014-6-26T121-21-6-000
If I set the locale as follows, instead of currentLocale for all the users across the world:
[dateFormatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"]];
then the code works, but I would like to know if this cause any issues in future?
Why we need set the locale property for converting the dates ?
Why the currentLocale fails in my case but not the en_US locale even though the date format is matched properly ?
Whenever you’re dealing with ISO 8601 or RFC 3339 dates (i.e. dates exchanged with web services and/or stored as a string in some data store) use en_US_POSIX. See Technical Note 1480.
Or one can use NSISO8601DateFormatter and you don’t have to deal with this locale silliness. E.g.
NSString *string = #"2014-06-26T12:21:06.000Z";
NSISO8601DateFormatter *formatter = [[NSISO8601DateFormatter alloc] init];
formatter.formatOptions = NSISO8601DateFormatWithInternetDateTime | NSISO8601DateFormatWithFractionalSeconds;
NSDate *date = [formatter dateFromString:string];
Also, standard representations of ISO 8601 and RFC 3339 datetime strings, you’d generally use a format like 2014-06-26T12:21:06.000Z where:
the hour is less than 24;
numbers are zero-padded;
separators between hours and minutes and seconds are :;
the separator between seconds and milliseconds is .; and
you'd often add Z at the end of the string to unambiguously designate that the time string is in GMT/UTC/Zulu.

Convert NSString to NSDate in Spanish Locale

I have integrate RSS feed parser into iOS application. One of the field in the received data is published date. I'm able to parse that date if the iPhone locale is English-United States. But when I change the language of iPhone to Spanish, its not able to convert the string to NSDate object.
Here's the code that I wrote:
NSString* dt = #"Fri, 26 Jun 2015 00:00:00";
NSDateFormatter* dtFormatter = [[NSDateFormatter alloc] init];
//set the locale to spanish
[dtFormatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:#"es"]];
[dtFormatter setDateFormat:#"EEE, dd MMM yyyy hh:mm:ss"];
NSDate* conDt = [dtFormatter dateFromString:dt ];
NSLog(#"%#", conDt); //This value is always (null)
Even after setting the locale to "es" (which is spanish), its still not able to parse it properly. How can I convert the string to date in iOS?
When you set the locale, you don't want to use the locale of the device, but rather the locale used when the string was created (because you're taking an English string and want to convert it to NSDate regardless of the locale of the device). In fact, it's advised to use en_US_POSIX:
[dtFormatter setLocale:[NSLocale localeWithLocaleIdentifier:#"en_US_POSIX"]];
See Technical Q&A #1480. This focuses on the Gregorian calendar issue with RFC 3999/ISO 8601 date strings, but it is applicable to language settings, too.
By the way, I notice that you're not setting the timezone. Often when dates do not bear any timezone information, they've been converted to GMT/UTC/Zulu. So you may want to set the timezone for your formatter, too:
[dtFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
Given that the time component of your string is "00:00:00", perhaps this isn't significant, but if dealing with datetime strings, you often want to make sure you correctly capture the timezone used within the string, as well.

Date conversion from string to NSDate in ios

I have searched over internet for a long time to get this but I can't find the solution. I have received a date string from web services as "22 May 2014", I have to convert into NSDate format for check it with current date. And I have to find out the date from web service is in future or in past time.
The actual problem is that when I convert this using
NSDate *date;
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"dd MMMM YYYY"];
date = [dateFormatter dateFromString:dateString];
But I get an entirely Different Date, Sample Input dateString:22 June 2014 and Output I get is 2013-12-21 18:30:00+0000
Please suggest any solutions.
Thanks in advance. :)
You're using YYYY, which doesn't mean what you think it means. From the TR35-31 documentation, Y is the symbol for "year in week-of-year calendars".
You want dd MMMM yyyy instead as your format string. Mixing week-of-year-based fields and regular day/month/year fields is a recipe for odd problems.
Additionally, you may well want to set the time zone in your formatter - if you're just parsing a date, then you should consider using UTC, and make sure that all your calculations and formatting/parsing use UTC.
(I suspect the issue here is that week-of-year hasn't been set, so is assumed to be 1... and the week-year 2014 started on December 30th. Then the day-of-month is set to 22 by the dd part, and then your time zone offset of UTC+05:30 is taken into account.)

What types of dates are these?

I have a plist with this format date:
Mar 11, 2013 10:16:31 AM
which shows up in my console as
2013-03-11 16:16:31 +0000
whereas a webservice is returning something that in the console looks like this:
2013-03-01T18:21:45.231Z
How do I fix my plist date to the same format as the web service?
Regarding your three date formats:
The first is just the date format when you look at a NSDate in a plist in Xcode, a human readable date in the current locale (but if you look at the plist in a text editor, you'll see it's actually written in #"yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'" format).
The second is the default formatting from the description method a NSDate (e.g. you NSLog a NSDate).
The third is RFC 3339/ISO 8601 format (with fractions of a second), often used in web services.
See Apple's Technical Q&A QA1480.
As an aside, that Technical Note doesn't include the milliseconds, so you might want to use something like #"yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'SSS'Z'", for example:
NSDate *date = [NSDate date];
NSLocale *enUSPOSIXLocale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.locale = enUSPOSIXLocale;
formatter.dateFormat = #"yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'SSS'Z'";
formatter.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
NSString *dateString = [formatter stringFromDate:date];
NSLog(#"%#", dateString);
You can use this if you want to store the date as a string in RFC 3339/ISO 8601 format in the plist (or alternatively, if you need to convert a NSDate to a string for transmission to your web service). As noted above, the default plist format does not preserve fractions of a second for NSDate objects, so if that's critical, storing dates as strings as generated by the above code can be useful.
And this date formatter can be used for converting dates to strings (using stringFromDate), as well as converting properly formatting strings to NSDate objects (using dateFromString).

Need information on printing [NSDate date]

When I am printing the date
//getting the current date and time
self.date = [NSDate date];
NSLog(#"%#",date);
The date which I am getting is correct, but there is a delay in time by 6 hrs. My system time is correct.
try this
NSLocale* currentLoc = [NSLocale currentLocale];
NSLog(#"%#",[[NSDate date] descriptionWithLocale:currentLoc]);
Make use of NSDateFormatter
NSDate *today = [NSDate date];
//Create the dateformatter object
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
//Set the required date format
[dateFormatter setDateFormat:#"yyyy-MM-dd HH:mm:ss"];
//Get the string date
NSString *dateString = [dateFormatter stringFromDate:today];
//Display on the console
NSLog(dateString);
Logging an NSDate in the debugger is somewhat misleading as it gives you a calendar day and time for a particular time zone - UTC / GMT. However, NSDate has no inherent time zone or any inherent relationship to how humans perceive and think about dates at all. Instead, it is a timestamp. Classes like NSDateComponents, NSTimeZone, NSDateFormatter, and so on all exist to provide human context and formatting.
So what you see is the timestamp formatted to that particular format and UTC time zone, which is how NSDate will always appear when printed in the debugger or the console. If you were to calculate the time zone offset between UTC and your own time zone, you'd find that the date represents the time stamp you gave it, and not one however many hours off.
you can set current time zone for customizing your date format.
This link can help:
https://stackoverflow.com/a/7213629/456471
The default date string representation is probably formatting the date as UTC, rather than your local time zone (the exact format that it will use is not defined, and may change from release to release, so you shouldn't rely on it). You should use the NSDateFormatter class if you need to format a date in a particular format (or with a particular time zone, including the local time zone); see the Data Formatting Guide and the NSDateFormatter Class Reference for more information.

Resources