11

Is it possible to specify custom format for TimeSpan serialization? Using Newtonsoft.Json.

I would like to have serialized string in format HH:mm, so for example:

TimeSpan.FromHours(5) -> // "+05:00"

TimeSpan.FromHours(-5) -> // "-05:00"

Thanks!

Mikhail
  • 978
  • 2
  • 13
  • 28

3 Answers3

21

Here's a TimeSpan converter you can add to your project:

using System;
using Newtonsoft.Json;

namespace JsonTools
{
    /// <summary>
    /// TimeSpans are not serialized consistently depending on what properties are present. So this 
    /// serializer will ensure the format is maintained no matter what.
    /// </summary>
    public class TimespanConverter : JsonConverter<TimeSpan>
    {
        /// <summary>
        /// Format: Days.Hours:Minutes:Seconds:Milliseconds
        /// </summary>
        public const string TimeSpanFormatString = @"d\.hh\:mm\:ss\:FFF";

        public override void WriteJson(JsonWriter writer, TimeSpan value, JsonSerializer serializer)
        {
            var timespanFormatted = $"{value.ToString(TimeSpanFormatString)}";
            writer.WriteValue(timespanFormatted);
        }

        public override TimeSpan ReadJson(JsonReader reader, Type objectType, TimeSpan existingValue, bool hasExistingValue, JsonSerializer serializer)
        {
            TimeSpan parsedTimeSpan;
            TimeSpan.TryParseExact((string)reader.Value, TimeSpanFormatString, null, out parsedTimeSpan);
            return parsedTimeSpan;
        }
    }
}

It can be used like this:

public class Schedule
{
    [JsonConverter(typeof(TimespanConverter))]
    [JsonProperty(TypeNameHandling = TypeNameHandling.All)]
    public TimeSpan Delay { get; set; }
}

Notes:

  1. Reference for TimeSpan serialization formats

  2. I found that when generating a schema using Newtonsoft I had to include the TypeNameHandling attribute or the TimeSpan type name was not being serialized properly in the generated schema. That isn't necessary for the purpose here, but I included it anyway.

Timothy Jannace
  • 1,401
  • 12
  • 18
6

As you can see in the source code, there is no way of changing the format using predefined setting (like for DateTime).

What you can do is write a new JsonConverter for TimeSpan and handle the formatting as you see fit. Just be sure to use it by including it in JsonSerializerSettings.Converters or by modifying the default settings.

kiziu
  • 1,111
  • 1
  • 11
  • 15
0

You can get a DateTime instance, and then add and subtract time from it like:

System.DateTime timeNow = System.DateTime.Now;
DateTime futureDateTime = timeNow.Add(new TimeSpan(5, 0, 0));
DateTime prevDateTime = timeNow.Add(new TimeSpan(-5, 0, 0));

To specify the times that you need. Then to put them into your string format:

futureDateTime.ToString("hh:mm") // 12 hour clock

To deserialize the string value back into DateTime objects with a certain format, there's an example of specifying a DateTimeFormat and IsoDateTimeConverter in this post: Deserializing dates with dd/mm/yyyy format using Json.Net

Community
  • 1
  • 1
Jeremy
  • 461
  • 4
  • 6
  • 2
    This is incorrect. If you want to hack `DateTime` like this, you would have to use `.Date`, eg. `DateTime.Now.Date` (aka `DateTime.Today`), so the time component is empty and added `TimeSpan` is presented correctly. What is more, this will only work for values less than 24h and only non-negative ones - how do you want to present negative time component in `DateTime`? – kiziu Oct 05 '16 at 14:46