次の方法で共有


System.Formats.Cbor DateTimeOffset の書式設定の変更

.NET 5 でリリースされて以降、System.Formats.Cbor NuGet パッケージには、RFC 7049 に従って DateTimeOffset 値をシリアル化および逆シリアル化するための組み込みメソッドが含まれてきました。 残念ながら、実装では、DateTimeOffset 値の書式設定と解析時にインバリアント カルチャは使用されていませんでした。 その結果、グレゴリオ暦以外のカレンダーを使用するカルチャを持つコンピューターでは、日付のエンコードに一貫性がない、または正しくない可能性がありました。

DateTimeOffset 値の解析と書式設定時にインバリアント カルチャが常に使用されるように動作が変更されました。 以前の動作に依存している場合、この変更によってコードが中断される可能性があります。 また、以前のバージョンの System.Formats.Cbor NuGet パッケージでエンコードされた日付値を読み取ることができない場合もあります。

導入されたバージョン

.NET 8

以前の動作

文字列から DateTimeOffset 値を解析し、CBOR を使用してエンコードする次のコードに場合を考えてみましょう:

// Install a culture with a non-Gregorian calendar
var culture = new CultureInfo("he-IL");
culture.DateTimeFormat.Calendar = new HebrewCalendar();
Thread.CurrentThread.CurrentCulture = culture;

DateTimeOffset value = DateTimeOffset.Parse("2020-04-09T14:31:21.3535941+01:00", CultureInfo.InvariantCulture);

var writer = new CborWriter();
writer.WriteDateTimeOffset(value);
byte[] cborEncoding = writer.Encode();

Console.WriteLine(Convert.ToHexString(cborEncoding));

以前は、このコードでは次の CBOR エンコードが生成されました:

C07828D7AAD7A922D7A42DD796272DD79822D7955431343A33313A32312E333533353934312B30313A3030

このエンコードは、CBOR 診断表記の 0(תש\"פ-ז'-ט\"וT14:31:21.3535941+01:00) に対応しています。これは RFC 7049 では無効な日付表現です。

新しい動作

.NET 8 以降では、同じコードによって次の CBOR エンコードが生成されます:

C07821323032302D30342D30395431343A33313A32312E333533353934312B30313A3030

このエンコードは CBOR 診断表記の 0("2020-04-09T14:31:21.3535941+01:00") に対応します。

破壊的変更の種類

この変更は、動作変更です。

変更理由

以前の動作では、RFC 7049 では無効な日付エンコードが生成されました。

System.Formats.Cbor NuGet パッケージの最新バージョンにアップグレードしない場合は、以前のバージョンの System.Formats.Cbor を使用して永続化された CBOR 日付エンコードを読み取ることができる必要がある場合があります。

または、次の拡張メソッドを使用するようにコードを変更することもできます:

public static class CborReaderExtensions
{
    private const string Rfc3339FormatString = "yyyy-MM-ddTHH:mm:ss.FFFFFFFK";

    public static DateTimeOffset ReadDateTimeOffsetReplacement(this CborReader reader, CultureInfo? cultureInfo = null)
    {
        CborTag tag = reader.PeekTag();
        if (tag != CborTag.DateTimeString)
        {
            throw new InvalidOperationException($"Expected CborTag {(int)CborTag.DateTimeString}");
        }

        reader.ReadTag();
        string dateString = reader.ReadTextString();
        return DateTimeOffset.ParseExact(dateString, Rfc3339FormatString, cultureInfo, DateTimeStyles.    RoundtripKind);
    }
}

この拡張メソッドを使用して、CBOR 日付エンコードを次のように読み取ります:

var reader = new CborReader(cborEncoding);
DateTimeOffset date = reader.ReadDateTimeOffsetReplacement(culture);
Console.WriteLine(date.ToString(CultureInfo.InvariantCulture));

影響を受ける API