<div dir="ltr">Re-reading the thread, it seems part of the question is why the word "Standard" is present in "(UTC-03:00) Brasilia Standard Time (Sao Paulo)".  That's due to the 184 day rule, specified in the "TypeFallback" section of the TR35 spec that ICU uses to interpret CLDR data.  See <a href="https://www.unicode.org/reports/tr35/tr35-dates.html#Using_Time_Zone_Names" target="_blank">https://www.unicode.org/reports/tr35/tr35-dates.html#Using_Time_Zone_Names</a><div><br></div><div><div>.NET tries to side-step that, in the FixupTimeZoneGenericDisplayName function here:</div><div><a href="https://github.com/dotnet/runtime/blob/f20509b9ea563da18af963976b7db0e523e6837e/src/native/libs/System.Globalization.Native/pal_timeZoneInfo.c#L98" target="_blank">https://github.com/dotnet/runtime/blob/f20509b9ea563da18af963976b7db0e523e6837e/src/native/libs/System.Globalization.Native/pal_timeZoneInfo.c#L98</a></div><div><br></div><div>Unfortunately, the fixup function only works if there's at least one zone in the same metazone whose generic name doesn't get the 184 day rule applied.  So it can make all zones that have a generic name of "Mountain Standard Time" use the name "Mountain Time" instead (thanks to America/Phoenix), but it can't find any alternative to "Brasilia Standard Time" because all the zones in "Brasilia" metazone all have the same generic name, "Brasilia Standard Time".   (Note, one can't simply remove words from the string, because you'd have to account for the equivalent of "Standard" in every supported language).</div><div><br></div><div>Metazones are in CLDR here:<br></div><div><a href="https://github.com/unicode-org/cldr/blob/main/common/supplemental/metaZones.xml">https://github.com/unicode-org/cldr/blob/main/common/supplemental/metaZones.xml</a><br></div><div><br></div><div>And here's the language entry for English for the Brasilia metazone:</div><div><a href="https://github.com/unicode-org/cldr/blob/657e6e996b88b891132db29cc4fc61c36f174689/common/main/en.xml#L4168-L4174">https://github.com/unicode-org/cldr/blob/657e6e996b88b891132db29cc4fc61c36f174689/common/main/en.xml#L4168-L4174</a><br></div><div><br></div><div><metazone type="Brasilia"><br>  <long><br>    <generic>Brasilia Time</generic><br>    <standard>Brasilia Standard Time</standard><br>    <daylight>Brasilia Summer Time</daylight><br>  </long><br>                    </metazone><br></div><div><br></div><div>So, you get "Brasilia Standard Time" because according to ICU, that is the generic name for the Brasilia metazone, even though CLDR has "Brasilia Time" - the 184 day rule applies and ICU overrides it with the standard name.</div><div><br></div><div>Unfortunately, I have not found a way to get the generic name directly from ICU4C (via a C API, not C++), that doesn't apply the 184 day rule.</div><div><br></div><div>-Matt<br><div><br></div></div></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Thu, Oct 12, 2023 at 9:53 AM Matt Johnson-Pint <<a href="mailto:mattjohnsonpint@gmail.com" target="_blank">mattjohnsonpint@gmail.com</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"><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" target="_blank">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" target="_blank">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" target="_blank">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" target="_blank">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" target="_blank">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" target="_blank">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>
</blockquote></div>