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

이 인코딩은 0("2020-04-09T14:31:21.3535941+01:00") CBOR 진단 표기법에서 해당합니다.

파괴적 변경 유형

이 변경 사항은 행동 변화입니다.

변경 이유

이전 동작은 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