您需要一个时区数据库来执行所需的日期和时间转换。时区比单纯偏移更复杂,因为许多时区都包含夏时制规则。
.NET框架允许您通过使用TimeZoneInfo
类来使用基础Windows时区数据库。但是,您可以考虑Windows时区数据库专有的。 IANA保留Best Current Practice (BCP) 175中描述的Time Zone Database (TZDB)。
库Noda Time具有支持TZDB和提供的本地时间戳作为.NET DateTime
和可以计算相应的UTC时间戳的时区标识符:
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:在http://www.citytimezones.info/
var instant = Instant.FromDateTimeUtc(utcDateTime);
var timeZone = DateTimeZoneProviders.Tzdb[timeZoneId];
var zonedDateTime = instant.InZone(timeZone);
var localDateTime = zonedDateTime.ToDateTimeUnspecified();
服用后一看似乎cities.txt
包含Windows时区ID为最后一列中的每个城市。这使您可以根据城市查找Windows时区ID。
然后,您可以使用此代码转换本地DateTime
到UTC:
var timeZoneId = "Eastern Standard Time";
var timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(timeZoneId);
var utcDateTime = TimeZoneInfo.ConvertTimeToUtc(localDateTime, timeZoneInfo);
注意ConvertTimeToUtc
如果本地时间戳是模糊的或无效将抛出ArgumentException
。
从UTC为本地时间的逆变换:
var localDateTime = TimeZoneInfo.ConvertTimeFromUtc(utcDateTime, timeZoneInfo);
如果未来的时区规则发生变化,那么未来的UTC时间可能会变得不正确。时区规则经常令人惊讶地发生变化。显然,这个问题适用于所有多时区调度应用程序,我认为唯一的解决方案是存储原始本地时间,以便在将来适用的时区规则发生变化时重新计算UTC时间。 –
@MartinLiversage是的,我打算存储这样做。调度还会保存当地时间,以便我们可以重新计算UTC时间。 – Emmanuel
我不知道为什么这被标记为“DateTime vs DateTimeOffset”的重复。这太荒谬了,因为另一个问题甚至没有谈到时区之间的翻译。充其量,这可能是“谷歌地图时区API vs DateTimeOffset”,但这是它的延伸。 – Emmanuel