DocumentModel Primitiveは、ラウンドトリップシリアル化を適切にサポートしていません。 タイムゾーンとミリ秒が正しく保持されるように、DateTimeをシリアル化するときにフォーマット指定子「o」を使用する必要があります。
DateTimeとNullableDateTimeの正しいシリアル化を説明するために、以下のIPropertyConverterを作成しました。
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 SDKで行われました。日付をISO8601 UTC形式で保存すると、一貫した検索と並べ替えが可能になります。これは、タイムゾーンが指定されている場合は不可能です。文字列値が大きいほど、必ずしも「大きい」日付値を意味するわけではなく、単一の「一意の」日付に対して複数の表現を持つことができます。 後者は、検索(クエリとスキャン)だけでなく、すべての操作で問題を引き起こす可能性があります。キーとしてDateTimeを持つアイテムが特定のタイムゾーンで保存されている場合、同じ正確なタイムゾーンが使用されている場合にのみ取得できます。 そのため、アプリケーションの構造によっては、タイムゾーンを変更すると、キーが一致しないため、すべてのデータ呼び出しが失敗する可能性があります。
.NET SDKに上記の変更を加えることは、更新されていないクライアントが新しい形式を解析できないため、複数のSDKまたは異なるバージョンの.NETSDKを使用している可能性のあるユーザーにとって重大な変更になります。 ただし、提供されているコンバーターは、データが同じフォーマットを使用して一貫して読み書きされ、前述の考慮事項のいくつかが考慮されている限り、タイムゾーンでより高精度の日付を格納するための優れたアプローチです。
@PavelSafronov 、返信ありがとう
私がそれを取り上げた理由は、UTC日付を保存し、アイテムをフェッチするとローカルタイムゾーンに戻ってきたという予期しない動作でした。 これは、APIを使用してUTCを使用してデータを適切に保存および取得する私たちにとっては予想外のことです。 APIは、着信DateTimeがUTCではないと想定しているため、逆シリアル化の現地時間であると想定しています。 したがって、それは一貫性のない仮定をします。
AWSSDK.DynamoDBv2.ConvertersというNugetパッケージをまとめて、日付の一貫したシリアル化動作を必要とする他のユーザーを支援します。 (ソースはGitHubにあります。)
この情報がチームに役立つことを願っています。
@radletaと同様のユースケースがある場合は、上記でリンクされているコンバーターを使用する必要があります。 メインSDKの場合、重大な変更が発生するため、変換は更新されません。