Aws-sdk-net: DateTime no admite la serialización de ida y vuelta con DocumentModel

Creado en 2 jul. 2014  ·  3Comentarios  ·  Fuente: aws/aws-sdk-net

DocumentModel Primitive no admite correctamente la serialización de ida y vuelta. Debe usar el especificador de formato "o" al serializar DateTime para garantizar que la zona horaria y los milisegundos se conserven correctamente.

Creé un IPropertyConverter a continuación para ilustrar la serialización correcta para DateTime y 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);
    }
}

Algunas referencias importantes:

Todos 3 comentarios

Gracias por mencionar esto. Como señaló, la implementación actual usa el formato ISO 8601 UTC, que no almacena la zona horaria y tiene una precisión menor que la posible con el formato "o".

La decisión original de utilizar este formato se tomó en todos los SDK de AWS que implementan una API de DynamoDB de alto nivel (Table y DynamoDBContext en .NET, DynamoDBMapper en Java, etc.). El almacenamiento de fechas en formato UTC ISO 8601 permite una búsqueda y clasificación coherentes. lo cual no es posible si se especifican zonas horarias: valores de cadena mayores no significan necesariamente valores de fecha "mayores", y es posible tener múltiples representaciones para una sola fecha "única". Esto último puede causar problemas con todas las operaciones, no solo con las búsquedas (Consulta y Escaneo): si un elemento con DateTime como clave se almacena con una zona horaria específica, solo se puede recuperar si se usa la misma zona horaria exacta. Entonces, dependiendo de cómo esté estructurada una aplicación, un cambio en la zona horaria puede hacer que fallen todas las llamadas de datos, ya que la clave no coincidirá.

Hacer el cambio anterior al .NET SDK será un cambio importante para los usuarios que pueden estar usando varios SDK o diferentes versiones del .NET SDK, ya que los clientes no actualizados no podrán analizar los nuevos formatos. Pero los convertidores proporcionados son un enfoque excelente para almacenar fechas de mayor precisión con zonas horarias, siempre que los datos se lean y escriban de manera consistente utilizando el mismo formato y se tengan en cuenta algunas de las consideraciones mencionadas.

@PavelSafronov , ¡gracias por la respuesta!

La razón por la que lo mencioné fue un comportamiento inesperado de guardar una fecha UTC y luego, al buscar el elemento, regresó en la zona horaria local. Esto es inesperado para aquellos de nosotros que usamos la API para almacenar y recuperar datos correctamente usando UTC. La API asume que la fecha y hora entrante NO es UTC, por lo tanto, asume que debe ser la hora local en la deserialización. Entonces hace una suposición inconsistente.

Reuní un paquete Nuget llamado AWSSDK.DynamoDBv2.Converters para ayudar a otros que necesitan un comportamiento de serialización consistente de fechas. (La fuente está en GitHub ).

Espero que esta información ayude al equipo.

Los convertidores vinculados anteriormente deben usarse si tiene un caso de uso similar al de @radleta. Para el SDK principal, no actualizaremos las conversiones, ya que eso introducirá un cambio importante.

¿Fue útil esta página
0 / 5 - 0 calificaciones