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));