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);
}
}
一些重要的参考资料:
谢谢你提出这个问题。 正如您所指出的,当前的实现使用 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,我们不会更新转换,因为这会引入重大更改。