Aws-sdk-net: DateTime 不支持与 DocumentModel 的往返序列化

创建于 2014-07-02  ·  3评论  ·  资料来源: aws/aws-sdk-net

DocumentModel Primitive 不正确支持往返序列化。 它应该在序列化 DateTime 时使用格式说明符“o”,以确保正确保留时区和毫秒。

我在下面创建了一个 IPropertyConverter 来说明 DateTime 和 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);
    }
}

一些重要的参考资料:

所有3条评论

谢谢你提出这个问题。 正如您所指出的,当前的实现使用 ISO 8601 UTC 格式,它不存储时区并且精度低于“o”格式。

使用这种格式的最初决定是在所有实现高级 DynamoDB API(.NET 中的表和 DynamoDBContext,Java 中的 DynamoDBMapper 等)的 AWS 开发工具包中做出的。以 ISO 8601 UTC 格式存储日期允许一致的搜索和排序,如果指定了时区,这是不可能的:更大的字符串值不一定意味着“更大”的日期值,并且单个“唯一”日期可能有多种表示形式。 后者可能会导致所有操作出现问题,而不仅仅是搜索(查询和扫描):如果以 DateTime 作为键的项目使用特定时区存储,则只有使用相同的时区才能检索它。 因此,根据应用程序的结构,时区的更改可能会导致所有数据调用失败,因为键将不匹配。

对 .NET SDK 进行上述更改对于可能使用多个 SDK 或不同版本的 .NET SDK 的用户来说将是一个重大更改,因为未更新的客户端将无法解析新格式。 但是,提供的转换器是存储带时区的更高精度日期的绝佳方法,只要使用相同的格式始终如一地读取和写入数据,并且考虑到一些提到的注意事项。

@PavelSafronov ,感谢您的回复!

我提出它的原因是一个意外的行为,即保存 UTC 日期然后在获取它在本地时区返回的项目时。 对于我们这些使用 API 使用 UTC 正确存储和检索数据的人来说,这是出乎意料的。 API 假定传入的 DateTime 不是 UTC,因此,它假定它们应该是反序列化的本地时间。 所以它做出了不一致的假设。

我将一个名为AWSSDK.DynamoDBv2.Converters的 Nuget 包放在一起,以帮助其他需要一致的日期序列化行为的人。 (来源在GitHub 上。)

希望这些信息对团队有帮助。

如果您有与@radleta 类似的用例,则应使用上面链接的转换器。 对于主 SDK,我们不会更新转换,因为这会引入重大更改。

此页面是否有帮助?
0 / 5 - 0 等级