We do seem to be short on time... (Windows 7 edition)

by Michael S. Kaplan, published on 2010/01/27 07:01 -05:00, original URI: http://blogs.msdn.com/b/michkap/archive/2010/01/27/9953946.aspx


The question was easy enough:

Hi,

I am trying to use the GetTimeFormat to retrieve the Time format from the system. Win7 added the new customized format. How can I get the format(as in the attached image)?



Which Locale ID should I use?

Thanks

Well, first let's take a moment to recognize something important that this screenshot shows.

Do you see it?

Hint #1: It is from windows 7.

Now?

Hint #2: Remember blogs like Customizing the SHORT time format? and We do seem to be short on time... and I see LONG TIME and SHORT TIME; where are SHORTER TIME and SHORTEST TIME? and Predictably (in retrospect), aka Where Wild^H^H^Hindows-Only Things Are, aka SHORT [on ]TIME for a LONG TIME and such.

Oh, never mind. I gave it away.

They added a short time format to Regional and Language Options!

Awesome, right? Now there is parity between this piece of managed code and native code, between NLS and the Globalization classes.

Very cool!

Well, almost.

Getting back to that question:

I am trying to use the GetTimeFormat to retrieve the Time format from the system. Win7 added the new customized format. How can I get the format

Suddenly we lose some awesomeness, here.

You see, GetTimeFormat/GetTimeFormatEx add no new flags to get at this new data item that Regional and Language Options exposes. They have the same old flags they always had, but no new meanings atre ascribed to them, and behavior changes would be bad so it is probablyh good that nothing changed here.

And the Windows 7 version of winnls.h adds no new flags to get at the short time, either (just in case there was some worry that the docs were falling behind the product features).

There is no way to directly get at this new format that you can get at the time for formatting from the time formatting functions.

Though you can get at it through EnumTimeFormats/EnumTimeFormatsEx with the new TIME_NOSECONDS flag, or GetLocaleInfo/GetLocaleInfoEx with the LOCALE_SSHORTTIME flag.

As a by the way, the LOCALE_SSHORTTIME flag has some really disturbing (to me, at least) information:

Windows 7 and later: Short time formatting string for the locale. Patterns are typically derived by removing the "ss" (seconds) value from the long time format pattern. For example, if the long time format is "h:mm:ss tt", the short time format is most likely "h:mm tt". This constant can specify multiple formats in a semicolon-delimited list. However, the preferred short time format should be the first value listed.

Um, if true, that means that LOCALE_SSHORTTIME does not behave like LOCALE_SSHORTDATE or LOCALE_SLONGDATE. It returns the semicolon-delimited list of short times that EnumTimeFormats/EnumTimeFormatsEx enumerate.

Now if true that would make it easy for the .NET Framework's new upcoming version to ask Windows for information since that is the format it grabs out itself anyway, but not so easy for developers in Windows or outside of Microsoft using Windows, since which entry is the (possibly customized but if nothing else "current default" is not documented and thus the Windows code that grabs formats out of EnumTimeFormats/EnumTimeFormatsEx can't be officially relied on (in practice it should be the first one, I suppose - maybe that should be officially documented).

And even if it could, parsing a semicolon delimited list of formats is easier than calling the enumeration functions which make callbacks and so forth.

That may be why LOCALE_SSHORTTIME has this unusual data return value - the fact that this keeps the .Net folks from having to call the complicated callback function. So at least someone might have had an easier job.

The solution to the original problem?

Well, Step 1 is to call GetLocaleInfo/GetLocaleInfoEx with the LOCALE_SSHORTTIME flag.

And then Step 2 is to take the string that is returned and pass it as the format to GetTimeFormat/GetTimeFormatEx.

And of course that last question (which locale?), is to use either the LOCALE_USER_DEFAULT or LOCALE_NAME_USER_DEFAULT constant, depending on which function you call.

You might get a sense of why I stopped thinking it was awesome.

I mean, don't get me wrong, it is better than nothing.

But there is a lot of room for improvement in future versions, based on the ways that developers might want to make use of the information....

UPDATE 12:32pm - it seems that they did the work in GetTimeFormat[Ex] to support the formatting; if you pass TIME_NOSECONDS they give you the short time in Regional and Language Options, with seconds stripped out if you added them. Though is you want what the user put in you have to go through the above steps due to the overloading of this flag that has had its meaning changed. Maybe I'll write about that tomorrow....


# Random832 on 30 Jan 2010 10:45 PM:

Under what circumstances will an item other than the first from this "multiple formats in a semicolon-delimited list" be used?

Or, put another way, what is the effect of allowing this to occur other than to gratuitously prevent semicolon from being a valid character in the short time format?

# Michael S. Kaplan on 31 Jan 2010 12:50 AM:

This information is not documented so there is not currently an official answer....

# Michael S. Kaplan on 31 Jan 2010 6:28 AM:

Well some of it is clear in the way of defacto behavior - like the strange setlocaleinfo behavior, which is I suspect the reason for the "maybe" language surrounding the semicolon....


referenced by

2011/01/28 Punishing a locale for its language's letter choices is just unseemly

2010/02/20 The road not traveled (or, more to the point, the road not built) for Amharic

go to newer or older post, or back to index or month or day