web-dev-qa-db-fra.com

Sérialisation JSON Date et DateTime en c # et newtonsoft

Nous envoyons JSON à une API définie par swagger selon laquelle certaines propriétés sont DateTime au format aaaa-MM-jjThh: mm: ss.000Z (les millisecondes doivent être de 3 chiffres ou la validation échoue au niveau du noeud final) et certaines sont de type Date (non temps) propriétés.

J'ai vu beaucoup de messages disant d'utiliser les formateurs comme ceci:

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

mais cela ne convertit pas les DateTimes au format correct, et comment C # traite-t-il un type de type Date uniquement? Il semble toujours mettre en série comme DateTime.MinValue ()

Voici un exemple:

Quelqu'un m'envoie json sous forme de chaîne, mais les dates et les dates/heures dans un format incorrect sont envoyées au noeud final. J'espérais que la classe swagger et la désérialisation json les formatteraient mais ce n'est pas le cas.

C'est la classe swagger générée

 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; }
    }

Donc, j'essaie de contraindre le JSON à être correct mais je le fais mal ou quelque chose manque

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

Comme je l'ai mentionné dans un commentaire, il n'y a pas de représentation de date standard dans JSON. ISO8601 est la norme de facto, c'est-à-dire que la plupart des gens l'utilisent depuis quelques années. ISO8601 ne pas nécessite des millisecondes. Si l'autre point d'extrémité le requiert, il enfreint le standard de facto.

Json.NET utilise IOS8601 depuis la version 4.5. Le courant est 10.0.3. Le code suivant:

JsonConvert.SerializeObject(DateTime.Now)

résultats 

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

Sur ma machine. Notez le décalage horaire. Cela fait également partie de la norme. Z signifie UTC.

Vous pouvez spécifiez votre propre format d'heure, à condition que ce soit le bon. Dans ce cas, il devrait s'agir de yyyy-MM-ddTH:mm:ss.fffZ. Notez que fff pour millisecondes etHH pendant 24 heures.

Le code suivant

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

résultats

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

La chaîne de formatage non force la traduction du fuseau horaire. Vous pouvez indiquer à Json.NET de traiter l'heure en tant que Local ou Utc via le paramètre DateTimeZoneHandling:

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

Résultats :

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

METTRE &AGRAVE; JOUR 

Comme Matt Johnson l'explique, Z n'est qu'un littéral, alors que K génère soit Z, soit un décalage, en fonction du paramètre DateTimeZoneHandling.

Le format de chaîne yyyy-MM-ddTH:mm:ss.fffK avec DateTimeZoneHandling.Utc:

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

Reviendra:

2017-09-11T9:10:08.293Z

Passer à DateTimeZoneHandling.Utc retournera 

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

Soit dit en passant, le comportement par défaut de Json.NET, mis à part la précision forcée en millisecondes.

Enfin, .NET n'a pas de type Date- only encore. DateTime est utilisé pour les dates et les valeurs date + heure. Vous pouvez obtenir la partie date d'un DateTime avec la propriété DateTime.Date . Vous pouvez récupérer la date du jour avec DateTime.Today .

L'heure est représentée par le type Timespan. Vous pouvez extraire l'heure du jour d'une valeur DateTime avec DateTime.TimeOfDay . Timespan n'est pas strictement _ un type d'heure, car il peut représenter plus de 24 heures.

Qu'est-ce que c'était encore?

La prise en charge de Date explicite, TimeOfDay arrive via le projet CoreFX Lab . Cela contient des fonctionnalités "expérimentales" qui sont extrêmement susceptibles d'apparaître dans le runtime .NET comme le support UTF8, Date, String, Channles. Certains d'entre eux apparaissent déjà sous forme de packages NuGet distincts. 

On peut déjà utiliser les classes System.Time , soit en copiant le code, soit en les ajoutant via le code expérimental NuGet. 

14
Panagiotis Kanavos

Obtenez le format actuel de l'heure universaltime au format json et vice versa:

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

Voici les deux méthodes:

/// <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