Tuesday, May 26, 2015

Predictable Date Formatting

Daniel Jalkut:

That “HH” is supposed to reflect the hour as a zero-padded number between 00 and 23. And it does, or at least it has, ever since I started using this formatting string in MarsEdit eight years ago.

Starting very recently, I think with 10.10.3, NSDateFormatter may return a string formatted for the user’s 12-hour clock preference, and with a troubling “am” or “pm” component embedded within.

I don’t think I saw this problem because my date formatters like this were configured to use the “en_US” locale. However, Jalkut points out that even better is to use “en_US_POSIX”.

Update (2015-05-28): Ali Rantakari:

My @fauxpasapp can help find/detect cases like this and suggests `en_US_POSIX`.

6 Comments RSS · Twitter

@charles Thanks for the link. It sounds like Paul Kim is talking about a different use case? Jalkut (and I) specifically want a fixed format for Internet dates (always English), which I think is what en_US_POSIX does.

Indeed, he has different goals, but what strikes me is how many not-so-subtle bugs there are in an API that is highly testable. Maybe I am naive ;-)

@charles Are they really bugs, or is this how ICU is intended to work?

Good point, and to be honest, I had not researched that. But now, from the Unicode ref:

"... all ASCII letters from a to z and A to Z are reserved as syntax characters, and require quoting if they are to represent literal characters. In addition, certain ASCII punctuation characters may become variable in the future (for example, ":" being interpreted as the time separator and '/' as a date separator, and replaced by respective locale-sensitive characters in display)."

Thus it looks like non-letter characters should not be interpreted specially. At least for the time being.

There is also nothing in the specs that justifies the 'a' being silently skipped when combined with 'hh' when the user pref is set to 24 hours. And of course, no good reason for 'hh' to output something higher than 12. In fact, this whole mess with hh/HH is not necessary as there is 'j':

"Note that use of 'j' in a skeleton passed to an API is the only way to have a skeleton request a locale's preferred time cycle type (12-hour or 24-hour)."

**The only way**

(http://www.unicode.org/reports/tr35/tr35-31/tr35-dates.html#Date_Format_Patterns)

Maybe I am misinterpreting the specs (one thing unclear is what's a 'skeleton'?!), but they are quite straightforward and clear, and also seem sensible. In any case, I agree with Paul Kim when he says "this API is at a much lower level and should respect the literal pattern provided the developer". I don't understand why one would have to go through such hoops when being so explicit about a meticulously crafted output format. And yes, it's often a mistake to try to be too smart about date/time formatting as it tends to ignore some users' locales in bad ways, but if Apple gives us a gun to play with, we should be free to shoot ourselves in the foot. OK, bad analogy.

@charles Yes, this is all very strange. At minimum, it should be documented better what the Apple APIs do.

Leave a Comment