关于c#:使用时区城市坐标和当地时间进行时区转换

Time zone conversion using time zone city coordinates and local time

本问题已经有最佳答案,请猛点这里访问。

我正在开发一个安排网站,您可以在其中指定日期,时间,时区城市。我希望在UTC时间将其保存在后端。所以我必须在服务器上以某种方式转换它。我还希望能够即时转换到不同的时区。

在Javascript中,我有一个日期/时间值以及一个时区城市(来自http://www.citytimezones.info,它给出了我的地理坐标)。我没有UTC时间,只有指定时区的时间。

现在我需要将此未来的本地时间转换为UTC。当然,它必须考虑到当时适用的夏令时偏移。

此外,我想使用第二个时区城市转换为不同的当地时间。

我考虑使用谷歌地图时区API,但这会强制你传递UTC时间,我没有,因为我正在尝试计算它。

换句话说,理想情况下我需要一个采用这些参数的系统:

  • 未来的时间/日期
  • 源时区城市坐标
  • 目的地时区城市坐标(或null = UTC时间)

并将返回转换时间。

知道我能做些什么来实现这个目标吗?

这可以是Web服务或Windows C#库。


将问题分成两部分:

  • 从位置协调确定时区
  • 转换时区之间的时间

你会发现有几种方法可以做到。

对于第1步,您提到了Google时区API和CityTimeZones。这里列出了这两个方法以及其他几种方法。

对于第2步,您对.NET的选择主要在Noda Time或TimeZoneInfo之间。马丁在答案中给出了几个很好的例子。

此外,考虑到调度比大多数情况更困难。您应该阅读这篇文章了解更多详情。


您需要一个时区数据库来执行所需的日期和时间转换。时区比简单地作为偏移更复杂,因为许多时区包括夏令时规则。

.NET框架允许您使用TimeZoneInfo类来使用基础Windows时区数据库。但是,您可以将Windows时区数据库视为专有。 IANA维护时区数据库(TZDB),该数据库在最佳实践(BCP)175中有所描述。

Noda Time库支持TZDB并提供本地时间戳作为.NET DateTime和时区标识符,您可以计算相应的UTC时间戳:

1
2
3
4
5
var localDateTime = LocalDateTime.FromDateTime(dateTime);
var timeZoneId ="America/New_York"];
var timeZone = DateTimeZoneProviders.Tzdb[timeZoneId];
var zonedDateTime = timeZone.AtLeniently(localDateTime);
var utcDateTime = zonedDateTime.ToDateTimeUtc();

请注意,本地时间戳可能不明确或无效。这种情况发生在夏令时转换期间,其中本地时钟向后移动(产生歧义)或向前移动(产生无效时间)。 AtLeniently方法对如何处理歧义和无效时间戳做了一些假设。这可能是您的应用程序中的错误来源。

如果您有UTC时间戳和时区ID,则可以以类似的方式转换为本地时间:

1
2
3
4
var instant = Instant.FromDateTimeUtc(utcDateTime);
var timeZone = DateTimeZoneProviders.Tzdb[timeZoneId];
var zonedDateTime = instant.InZone(timeZone);
var localDateTime = zonedDateTime.ToDateTimeUnspecified();

在查看http://www.citytimezones.info/之后,似乎cities.txt包含最后一列中每个城市的Windows时区ID。这使您可以根据城市查找Windows时区ID。

然后,您可以使用以下代码将本地DateTime转换为UTC:

1
2
3
var timeZoneId ="Eastern Standard Time";
var timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(timeZoneId);
var utcDateTime = TimeZoneInfo.ConvertTimeToUtc(localDateTime, timeZoneInfo);

请注意,如果本地时间戳不明确或无效,ConvertTimeToUtc将抛出ArgumentException

从UTC到本地时间的反向转换:

1
var localDateTime = TimeZoneInfo.ConvertTimeFromUtc(utcDateTime, timeZoneInfo);