[tz] Timezone selectors (was RES: Timezone for Brazil)

Matt Johnson-Pint mattjohnsonpint at gmail.com
Thu Oct 12 16:53:05 UTC 2023


Hi.  I contributed most of the improvements to time zone display name logic
for .NET, so I can offer some clarity here.  The original PR for this work
is at: https://github.com/dotnet/runtime/pull/48931.  There's also a
detailed blog post here:
https://devblogs.microsoft.com/dotnet/date-time-and-time-zone-enhancements-in-net-6/#time-zone-display-names-on-linux-and-macos

First off - Ignore anything related to the System.TimeZone class.  That
only exists for legacy reasons and is generally considered deprecated.
Only System.TimeZoneInfo should be used in .NET today.

As of .NET 6, when running on Linux or MacOS, TimeZoneInfo gets its display
names from ICU4C.  As you suspected, it cannot leverage ICU4J.  It is also
limited to the C APIs.  It cannot use ICU's C++ APIs.

To construct time zone display names, .NET makes calls to both
ucal_getTimeZoneDisplayName, and udat_format with several
different formats. You can see these ICU calls and others in the following
file:

https://github.com/dotnet/runtime/blob/f20509b9ea563da18af963976b7db0e523e6837e/src/native/libs/System.Globalization.Native/pal_timeZoneInfo.c

You'll also want to look at the implementation of the
GetFullValueForDisplayNameField method here:

https://github.com/dotnet/runtime/blob/f20509b9ea563da18af963976b7db0e523e6837e/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.FullGlobalizationData.Unix.cs#L156

(git hashes are just the current values, for permalink purposes)

Between the two files, you'll notice that to use ICU alone to build a list
of time zone display names is quite challenging.  It's not quite as simple
as just taking the LONG_GENERIC of each one.  For example, if you do that,
you'll find at least 13 different entries that all have the same display
name, "Mountain Standard Time".  While useful on a single zone, they're
useless when distinguishing one zone from the next in a list.
Additionally, the word "Standard" can get in the way.  Ultimately one
desires names like "Mountain Time (Phoenix)" vs "Mountain Time (Denver)" -
so that they are disambiguated.

There are lots of other edge cases though, and some of it requires an
opinionated mindset.  For example, see some of the overrides here:

https://github.com/dotnet/runtime/blob/f20509b9ea563da18af963976b7db0e523e6837e/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.FullGlobalizationData.Unix.cs#L17-L25

Hope that helps.  Feel free to ask any follow up questions.

-Matt


On Tue, Oct 10, 2023 at 5:12 PM Guy Harris via tz <tz at iana.org> wrote:

> On Oct 10, 2023, at 4:48 PM, Doug Ewell <doug at ewellic.org> wrote:
>
> > This is what we get from a known, reliable source that offers
> human-readable names in English (or, importantly, 140 other languages)
> corresponding to tzids. Some of the names are probably not perfect for a
> picker. We already know that “(other)” and “(most locations)” are not
> always perfect either, especially when presented out of context: Other than
> what? What does “most” include?
>
> Perhaps it's time for somebody to run some UI experiments to determine
> what works best for what groups of users.  (Complaints that you live in
> city X but the selector only offers city Y count against "works best".)
>
> > We’re using a standard .NET Core call that queries ICU in a Linux
> container, and makes a Windows call when running on Windows. There are no
> options to select names for standard, daylight, or generic, and I don’t
> know why it chooses standard by default. The ICU folks might know.
>
> I'm guessing it's easier for .NET languages to use ICU4C than ICU4J; the
> icu::TimeZone Class Reference:
>
>
> https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/classicu_1_1TimeZone.html#a07cc5464421c1ae84f55ada930cf03df
>
> appears to offer several flavors of the getDisplayName method, with:
>
>         UnicodeString &getDisplayName(UBool inDaylight, EDisplayType
> style, UnicodeString &result) const
>
> and
>
>         UnicodeString &getDisplayName(UBool inDaylight, EDisplayType
> style, const Locale &locale, UnicodeString &result) const
>
> having the style argument, which is an EDisplayType:
>
>
> https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/classicu_1_1TimeZone.html#a07cc5464421c1ae84f55ada930cf03df
>
> I'm guessing that SHORT and LONG use the inDaylight value to determine
> whether to provide the short or long standard time or the short or long
> daylight time name, and SHORT_GENERIC and LONG_GENERIC provide the short or
> long generic name.
>
> At least from what I see on Microsoft Learn, the .NET 7.0 TimeZone class:
>
>
> https://learn.microsoft.com/en-us/dotnet/api/system.timezone?view=net-7.0
>
> only has the standard and daylight names as properties
>
> However, the .NET 7.0 TimeZoneInfo class:
>
>
> https://learn.microsoft.com/en-us/dotnet/api/system.timezoneinfo?view=net-7.0
>
> also has the DisplayName property, which "Gets the general display name
> that represents the time zone", and might provide the generic name when
> it's using ICU.
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mm.icann.org/pipermail/tz/attachments/20231012/1c66d370/attachment.htm>


More information about the tz mailing list