Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -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);
Expand All @@ -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);
}
}

Expand All @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, TimeZoneInfo>(StringComparer.OrdinalIgnoreCase)
{
{ UtcId, s_utcTimeZone }
Expand All @@ -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);
}
Expand Down
71 changes: 22 additions & 49 deletions src/libraries/System.Runtime/tests/System/TimeZoneInfoTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<TimeZoneInfo, string, string, string> GetBrowser_TimeZoneNamesTestData()
{
return new TheoryData<TimeZoneInfo, string, string, string>
{
{ 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()
{
Expand Down Expand Up @@ -2317,16 +2291,15 @@ 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)
{
string offset = Regex.Match(tzi.DisplayName, @"(-|)[0-9]{2}:[0-9]{2}").Value;
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
Expand Down