NSDateFormatter local date format issue - ios

I have NSDate, and I need to convert it to string.
Usually I use this code:
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"MM/dd/yyyy"];
NSString *stringFromDate = [formatter stringFromDate:date];
return stringFromDate;
But I need to show data according to local date format. For instance, in USA the date usually starts from the month, but in Russia the date starts from day (#"dd/MM/yyyy"). And may be there is a different way of separators in different countries: '/', '.' ',' '-'
What is the best approach to do this?
Update (according to Jon Skeet answer):
if I specify NSDateFormatterMediumStyle the date is "4.9.2013", but for me it's better "04.09.2013". NSDateFormatterShortStyle doesn't help with this neither. Is there a way to add zeroes ?

See the date formatter guide which gives advice about this, suggesting that you set the style rather than calling setDateFormat:
NSDateFormatter makes it easy for you to format a date using the settings a user configured in the International preferences panel in System Preferences. The NSDateFormatter style constants—NSDateFormatterNoStyle, NSDateFormatterShortStyle, NSDateFormatterMediumStyle, NSDateFormatterLongStyle, and NSDateFormatterFullStyle—specify sets of attributes that determine how a date is displayed according to the user’s preferences.
It then gives a listing showing an example starting with this:
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateStyle:NSDateFormatterMediumStyle];
[dateFormatter setTimeStyle:NSDateFormatterNoStyle];
It sounds like you'd want NSDateFormatterShortStyle instead though.
setDateFormat is what you use for a custom format. More advice from the same document:
There are broadly speaking two situations in which you need to use custom formats:
For fixed format strings, like Internet dates.
For user-visible elements that don’t match any of the existing styles

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.

NSDate conversion to NSString doesn't follow NSDateFormatter [duplicate]

This question already has answers here:
What is the best way to deal with the NSDateFormatter locale "feature"?
(4 answers)
Closed 7 years ago.
I have problems with NSDate to NSString conversion, I have the following code in a method
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
NSTimeZone *timeZone = [NSTimeZone timeZoneWithName:#"UTC"];
[formatter setTimeZone:timeZone];
[formatter setDateFormat:#"yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'zzz'"];
return [formatter stringFromDate:date];
If I´m not mistaken this should return a String like
"2016-01-15T22:45:40.GMT"
But the resulting string depends on the device configuration, meaning if the device shows the date as 24 hour then i get the result above, on the other hand if the device is configured to show the house as A.M. P.M. then I get
"2016-01-15T10:46:50 p.m..GMT"
From the documentation:
Although in principle a format string specifies a fixed format, by default NSDateFormatter still takes the user’s preferences (including the locale setting) into account. You must consider the following points when using format strings:
In iOS, the user can override the default AM/PM versus 24-hour time setting. This may cause NSDateFormatter to rewrite the format string you set.
I think you'll have to consider using your own formatting method if you want the result to have a fixed format, regardless of user settings.
Actually, from this answer (as pointed out by pbasdf), it appears that you can circumvent this by simply setting the locale:
NSLocale* en_US_POSIX = [[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"];
[formatter setLocale:en_US_POSIX];

Conversion: NSString to NSDate

This is a really common question, but mine might be unique since I have long decimal places for the seconds.
NSString *timestamp = #"2015-11-06 15:27:34.0000000";
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd'T'HH:mm:ss zzz"];
NSDate *capturedStartDate = [dateFormatter dateFromString: timestamp];
My capturedStartDate is null.
For the date format, I've tried replacing zzz with Z, a, and removing it completely. I've also tried with and without the 'T'. Does someone know the correct format to retrieve this date from the string?
Your date string doesn't have a time zone in it, so you should remove that Z. Also, you have fractions of a second, too. And there's no T in the date string. So you want
yyyy-MM-dd HH:mm:ss.SSSSSS
This does beg the question as to what time zone that string represents. If it is UTC, you'll want to set the time zone of the formatter, accordingly.
Likewise, you might want to be careful about users with non-Gregorian calendars. See Apple Technical Q&A 1480 regarding setting the locale to en_US_POSIX.

NSDateFormatter: stringFromDate and dateFromString not reversible?

I'm having problems using a custom date formatter with NSDateFormatter to convert a string into a date. Here's a short example that creates a string from today's date but fails to convert this back to an NSDate:
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"Mdyyyy"];
NSString *example = [dateFormatter stringFromDate:now]; // e.g., 10292013
NSDate *reverse = [dateFormatter dateFromString:example]; // nil?
So basically it seems that NSDateFormatter is creating a date string that it itself can't turn back into a NSDate using the same format that created the string.
Using MMddyyyy as the date string works, although I can't see from the documentation (which conveniently only goes up to iOS 6.0) why it would matter:
month M 1..2 09 Month - Use one or two for the numerical month, ....
...
day d 1..2 1 Date - Day of the month
The reason why I'm trying to use Mdyyyy instead of MMddyyyy is because it's closer to what NSDateFormatterShortStyle returns for my current NSLocale (M/d/yy).
Perhaps someone might have some insight here as two what I'm doing wrong, or if I'm wrong in my understanding of how this should work. (I know there are a lot of questions here regarding NSDateFormatter, but I didn't find one that fits my problem.)
Mdyyyy is ambiguous as a string ->date mapping. One cannot tell if "1112013" is Jan 11 or November 1. Hence NSDateFormatter will not allow it for string ->date.

Change language for NSDate weekday and month

I want to display a date like this : weekday 7 month.
I did this and I have the correct syntax.
NSDateFormatter* df = [[NSDateFormatter alloc] init];
[df setDateFormat:#"EEEE dd MMMM"];
[df setTimeZone:[NSTimeZone localTimeZone]];
The result logged is : Saturday 16 March. I just want to have the french date, not the english one. I try to set the local time zone but it changes nothing. Do you have an idea of how to do this ?
initialize a locale using an identifer.
you can get all available identifiers from
[NSLocale availableLocaleIdentifiers];
i believe #"fr_BI" is one of the french identifiers
NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:#"fr_BI"];
[dateFormatter setLocale:locale];
You set the locale of the date formatter using the appropriate NSLocale object.
Also, be wary of hard-coded date formats like that. Your users may not like seeing dates in that format, so you should run the format string through +[NSDateFormatter dateFormatFromTemplate:options:locale:] first. The WWDC 2012 session "Internationalization Tips & Tricks" had a bunch of useful information about this.

Resources