Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Supposedly identical K8S pods are returning different values #70

Closed
jslaybaugh opened this issue May 27, 2020 · 4 comments
Closed

Supposedly identical K8S pods are returning different values #70

jslaybaugh opened this issue May 27, 2020 · 4 comments

Comments

@jslaybaugh
Copy link

Using:

  • TimeZoneConverter 3.2
  • .net core 2.2
  • Kubernetes 1.15.10
  • base image: mcr.microsoft.com/dotnet/core/aspnet:2.2-stretch-slim
  • build image: mcr.microsoft.com/dotnet/core/sdk:2.2-stretch

Problem

Our application is running on linux containers in an Azure Kubernetes cluster. I have 5 pods in a single deployment in the kubernetes cluster and different pods are returning different values for TimeZoneInfo.StandardName and TimeZoneInfo.DaylightName on some pods from other pods in spite of the pods being identical images running identical code on identical configs. When I bash into the pods and run apt list they both show to have tzdata installed and show the same information for each:

$ apt list
...
tzdata/oldstable,oldstable-updates,now 2019c-0+deb9u1 all [installed,automatic]
...

I created a page to reproduce this that you can hit at https://brushfire.com/test/timezones. The first several lines are the machine name and the OS version and culture. Then it lists all the timezones in the following format:

{DisplayName}, {StandardName}, {DaylightName}, {Abbreviation}

As you can see from the following screenshots, on one pod I'm getting different values from another pod. All my code for returning this list and for my creation of the abbreviation is included below, but fundamentally the issue stems from TimeZoneInfo.StandardName and TimeZoneInfo.DaylightName returning different values on different pods. Any idea why this may be happening?

Screen Shot 2020-05-27 at 11 33 20 AM

Screen Shot 2020-05-27 at 11 33 39 AM

TestController.cs

public ActionResult TimeZones()
{
	var values = LocalizationUtility.GetWindowsTimeZones().Select(x=> $"{x.DisplayName}, {TZConvert.GetTimeZoneInfo(x.Id).StandardName}, {TZConvert.GetTimeZoneInfo(x.Id).DaylightName}, {TZConvert.GetTimeZoneInfo(x.Id).Abbreviation(new DateTime(2020,12,1,13,15,16))}").ToList();
	values.Insert(0, $"Current Culture: {System.Threading.Thread.CurrentThread.CurrentCulture}");
	values.Insert(0, $"Current UI Culture: {System.Threading.Thread.CurrentThread.CurrentUICulture}");
	values.Insert(0, $"Version: {Environment.Version}");
	values.Insert(0, $"OSVersion: {Environment.OSVersion}");
	values.Insert(0, $"Machine: {Environment.MachineName}");
	return Content(string.Join(Environment.NewLine, values),"text/plain", Encoding.UTF8);
}

LocalizationUtility.cs

public static List<FormattedTimeZone> GetWindowsTimeZones()
{
	var ids = TZConvert.KnownWindowsTimeZoneIds
		.ToList();

	var list = new List<FormattedTimeZone>();

	ids.ForEach(x =>
	{
		TimeZoneInfo tz;
		var res = TZConvert.TryGetTimeZoneInfo(x, out tz);
		if (res)
		{
			// get the more helpful name from our custom lookup
			if (TIMEZONE_WINDOWS_LOOKUP.ContainsKey(x))
			{
				list.Add(new FormattedTimeZone { Id = x, Name = TIMEZONE_WINDOWS_LOOKUP[x], Offset = tz.BaseUtcOffset });
			}
		}
	});

	return list
		.OrderBy(x=>x.Offset)
		.ThenBy(x=>x.Name)
		.ToList();
}

private static readonly Dictionary<string, string> TIMEZONE_WINDOWS_LOOKUP = new Dictionary<string, string>
{
	{"Dateline Standard Time", "International Date Line West"},
	{"UTC-11", "Coordinated Universal Time-11"},
	{"Aleutian Standard Time", "Aleutian Islands"},
	{"Hawaiian Standard Time", "Hawaii"},
	{"Marquesas Standard Time", "Marquesas Islands"},
	{"Alaskan Standard Time", "Alaska"},
	{"UTC-09", "Coordinated Universal Time-09"},
	{"Pacific Standard Time (Mexico)", "Baja California"},
	{"UTC-08", "Coordinated Universal Time-08"},
	{"Pacific Standard Time", "Pacific Time (US & Canada)"},
	{"US Mountain Standard Time", "Arizona"},
	{"Mountain Standard Time (Mexico)", "Chihuahua, La Paz, Mazatlan"},
	{"Mountain Standard Time", "Mountain Time (US & Canada)"},
	{"Central America Standard Time", "Central America"},
	{"Central Standard Time", "Central Time (US & Canada)"},
	{"Easter Island Standard Time", "Easter Island"},
	{"Central Standard Time (Mexico)", "Guadalajara, Mexico City, Monterrey"},
	{"Canada Central Standard Time", "Saskatchewan"},
	{"SA Pacific Standard Time", "Bogota, Lima, Quito, Rio Branco"},
	{"Eastern Standard Time (Mexico)", "Chetumal"},
	{"Eastern Standard Time", "Eastern Time (US & Canada)"},
	{"Haiti Standard Time", "Haiti"},
	{"Cuba Standard Time", "Havana"},
	{"US Eastern Standard Time", "Indiana (East)"},
	{"Turks And Caicos Standard Time", "Turks and Caicos"},
	{"Paraguay Standard Time", "Asuncion"},
	{"Atlantic Standard Time", "Atlantic Time (Canada)"},
	{"Venezuela Standard Time", "Caracas"},
	{"Central Brazilian Standard Time", "Cuiaba"},
	{"SA Western Standard Time", "Georgetown, La Paz, Manaus, San Juan"},
	{"Pacific SA Standard Time", "Santiago"},
	{"Newfoundland Standard Time", "Newfoundland"},
	{"Tocantins Standard Time", "Araguaina"},
	{"E. South America Standard Time", "Brasilia"},
	{"SA Eastern Standard Time", "Cayenne, Fortaleza"},
	{"Argentina Standard Time", "City of Buenos Aires"},
	{"Greenland Standard Time", "Greenland"},
	{"Montevideo Standard Time", "Montevideo"},
	{"Magallanes Standard Time", "Punta Arenas"},
	{"Saint Pierre Standard Time", "Saint Pierre and Miquelon"},
	{"Bahia Standard Time", "Salvador"},
	{"UTC-02", "Coordinated Universal Time-02"},
	{"Mid-Atlantic Standard Time", "Mid-Atlantic - Old"},
	{"Azores Standard Time", "Azores"},
	{"Cape Verde Standard Time", "Cabo Verde Is."},
	{"UTC", "(UTC) Coordinated Universal Time"},
	{"GMT Standard Time", "Dublin, Edinburgh, Lisbon, London"},
	{"Greenwich Standard Time", "Monrovia, Reykjavik"},
	{"Sao Tome Standard Time", "Sao Tome"},
	{"Morocco Standard Time", "Casablanca"},
	{"W. Europe Standard Time", "Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna"},
	{"Central Europe Standard Time", "Belgrade, Bratislava, Budapest, Ljubljana, Prague"},
	{"Romance Standard Time", "Brussels, Copenhagen, Madrid, Paris"},
	{"Central European Standard Time", "Sarajevo, Skopje, Warsaw, Zagreb"},
	{"W. Central Africa Standard Time", "West Central Africa"},
	{"Jordan Standard Time", "Amman"},
	{"GTB Standard Time", "Athens, Bucharest"},
	{"Middle East Standard Time", "Beirut"},
	{"Egypt Standard Time", "Cairo"},
	{"E. Europe Standard Time", "Chisinau"},
	{"Syria Standard Time", "Damascus"},
	{"West Bank Standard Time", "Gaza, Hebron"},
	{"South Africa Standard Time", "Harare, Pretoria"},
	{"FLE Standard Time", "Helsinki, Kyiv, Riga, Sofia, Tallinn, Vilnius"},
	{"Israel Standard Time", "Jerusalem"},
	{"Kaliningrad Standard Time", "Kaliningrad"},
	{"Sudan Standard Time", "Khartoum"},
	{"Libya Standard Time", "Tripoli"},
	{"Namibia Standard Time", "Windhoek"},
	{"Arabic Standard Time", "Baghdad"},
	{"Turkey Standard Time", "Istanbul"},
	{"Arab Standard Time", "Kuwait, Riyadh"},
	{"Belarus Standard Time", "Minsk"},
	{"Russian Standard Time", "Moscow, St. Petersburg"},
	{"E. Africa Standard Time", "Nairobi"},
	{"Iran Standard Time", "Tehran"},
	{"Arabian Standard Time", "Abu Dhabi, Muscat"},
	{"Astrakhan Standard Time", "Astrakhan, Ulyanovsk"},
	{"Azerbaijan Standard Time", "Baku"},
	{"Russia Time Zone 3", "Izhevsk, Samara"},
	{"Mauritius Standard Time", "Port Louis"},
	{"Saratov Standard Time", "Saratov"},
	{"Georgian Standard Time", "Tbilisi"},
	{"Volgograd Standard Time", "Volgograd"},
	{"Caucasus Standard Time", "Yerevan"},
	{"Afghanistan Standard Time", "Kabul"},
	{"West Asia Standard Time", "Ashgabat, Tashkent"},
	{"Ekaterinburg Standard Time", "Ekaterinburg"},
	{"Pakistan Standard Time", "Islamabad, Karachi"},
	{"Qyzylorda Standard Time", "Qyzylorda"},
	{"India Standard Time", "Chennai, Kolkata, Mumbai, New Delhi"},
	{"Sri Lanka Standard Time", "Sri Jayawardenepura"},
	{"Nepal Standard Time", "Kathmandu"},
	{"Central Asia Standard Time", "Astana"},
	{"Bangladesh Standard Time", "Dhaka"},
	{"Omsk Standard Time", "Omsk"},
	{"Myanmar Standard Time", "Yangon (Rangoon)"},
	{"SE Asia Standard Time", "Bangkok, Hanoi, Jakarta"},
	{"Altai Standard Time", "Barnaul, Gorno-Altaysk"},
	{"W. Mongolia Standard Time", "Hovd"},
	{"North Asia Standard Time", "Krasnoyarsk"},
	{"N. Central Asia Standard Time", "Novosibirsk"},
	{"Tomsk Standard Time", "Tomsk"},
	{"China Standard Time", "Beijing, Chongqing, Hong Kong, Urumqi"},
	{"North Asia East Standard Time", "Irkutsk"},
	{"Singapore Standard Time", "Kuala Lumpur, Singapore"},
	{"W. Australia Standard Time", "Perth"},
	{"Taipei Standard Time", "Taipei"},
	{"Ulaanbaatar Standard Time", "Ulaanbaatar"},
	{"Aus Central W. Standard Time", "Eucla"},
	{"Transbaikal Standard Time", "Chita"},
	{"Tokyo Standard Time", "Osaka, Sapporo, Tokyo"},
	{"North Korea Standard Time", "Pyongyang"},
	{"Korea Standard Time", "Seoul"},
	{"Yakutsk Standard Time", "Yakutsk"},
	{"Cen. Australia Standard Time", "Adelaide"},
	{"AUS Central Standard Time", "Darwin"},
	{"E. Australia Standard Time", "Brisbane"},
	{"AUS Eastern Standard Time", "Canberra, Melbourne, Sydney"},
	{"West Pacific Standard Time", "Guam, Port Moresby"},
	{"Tasmania Standard Time", "Hobart"},
	{"Vladivostok Standard Time", "Vladivostok"},
	{"Lord Howe Standard Time", "Lord Howe Island"},
	{"Bougainville Standard Time", "Bougainville Island"},
	{"Russia Time Zone 10", "Chokurdakh"},
	{"Magadan Standard Time", "Magadan"},
	{"Norfolk Standard Time", "Norfolk Island"},
	{"Sakhalin Standard Time", "Sakhalin"},
	{"Central Pacific Standard Time", "Solomon Is., New Caledonia"},
	{"Russia Time Zone 11", "Anadyr, Petropavlovsk-Kamchatsky"},
	{"New Zealand Standard Time", "Auckland, Wellington"},
	{"UTC+12", "Coordinated Universal Time+12"},
	{"Fiji Standard Time", "Fiji"},
	{"Kamchatka Standard Time", "Petropavlovsk-Kamchatsky - Old"},
	{"Chatham Islands Standard Time", "Chatham Islands"},
	{"UTC+13", "Coordinated Universal Time+13"},
	{"Tonga Standard Time", "Nuku'alofa"},
	{"Samoa Standard Time", "Samoa"},
	{"Line Islands Standard Time", "Kiritimati Island"},
};

Extensions.cs

public static string Abbreviation(this TimeZoneInfo tz, DateTime? dt)
{
	// we use standard stuff but in the event that culturally they use something
	// different, handle the overrides here
	if (tz.StandardName.MatchesTrimmed("GMT Standard Time"))
	{
		if (dt.HasValue && tz.IsDaylightSavingTime(dt.Value)) return "BST"; //summer is known as British Summer Time more than GMT Daylight time
		return "GMT"; //apparently the other times are known as GMT instead of GST
	}
	else if (tz.StandardName.MatchesTrimmed("E. Australia Standard Time"))
	{
		if (dt.HasValue && tz.IsDaylightSavingTime(dt.Value)) return "AEDT";
		return "AEST";
	}
	else if (tz.StandardName.MatchesTrimmed("W. Australia Standard Time"))
	{
		if (dt.HasValue && tz.IsDaylightSavingTime(dt.Value)) return "AWDT";
		return "AWST";
	}
	else if (tz.StandardName.MatchesTrimmed("Malay Peninsula Standard Time"))
	{
		if (dt.HasValue && tz.IsDaylightSavingTime(dt.Value)) return "SGT";
		return "SGT";
	}

	// ok now the normal stuff
	var name = tz.StandardName;
	if (dt.HasValue && tz.IsDaylightSavingTime(dt.Value)) name = tz.DaylightName;

	var words = name.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

	if (words.Length > 1)
		return string.Join("", words.Select(x => x.Substring(0, 1).ToUpper()).Where(x => !x.MatchesRegex(@"\(|\)")).ToArray());
	else
		return name;
}
@mattjohnsonpint
Copy link
Owner

The values returned from properties of a TimeZoneInfo object are coming from .NET itself, not from TimeZoneConverter.

On non-Windows systems, those values come from ICU when available, and fall back to offsets when not. You can parse through the source code here to understand the details.

On Windows, those value come from NLS data in the registry - up until .NET 5 which is switching to ICU across the board.

@mattjohnsonpint
Copy link
Owner

You might also be interested in my companion library - TimeZoneNames

@jslaybaugh
Copy link
Author

Thanks, I'll definitely check out that library for the names -- it'll save me a bunch of lines of code in doing that myself.

But I'm still unclear on how two (seemingly) identical non-windows systems would return different values?

@mattjohnsonpint
Copy link
Owner

mattjohnsonpint commented Sep 12, 2020

Sorry for the delayed response. Is it possible this is the solution: dotnet/core#2186 (comment) ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants