Description
Description
Since it was released in .NET 5, the System.Formats.Cbor
NuGet package included built-in methods for serializing and deserializing DateTimeOffset
values according to RFC 7049. Unfortunately, the implementations weren't using invariant culture when formatting/parsing DateTimeOffset
values. This can result in inconsistent or even incorrect date encodings in machines with cultures using non-Gregorian calendars.
The PR in dotnet/runtime#92924 changes the DateTimeOffset behavior so that invariant culture is always being used. This can cause breaking changes for users relying on the previous behavior, including making it impossible to read date values that have been encoded with earlier versions of the System.Formats.Cbor NuGet package.
Version
.NET 8 GA
Previous behavior
The code
// 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));
produces the CBOR encoding
C07828D7AAD7A922D7A42DD796272DD79822D7955431343A33313A32312E333533353934312B30313A3030
which corresponds to 0(תש\"פ-ז'-ט\"וT14:31:21.3535941+01:00)
in CBOR diagnostic notation. This is an invalid date representation per RFC 7049.
New behavior
The same code will produce the CBOR encoding
C07821323032302D30342D30395431343A33313A32312E333533353934312B30313A3030
which corresponds to 0("2020-04-09T14:31:21.3535941+01:00")
in CBOR diagnostic notation.
Type of breaking change
- Binary incompatible: Existing binaries may encounter a breaking change in behavior, such as failure to load or execute, and if so, require recompilation.
- Source incompatible: When recompiled using the new SDK or component or to target the new runtime, existing source code may require source changes to compile successfully.
- Behavioral change: Existing binaries may behave differently at run time.
Reason for change
The previous behavior produced invalid date encodings per RFC 7049.
Recommended action
You might have to be able to read CBOR date encodings that were persisted using earlier versions of System.Formats.Cbor. This can be achieved either by
- Not upgrading to the latest version of the System.Formats.Cbor NuGet package or
- Change your code to use the extension method provided below.
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);
}
}
Which can be used to roundtrip the previous example as follows:
var reader = new CborReader(cborEncoding);
DateTimeOffset date = reader.ReadDateTimeOffsetReplacement(culture);
Console.WriteLine(date.ToString(CultureInfo.InvariantCulture));
Feature area
Other (please put exact area in description textbox)
Affected APIs
- System.Formats.Cbor.CborWriter.WriteDateTimeOffset
- System.Formats.Cbor.CborRead.ReadDateTimeOffset