Почему функция UtcDateTime не добавляет смещение к дате UTC? - PullRequest
0 голосов
/ 08 мая 2018

Для мгновенного отслеживания DateTime я использую тип данных DateTimeOffset. Следующая функция добавляет пользователю соответствующее смещение идентификатора TimeZone к свойству UTC DateTime, равному DateTimeOffset

Согласно документации , UtcDateTime будет выполнять как преобразование часового пояса, так и преобразование типа для DateTimeOffset. Следующий код не делает, хотя. Почему не происходит конвертация?

Функция добавления смещения TimeSpan,

public static DateTimeOffset GetUtcDateTime (DateTime sourceDateTime, string timeZoneId) {
 TimeZoneInfo timeZone = TimeZoneInfo.FindSystemTimeZoneById (timeZoneId);
 TimeSpan offset = timeZone.GetUtcOffset (sourceDateTime);
 DateTimeOffset utcTime = new DateTimeOffset (sourceDateTime, offset);
 return utcTime;
 }

и вот где я пытаюсь конвертировать,

DateTimeOffset utcDate = (DateTime.UtcNow);
DateTime fromUtc = utcDate.DateTime;
DateTimeOffset UtcDate = StaticHandlers.GetUtcDateTime (fromUtc, "America/Los_Angeles");
Console.WriteLine ("UTC now is {0} and UTC Date LA is {1} and UtcDateTime LA is {2}", utcDate, UtcDate, utcDate.UtcDateTime);

вывод:

UTC теперь 5/8/18 6:43:37 AM +00: 00, а дата UTC LA - 5/8/18 6:43:37 AM -07: 00 UtcDateTime LA 5/8/18 6:43:37 AM

обновление

Я хочу сохранить как UTC, так и смещение пользователя для целей отслеживания. DST имеет значение в этом контексте. Пример ниже показывает, о чем я говорю.

DateTime currentDateTime = DateTime.Now;
DateTime beforeDST_LA = new DateTime (2018, 3, 11, 0, 0, 0);
DateTime afterDST_LA = new DateTime (2018, 3, 12, 0, 0, 0);
TimeSpan offsetCurrent = tzi.GetUtcOffset (currentDateTime);
TimeSpan offsetBeforeDST = tzi.GetUtcOffset (beforeDST_LA);
TimeSpan offsetAfterDST = tzi.GetUtcOffset (afterDST_LA);
Console.WriteLine ("Current offset is {0} before DST is {1} and After DST is {2}", offsetCurrent, offsetBeforeDST, offsetAfterDST);

Текущее смещение составляет -07: 00: 00 до DST -08: 00: 00 и после DST -07: 00: 00

1 Ответ

0 голосов
/ 08 мая 2018

Во-первых, я бы не назвал вашу функцию GetUtcDateTime, потому что это не то, что она делает. Он пытается получить DateTimeOffset для определенного часового пояса за определенное время, поэтому назовите его как GetDateTimeOffset.

Основная концепция, которую вам не хватает в вашем коде, заключается в том, что DateTime имеет свойство .Kind, которое устанавливает значение DateTimeKind. Вид учитывается несколькими местами в вашем коде:

  • GetUtcOffset преобразует Utc или Local видов в указанную зону до определения смещения.

  • new DateTimeOffset (конструктор) выдаст ошибку, если тип и смещение конфликтуют, если вы предоставите смещение.

  • Когда вы присваиваете DateTime для DateTimeOffset, неявное преобразование оценивает тип.

  • Когда вы звоните .DateTime из DateTimeOffset, вид будет всегда быть Unspecified - независимо от смещения.

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

public static DateTimeOffset GetDateTimeOffset(DateTime sourceDateTime, string timeZoneId)
{
    TimeZoneInfo timeZone = TimeZoneInfo.FindSystemTimeZoneById(timeZoneId);

    // here, is where you need to convert
    if (sourceDateTime.Kind != DateTimeKind.Unspecified)
        sourceDateTime = TimeZoneInfo.ConvertTime(sourceDateTime, timeZone);

    TimeSpan offset = timeZone.GetUtcOffset(sourceDateTime);
    return new DateTimeOffset(sourceDateTime, offset);
}

Теперь, когда это решено, перейдите к следующему набору проблем, где вы его и называете.

DateTimeOffset utcDate = (DateTime.UtcNow);
DateTime fromUtc = utcDate.DateTime;

В строке 1 неявное приведение от DateTime до DateTimeOffset устанавливает смещение на 00:00 - потому что DateTime.UtcNow имеет .Kind == DateTimeKind.Utc.

В строке 2 вызов свойства .DateTime устанавливает fromUtc.Kind == DateTimeKind.Unspecified. По сути, вы отстранены от вида.

Так что вместо этого просто передайте DateTime.UtcNow непосредственно в функцию. Тип сохранится, и все будет работать - теперь, когда Kind распознан и преобразование происходит внутри функции.

С учетом всего сказанного, если все ваши исходные значения равны DateTimeOffset (например, DateTimeOffset.UtcNow), тогда вам вообще не нужна эта функция. Просто позвоните TimeZoneInfo.ConvertTime с DateTimeOffset напрямую.

...