#c# #datetime #timespan
#c# #дата и время #промежуток времени
Вопрос:
Я предположил, что при вычитании 2 даты и времени фреймворк проверит их часовой пояс и выполнит соответствующие преобразования.
Я протестировал это с помощью этого кода:
Console.WriteLine(DateTime.Now.ToUniversalTime() - DateTime.UtcNow.ToUniversalTime());
Console.WriteLine(DateTime.Now.ToUniversalTime() - DateTime.UtcNow);
Console.WriteLine(DateTime.Now - DateTime.UtcNow);
Вывод:
-00:00:00.0020002
-00:00:00.0020001
01:59:59.9989999
К моему удивлению, DateTime.Now - DateTime.UtcNow
соответствующее преобразование не выполняется автоматически. В то же время DateTime.UtcNow
это то же DateTime.UtcNow.ToUniversalTime()
самое, что и, поэтому, очевидно, существует некоторый внутренний флаг, который указывает часовой пояс.
Правильно ли это, не выполняет ли эта платформа соответствующее преобразование часового пояса автоматически, даже если информация уже присутствует? Если это так, ToUniversalTime()
безопасно ли применять как для UTC, так и для не UTC datetimes, т. Е. Уже UTC datetime не будет неправильно исправлено ToUniversalTime()
?
Комментарии:
1. Другой результат в mono: ideone.com/AfFUpV
2. @zerkms Я на VS2015, я не знаю, имеет ли это значение. Можете ли вы проверить ideone с помощью Visual Studio? Я лично не часто использовал ideone, поэтому не могу понять, как это сделать.
3. В DateTime нет часового пояса, в нем просто хранятся дата и время. Таким образом, он не знает, в каком часовом поясе находится это DateTime.
4. Вы просто констатируете факт, легко видимый из справочного источника . Вместо этого используйте DateTimeOffset .
Ответ №1:
Тип System.DateTime
не содержит информации о часовом поясе, только .Kind
свойство, которое указывает, является ли оно локальным или UTC. Но до .NET 2.0 не было даже .Kind
свойства.
Когда вы вычитаете (или выполняете другую арифметику, например ==
, или >
, вкл.) два DateTime
значения, их «виды» вообще не учитываются. Учитывается только количество тиков. Это обеспечивает совместимость с .NET 1.1, когда не существовало никаких типов.
Функциональность, которую вы запрашиваете (и ожидаете), находится в более новом и богатом типе System.DateTimeOffset
. В частности, если вы выполните вычитание DateTimeOffset.Now - DateTimeOffset.UtcNow
, вы получите желаемый результат. DateTimeOffset
Структура не имеет локального флага / UTC; вместо этого она содержит весь часовой пояс, например 02:00 в вашем регионе.
Комментарии:
1. Да, исходя из Qt, QDateTime содержит время UTC плюс смещение часового пояса. Я ожидал, что DateTime будет использовать его, и был немного смущен, когда Ханс Пассант упомянул DateTimeOffset, потому что это звучало как TimeSpan, а не как DateTime должно было быть.
2. Не очень правильное объяснение, ИМХО. В .NET Framework мало что остается (или когда-либо оставалось) связанным с обратной совместимостью .NET 1.0 / 1.1, .NET 2.0 — это совместимость, к которой стремятся.
3.@MahmoudAl-Qudsi Тип
DateTimeOffset
, о котором я упоминал, был введен в .NET 2.0. Когда я описывал, почему функциональностьDateTime
была выбрана так, как она была, когда .NET 2.0 был представлен иDateTime
приобрелKind
свойство, я немного догадывался. Однако, когда я описал, какDateTime
это работает на самом деле, начиная с .NET 2.0, я был прав.
Ответ №2:
Фреймворк ничего не делает с датой, если она уже UTC:
internal static DateTime ConvertTimeToUtc(DateTime dateTime, TimeZoneInfoOptions flags)
{
if (dateTime.Kind == DateTimeKind.Utc)
{
return dateTime;
}
CachedData cachedData = s_cachedData;
return ConvertTime(dateTime, cachedData.Local, cachedData.Utc, flags, cachedData);
}
Комментарии:
1. Хотя вы должны быть осторожны
DateTimeKind.Unknown
(что часто может быть связано с запросом к БД). В этом случае, если вы вызоветеToUniversalTime
, он примет локальный и преобразует в UTC, а если вы вызоветеToLocalTime
, он примет UTC и преобразует в локальный.2. @ChrisChilvers Это важное наблюдение.
3. Вопрос сосредоточен на случае, когда
ToUniversalTime()
не используется. Объяснение того, какConvertTimeToUtc
это работает, не помогает ответить на заданный вопрос. В этом случае метод не вызывается. Если вы хотите опубликовать исходный код, опубликуйте код дляpublic static TimeSpan operator -(DateTime d1, DateTime d2)
.4. @JeppeStigNielsen , один из вопросов заключался в том, безопасно ли применять ToUniversalDateTime к дате и времени UTC.
5. Вы правы, я слишком много внимания уделял одному аспекту вопроса (тому, который в теме).