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)
{
}
_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)
{
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)
{
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)
using System.Runtime.InteropServices;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text.RegularExpressions;
+using Microsoft.DotNet.RemoteExecutor;
using Xunit;
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<TException>(DateTimeOffset inputTime, string destinationTimeZoneId) where TException : Exception
{
Assert.ThrowsAny<TException>(() => TimeZoneInfo.ConvertTime(inputTime, TimeZoneInfo.FindSystemTimeZoneById(destinationTimeZoneId)));