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