/System.DateTimeOnly

Make DateOnly and TimeOnly data types available for all .NET versions prior to .NET 6

Primary LanguageC#MIT LicenseMIT

Build Codacy Grade Codacy Coverage PVS-Studio Sponsors

Logo Portable.System.DateTimeOnly Nuget Nuget

The .NET 6 introduced two new data types System.DateOnly and System.TimeOnly that can be used in various scenarios. If you want to use the same types in the .NET versions below to .NET 6 you can use this library in form of the NuGet package. You can also use it in your own NuGet package if you want to provide an API that uses these types and make it compatible with all currently supported .NET versions at the same time.

String Parsing Performance

The original version of this package used the simplified string parsing approach - it just reuses the default System.DateTime parsing logic as is. It works well in most use cases but parsing behavior was not matched 100% to the .NET 6 System.DateOnly and System.TimeOnly data types. Their raise the System.FormatException exception in case if the input string contains the time part for the System.DateOnly or the date part in the case of System.TimeOnly types.

Unfortunately, this behavior in .NET 6 implementation depends heavily on an internal parser that provides a lot more information about parsing results than a public version of parsing API. Porting this parser required porting a lot of culture-specific code and looks unpractical for such a simple package. So another approach selected for solving this issue - double parsing using System.DateTime.TryParseExact method with proper formatting strings.

This approach, of course, has an obvious disadvantage - in some cases, we have to parse the same string twice. If performance is critical for you and you are OK with the incorrect parsing results in some rare cases you can restore the original behavior using the application context switch named Portable.System.DateTimeOnly.UseFastParsingLogic. Check the FastStrictParsingLogicTests for more examples for this issue.

Logo Portable.System.DateTimeOnly.Json Nuget Nuget

The System.Text.Json NuGet package contains the built-in support for the System.DateOnly and System.TimeOnly types serialization/deserialization. Of course, the backported versions of the same types are not supported by default by this library. If you already use the portable versions of these types in your code and want to make them compatible with the System.Text.Json you can implement custom converters or use this package for cross-framework compatible approach.

Reflection-based Serialization

The package provides two concrete implementations of the System.Text.Json.Serialization.JsonConverter<T> class: System.Text.Json.DateOnlyConverter and System.Text.Json.TimeOnlyConverter for converting System.DateOnly and System.TimeOnly data types. You can use this converter as usual System.Text.Json converters: with the System.Text.Json.Serialization.JsonConverterAttribute attribute or System.Text.Json.JsonSerializerOptions.Converters property.

The main disadvantage of this "direct" approach for configuring System.DateOnly and System.TimeOnly data types handling by the System.Text.Json library is that in this case you'll always use the backported converters even if your code runs on .NET 6 and later. The package also provides two helper attributes System.Text.Json.DateOnlyConverterAttribute and System.Text.Json.TimeOnlyConverterAttribute for mitigating this problem. These attributes use built-in converters on .NET 6 and later and fall back to the backported one in other cases.

Source Generators Workaround

Unfortunately, attributes-based approach will not work if you'll try to use System.DateOnly and/or System.TimeOnly data types with the System.Text.Json source generators. The only way to make generated code compilable is to use any type names not equal to System.DateOnly and/or System.TimeOnly available in object graph processed by the source generator.

The package provides two helper types: System.Text.Json.DateOnly and System.Text.Json.TimeOnly (same class names but different full type names). These types have no public properties but they provide implicit conversion operations from/to the System.DateOnly and System.TimeOnly data types respectively. You can use them safely in your JSON-mapping objects with any type of serialization available in the System.Text.Json library. These types have custom System.Text.Json.Serialization.JsonConverterAttribute applied with helper converters that delegate work to System.Text.Json.DateOnlyConverter and System.Text.Json.TimeOnlyConverter types without code duplication.

Contributors

Thanks a lot for all contributors. See the full list of project supporters in the CONTRIBUTORS file.

SAST Tools

This project uses PVS-Studio - static analyzer for C, C++, C#, and Java code.