У меня вопрос, похожий на этот: Как удалить часовой пояс из DateTime в .NET Core, но я не хочу использовать какой-либо анализ на основе строк.
По сути, у меня есть события из разных мест мира, временные метки которых собраны с помощью DateTime.Now
Я хочу сообщать о событиях с соответствующими локальными временными метками создания (не utc).
Итак, учитывая, что каждая дата и время в основном представлена следующим образом: 2024-05-08T17:31:53.9744487+03:00
Я хочу извлечь только 2024-05-08T17:31:53.9744487
в качестве DateTime, чтобы можно было сообщить местное время события.
Я не хочу выполнять какой-либо анализ строк, как в ответе выше (или какие-либо манипуляции со строками), поскольку они подвержены ошибкам.
Вот тестовый пример, который я хотел бы пройти:
[Fact]
public void DateTimeConversionTest()
{
// Arrange
var testDateTime = DateTime.Parse("2024-05-08T17:31:53.9744487+03:00");
var expectedTimeString = "17:31:53";
// Act
var convertedDateTime = testDateTime; // convert DateTime to local DateTime here
var convertedTimeString = convertedDateTime.ToString("HH:mm:ss");
// Assert
Assert.Equal(expectedTimeString, convertedTimeString);
}
Кажется, эту проблему на C# решить на удивление сложно, поскольку я не смог найти ничего работающего в Интернете.
Кто-нибудь знает, как это решить?
Обновлено: После объяснений Деррика и Гуру ниже я понимаю, что этот вопрос неверен, поскольку дата, проанализированная из строки, сразу теряет смещение часового пояса. Таким образом, решением было бы использовать DateTimeOffset
вместо этого.
EDIT2: Для тех, кто борется с той же десериализацией System.Text.Json
, получая DateTime в виде строки, такой как 2024-05-08T17:31:53.9744487+03:00
, и пытаясь удалить часовой пояс, решением оказалось просто изменить тип свойства принимающего объекта с DateTime
на DateTimeOffset
.
Затем System.Text.Json
правильно десериализует его в DateTimeOffset
, и тогда становятся возможными манипуляции DateTimeOffset
, например получение DateTimeOffset.DateTime
, что решает проблему удаления часового пояса.
Итак, предполагая, что этот класс:
public class MyEvent
{
public string FullName { get; set; }
public DateTime Created { get; set; }
public DateTime CreatedUtc { get; set; }
}
меняется на это:
public class MyEvent
{
public string FullName { get; set; }
public DateTimeOffset Created { get; set; }
public DateTime CreatedUtc { get; set; }
}
теперь это работает правильно:
var myEvent = JsonSerializer.Deserialize<MyEvent>(json)
и мы можем использовать myEvent.Created.DateTime
, чтобы получить DateTime без часового пояса.
У вас есть смещение? Если да, создайте новый объект DateTimeOffset с вашим объектом даты и смещением как объект TimeSpan.
У меня нет смещения, но вся необходимая информация уже предоставлена в DateTime. Я имею в виду, что вы можете визуально увидеть местную дату и время, глядя на него.
Это местная дата и время, где расположен ваш сервер. Вам понадобится либо часовой пояс, либо смещение.
DateTime.Parse()
возвращает локальную дату и время, часовой пояс на этот момент уже потерян, и вы не можете вернуть его, если только не всегда +03:00, и вы хотите жестко запрограммировать его?
В каком свойстве DateTime
указано исходное местное время? testDateTime
должно соответствовать местному времени сервера/приложения, на котором выполняется код.
Если я вас правильно понял, вы можете использовать DateTimeOffset
со свойством DateTimeOffset.DateTime:
На свойство DateTime не влияет значение свойства Offset.
var parsed = DateTimeOffset.Parse("2024-05-08T17:31:53.9744487+01:00");
var originalLocalDateTime = parsed.DateTime; // DateTimeKind.Unspecified
Учитывая тестовый пример, который я написал выше, как бы вы манипулировали testDateTime
, чтобы сделать это?
@Tanuki var testDateTime = DateTimeOffset.Parse(..)
, а затем его использование - var convertedTimeString = testDateTime.ToString("HH:mm:ss");
помогает мне.
Я имею в виду, если у вас уже есть переменная datetime, созданная следующим образом: var testDateTime = DateTime.Parse("2024-05-08T17:31:53.9744487+03:00");
как бы вы это сделали без синтаксического анализа или манипуляций со строками?
@Tanuki - нет. Вот и все. DateTime
не хранит информацию об исходном часовом поясе/смещении, поэтому, если вы не можете получить эту информацию из исходной строки (или каким-либо другим способом), вы ничего не сможете здесь сделать. По сути, вы здесь работаете с неправильной абстракцией.
Я не имеет для меня смысла. При просмотре строкового представления вы можете увидеть +03:00, и это именно то, что следует использовать. Почему это нельзя как-то использовать?
@Tanuki, о каком именно строковом представлении ты говоришь? Тот, который отправляется на DateTime.Parse
? Если да, оно используется для преобразования времени в местный часовой пояс (в основном, часовой пояс сервера, на котором вы работаете). Но это смещение не сохраняется типом.
+03:00 — это смещение UTC, поэтому можно получить правильную местную дату и время, удалив эти 03:00 часов. Никакого отдельного смещения не требуется.
После вызова DateTime.Parse()
ваш вновь возвращенный DateTime
объект не содержит исходного смещения. Вы не сможете вернуть его обратно, если у вас есть только testDateTime
.
@Tanuki еще раз, когда вы проанализируете дату и время, он обработает это смещение +03:00
и будет использовать его для преобразования строки даты и времени в местное время (сервер) с его смещением, если смещение вашего локального часового пояса соответствует значению в строке, то время, которое вы под рукой уже местное время.
@Tanuki, то есть мое текущее смещение TZ +03:00
, так что твой тест для меня просто пройдет. Но если строка будет иметь другое смещение (например, +01:00
) или мое смещение будет другим, то этого не произойдет, и невозможно получить +01:00
из самого проанализированного DateTime
.
Теперь я понял, спасибо Деррику и Гуру за объяснения. Мой вопрос неверен в примере DateTime.Parse()
. На самом деле мои данные поступают в виде строки Json, и смещение времени теряется во время преобразования строки в объект. Теперь я понимаю почему. Позвольте мне посмотреть, можно ли лучше изменить вопрос (или просто признать, что я спросил невозможное)
@Tanuki звучит так, будто вы можете просто использовать DateTimeOffset
вместо DateTime
в своем объекте и все.
Да, это действительно похоже на решение. Мне нужно будет найти, как это сделать для STJ JsonSerializer.Deserialize
, но это совсем другой вопрос/исследование. Спасибо вам за помощь.
«чтобы я мог сообщить местное время События». - а какое местное смещение? Не могли бы вы немного подробнее описать проблему? Какой результат вы получаете?