Search code examples
c#.netsystem.text.jsonnodatime

How to deserialize java duration in c#?


Assuming that I got a duration from Java: "PT-328H-46M-43.2082074S". How to deserialize it to NodaTime Duration in system.text.json?


Solution

  • That's the format that Noda Time usually uses for periods rather than durations. Unfortunately the presence of multiple signs within the value means you can't parse it using DurationPattern - but PeriodPattern.NormalizingIso appears to work okay:

    
    using NodaTime.Text;
    
    var pattern = PeriodPattern.NormalizingIso;
    var result = pattern.Parse("PT-328H-46M-43.2082074S");
    var period = result.Value;
    var duration = period.ToDuration();
    
    Console.WriteLine(duration);
    

    To use that within System.Text.Json, you'd need to specify the right period pattern... and then potentially sort of "trampoline" from the period to the duration. Here's a complete example:

    Program.cs:

    using NodaTime;
    using NodaTime.Serialization.SystemTextJson;
    using NodaTime.Text;
    using System.Text.Json;
    
    string json = """
    {
      "name": "Jon",
      "duration": "PT-328H-46M-43.2082074S"
    }
    """;
    
    var settings = new NodaJsonSettings
    {
        PeriodConverter = new NodaPatternConverter<Period>(PeriodPattern.NormalizingIso)
    };
    var options = new JsonSerializerOptions().ConfigureForNodaTime(settings);
    
    var model = JsonSerializer.Deserialize<Model>(json, options);
    Console.WriteLine(model.Duration);
    

    Model.cs:

    using NodaTime;
    using System.Text.Json.Serialization;
    
    public class Model
    {
        [JsonPropertyName("name")]
        public string Name { get; set; }
    
        [Obsolete]
        [JsonPropertyName("duration")]
        public Period Period
        {
            // TODO: A getter, if you want to be able to serialize back.
            // That's a little more work as there isn't a Duration.ToPeriod conversion.
            set => Duration = value.ToDuration();
        }
    
        [JsonIgnore]
        public Duration Duration { get; set; }
    }