2016-10-12 3 views
2

Я предположил, что при вычитании 2-х дней структура проверит их часовой пояс и сделает соответствующие преобразования.Вычитание UTC и не-UTC DateTime в C#

Я тестировал его с этим кодом:

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, т. Е. Дата и время UTC уже не будут неправильно исправлены ToUniversalTime()?

+0

Различные результаты в моно: http://ideone.com/AfFUpV – zerkms

+0

@zerkms Я на VS2015, я не знаю, имеет ли это значение. Вы можете проверить идеон с помощью Visual Studio? Я лично не использовал идеон, поэтому не могу понять, как это сделать. – sashoalm

+0

В DateTime отсутствует часовой пояс, в котором хранится дата и время. Поэтому он не знает, в какой временной зоне есть DateTime. –

ответ

5

Тип System.DateTime не содержат информацию о часовом поясе, только .Kind свойство, указывающее, является ли это местное или UTC. Но до .NET 2.0 не было даже свойства .Kind.

Когда вы вычитаете (или выполняете другие арифметические операции, например == или >, on) два значения DateTime, их «виды» вообще не учитываются. Учитываются только числа тиков. Это дает совместимость с .NET 1.1 при no kinds existed.

Функциональность, которую вы запрашиваете (и ожидаете), находится в новом и более богатом type System.DateTimeOffset. В частности, если вы вычитаете DateTimeOffset.Now - DateTimeOffset.UtcNow, вы получите нужный результат. Структура DateTimeOffset не имеет локального/UTC-флага; вместо этого он удерживает весь часовой пояс, например +02: 00 в вашей области.

+0

Да, исходя из Qt, QDateTime имеет время UTC плюс смещение часового пояса.Я ожидал, что DateTime будет использовать его, и немного запутался, когда Ханс Пассент упомянул DateTimeOffset, потому что это звучало как TimeSpan, а не то, что должно было быть DateTime. – sashoalm

+0

Немного правильного объяснения, ИМХО. В .NET Framework, который остается (или когда-либо остался), не так много, что требуется для обратной совместимости .NET 1.0/1.1, .NET 2.0 - это совместимость. –

+0

@ MahmoudAl-Qudsi Тип 'DateTimeOffset', о котором я упоминал, был представлен в .NET 2.0. Когда я описал _why_, функциональность 'DateTime' была выбрана так, как это было, когда .NET 2.0 был введен, и' DateTime' приобрел свойство 'Kind', я немного догадывался. Однако, когда я описал _how_ 'DateTime', на самом деле работает, так как .NET 2.0, я был прав. –

0

Каркас ничего не делает с датой, если она уже 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'it, он примет UTC и преобразуется в локальный. –

+0

@ChrisChilvers Это важное наблюдение. –

+0

Вопрос фокусируется на случае, когда используется 'ToUniversalTime()' ___not___. Объяснение того, как работает ConvertTimeToUtc, не помогает при ответе на вопрос, на который задан вопрос. В этом случае метод не вызывается. Если вы хотите опубликовать исходный код, напишите код для публичного статического оператора TimeSpan - (DateTime d1, DateTime d2) '. –