NSDateFormatter format string for RFC 3339 date string without milliseconds - cocoa-touch

I am having an issue trying to parse an Atom RFC 3339 date coming from a feed. Is is coming in is form: #"2014-07-21T11:36:05-05:00" and the following formats fail to parse it... any help?
[dateFormatter setDateFormat:#"yyyy'-'MM'-'dd'T'HH':'mm':'ssZZZ"];
[dateFormatter setDateFormat:#"yyyy'-'MM'-'dd'T'HH':'mm':'ss.SSSZZZ"];
[dateFormatter setDateFormat:#"yyyy'-'MM'-'dd'T'HH':'mm':'ss"];
[dateFormatter setDateFormat:#"yyyy'-'MM'-'dd'T'HH':'mm':'ss.ZZZZ"];

The format you need is
yyyy-MM-dd'T'HH:mm:ssZZZZZ
The five Z pattern is a recent-ish addition to the formatting library that handles exactly this time zone format.
(Despite Apple's Technical Q&A 1480 on this topic (and the identical code in the date formatting guide), the only item in the format string that needs to be escaped with apostrophes is the T -- Unicode Technical Standard #35, which governs the format strings, says that only ASCII letters, a-z and A-Z, are reserved. It also says, however, that punctuation may be used in the future, so you can quote the colons and hyphens if you like.)

Related

Changing numeral symbols for NSDateFormatter

So my scenario is basically this: If a user has an Arabic Locale, a date is formatted into this string: ١٩‏/١٠‏/٢٠١٢ ٣:٢١ م
The numerals are Arabic and the date is ordered/formatted a certain way according to the Arabic locale/region format. The problem is that some users might have a Locale of Arabic, but the Language set to English (because he/she might not be able to read Arabic).
Is there a way to change just the numerals to arabic, while preserving everything else in the formatter from the Locale? That is, format that date according to the locale/region format (preserving order) but to use English numerals rather than the Arabic numerals. I don't see any way that Apple has provided us with making such a change.
Thanks in advance!
You have to use one of the locale identifiers that have the English numeral symbols. E.g:
NSDateFormatter *dateFormatter = [NSDateFormatter new];
dateFormatter.dateFormat = #"EEEE dd MMM | hh:mm a";
dateFormatter.locale = [NSLocale localeWithLocaleIdentifier:#"ar_TN"];
NSLog(#"%#", [dateFormatter stringFromDate:[NSDate date]]);
This will print:
الخميس 14 جانفي | 02:02 م
The following post may answer your question:
String replacement in Objective-C
NSString *str = #"This is a string";
str = [str stringByReplacingOccurrencesOfString:#"string"
withString:#"duck"];
For each formatted date string you would call this 10 times (0,1,2,...,8,9). Maybe this will help you.

NSDateFormatter string with subseconds and timezone

I have banged my head against this for too long now!
I have a string: 2012-09-27T18:00:00.000-04:00
I have a format: [dateFormatter setDateFormat:#"yyyy-MM-dd'T'HH:mm:ss'Z'"];
I get a null result converting the string.
Can someone help with the correct date format?
According to the documentation for NSDateFormatter:
The format string uses the format patterns from the Unicode Technical Standard #35. The version of the standard varies with release of the operating system:
Formatters in OS X v10.8 and iOS 6.0 use [version tr35-25].
Following that link:
s 1..2 12 Second. Use one or two for zero padding.
In other words, s for seconds means only the integral part.
But right underneath that, there's:
S 1..n 3456 Fractional Second - truncates (like other time fields) to the count of letters. (example shows display using pattern SSSS for seconds value 12.34567)
Then, the reason you aren't matching the timezone is that you're quoting the Z, so it matches a literal Z rather than a timezone format.
To match the ISO8601 timezone format you're seeing, the same documentation says you want ZZZZZ.
So, it looks like, at least for 10.8/iOS 6, you want:
[dateFormatter setDateFormat:#"yyyy-MM-dd'T'HH:mm:ss'.'SSSZZZZZ"]
For earlier versions, you've got the links to the docs; you should be able to figure it out now.
Testing this (in Python, to save a few lines of code):
>>> import Cocoa
>>> df = Cocoa.NSDateFormatter.alloc().init()
>>> df.setDateFormat_("yyyy-MM-dd'T'HH:mm:ss'.'SSSZZZZZ")
>>> print df.dateFromString_(2012-09-27T18:00:00.000-04:00')
2012-09-27 22:00:00 +0000

Need to parse a string to date without padded 0's

I've read through a lot of examples, but the problem I'm facing is the date I'm getting doesn't have leading 0's and all the objective-c stuff I've found has them. So I need to take the date:
4/9/2012 1:30 PM
And determine if it is today. My place was to either grab today's date and compare it to the first part of that string, but as I said before I can't find anyway to make a date in objective c without leading 0's. I'm hoping to avoid parsing that string manually to add leading 0's.
Use an NSDateFormatter object
[dateFormatter setDateFormat:#"h:mm a"];
if you want 0's
[dateFormatter setDateFormat:#"hh:mm a"];
I think that using the single M option for your date format string will allow it to parse a single digit month value:
The possible date formats are specified here
#ynistersix answer is correct. In Data Formatting Guide, they said that NSDateFormatter follows http://unicode.org/reports/tr35/tr35-dates.html
h 1..2 11 Hour [1-12]. When used in skeleton data or in a skeleton
passed in an API for flexible date pattern generation, it should match
the 12-hour-cycle format preferred by the locale (h or K); it should
not match a 24-hour-cycle format (H or k). Use hh for zero padding.
This is consistent with most other languages. Like .NET
"h" The hour, using a 12-hour clock from 1 to 12.
2009-06-15T01:45:30 -> 1
2009-06-15T13:45:30 -> 1
"hh" The hour, using a 12-hour clock from 01 to 12.
2009-06-15T01:45:30 -> 01
2009-06-15T13:45:30 -> 01

NSNumberFormatter, localized setGroupingSeparator?

With NSNumberFormatter it is very easy to format a number using a fixed string as GroupingSeparator.
[numberFormatter setGroupingSeparator:#"."];
But in some countries #"." is not the valid separator: #"," (a comma) is instead. How can I get a localized grouping separator from the system so my formatting is correct all around the world in any language?
You can use setLocale::
[numberFormatter setLocale:[NSLocale currentLocale]];
The locale exposes the correct symbols for things like decimal separator, quotation marks, and units of measurement and currency.
However! Beware of using this for currency; there is no automatic value conversion. If you have a number representing some amount of U.S. dollars, and just format it as if it were euros, it will be formatted correctly, but will not have the correct meaning.

Localizing concatenated or dynamic strings

I'm familiar with using NSLocalizedString() to localize strings, but the problem I have today requires a little more finesse. My situation is like this:
NSString *userName; //the users name, entered by the user. Does not need localized
NSString *favoriteFood; //the users favorite food, also entered by user, and not needing localized
NSString *summary = [NSString stringWithFormat:#"%#'s favorite food is %#", userName, favoriteFood];
This works fine for english, but not every language uses the same word ordering as English, for example, a word-by-word translation of the same sentance from Japanese into English would read:
UserName's favorite food pizza is
Not to mention that 's is doesn't make a possessive in every language.
What techniques are available for localizing this type of concatenated sentence?
UPDATE FOR THE BENEFIT OF OTHERS:
#Jon Reed is right, positional specifiers are very important to localization. The document he linked only contains a reference to the fact that they can be used with NSString, NSLog, an others, the link doesn't really tell HOW to use them.
I found this link, that explains it well. It also explains my question better than I did. From the link:
Format strings for printf and sprintf
(see Printf) present a special problem
for translation. Consider the
following:1
printf(_"String `%s' has %d characters\n",
string, length(string))) A possible German
translation for this might be:
"%d Zeichen lang ist die Zeichenkette `%s'\n" The problem
should be obvious: the order of the
format specifications is different
from the original! Even though gettext
can return the translated string at
runtime, it cannot change the argument
order in the call to printf.
To solve this problem, printf format
specifiers may have an additional
optional element, which we call a
positional specifier. For example:
"%2$d Zeichen lang ist die Zeichenkette `%1$s'\n" Here, the
positional specifier consists of an
integer count, which indicates which
argument to use, and a ‘$’. Counts are
one-based, and the format string
itself is not included. Thus, in the
following example, ‘string’ is the
first argument and ‘length(string)’ is
the second:
$ gawk 'BEGIN {
> string = "Dont Panic"
> printf _"%2$d characters live in \"%1$s\"\n",
> string, length(string)
> }'
-| 10 characters live in "Dont Panic"
To specify order of substitution, use %1$# and %2$# as your format specifiers. The localized format string can use them in any order. For example, say your string key is "FavoriteFood". Call
NSString *summary =
[NSString stringWithFormat:NSLocalizedString(#"FavoriteFood", nil),
userName, favoriteFood];
The localization places the format specifiers wherever it makes sense for its locale. Example:
"FavoriteFood" = "%2$# is the favorite food of %1$#";
See String Format Specifiers
Applying NSLocalizedString() to the format string #"%#'s favorite food is %#" should allow it to be replaced with the proper word order and possessives for the local language.