0

Is it possible to convert a string to a TimeSpan object using a custom JsonConverter, but have it only convert when the string is in the format "hh:mm:ss"?

I've looked at building a custom JsonConverter but the CanConvert() method only accepts a Type object, so there's no way to return false if the string is not in the "hh:mm:ss" format.

David Klempfner
  • 8,700
  • 20
  • 73
  • 153

1 Answers1

0

You're correct that CanConvert only deals with Types and so you cannot make the converter conditional on specific JSON values. However, you said that your desired behavior is that the conversion from string to TimeSpan is not performed if the format does not exactly match hh:mm:ss, which I take to mean that you would expect the TimeSpan in your deserialized object to have a default value of zero, correct? In that case, you could just make the ReadJson method in the converter do the same thing, i.e. return a default TimeSpan if the format does not exactly match:

public class TimeSpanConverter : JsonConverter<TimeSpan>
{
    public string TimeSpanFormat { get; set; } = @"hh\:mm\:ss";
    public TimeSpan DefaultTimeSpan { get; set; } = TimeSpan.Zero;

    public override TimeSpan Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        string timeString = reader.GetString();
        if (TimeSpan.TryParseExact(timeString, TimeSpanFormat, CultureInfo.InvariantCulture, out TimeSpan timeSpan))
        {
            return timeSpan;
        }
        return DefaultTimeSpan;
    }

    public override void Write(Utf8JsonWriter writer, TimeSpan value, JsonSerializerOptions options)
    {
        writer.WriteStringValue(value.ToString(TimeSpanFormat));
    }
}

Here's a short program to demonstrate usage:

public static void Main(string[] args)
{
    string json = @"
    {
      ""TimeSpan1"": ""15:46:03"",
      ""TimeSpan2"": ""3:04""
    }";

    var options = new JsonSerializerOptions();
    options.Converters.Add(new TimeSpanConverter());
    var foo = JsonSerializer.Deserialize<Foo>(json, options);
    Console.WriteLine(foo.TimeSpan1.ToString(@"hh\:mm\:ss"));
    Console.WriteLine(foo.TimeSpan2.ToString(@"hh\:mm\:ss"));
}

public class Foo
{
    public TimeSpan TimeSpan1 { get; set; }
    public TimeSpan TimeSpan2 { get; set; }
}

Output:

15:46:03
00:00:00
Brian Rogers
  • 125,747
  • 31
  • 299
  • 300
  • But I only want the conversion to happen if the string is in the required format. If it's not, then the conversion should not happen at all ie. no default value. A string not in the required format should just stay a string. – David Klempfner Apr 10 '20 at 04:37
  • How would you represent that property in your class then? `TimeSpan` and `string` are not compatible. Would you declare the property as `object`? – Brian Rogers Apr 10 '20 at 04:44
  • yeah it would be object. – David Klempfner Apr 10 '20 at 07:39