Можно ли указать смещение для десериализации JSON.NET DateTimeOffset?

Следующее утверждение печатает "01.01.00 4:00:00 PM -05:00"

Console.WriteLine(JsonConvert.DeserializeObject<DateTimeOffset>("\"0001-01-01T16:00:00\""));

Это происходит потому, что когда json.net десериализует строку DateTime (которая не имеет смещения) для объекта DateTimeOffset, он назначает локальное смещение, которое в этом случае равно -05:00.

Что если я не хочу использовать локальное смещение? Есть ли способ указать смещение для этой десериализации?

(Вариант использования: сервер базы данных и веб-сервер находятся в разных часовых поясах, и мне нужны входящие запросы с неопределенным для зоны временем, чтобы смещение сервера базы данных после десериализации.)

Обновление: я не могу контролировать формат строки входящего времени. У меня есть класс объекта передачи данных, который имеет свойство DateTimeOffset, и мне нужно сохранить данные о времени поступления в это свойство.

2 ответа

Решение

Тип, в который вы десериализуетесь, должен соответствовать ожидаемым данным. Если вы не ожидаете, что смещение будет включено, не десериализуйте в DateTimeOffset, Вместо этого десериализовать в DateTime, Это будет иметь DateTimeKind.Unspecified для его .Kind имущество.

Знания о часовом поясе веб-сервера не имеют ничего общего с задачей десериализации. Так что применяйте это отдельно, после-фактического.

// deserialize the json
DateTime dt = JsonConvert.DeserializeObject<DateTime>("\"2014-01-01T00:00:00\"");

// find your target time zone
TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time");

// apply the time zone to determine the offset, and create the DateTimeOffset
DateTimeOffset dto = new DateTimeOffset(dt, tz.GetUtcOffset(dt));

Обновить

Согласно комментариям, если вам нужно сделать это преобразование так, как вы просили, вам понадобится специальный конвертер json. Это должно сделать трюк:

public class CustomDateTimeConverter : IsoDateTimeConverter
{
    private readonly string defaultTimeZoneId;

    public CustomDateTimeConverter(string defaultTimeZoneId)
    {
        this.defaultTimeZoneId = defaultTimeZoneId;
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (objectType != typeof (DateTimeOffset) && objectType != typeof (DateTimeOffset?))
            return base.ReadJson(reader, objectType, existingValue, serializer);

        var dateText = reader.Value.ToString();
        if (objectType == typeof(DateTimeOffset?) && string.IsNullOrEmpty(dateText))
            return null;

        if (dateText.IndexOfAny(new[] { 'Z', 'z', '+'}) == -1 && dateText.Count(c => c == '-') == 2)
        {
            var dt = DateTime.Parse(dateText);
            var tz = TimeZoneInfo.FindSystemTimeZoneById(this.defaultTimeZoneId);
            var offset = tz.GetUtcOffset(dt);
            return new DateTimeOffset(dt, offset);
        }

        return DateTimeOffset.Parse(dateText);
    }
}

Затем вы можете подключить его во время конвертации:

var settings = new JsonSerializerSettings();
settings.DateParseHandling = DateParseHandling.None;
settings.Converters.Add(new CustomDateTimeConverter(defaultTimeZoneId: "Eastern Standard Time"));
DateTimeOffset dto = JsonConvert.DeserializeObject<DateTimeOffset>("\"2014-01-01T00:00:00\"", settings);

Обязательно используйте действительный идентификатор часового пояса. Не используйте фиксированное смещение.

Кроме того, это не будет правильным подходом, если вы пытаетесь провести время без даты. Это совершенно другая проблема, и прохождение 0001-01-01 для свидания не отличный подход. Я буду рад обсудить с вами в чате.

Если у вас есть смещение в исходной строке (-8:00):

Console.WriteLine(JsonConvert.DeserializeObject<DateTimeOffset>("\"0001-01-01T16:00:00-08:00\""));

Если нет, попробуйте это

var dateTime = JsonConvert.DeserializeObject<DateTime>("\"0001-01-01T16:00:00\"");
DateTimeOffset dto = new DateTimeOffset(dateTime, TimeSpan.FromHours(-8));
Другие вопросы по тегам