it-roy-ru.com

JSON Дата и DateTime сериализация в C # & Newtonsoft

Мы отправляем JSON в API, определенный swagger, что некоторые свойства имеют DateTime в формате yyyy-MM-ddThh: mm: ss.000Z (миллисекунды должны состоять из 3 цифр или не проходят проверку в конечной точке), а некоторые - Date (нет время) свойства.

Я видел много сообщений, говорящих об использовании форматеров как это:

var jsonSettings = new JsonSerializerSettings();
jsonSettings.DateFormatString = "yyyy-MM-ddThh:mm:ss.000Z"; //try .fffZ too
var jsonObject= Newtonsoft.Json.JsonConvert.DeserializeObject<OurSwaggerObject>(json , setting);

но это не конвертирует DateTimes в правильный формат, и как C # работает с типом только Date? Кажется, он всегда сериализуется как DateTime.MinValue ()

Вот пример:

Кто-то отправляет мне json в виде строки, но даты и время в неправильном формате отправляются конечной точке. Я надеялся, что класс Swagger и десериализация JSON отформатируют их, но это не так.

Это сгенерированный чванством класс

 public class OurSwaggerObject
    {
        [Newtonsoft.Json.JsonProperty("dateTimeField", Required = Newtonsoft.Json.Required.Always)]
        [System.ComponentModel.DataAnnotations.Required]
        [System.ComponentModel.DataAnnotations.RegularExpression(@"^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d\.\d{3}Z$")]
        public DateTime dateTimeField { get; set; }

        [Newtonsoft.Json.JsonProperty("dateField", Required = Newtonsoft.Json.Required.Always)]
        [System.ComponentModel.DataAnnotations.Required]
        [System.ComponentModel.DataAnnotations.RegularExpression(@"^\d{4}-\d\d-\d\d$")]
        public DateTime dateField { get; set; }
    }

Поэтому я пытаюсь заставить JSON быть правильным, но я делаю это неправильно или что-то не хватает

string json = @"{ 'dateTimeField': '1995-04-07T00:00:00',
                          'dateField': '1995-04-07T00:00:00'
                           }";

        /* The json we need to satisfy the swagger endpoint is:

          { 'dateTimeField': '1995-04-07T00:00:00.000Z',
            'dateField': '1995-04-07'
                           }              
          */

        OurSwaggerObject deserialisedIntoObject = Newtonsoft.Json.JsonConvert.DeserializeObject<OurSwaggerObject>(json);

        string serialisedToString = Newtonsoft.Json.JsonConvert.SerializeObject(deserialisedIntoObject);
        //serialisedToString= "{\"dateTimeField\":\"1995-04-07T00:00:00\",\"dateField\":\"1995-04-07T00:00:00\"}"

        var jsonSettings = new JsonSerializerSettings();
        jsonSettings.DateFormatString = "yyyy-MM-ddThh:mm:ss.fffZ"; //this won't help much for the 'date' only field!
        deserialisedIntoObject = Newtonsoft.Json.JsonConvert.DeserializeObject<OurSwaggerObject>(json,jsonSettings);
        serialisedToString = Newtonsoft.Json.JsonConvert.SerializeObject(deserialisedIntoObject, jsonSettings);
        //serialisedToString="{\"dateTimeField\":\"1995-04-07T00:00:00\",\"dateField\":\"1995-04-07T00:00:00\"}"
7
DomBat

Как я уже упоминал в комментарии, в JSON нет стандартного представления даты. ISO8601 является стандартом де-факто, т.е. большинство людей начали использовать его несколько лет назад. ISO8601 не требует миллисекунд. Если другая конечная точка требует их, это нарушает стандарт defacto.

Json.NET использует IOS8601 начиная с версии 4.5. Текущий - 10.0.3. Следующий код:

JsonConvert.SerializeObject(DateTime.Now)

возвращается 

"2017-09-08T19:01:55.714942+03:00"

На моей машине. Обратите внимание на смещение часового пояса. Это тоже часть стандарта. Z означает UTC.

Вы можете указать свой собственный формат времени, если он правильный. В этом случае это должен быть yyyy-MM-ddTH:mm:ss.fffZ. Обратите внимание на fff для миллисекунд иHH на 24 часа.

Следующий код

var settings=new JsonSerializerSettings{DateFormatString ="yyyy-MM-ddTH:mm:ss.fffZ"};
var json=JsonConvert.SerializeObject(DateTime.Now,settings);

возвращается

"2017-09-08T19:04:14.480Z"

Строка формата not принудительно переводит часовой пояс. Вы можете указать Json.NET обрабатывать время как локальное или Utc с помощью параметра DateTimeZoneHandling:

var settings=new JsonSerializerSettings{
                              DateFormatString ="yyyy-MM-ddTH:mm:ss.fffZ",
                              DateTimeZoneHandling=DateTimeZoneHandling.Utc};
var json=JsonConvert.SerializeObject(DateTime.Now,settings);

Возвращает:

"2017-09-08T16:08:19.290Z"

ОБНОВЛЕНИЕ 

Как объясняет Мэтт Джонсон, Z - это просто литерал, а K генерирует либо Z, либо смещение, в зависимости от настройки DateTimeZoneHandling.

Строка формата yyyy-MM-ddTH:mm:ss.fffK с DateTimeZoneHandling.Utc:

var settings=new JsonSerializerSettings{
                              DateFormatString ="yyyy-MM-ddTH:mm:ss.fffK",
                              DateTimeZoneHandling=DateTimeZoneHandling.Utc};
var json=JsonConvert.SerializeObject(DateTime.Now,settings);

Вернусь :

2017-09-11T9:10:08.293Z

Изменение на DateTimeZoneHandling.Utc вернет 

2017-09-11T12:15:12.862+03:00

Что, кстати, является поведением default в Json.NET, за исключением принудительной точности в миллисекундах.

Наконец, .NET пока не имеет Date- только тип . DateTime используется для значений даты и даты + время. Вы можете получить часть даты DateTime с помощью свойства DateTime.Date . Вы можете получить текущую дату с помощью DateTime.Today .

Время дня представлено типом Timespan. Вы можете извлечь время дня из значения DateTime с помощью DateTime.TimeOfDay . Timespan не является строго типом времени суток, поскольку может представлять более 24 часов.

Что это было еще?

Поддержка явного Date, TimeOfDay приходит через проект лаборатории CoreFX . Он содержит «экспериментальные» функции, которые чрезвычайно могут появляться в .NET Runtime, такие как поддержка UTF8, Date, String, Channles. Некоторые из них уже появляются как отдельные пакеты NuGet. 

Уже можно использовать классы System.Time , либо скопировав код, либо добавив их через экспериментальный источник NuGet. 

14
Panagiotis Kanavos

Получите текущий формат даты и времени от Universal Time до JSON и наоборот:

DateTime currentDateTime = DateTime.Now.ToUniversalTime();
var jsonDateTime = GetJSONFromUserDateTime(currentDateTime);
DateTime getDateTime = GetUserDateTimeFromJSON(jsonDateTime);

Вот оба метода:

/// <summary>
/// Convert UserDateTime({9/7/2018 8:37:20 AM}) to JSON datetime(1536309440373) format
/// </summary>
/// <param name="givenDateTime"></param>
/// <returns></returns>
public static string GetJSONFromUserDateTime(DateTime givenDateTime)
{
    string jsonDateTime = string.Empty;
    if (givenDateTime != null)
    {
        JsonSerializerSettings microsoftDateFormatSettings = new JsonSerializerSettings
        {
            DateFormatHandling = DateFormatHandling.MicrosoftDateFormat
        };
        jsonDateTime = JsonConvert.SerializeObject(givenDateTime, microsoftDateFormatSettings);
        jsonDateTime = jsonDateTime.Replace("\"\\/Date(", "").Replace(")\\/\"", "");
    }
    return jsonDateTime;
}

/// <summary>
/// Convert JSON datetime(1536309440373) to user datetime({9/7/2018 8:37:20 AM})
/// </summary>
/// <param name="jsonDateTime"></param>
/// <returns></returns>
public static dynamic GetUserDateTimeFromJSON(string jsonDateTime)
{
    dynamic userDateTime = null;
    if (!string.IsNullOrEmpty(jsonDateTime))
    {
        JsonSerializerSettings microsoftDateFormatSettings = new JsonSerializerSettings
        {
            DateFormatHandling = DateFormatHandling.MicrosoftDateFormat
        };
        userDateTime = JsonConvert.DeserializeObject("\"\\/Date(" + jsonDateTime + ")\\/\"", microsoftDateFormatSettings);
    }
    return userDateTime;
}
0
kumar kashyap pandey