Remora / Remora.Rest

Reusable tooling for interacting with JSON-driven REST APIs
GNU Lesser General Public License v3.0
7 stars 10 forks source link

Add ISO8601DurationConverter #11

Closed Foxtrek64 closed 2 years ago

Foxtrek64 commented 2 years ago

Description ISO8601 describes a duration format, such as P3Y6M4DT12H30M5S.

The P stands for Period and must start all duration strings.

3Y = 3 years 6M = 6 months 4D = 4 Days T = time separator 12H = 12 hours 30M = 30 minutes 5S = 5 seconds

Why This is Needed

Some APIs use this format for their durations.

Implementation Example

/// <summary>
/// Converts instances of the <see cref="TimeSpan"/> struct to and from an ISO8601 representation in JSON.
/// </summary>
public sealed class ISO8601DurationConverter : JsonConverter<TimeSpan>
{
    /// <inheritdoc/>
    public override TimeSpan Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        switch (reader.TokenType)
        {
            case JsonTokenType.String:
            {
                try
                {
                    return XmlConvert.ToTimeSpan(reader.GetString()!);
                }
                catch (FormatException fe)
                {
                    throw new JsonException(fe.Message, fe);
                }
            }
            default:
            {
                throw new JsonException();
            }
        }
    }

    /// <inheritdoc/>
    public override void Write(Utf8JsonWriter writer, TimeSpan value, JsonSerializerOptions options)
    {
        writer.WriteStringValue(XmlConvert.ToString(value));
    }
}

Other Thoughts TimeStamp.Parse() does not support this format. XmlConvert works, but it relies on a reference to System.Xml and there is no TryXXX methods, so we're stuck with this try/catch pattern. Thoughts welcome.

Foxtrek64 commented 2 years ago

Closing this issue.

TimeSpan does not support any time periods above days natively.

A better fit is NodaTime.Period which already includes S.T.J converters under the NodaTime.Serialization.SystemTextJson nuget package.

Edit: see dotnet/runtime#72064