#c# #datetime
#c# #дата и время
Вопрос:
Дана следующая строка даты UTC: «2020-10-10T12:00:00»
Почему при преобразовании в строку я теряю смещение даты и времени, несмотря на указание его в формате?
string parseString = "2020-10-10T12:00:00";
if (DateTime.TryParseExact(parseString, "s", null, DateTimeStyles.None, out DateTime parsedDate))
{
TimeZoneInfo timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Pacific/Honolulu");
DateTime atUtc = DateTime.SpecifyKind(parsedDate, DateTimeKind.Utc);
DateTimeOffset dateAtTimeZone = TimeZoneInfo.ConvertTime(atUtc, timeZoneInfo);
Console.WriteLine(dateAtTimeZone.ToString("O"));
Console.WriteLine(dateAtTimeZone.ToString("yyyy-MM-ddTHH:mm:ss.fffffffK"));
}
Почему я возвращаю следующее: 2020-10-10T02:00:00.0000000 13:00
Вместо: 2020-10-10T02:00:00.0000000-10:00
Комментарии:
1. Тогда не используйте
DateTime
( learn.microsoft.com/en-us/dotnet/api /… ).2. @JeremyLakeman — вы хотите сказать, что я должен вручную указать смещение? Это то, что я получил по вашей ссылке. Я предположил, что если вы преобразуете объект DateTime с использованием часового пояса, он будет содержать некоторую информацию о локализации / смещении, и я мог бы применить, например, следующие форматы: learn.microsoft.com/en-us/dotnet/standard/base-types /…
3. @nealsu «по сути, это будет содержать некоторую информацию о локализации / смещении» Нет, это не так. Это задача
DateTimeOffset
.4. Дата-время четко определено только для UTC и часового пояса этого компьютера. Слишком много методов сделают что-то удивительное, если вид не указан. ИМХО использует его только для хранения UTC. Как только вам понадобятся «локальные» или «пользовательские» значения времени, используйте DateTimeOffset .
5. Потому
TimeZoneInfo.ConvertTime
что все еще работает наDateTime
s. На самом деле вы ничего не изменили. Вы только что преобразовали неверный результат из before в anDateTimeOffset
. Вы также должны сделатьatUtc
DateTimeOffset
.
Ответ №1:
Есть два TimeZoneInfo.ConvertTime
параметра, которые принимают 2 параметра — один, который принимает a DateTime
и возвращает a DateTime
, и один, который принимает an DateTimeOffset
и возвращает a DateTimeOffset
. Прямо сейчас вы вызываете тот, который принимает DateTime
:
DateTime atUtc = DateTime.SpecifyKind(parsedDate, DateTimeKind.Utc);
DateTimeOffset dateAtTimeZone = TimeZoneInfo.ConvertTime(atUtc, timeZoneInfo); // atUtc is a DateTime here!
Тот факт, что вы присваиваете результат DateTimeOffset
, не имеет значения, поскольку тип возвращаемого значения не участвует в разрешении перегрузки.
Перегрузка, которая принимает a DateTime
, просто изменяет переданные части даты и времени DateTime
, поскольку информация о часовом поясе / смещении не является частью DateTime
s . Когда вы преобразуете его в DateTimeOffset
, ваше локальное смещение добавляется к нему во время преобразования, и это то, что печатается.
То, что вы должны вызывать, — это перегрузка, которая принимает DateTimeOffset
. Поскольку он принимает a DateTimeOffset
, он может изменять часть смещения DateTimeOffset
, а также части даты и времени, до желаемых значений. Вам также необходимо объявить atUtc
как DateTimeOffset
:
DateTimeOffset atUtc = DateTime.SpecifyKind(parsedDate, DateTimeKind.Utc);
DateTimeOffset dateAtTimeZone = TimeZoneInfo.ConvertTime(atUtc, timeZoneInfo);
Или лучше использовать DateTimeOffset.TryParseExact
в первую очередь!