关注我的last question @Jon Skeet给了我很多帮助(再次感谢!)
我现在想知道当他们被转换回本地日期/时间时,如何安全使用以UTC格式存储的日期/时间。
正如乔恩在我上一期提出的问题所指出的那样,使用DateTimeOffset
及时表示即时并且没有办法预测一分钟后当地时间会说什么。我需要能够根据这些日期/时间进行计算。
那么,我如何保证从数据库中提取日期,将它们转换为本地日期/时间并对它们进行具体计算,它们将是准确的?
示例
我的应用程序记录通过电子邮件发送的信息。收到电子邮件的日期/时间记录为提交时间。电子邮件是从交换中提取的。
我需要知道的是:
1)如果这些电子邮件来自不同的国家/地区,我是否只将电子邮件的Recieved
日期/时间转换为UTC格式并存储?例如Email.Received.ToUniversalTime()
答案 0 :(得分:6)
不,你不能这么认为。 UTC时间是完全线性的,您可以安全地对它们进行计算。一旦将其转换为当地时间,它就不再是完全线性的。
当夏令时发生变化时,当地时间会有重叠或间隙。如果您进行的计算跨越夏令时变化,结果将会减少一个小时(如果这是多少时间变化,这是最常见的)。
如果在将DateTime / DateTimeOffset值转换为本地时间之前进行计算,结果将始终正确。但请注意,将值转换为本地DateTime值可能会使其不明确,如果值在夏令时变化时恰好落在重叠内,则无法判断它是第一次还是第二次确切时间发生在当天。
答案 1 :(得分:2)
正确处理日期/时间的最安全方法是将所有内容存储为UTC并以当地时间显示。所有日期/时间数学都应该按照Guffa建议的UTC进行。以UTC格式存储,并在显示时即时转换为当地时间。
Microsoft有一篇关于如何将DateTime和TimeZoneInfo变量封装到结构here中的文章。
这是Microsoft的示例结构,添加了1个属性以轻松获取本地时间。这需要更多的工作才能完全有用,但这是一个良好的开端。
public struct TimeZoneTime
{
public TimeZoneInfo TimeZone;
public DateTimeOffset Time;
public TimeZoneTime(DateTimeOffset time)
{
this.TimeZone = TimeZone.Local;
this.Time = time;
}
public TimeZoneTime(TimeZoneInfo tz, DateTimeOffset time)
{
if (tz == null)
throw new ArgumentNullException("The time zone cannot be a null reference.");
this.TimeZone = tz;
this.Time = time;
}
public TimeZoneTime AddTime(TimeSpan interval)
{
// Convert time to UTC
DateTimeOffset utcTime = TimeZoneInfo.ConvertTime(this.Time, TimeZoneInfo.Utc);
// Add time interval to time
utcTime = utcTime.Add(interval);
// Convert time back to time in time zone
return new TimeZoneTime(this.TimeZone, TimeZoneInfo.ConvertTime(utcTime, this.TimeZone));
}
public DateTime LocalDate
{
get { return Time.ToOffset(TimeZone); }
}
}
是的,使用邮件对象的ReceivedTime或SentOn,并将其转换为UTC进行存储&计算。这比上面的样本复杂得多。
Message msg = new Message();
DateTime received = msg.ReceivedTime.ToUniversalTime();
received.AddDays(7);
Console.WriteLine(received.ToLocalTime());