Безопасно конвертировать время по Гринвичу в местное время (на основе TZ) для расчетов? - PullRequest
2 голосов
/ 15 апреля 2010

Исходя из моего последнего вопроса , который @ Jon Skeet оказал мне большую помощь (спасибо еще раз!)

Теперь мне интересно, как можно безопасно работать с датой / временем, сохраненным в формате UTC, когда они конвертируются обратно в локальную дату / время.

Как указал Джон в моем последнем вопросе, использование DateTimeOffset представляет собой момент во времени, и нет никакого способа предсказать, какое местное время будет сказано через минуту. Мне нужно уметь делать расчеты на основе этих даты / времени.

Так как же я могу убедиться, что когда я извлекаю даты из базы данных, конвертирую их в локальную дату / время и выполняю конкретные расчеты, они будут точными?

Сценарий

Мое приложение записывает информацию, отправленную по электронной почте. Дата / время получения электронного письма записывается как время отправки. Письма извлекаются из обмена.

Что мне нужно знать, это:

1) Если эти письма приходят из разных стран, могу ли я просто преобразовать дату / время Recieved письма в формат UTC и сохранить их? например Email.Received.ToUniversalTime()

Ответы [ 2 ]

6 голосов
/ 15 апреля 2010

Нет, вы не можете этого допустить. Время UTC полностью линейно, и вы можете смело делать расчеты на них. Как только вы преобразовали его в местное время, оно больше не будет полностью линейным.

Когда происходят изменения летнего времени, местное время перекрывается или перекрывается. Если вы выполняете вычисление, которое охватывает изменение летнего времени, результат будет отключен на один час (если это то, сколько времени меняется, что является наиболее распространенным).

Если вы выполняете расчет до преобразования значения DateTime / DateTimeOffset в местное время, результат всегда будет правильным. Тем не менее, обратите внимание, что преобразование значения в локальное значение DateTime может сделать его неоднозначным. Если значение оказывается в перекрытии при изменении летнего времени, невозможно определить, наступает ли точное время в первый или второй раз в этот день.

2 голосов
/ 15 апреля 2010

Самый безопасный способ правильно обработать дату / время - это хранить все как UTC и отображать его по местному времени. Вся математика даты / времени должна быть сделана в 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 для хранения и расчетов. Это гораздо менее сложно, чем примеры выше.

    Message msg = new Message();
    DateTime received = msg.ReceivedTime.ToUniversalTime();
    received.AddDays(7);
    Console.WriteLine(received.ToLocalTime());
    
...