Aws-sdk-net: DateTime ne prend pas en charge la sérialisation aller-retour avec le DocumentModel

Créé le 2 juil. 2014  ·  3Commentaires  ·  Source: aws/aws-sdk-net

Le DocumentModel Primitive ne prend pas correctement en charge la sérialisation aller-retour. Il doit utiliser le spécificateur de format "o" lors de la sérialisation de DateTime pour s'assurer que le fuseau horaire et les millisecondes sont conservés correctement.

J'ai créé un IPropertyConverter ci-dessous pour illustrer la sérialisation correcte pour DateTime et NullableDateTime.

using Amazon.DynamoDBv2.DataModel;
using Amazon.DynamoDBv2.DocumentModel;
using System.Globalization;

/// <summary>
/// The <see cref="IPropertyConverter"/> to properly support round-trip serialization of <see cref="DateTime"/>.
/// </summary>
public class RoundTripNullableDateTimeTypeConverter : IPropertyConverter
{
    /// <summary>
    /// Converts the <c>value</c> to a <see cref="Primitive"/>.
    /// </summary>
    /// <param name="value">The value to convert.</param>
    /// <returns>The primitive of the <c>value</c>.</returns>
    public DynamoDBEntry ToEntry(object value)
    {
        var date = value as DateTime?;
        return new Primitive 
        {
            Value = date.HasValue ? date.Value.ToString("o", CultureInfo.InvariantCulture) : null
        };
    }

    /// <summary>
    /// Converts the <c>entry</c> to <see cref="DateTime"/>.
    /// </summary>
    /// <param name="entry">The entry to convert.</param>
    /// <returns>The date time of the entry.</returns>
    public object FromEntry(DynamoDBEntry entry)
    {
        var entryString = entry.AsString();
        if (string.IsNullOrEmpty(entryString))
            return null;
        else
            return DateTime.ParseExact(entryString, "o", CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind);
    }
}

/// <summary>
/// The <see cref="IPropertyConverter"/> to properly support round-trip serialization of <see cref="DateTime"/>.
/// </summary>
public class RoundTripDateTimeTypeConverter : IPropertyConverter
{
    /// <summary>
    /// Converts the <c>value</c> to a <see cref="Primitive"/>.
    /// </summary>
    /// <param name="value">The value to convert.</param>
    /// <returns>The primitive of the <c>value</c>.</returns>
    public DynamoDBEntry ToEntry(object value)
    {
        return new Primitive
        {
            Value = ((DateTime)value).ToString("o", CultureInfo.InvariantCulture)
        };
    }

    /// <summary>
    /// Converts the <c>entry</c> to <see cref="DateTime"/>.
    /// </summary>
    /// <param name="entry">The entry to convert.</param>
    /// <returns>The date time of the entry.</returns>
    public object FromEntry(DynamoDBEntry entry)
    {
        return DateTime.ParseExact(entry.AsString(), "o", CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind);
    }
}

Quelques références importantes :

Tous les 3 commentaires

Merci de le mentionner. Comme vous l'avez souligné, l'implémentation actuelle utilise le format ISO 8601 UTC, qui ne stocke pas le fuseau horaire et a une précision inférieure à celle possible avec le format "o".

La décision initiale d'utiliser ce format a été prise dans tous les kits SDK AWS qui implémentent une API DynamoDB de haut niveau (Table et DynamoDBContext dans .NET, DynamoDBMapper dans Java, etc.) Le stockage des dates au format ISO 8601 UTC permet une recherche et un tri cohérents, ce qui n'est pas possible si des fuseaux horaires sont spécifiés : des valeurs de chaîne plus grandes ne signifient pas nécessairement des valeurs de date "plus grandes", et il est possible d'avoir plusieurs représentations pour une seule date "unique". Ce dernier peut poser des problèmes avec toutes les opérations, pas seulement les recherches (requête et analyse) : si un élément avec DateTime comme clé est stocké avec un fuseau horaire spécifique, il ne peut être récupéré que si le même fuseau horaire exact est utilisé. Ainsi, selon la structure d'une application, un changement de fuseau horaire peut entraîner l'échec de tous les appels de données, car la clé ne correspondra pas.

Apporter la modification ci-dessus au SDK .NET sera un changement décisif pour les utilisateurs qui peuvent utiliser plusieurs SDK ou différentes versions du SDK .NET, car les clients non mis à jour ne pourront pas analyser les nouveaux formats. Mais les convertisseurs fournis sont une excellente approche pour stocker des dates plus précises avec des fuseaux horaires, tant que les données sont lues et écrites de manière cohérente en utilisant le même formatage et que certaines des considérations mentionnées sont prises en compte.

@PavelSafronov , merci pour la réponse !

La raison pour laquelle je l'ai évoqué était un comportement inattendu d'enregistrement d'une date UTC, puis lors de la récupération de l'élément, il est revenu dans le fuseau horaire local. Ceci est inattendu pour ceux d'entre nous qui utilisent l'API pour stocker et récupérer correctement les données à l'aide de l'UTC. L'API suppose que la date et l'heure entrantes ne sont PAS UTC. Par conséquent, elle suppose qu'elles doivent être l'heure locale lors de la désérialisation. Il fait donc une hypothèse incohérente.

J'ai mis en place un package Nuget appelé AWSSDK.DynamoDBv2.Converters pour aider les autres ayant besoin d'un comportement de sérialisation cohérent des dates. (La source est sur GitHub .)

J'espère que ces informations aideront l'équipe.

Les convertisseurs liés ci-dessus doivent être utilisés si vous avez un cas d'utilisation similaire à @radleta. Pour le SDK principal, nous ne mettrons pas à jour les conversions car cela introduira un changement décisif.

Cette page vous a été utile?
0 / 5 - 0 notes