这看起来像一个 Windows 时区,就像你得到的那种TimeZoneInfo
,但服务给你的DisplayName
不是Id
. 这使得使用它有点麻烦。特别是因为显示名称是本地化的 - 你有英文名称。在具有不同文化设置的计算机上看起来会有所不同。
您也不能只从那里取出偏移量 - 因为 Windows 显示名称始终显示标准偏移量,即使该区域处于夏令时也是如此。
基于它说“GMT”而不是“UTC”这一事实,我猜想它们来自旧计算机,例如 Windows XP、Windows Server 2003,或者可能是 Windows Embedded 计算机。例如,您会在此列表中找到它。
你真的应该回到那个服务的所有者那里,要求他们给你价值TimeZoneInfo.Id
而不是TimeZoneInfo.DisplayName
. 假设你不能这样做,这里有一种方法可以让你使用你所拥有的东西:
// Look up the time zone. This won't work on non-English language computers!
// (setting an English CultureInfo won't help you here)
var shippedTZ = TimeZoneInfo.GetSystemTimeZones()
.FirstOrDefault(x => x.DisplayName == shippedTimeZone.Replace("GMT", "UTC"));
if (shippedTZ == null)
throw new Exception("Time Zone Not Found!");
// You may want to handle the exception by hardcoding some specific time zones
// Let's turn your date/time strings into an actual DateTime
var shippedDT = DateTime.ParseExact(shippedDate + " " + shippedTime,
"MM/dd/yyyy hh:mm tt", CultureInfo.InvariantCulture);
// Then we'll use the time zone to get a DateTimeOffset.
var shippedDTO = new DateTimeOffset(shippedDT,
shippedTZ.GetUtcOffset(shippedDT));
// And the same thing for the received date...
var receivedTZ = TimeZoneInfo.Local;
var receivedDT = DateTime.ParseExact(receievedDate + " " + receivedTime,
"MM/dd/yyyy hh:mm tt", CultureInfo.InvariantCulture);
var receivedDTO = new DateTimeOffset(receivedDT,
receivedTZ.GetUtcOffset(receivedDT));
// Now you can subtract them
TimeSpan elapsed = receivedDTO - shippedDTO;
您需要在这里注意的另一件事 - 如果日期/时间值中的任何一个不明确,您可能无法获得正确的结果。这将在与夏令时相关的“回退”过渡期间发生。您对此无能为力,因为您在源数据中没有任何合格信息。
NodaTime - while an outstanding library, can't do a whole lot better than this for your particular problem. You will still have the same issues of resolving the time zone without the proper ID and mapping an ambiguous local datetime. But just for good measure, here is the same thing using NodaTime:
// Try to locate the time zone
var bclZoneProvider = DateTimeZoneProviders.Bcl;
var zoneShipped = bclZoneProvider.Ids
.Select(x => bclZoneProvider[x])
.Cast<BclDateTimeZone>()
.FirstOrDefault(x => x.DisplayName == shippedTimeZone.Replace("GMT", "UTC"));
if (zoneShipped == null)
throw new Exception("Time Zone Not Found!");
// You wanted the system time zone
var zoneReceived = bclZoneProvider.GetSystemDefault();
// Parse the date/time values as a LocalDateTime
var pattern = LocalDateTimePattern
.CreateWithInvariantCulture("MM/dd/yyyy hh:mm tt");
var ldtShipped = pattern.Parse(shippedDate + " " + shippedTime).Value;
var ldtReceived = pattern.Parse(receievedDate + " " + receivedTime).Value;
// Assign them to the zones.
// "Leniently" means to use the standard offset when there is an ambiguity.
var zdtShipped = ldtShipped.InZoneLeniently(zoneShipped);
var zdtReceived = ldtReceived.InZoneLeniently(zoneReceived);
// Subtract them to get the Duration you are looking for.
Duration elapsed = zdtReceived.ToInstant() - zdtShipped.ToInstant();