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

Deserialization of TimeOnly fails for "HH:mm" formatted times #2810

Open
dwfrancis opened this issue Feb 7, 2023 · 4 comments
Open

Deserialization of TimeOnly fails for "HH:mm" formatted times #2810

dwfrancis opened this issue Feb 7, 2023 · 4 comments

Comments

@dwfrancis
Copy link

dwfrancis commented Feb 7, 2023

Deserialization of TimeOnly fails for the HH:mm format - the seconds is required.
This leads to compatibility issues since HH:mm is the default format returned by HTML <input type="time" />
The similar TimeSpan properly deserializes this format.

Source/destination types

TimeOnly

Source/destination JSON

"17:05"

Expected behavior

The time is deserialized as 17:05

Actual behavior

Error converting value "17:05" to type 'System.TimeOnly'.

Steps to reproduce

JsonConvert.DeserializeObject<TimeOnly>("\"17:05\"")
@mariomeyrelles
Copy link

I am seeing this issue when I try to retrieve "09:00" from Cosmos. Can this change be merged soon? The solution seems to reasonable.

@stratdev3
Copy link

+1

@michelebenolli
Copy link

This is my temporary workaround while waiting for the issue to be fixed.

public class TimeOnlyConverter : JsonConverter
{
    public override object? ReadJson(JsonReader reader, Type type, object? existingValue, JsonSerializer serializer)
    {
        try
        {
            bool result = TimeOnly.TryParse(reader?.Value?.ToString(), out TimeOnly time);
            if (result)
            {
                return time;
            }
        }
        catch { }
        return Activator.CreateInstance(type);
    }

    public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
    {
        writer.WriteValue(((TimeOnly?)value)?.ToString("HH:mm", CultureInfo.InvariantCulture));
    }

    public override bool CanConvert(Type type)
    {
        return type == typeof(TimeOnly) || type == typeof(TimeOnly?);
    }
}

.AddNewtonsoftJson(o =>
{
    o.SerializerSettings.Converters.Add(new TimeOnlyConverter());
});

@JCDriessen
Copy link

JCDriessen commented Nov 27, 2023

To add to @michelebenolli workarround:
In my case, it was a TimeOnly property in an object I wanted to deserialize. This is also possible, you just need to add a ContractRevolver to change the behavior of the serializer/deserializer to use the custom converter instead of the normal one:

internal sealed class TimeOnlyContractResolver : DefaultContractResolver
    {
        protected override JsonProperty CreateProperty( MemberInfo member, MemberSerialization memberSerialization )
        {
            var property = base.CreateProperty( member, memberSerialization );

            if( property.PropertyType == typeof( TimeOnly ) )
            {
                property.Converter = new TimeOnlyConverter();
            }

            return property;
        }
    }

Then use it like so:

YourObject Result = JsonConvert.DeserializeObject<YourObject>(yourJsonString, new JsonSerializerSettings {
    ContractResolver = new TimeOnlyContractResolver() 
});

It is a bit of a workaround so I hope that this change will be merged after all this time. However, it does make you learn about how serialization/deserialization works :).

Some sites I used for this information:
https://stackoverflow.com/questions/45643903/anyway-to-get-jsonconvert-serializeobject-to-ignore-the-jsonconverter-attribute
#2056

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants