From: Tarek Mahmoud Sayed Date: Tue, 10 Mar 2020 16:38:34 +0000 (-0700) Subject: Fix getting time zone names with Invariant Culture (#33318) X-Git-Tag: submit/tizen/20210909.063632~9244 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=88cc71b26ba1eb430aaeeebddcd5675b3009f2ee;p=platform%2Fupstream%2Fdotnet%2Fruntime.git Fix getting time zone names with Invariant Culture (#33318) * Fix getting time zone names with Invariant Culture * Address the feedback * Restrict the test to English languages only. * Fix misspelling * Remove un-needed line --- diff --git a/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.cs index 3a5ecca..92d3130 100644 --- a/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.cs @@ -24,6 +24,7 @@ namespace System private const string ZoneTabFileName = "zone.tab"; private const string TimeZoneEnvironmentVariable = "TZ"; private const string TimeZoneDirectoryEnvironmentVariable = "TZDIR"; + private const string FallbackCultureName = "en-US"; private TimeZoneInfo(byte[] data, string id, bool dstDisabled) { @@ -80,9 +81,10 @@ namespace System } _displayName = _standardDisplayName; - GetDisplayName(Interop.Globalization.TimeZoneDisplayNameType.Generic, ref _displayName); - GetDisplayName(Interop.Globalization.TimeZoneDisplayNameType.Standard, ref _standardDisplayName); - GetDisplayName(Interop.Globalization.TimeZoneDisplayNameType.DaylightSavings, ref _daylightDisplayName); + string uiCulture = CultureInfo.CurrentUICulture.Name.Length == 0 ? FallbackCultureName : CultureInfo.CurrentUICulture.Name; // ICU doesn't work nicely with Invariant + GetDisplayName(Interop.Globalization.TimeZoneDisplayNameType.Generic, uiCulture, ref _displayName); + GetDisplayName(Interop.Globalization.TimeZoneDisplayNameType.Standard, uiCulture, ref _standardDisplayName); + GetDisplayName(Interop.Globalization.TimeZoneDisplayNameType.DaylightSavings, uiCulture, ref _daylightDisplayName); if (_standardDisplayName == _displayName) { @@ -108,7 +110,7 @@ namespace System ValidateTimeZoneInfo(_id, _baseUtcOffset, _adjustmentRules, out _supportsDaylightSavingTime); } - private unsafe void GetDisplayName(Interop.Globalization.TimeZoneDisplayNameType nameType, ref string? displayName) + private unsafe void GetDisplayName(Interop.Globalization.TimeZoneDisplayNameType nameType, string uiCulture, ref string? displayName) { if (GlobalizationMode.Invariant) { @@ -125,11 +127,28 @@ namespace System return Interop.Globalization.GetTimeZoneDisplayName(locale, id, type, bufferPtr, buffer.Length); } }, - CultureInfo.CurrentUICulture.Name, + uiCulture, _id, nameType, out timeZoneDisplayName); + if (!result && uiCulture != FallbackCultureName) + { + // Try to fallback using FallbackCultureName just in case we can make it work. + result = Interop.CallStringMethod( + (buffer, locale, id, type) => + { + fixed (char* bufferPtr = buffer) + { + return Interop.Globalization.GetTimeZoneDisplayName(locale, id, type, bufferPtr, buffer.Length); + } + }, + FallbackCultureName, + _id, + nameType, + out timeZoneDisplayName); + } + // If there is an unknown error, don't set the displayName field. // It will be set to the abbreviation that was read out of the tzfile. if (result) diff --git a/src/libraries/System.Runtime/tests/System/TimeZoneInfoTests.cs b/src/libraries/System.Runtime/tests/System/TimeZoneInfoTests.cs index 5ff7f8e..8738d64 100644 --- a/src/libraries/System.Runtime/tests/System/TimeZoneInfoTests.cs +++ b/src/libraries/System.Runtime/tests/System/TimeZoneInfoTests.cs @@ -10,6 +10,7 @@ using System.Linq; using System.Runtime.InteropServices; using System.Runtime.Serialization.Formatters.Binary; using System.Text.RegularExpressions; +using Microsoft.DotNet.RemoteExecutor; using Xunit; namespace System.Tests @@ -2268,6 +2269,29 @@ namespace System.Tests Assert.True(ReferenceEquals(TimeZoneInfo.FindSystemTimeZoneById("UTC"), TimeZoneInfo.Utc)); } + // We test the existance of a specific English time zone name to avoid failures on non-English platforms. + [ConditionalFact(nameof(IsEnglishUILanguage))] + public static void TestNameWithInvariantCulture() + { + RemoteExecutor.Invoke(() => + { + // We call ICU to get the names. When passing invariant culture name to ICU, it fail and we'll use the abbreviated names at that time. + // We fixed this issue by avoid sending the invariant culture name to ICU and this test is confirming we work fine at that time. + CultureInfo.CurrentUICulture = CultureInfo.InvariantCulture; + TimeZoneInfo.ClearCachedData(); + + TimeZoneInfo pacific = TimeZoneInfo.FindSystemTimeZoneById(s_strPacific); + + Assert.True(pacific.StandardName.IndexOf("Pacific", StringComparison.OrdinalIgnoreCase) >= 0, $"'{pacific.StandardName}' is not the expected standard name for Pacific time zone"); + Assert.True(pacific.DaylightName.IndexOf("Pacific", StringComparison.OrdinalIgnoreCase) >= 0, $"'{pacific.DaylightName}' is not the expected daylight name for Pacific time zone"); + Assert.True(pacific.DisplayName.IndexOf("Pacific", StringComparison.OrdinalIgnoreCase) >= 0, $"'{pacific.DisplayName}' is not the expected display name for Pacific time zone"); + + }).Dispose(); + + } + + private static bool IsEnglishUILanguage() => CultureInfo.CurrentUICulture.Name == "en" || CultureInfo.CurrentUICulture.Name.StartsWith("en-", StringComparison.Ordinal); + private static void VerifyConvertException(DateTimeOffset inputTime, string destinationTimeZoneId) where TException : Exception { Assert.ThrowsAny(() => TimeZoneInfo.ConvertTime(inputTime, TimeZoneInfo.FindSystemTimeZoneById(destinationTimeZoneId)));