Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Date/TimeOnly to STJ #51302

Closed
devsko opened this issue Apr 15, 2021 · 12 comments
Closed

Add support for Date/TimeOnly to STJ #51302

devsko opened this issue Apr 15, 2021 · 12 comments
Labels
api-suggestion Early API idea and discussion, it is NOT ready for implementation area-System.Text.Json
Milestone

Comments

@devsko
Copy link
Contributor

devsko commented Apr 15, 2021

Background and Motivation

The recently added types DateOnly and TimeOnly should be fully supported by System.Text.Json. Even when it's possible to make them serializable via a built-in or custom converter, adding support to Utf8JsonReader/Writer brings them on par with other types like DateTimeOffset.

Proposed API

namespace System.Text.Json
{
    public ref partial struct Utf8JsonReader
    {
+        public DateOnly GetDateOnly();
+        public TimeOnly GetTimeOnly();
+        public bool TryGetDateOnly(out DateOnly value);
+        public bool TryGetTimeOnly(out TimeOnly value);
    }

    public sealed partial class Utf8JsonWriter
    {
+        public void WriteString(JsonEncodedText propertyName, DateOnly value);
+        public void WriteString(JsonEncodedText propertyName, TimeOnly value);
+        public void WriteString(string propertyName, DateOnly value);
+        public void WriteString(string propertyName, TimeOnly value);
+        public void WriteString(ReadOnlySpan<char> propertyName, DateOnly value);
+        public void WriteString(ReadOnlySpan<char> propertyName, TimeOnly value);
+        public void WriteString(ReadOnlySpan<byte> utf8PropertyName, DateOnly value);
+        public void WriteString(ReadOnlySpan<byte> utf8PropertyName, TimeOnly value);
+        public void WriteStringValue(DateOnly value);
+        public void WriteStringValue(TimeOnly value);
    }

    public readonly partial struct JsonElement
    {
+        public DateOnly GetDateOnly();
+        public TimeOnly GetTimeOnly();
+        public bool TryGetDateOnly(out DateOnly value)
+        public bool TryGetTimeOnly(out TimeOnly value)
    }
}

namespace System.Text.Json.Node
{
    public abstract partial class JsonNode
    {
+        public static explicit operator DateOnly(JsonNode value);
+        public static explicit operator TimeOnly(JsonNode value);
+        public static explicit operator DateOnly?(JsonNode? value);
+        public static explicit operator TimeOnly?(JsonNode? value);
+        public static implicit operator JsonNode(DateOnly value);
+        public static implicit operator JsonNode(TimeOnly value);
+        public static implicit operator JsonNode?(DateOnly? value);
+        public static implicit operator JsonNode?(TimeOnly? value);
    }
}

namespace System.Text.Json.Serialization.Metadata
{
    public static partial class JsonMetadataServices
    {
+        public static JsonConverter<DateOnly> DateOnlyConverter { get; }
+        public static JsonConverter<TimeOnly> TimeOnlyConverter { get; }
    }
}

namespace System.Buffers.Text
{
    public static partial class Utf8Formatter
    {
+        public static bool TryFormat(DateOnly value, Span<byte> destination, out int bytesWritten, StandardFormat format = default);
+        public static bool TryFormat(TimeOnly value, Span<byte> destination, out int bytesWritten, StandardFormat format = default);
    }
    public static partial class Utf8Parser
    {
+        public static bool TryParse(ReadOnlySpan<byte> source, out DateOnly value, out int bytesConsumed, char standardFormat = default);
+        public static bool TryParse(ReadOnlySpan<byte> source, out TimeOnly value, out int bytesConsumed, char standardFormat = default);
    }
}

Usage Examples

    var value = reader.GetDateOnly();
    writer.WriteStringValue(value);

Alternative Designs

As mentioned it would be possible to just add serialization converters for these types without supporting the Utf8Reader/Writer scenarios.

Risks

Obviously this API cannot be added to platforms prior .NET 6. Thus it would be necessary to only include it in the .NET 6 version of STJ.

Updates

  • Added Utf8Formatter.TryFormat and Utf8Parser.TryParse overloads.
@devsko devsko added the api-suggestion Early API idea and discussion, it is NOT ready for implementation label Apr 15, 2021
@dotnet-issue-labeler dotnet-issue-labeler bot added area-System.Text.Json untriaged New issue has not been triaged by the area owner labels Apr 15, 2021
@ghost
Copy link

ghost commented Apr 15, 2021

Tagging subscribers to this area: @eiriktsarpalis, @layomia
See info in area-owners.md if you want to be subscribed.

Issue Details

Background and Motivation

The recently added types DateOnly and TimeOnly should be fully supported by System.Text.Json. Even when it's possible to make them serializable via a built-in or custom converter, adding support to Utf8JsonReader/Writer brings them on par with other types like DateTimeOffset.

Proposed API

namespace System.Text.Json
{
    public ref partial struct Utf8JsonReader
    {
+        public System.DateOnly GetDateOnly();
+        public System.TimeOnly GetTimeOnly();
+        public bool TryGetDateOnly(out System.DateOnly value);
+        public bool TryGetTimeOnly(out System.TimeOnly value);
    }

    public sealed partial class Utf8JsonWriter
    {
+        public void WriteString(JsonEncodedText propertyName, System.DateOnly value);
+        public void WriteString(JsonEncodedText propertyName, System.TimeOnly value);
+        public void WriteString(string propertyName, System.DateOnly value);
+        public void WriteString(string propertyName, System.TimeOnly value);
+        public void WriteString(ReadOnlySpan<char> propertyName, System.DateOnly value);
+        public void WriteString(ReadOnlySpan<char> propertyName, System.TimeOnly value);
+        public void WriteString(ReadOnlySpan<byte> utf8PropertyName, System.DateOnly value);
+        public void WriteString(ReadOnlySpan<byte> utf8PropertyName, System.TimeOnly value);
+        public void WriteStringValue(System.DateOnly value);
+        public void WriteStringValue(System.TimeOnly value);
    }

    public readonly partial struct JsonElement
    {
+        public System.DateOnly GetDateOnly();
+        public System.TimeOnly GetTimeOnly();
+        public bool TryGetDateOnly(out System.DateOnly value)
+        public bool TryGetTimeOnly(out System.TimeOnly value)
    }
}

namespace System.Text.Json.Node
{
    public abstract partial class JsonNode
    {
+        public static explicit operator System.DateOnly(JsonNode value);
+        public static explicit operator System.TimeOnly(JsonNode value);
+        public static explicit operator System.DateOnly?(JsonNode? value);
+        public static explicit operator System.TimeOnly?(JsonNode? value);
+        public static implicit operator JsonNode(System.DateOnly value);
+        public static implicit operator JsonNode(System.TimeOnly value);
+        public static implicit operator JsonNode?(System.DateOnly? value);
+        public static implicit operator JsonNode?(System.TimeOnly? value);
    }
}

namespace System.Text.Json.Serialization.Metadata
{
    public static partial class JsonMetadataServices
    {
+        public static JsonConverter<System.DateOnly> DateOnlyConverter { get; }
+        public static JsonConverter<System.TimeOnly> TimeOnlyConverter { get; }
    }
}

Usage Examples

    var value = reader.GetDateOnly();
    writer.WriteStringValue(value);

Alternative Designs

As mentioned it would be possible to just add serialization converters for these types without supporting the Utf8Reader/Writer scenarios.

Risks

Obviously this API cannot be added to platforms prior .NET 6. Thus it would be necessary to only include it in the .NET 6 version of STJ.

Author: devsko
Assignees: -
Labels:

api-suggestion, area-System.Text.Json, untriaged

Milestone: -

@eiriktsarpalis
Copy link
Member

Tagging @layomia and @steveharter for thoughts. It stands to reason that we should aim to release support for the new types in .NET 6 (presumably conforming to ISO 8601 date only/time only formats).

@devsko
Copy link
Contributor Author

devsko commented Apr 15, 2021

A small collection of ISO 8601 related issues:

@devsko
Copy link
Contributor Author

devsko commented Apr 16, 2021

IMO the formatting/parsing of the new types should be implemented identically as for DateTime(Offset) (and TimeSpan). Any changes wrt ISO 8601 are orthogonal and should be applied to all of these types in the same way.

@eiriktsarpalis eiriktsarpalis added this to the Future milestone Apr 19, 2021
@eiriktsarpalis eiriktsarpalis removed the untriaged New issue has not been triaged by the area owner label Apr 19, 2021
@mattjohnsonpint
Copy link
Contributor

I agree these should have full parity with the other date/time types.

In the meantime, here's some simple converters that will do the trick. (Though ultimately, they should not be needed.)

public class DateOnlyJsonConverter : JsonConverter<DateOnly>
{
    private const string DateFormat = "yyyy-MM-dd";

    public override DateOnly Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        return DateOnly.ParseExact(reader.GetString(), DateFormat, CultureInfo.InvariantCulture);
    }

    public override void Write(Utf8JsonWriter writer, DateOnly value, JsonSerializerOptions options)
    {
        writer.WriteStringValue(value.ToString(DateFormat, CultureInfo.InvariantCulture));
    }
}

public class TimeOnlyJsonConverter : JsonConverter<TimeOnly>
{
    private const string TimeFormat = "HH:mm:ss.FFFFFFF";

    public override TimeOnly Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        return TimeOnly.ParseExact(reader.GetString(), TimeFormat, CultureInfo.InvariantCulture);
    }

    public override void Write(Utf8JsonWriter writer, TimeOnly value, JsonSerializerOptions options)
    {
        writer.WriteStringValue(value.ToString(TimeFormat, CultureInfo.InvariantCulture));
    }
}

@ericstj
Copy link
Member

ericstj commented May 25, 2021

cc @tarekgh - should we look for elsewhere in the framework that has special handling for DateTime/DateTimeOffset and ensure we add handling for DateOnly/TimeOnly as well?

@tarekgh
Copy link
Member

tarekgh commented May 25, 2021

should we look for elsewhere in the framework that has special handling for DateTime/DateTimeOffset and ensure we add handling for DateOnly/TimeOnly as well?

@ericstj yes this is in our radar but not really planned for 6.0 release. It would be good candidate for 7.0 release. If we get a chance before then we should consider it.

@layomia
Copy link
Contributor

layomia commented Jun 1, 2021

We likely won't get to this level of support in .NET 6.0, but can support them in JsonSerializer now - #53539.

@LaughingJohn
Copy link

Are XmlSerializer and DataContractSerializer also going to be supported?

@eiriktsarpalis
Copy link
Member

@LaughingJohn I created a separate issue on that question to be considered by the area owners of those serializers.

@LaughingJohn
Copy link

Thanks @eiriktsarpalis!

@eiriktsarpalis
Copy link
Member

Closing in favor of #53539.

@ghost ghost locked as resolved and limited conversation to collaborators Nov 22, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
api-suggestion Early API idea and discussion, it is NOT ready for implementation area-System.Text.Json
Projects
None yet
Development

No branches or pull requests

7 participants