<div dir="ltr">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: <a href="https://github.com/dotnet/runtime/pull/48931">https://github.com/dotnet/runtime/pull/48931</a>.  There's also a detailed blog post here:<br><a href="https://devblogs.microsoft.com/dotnet/date-time-and-time-zone-enhancements-in-net-6/#time-zone-display-names-on-linux-and-macos">https://devblogs.microsoft.com/dotnet/date-time-and-time-zone-enhancements-in-net-6/#time-zone-display-names-on-linux-and-macos</a><br><div><div><br></div><div>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.</div><div><br></div><div>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.</div><div><br></div><div>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:</div><div><br></div><div><a href="https://github.com/dotnet/runtime/blob/f20509b9ea563da18af963976b7db0e523e6837e/src/native/libs/System.Globalization.Native/pal_timeZoneInfo.c">https://github.com/dotnet/runtime/blob/f20509b9ea563da18af963976b7db0e523e6837e/src/native/libs/System.Globalization.Native/pal_timeZoneInfo.c</a><br></div><div><br></div><div>You'll also want to look at the implementation of the GetFullValueForDisplayNameField method here:</div></div><div><br></div><div><a href="https://github.com/dotnet/runtime/blob/f20509b9ea563da18af963976b7db0e523e6837e/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.FullGlobalizationData.Unix.cs#L156">https://github.com/dotnet/runtime/blob/f20509b9ea563da18af963976b7db0e523e6837e/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.FullGlobalizationData.Unix.cs#L156</a><br></div><div><br></div><div>(git hashes are just the current values, for permalink purposes)</div><div><br></div><div>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.</div><div><br></div><div>There are lots of other edge cases though, and some of it requires an opinionated mindset.  For example, see some of the overrides here:</div><div><br></div><div><a href="https://github.com/dotnet/runtime/blob/f20509b9ea563da18af963976b7db0e523e6837e/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.FullGlobalizationData.Unix.cs#L17-L25">https://github.com/dotnet/runtime/blob/f20509b9ea563da18af963976b7db0e523e6837e/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.FullGlobalizationData.Unix.cs#L17-L25</a><br></div><div><br></div><div>Hope that helps.  Feel free to ask any follow up questions.</div><div><br></div><div>-Matt</div><div><br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Tue, Oct 10, 2023 at 5:12 PM Guy Harris via tz <<a href="mailto:tz@iana.org">tz@iana.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">On Oct 10, 2023, at 4:48 PM, Doug Ewell <<a href="mailto:doug@ewellic.org" target="_blank">doug@ewellic.org</a>> wrote:<br>
<br>
> 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?<br>
<br>
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".)<br>
<br>
> 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.<br>
<br>
I'm guessing it's easier for .NET languages to use ICU4C than ICU4J; the icu::TimeZone Class Reference:<br>
<br>
        <a href="https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/classicu_1_1TimeZone.html#a07cc5464421c1ae84f55ada930cf03df" rel="noreferrer" target="_blank">https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/classicu_1_1TimeZone.html#a07cc5464421c1ae84f55ada930cf03df</a><br>
<br>
appears to offer several flavors of the getDisplayName method, with:<br>
<br>
        UnicodeString &getDisplayName(UBool inDaylight, EDisplayType style, UnicodeString &result) const<br>
<br>
and<br>
<br>
        UnicodeString &getDisplayName(UBool inDaylight, EDisplayType style, const Locale &locale, UnicodeString &result) const<br>
<br>
having the style argument, which is an EDisplayType:<br>
<br>
        <a href="https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/classicu_1_1TimeZone.html#a07cc5464421c1ae84f55ada930cf03df" rel="noreferrer" target="_blank">https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/classicu_1_1TimeZone.html#a07cc5464421c1ae84f55ada930cf03df</a><br>
<br>
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.<br>
<br>
At least from what I see on Microsoft Learn, the .NET 7.0 TimeZone class:<br>
<br>
        <a href="https://learn.microsoft.com/en-us/dotnet/api/system.timezone?view=net-7.0" rel="noreferrer" target="_blank">https://learn.microsoft.com/en-us/dotnet/api/system.timezone?view=net-7.0</a><br>
<br>
only has the standard and daylight names as properties<br>
<br>
However, the .NET 7.0 TimeZoneInfo class:<br>
<br>
        <a href="https://learn.microsoft.com/en-us/dotnet/api/system.timezoneinfo?view=net-7.0" rel="noreferrer" target="_blank">https://learn.microsoft.com/en-us/dotnet/api/system.timezoneinfo?view=net-7.0</a><br>
<br>
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.<br>
<br>
<br>
</blockquote></div>