C# · 12月 27, 2021

c# – 将日期/时间作为UTC存储在数据库中

我将日期/时间作为UTC存储在数据库中,并根据具体时区在本地时间内将其计算回本地.例如我有以下日期/时间:

01/04/2010 00:00

说这是一个国家,例如观察DST(夏令时间)的英国,在这个特定时间我们正在夏令时.当我将此日期转换为UTC并将其存储在数据库中时,实际存储为:

31/03/2010 23:00

由于DST的日期将调整为-1小时.当您在提交时观察DST时,此功能正常.但是,当时钟被调整回来时会发生什么?当我从数据库中提取该日期并将其转换为当地时间,特定的日期时间将被视为31/03/2009 23:00,实际上它被处理为01/04/2010 00:00.

纠正我,如果我错了,但这不是一个缺点,当存储时间作为UTC?

时区转换示例

基本上我正在做的是将信息提交到我的系统的日期/时间,以允许用户做范围报告.这是我如何存储日期/时间:

public DateTime LocalDateTime(string timeZoneId){ var tzi = TimeZoneInfo.FindSystemTimeZoneById(timeZoneId); return TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow,tzi).ToUniversalTime().ToLocalTime(); }

存储为UTC:

var localDateTime = LocalDateTime(“AUS Eastern Standard Time”);WriteToDB(localDateTime.ToUniversalTime());解决方法 您不会根据您是否正在观察DST更改来调整DST更改的日期 – 您可以根据在描述时刻观察DST进行调整.所以在1月的情况下,你不会适用调整.

然而,有一个问题,当地的一些时代是不明确的.例如,2010年10月31日上午1:30在英国可以代表UTC 01:30或UTC 02:30,因为时钟从上午2点到凌晨1点.您可以从UTC所表示的任何瞬间获得当前时间显示的时间,但操作不可逆.

同样地,您可能有一个从不发生的当地时间 – 例如,2010年3月28日上午1:30在英国没有发生,因为在凌晨1点,时钟向上跳到凌晨2点.

很长一段时间,如果你想要及时表达一个瞬间,你可以使用UTC并得到一个明确的表示.如果您想要在特定时区表示时间,则需要使用时区本身(例如欧洲/伦敦)以及即时的UTC表示或当地日期和时间以及该特定时间的偏移量(消除DST转换周围的歧义).另一个选择是只存储UTC和它的偏移量;这可以让您在当时的时间告诉当地时间,但这意味着您无法预测当地时间将在一分钟之后,因为您不太了解时区. (这是DateTimeOffset存储的,基本上是)

我们希望能够在Noda Time中使用起来非常方便,但您仍然需要将其视为可能.

编辑:

您显示的代码不正确.这就是为什么我已经改变了代码的结构,使其更容易看到,但您会看到它执行相同的调用.

var tzi = TimeZoneInfo.FindSystemTimeZoneById(“AUS Eastern Standard Time”);var aussieTime = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow,tzi);var serverLocalTime = aussieTime.ToLocalTime(); var utcTime = serverLocalTime.ToUniversalTime();

所以,现在让我们考虑一下 – 当地时间是13:38(UTC 1,伦敦),12:38 UTC,22:39在悉尼.

您的代码将给出:

aussieTime = 22:39 (correct)serverLocalTime = 23:39 (*not* correct)utcTime = 22:39 (*not* correct)

你不应该在TimeZoneInfo.ConvertTimeFromUtc的结果上调用ToLocalTime – 它将假定它在UTC DateTime上被调用(除非它实际上有DateTimeKind.Local,在这种情况下不会).

因此,如果您在这种情况下准确保存22:39,则无法准确保存UTC的当前时间.