安全地将 UTC 日期时间转换为本地时间(基于 TZ)进行计算?

发布于 2024-08-28 16:07:42 字数 729 浏览 5 评论 0 原文

根据我的最后一个问题@Jon Skeet 给了我很多帮助(再次感谢!)

我现在想知道如何当日期/时间转换回本地日期/时间时,我可以安全使用存储为 UTC 的日期/时间。

正如 Jon 在我的上一个问题中指出的那样,使用 DateTimeOffset 表示时间上的瞬间,并且无法预测一分钟后的当地时间。我需要能够根据这些日期/时间进行计算。

那么,当我从数据库中提取日期、将它们转换为本地日期/时间并对它们进行特定计算时,如何确保它们是准确的呢?

场景

我的应用程序记录通过电子邮件发送的信息。收到电子邮件的日期/时间记录为提交时间。电子邮件是从 Exchange 中提取的。

我需要知道的是:

1)如果这些电子邮件来自不同的国家/地区,我是否只需将电子邮件的收到日期/时间转换为 UTC 格式并存储?例如 Email.Received.ToUniversalTime()

Following from my last question which @Jon Skeet gave me a lot of help with (thanks again!)

I am now wondering how I can safely work with date/times, stored as UTC, when they are converted back to Local Date/Time.

As Jon indicated in my last question using DateTimeOffset represents an instant in time and there is no way to predict what the local time would be say a minute later. I need to be able to do calculations based on these date/times.

So how can I assure when I pull the dates from the database, convert them to local date/time and do specific calculations on them they are going to be accurate?

Scenario

My application records information sent in via email. The date/time the email is received is recorded as the submission time. Emails are pulled from exchange.

What I need to know is:

1) If these emails are coming from different countries, do I just convert the Recieved date/time of the email to UTC format and store that? e.g. Email.Received.ToUniversalTime()

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

寂寞陪衬 2024-09-04 16:07:42

不,你不能这样假设。 UTC 时间是完全线性的,您可以安全地对其进行计算。一旦将其转换为当地时间,它就不再是完全线性的。

当夏令时发生变化时,当地时间会出现重叠或间隙。如果您进行跨越夏令时变化的计算,结果将偏差一小时(如果这是时间变化的程度,这是最常见的)。

如果在将 DateTime/DateTimeOffset 值转换为本地时间之前进行计算,结果将始终是正确的。但请注意,将该值转换为本地 DateTime 值可能会使其变得不明确,如果该值恰好落在夏令时更改的重叠范围内,则无法判断这是当天准确时间的第一次还是第二次。

No, you can't assume that. UTC time is completely linear, and you can safely do calculations on them. Once you converted it to a local time, it's no longer completely linear.

When daylight savings time changes occur, there is an overlap or gap in the local time. If you do a calculation that spans over a daylight savings time change, the result will be off by one hour (if that is how much the time changes, which is the most common).

If you do the calculation before converting the DateTime/DateTimeOffset value to local time, the result will always be correct. Note however that converting the value to a local DateTime value can make it ambiguous, if the value happens to fall inside an overlap at the daylight savings time change, it's impossible to tell if it's the first or second time that exact time occurs that day.

蓬勃野心 2024-09-04 16:07:42

正确处理日期/时间的最安全方法是将所有内容存储为 UTC 并以当地时间显示。正如 Guffa 建议的那样,所有日期/时间数学计算都应在 UTC 中完成。以 UTC 格式存储并在显示时即时转换为当地时间。

如何使时区感知日期/时间

Microsoft 有一篇文章介绍如何将 DateTime 和 TimeZoneInfo 变量封装到结构中 此处

下面是 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); }
    }
}

您的场景

  1. 是的,使用邮件对象的 ReceivedTime 或 SentOn 并将其转换为 UTC 进行存储和发送。计算。这比上面的示例简单得多。

    消息 msg = new Message();
    收到的日期时间 = msg.ReceivedTime.ToUniversalTime();
    收到。AddDays(7);
    Console.WriteLine(收到.ToLocalTime());
    

The safest way to handle date/time correctly is to store everything as UTC and display it in local time. All date/time math should be done in UTC as Guffa suggests. Store in UTC and convert to local time on the fly as you display it.

How to make a Time Zone aware date/time

Microsoft has an article on how to encapsulate a DateTime and TimeZoneInfo variable into a structure here.

Here's Microsoft's sample structure with 1 property added to easily get local time. This needs more work to be a fully useful, but it's a good start.

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); }
    }
}

Your Scenario

  1. Yes, use either the mail object's ReceivedTime or SentOn and convert it to UTC for storage & calculations. This is much less complex than the samples above.

    Message msg = new Message();
    DateTime received = msg.ReceivedTime.ToUniversalTime();
    received.AddDays(7);
    Console.WriteLine(received.ToLocalTime());
    
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文