diff --git a/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.GetDisplayName.Invariant.cs b/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.GetDisplayName.Invariant.cs deleted file mode 100644 index 14b302d86b8015..00000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.GetDisplayName.Invariant.cs +++ /dev/null @@ -1,13 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace System -{ - public sealed partial class TimeZoneInfo - { - private unsafe void GetDisplayName(Interop.Globalization.TimeZoneDisplayNameType nameType, string uiCulture, ref string? displayName) - { - displayName = _standardDisplayName; - } - } -} diff --git a/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.GetDisplayName.cs b/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.GetDisplayName.cs index b557c15384bb46..834b719fefe2cd 100644 --- a/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.GetDisplayName.cs +++ b/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.GetDisplayName.cs @@ -58,7 +58,7 @@ private unsafe void GetDisplayName(Interop.Globalization.TimeZoneDisplayNameType // 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) + if (result && !string.IsNullOrEmpty(timeZoneDisplayName)) { displayName = timeZoneDisplayName; } 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 a59d6ee5e6b4b0..30d4ca75718cbd 100644 --- a/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.cs @@ -23,8 +23,6 @@ public sealed partial class TimeZoneInfo private const string TimeZoneEnvironmentVariable = "TZ"; private const string TimeZoneDirectoryEnvironmentVariable = "TZDIR"; private const string FallbackCultureName = "en-US"; - private readonly string? _standardAbbrevName; - private readonly string? _daylightAbbrevName; private TimeZoneInfo(byte[] data, string id, bool dstDisabled) { @@ -36,6 +34,8 @@ private TimeZoneInfo(byte[] data, string id, bool dstDisabled) bool[] StandardTime; bool[] GmtTime; string? futureTransitionsPosixFormat; + string? standardAbbrevName = null; + string? daylightAbbrevName = null; // parse the raw TZif bytes; this method can throw ArgumentException when the data is malformed. TZif_ParseRaw(data, out t, out dts, out typeOfLocalTime, out transitionType, out zoneAbbreviations, out StandardTime, out GmtTime, out futureTransitionsPosixFormat); @@ -54,11 +54,11 @@ private TimeZoneInfo(byte[] data, string id, bool dstDisabled) if (!transitionType[type].IsDst) { _baseUtcOffset = transitionType[type].UtcOffset; - _standardAbbrevName = TZif_GetZoneAbbreviation(zoneAbbreviations, transitionType[type].AbbreviationIndex); + standardAbbrevName = TZif_GetZoneAbbreviation(zoneAbbreviations, transitionType[type].AbbreviationIndex); } else { - _daylightAbbrevName = TZif_GetZoneAbbreviation(zoneAbbreviations, transitionType[type].AbbreviationIndex); + daylightAbbrevName = TZif_GetZoneAbbreviation(zoneAbbreviations, transitionType[type].AbbreviationIndex); } } @@ -71,19 +71,25 @@ private TimeZoneInfo(byte[] data, string id, bool dstDisabled) if (!transitionType[i].IsDst) { _baseUtcOffset = transitionType[i].UtcOffset; - _standardAbbrevName = TZif_GetZoneAbbreviation(zoneAbbreviations, transitionType[i].AbbreviationIndex); + standardAbbrevName = TZif_GetZoneAbbreviation(zoneAbbreviations, transitionType[i].AbbreviationIndex); } else { - _daylightAbbrevName = TZif_GetZoneAbbreviation(zoneAbbreviations, transitionType[i].AbbreviationIndex); + daylightAbbrevName = TZif_GetZoneAbbreviation(zoneAbbreviations, transitionType[i].AbbreviationIndex); } } } + + // Use abbrev as the fallback + _standardDisplayName = standardAbbrevName; + _daylightDisplayName = daylightAbbrevName; _displayName = _standardDisplayName; + 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) { if (_baseUtcOffset >= TimeSpan.Zero) @@ -92,12 +98,6 @@ private TimeZoneInfo(byte[] data, string id, bool dstDisabled) _displayName = $"(UTC-{_baseUtcOffset:hh\\:mm}) {_standardDisplayName}"; } - if (string.IsNullOrEmpty(_daylightDisplayName) && !string.IsNullOrEmpty(_daylightAbbrevName)) - _daylightDisplayName = _daylightAbbrevName; - - if (string.IsNullOrEmpty(_standardDisplayName) && !string.IsNullOrEmpty(_standardAbbrevName)) - _standardDisplayName = _standardAbbrevName; - // TZif supports seconds-level granularity with offsets but TimeZoneInfo only supports minutes since it aligns // with DateTimeOffset, SQL Server, and the W3C XML Specification if (_baseUtcOffset.Ticks % TimeSpan.TicksPerMinute != 0) @@ -218,6 +218,7 @@ private static TimeZoneInfoResult TryGetTimeZoneFromLocalMachine(string id, out e = new InvalidTimeZoneException(SR.Format(SR.InvalidTimeZone_InvalidFileData, id, timeZoneFilePath)); return TimeZoneInfoResult.InvalidTimeZoneException; } + return TimeZoneInfoResult.Success; } @@ -1486,6 +1487,7 @@ private static void TZif_ParseRaw(byte[] data, out TZifHead t, out DateTime[] dt index += TZifHead.Length; timeValuesLength = 8; // the second version uses 8-bytes } + // initialize the containers for the rest of the TZ data dts = new DateTime[t.TimeCount]; typeOfLocalTime = new byte[t.TimeCount]; diff --git a/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.cs b/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.cs index 84b618e536c8c9..dacf92875a71d6 100644 --- a/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.cs +++ b/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.cs @@ -1859,12 +1859,11 @@ private static TimeZoneInfoResult TryGetTimeZone(string id, bool dstDisabled, ou private static TimeZoneInfoResult TryGetTimeZoneFromLocalMachine(string id, bool dstDisabled, out TimeZoneInfo? value, out Exception? e, CachedData cachedData) { TimeZoneInfoResult result; - Internal.Console.Write($"ID {id} DST DISABLED {dstDisabled}\n"); + result = TryGetTimeZoneFromLocalMachine(id, out TimeZoneInfo? match, out e); if (result == TimeZoneInfoResult.Success) { - Internal.Console.Write("TZ SUCCESS\n"); cachedData._systemTimeZones ??= new Dictionary(StringComparer.OrdinalIgnoreCase) { { UtcId, s_utcTimeZone } @@ -1884,7 +1883,6 @@ private static TimeZoneInfoResult TryGetTimeZoneFromLocalMachine(string id, bool } else { - // Internal.Console.Write($"CREATE TZ WITH DST {match._daylightDisplayName!}"); value = new TimeZoneInfo(match!._id, match._baseUtcOffset, match._displayName, match._standardDisplayName, match._daylightDisplayName, match._adjustmentRules, disableDaylightSavingTime: false); } diff --git a/src/libraries/System.Runtime/tests/System/TimeZoneInfoTests.cs b/src/libraries/System.Runtime/tests/System/TimeZoneInfoTests.cs index 2c131b7f1e75f1..c2194a7d24e410 100644 --- a/src/libraries/System.Runtime/tests/System/TimeZoneInfoTests.cs +++ b/src/libraries/System.Runtime/tests/System/TimeZoneInfoTests.cs @@ -81,54 +81,28 @@ public static void Names() Assert.NotNull(utc.ToString()); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsBrowser))] - public static void BrowserDayLightNames() - { - // Due to ICU size limitations, full daylight names are not included. - // daylight name abbreviations, if available, are used instead. - TimeZoneInfo pacific = TimeZoneInfo.FindSystemTimeZoneById(s_strPacific); - Assert.Equal("PDT", pacific.DaylightName); - TimeZoneInfo sydney = TimeZoneInfo.FindSystemTimeZoneById(s_strSydney); - Assert.Equal("AEDT", sydney.DaylightName); - TimeZoneInfo perth = TimeZoneInfo.FindSystemTimeZoneById(s_strPerth); - Assert.Equal("AWDT", perth.DaylightName); - Assert.Equal("CEST", s_amsterdamTz.DaylightName); - TimeZoneInfo moscow = TimeZoneInfo.FindSystemTimeZoneById(s_strRussian); - Assert.Equal("MSD", moscow.DaylightName); - Assert.Equal("WEST", s_LisbonTz.DaylightName); - Assert.Equal("NDT", s_NewfoundlandTz.DaylightName); - - // No IANA daylight name abbreviations available, default to - // UTC offset. - TimeZoneInfo iran = TimeZoneInfo.FindSystemTimeZoneById(s_strIran); - Assert.Equal("+0430", iran.DaylightName); - Assert.Equal("-02", s_catamarcaTz.DaylightName); - } - - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsBrowser))] - public static void BrowserStandardNames() - { - // Due to ICU size limitations, full standard names are not included. - // standard name abbreviations, if available, are used instead. - TimeZoneInfo pacific = TimeZoneInfo.FindSystemTimeZoneById(s_strPacific); - Assert.Equal("PST", pacific.StandardName); - TimeZoneInfo sydney = TimeZoneInfo.FindSystemTimeZoneById(s_strSydney); - Assert.Equal("AEST", sydney.StandardName); - TimeZoneInfo perth = TimeZoneInfo.FindSystemTimeZoneById(s_strPerth); - Assert.Equal("AWST", perth.StandardName); - Assert.Equal("CET", s_amsterdamTz.StandardName); - TimeZoneInfo moscow = TimeZoneInfo.FindSystemTimeZoneById(s_strRussian); - Assert.Equal("MSK", moscow.StandardName); - Assert.Equal("WET", s_LisbonTz.StandardName); - Assert.Equal("NST", s_NewfoundlandTz.StandardName); - - // No IANA standard name abbreviations available, default to - // UTC offset. - TimeZoneInfo iran = TimeZoneInfo.FindSystemTimeZoneById(s_strIran); - Assert.Equal("-03", s_catamarcaTz.StandardName); - Assert.Equal("+0330", iran.StandardName); + // Due to ICU size limitations, full daylight/standard names are not included. + // name abbreviations, if available, are used instead + public static TheoryData GetBrowser_TimeZoneNamesTestData() + { + return new TheoryData + { + { TimeZoneInfo.FindSystemTimeZoneById(s_strPacific), "(UTC-08:00) PST", "PST", "PDT" }, + { TimeZoneInfo.FindSystemTimeZoneById(s_strSydney), "(UTC+10:00) AEST", "AEST", "AEDT" }, + { TimeZoneInfo.FindSystemTimeZoneById(s_strPerth), "(UTC+08:00) AWST", "AWST", "AWDT" }, + { TimeZoneInfo.FindSystemTimeZoneById(s_strIran), "(UTC+03:30) +0330", "+0330", "+0430" }, + + { s_NewfoundlandTz, "(UTC-03:30) NST", "NST", "NDT" }, + { s_catamarcaTz, "(UTC-03:00) -03", "-03", "-02" } + }; } + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsBrowser))] + [MemberData(nameof(GetBrowser_TimeZoneNamesTestData))] + public static void Browser_TimeZoneNames(TimeZoneInfo tzi, string displayName, string standardName, string daylightName) + => Assert.Equal($"DisplayName: {tzi.DisplayName}, StandardName: {tzi.StandardName}, DaylightName: {tzi.DaylightName}", + $"DisplayName: {displayName}, StandardName: {standardName}, DaylightName: {daylightName}"); + [Fact] public static void ConvertTime() { @@ -2317,8 +2291,8 @@ public static void TimeZoneInfo_DisplayNameStartsWithOffset() if (tzi.Id != "UTC") { Assert.False(string.IsNullOrWhiteSpace(tzi.StandardName)); - Console.WriteLine($"DISPLAY NAME {tzi.DisplayName}"); - Assert.Matches(@"^\(UTC(\+|-)[0-9]{2}:[0-9]{2}\)( \S.*)*", tzi.DisplayName); + Assert.Matches(@"^\(UTC(\+|-)[0-9]{2}:[0-9]{2}\) \S.*", tzi.DisplayName); + // see https://github.com/dotnet/corefx/pull/33204#issuecomment-438782500 if (PlatformDetection.IsNotWindowsNanoServer && !PlatformDetection.IsWindows7) { @@ -2326,7 +2300,6 @@ public static void TimeZoneInfo_DisplayNameStartsWithOffset() TimeSpan ts = TimeSpan.Parse(offset); if (tzi.BaseUtcOffset != ts && tzi.Id.IndexOf("Morocco", StringComparison.Ordinal) >= 0) { - Console.WriteLine(tzi.BaseUtcOffset); // Windows data can report display name with UTC+01:00 offset which is not matching the actual BaseUtcOffset. // We special case this in the test to avoid the test failures like: // 01:00 != 00:00:00, dn:(UTC+01:00) Casablanca, sn:Morocco Standard Time