Search code examples
nodatimequantconnect

Noda time representation for close/open that is an entire day (24 hour period)


I am parsing some interestingly formatted data from https://raw.githubusercontent.com/QuantConnect/Lean/master/Data/market-hours/market-hours-database.json

It contains a snippet (removing some days) as below:

"Future-cme-[*]": {
      "dataTimeZone": "UTC",
      "exchangeTimeZone": "America/Chicago",
      "monday": [
        {
          "start": "00:00:00",
          "end": "1.00:00:00",
          "state": "market"
        }
      ],
      "friday": [
        {
          "start": "00:00:00",
          "end": "16:00:00",
          "state": "market"
        }
      ]
}

I am using a JsonConverter<LocalTime> to convert the above, and I can parse the friday properties start and end without any issues into a LocalTime.

However, the dates which this represents as an entire day, i.e. 1.00:00:00 it throws an error on as it is not an ISO format - this opens up questions on my (incorrect!) use of the structures.

Currently I have the format that uses the LocalTime as below:

public class MarketHoursSegment
{
    public LocalTime Start { get; init; }
    public LocalTime End { get; init; }
    public MarketHoursState State { get; init; }
}

And the formatter:

public class LocalTimeConverter : JsonConverter<LocalTime>
{
    public override LocalTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
         return LocalTimePattern
                    .GeneralIso
                    .Parse(reader.GetString())
                    .GetValueOrThrow();
    }

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

Is there a preferred way to deal with a LocalTime that represents a 24 hours span?

  1. Would I detect 1:00:00:00 in the reader.GetString() of the converter, and if so set to 00:00:00 (midnight) and check if Start == End then we know it is an entire 24 hour period?

  2. Or would it be more correct to have the Start as a LocalTime, and a Duration for the hours (i.e. 24 hours) with End => Start + Duration?


Solution

  • Is there a preferred way to deal with a LocalTime that represents a 24 hours span?

    It's worth taking a step back and separating different concepts very carefully and being precise. A LocalTime doesn't represent a 24 hour span - it's just a time of day. Two LocalTime values could effectively represent a 24 hour span without reference to a specific date, yes.

    If you can possibly change your JSON to use 00:00:00, and then treat a "start==end" situation as being the full day, that's what I'd do. That does mean, however, that you can never represent an empty period.

    Now, in terms of whether you should use a start and duration... that really depends on what you're trying to model. Are you trying to model a start time and an end time, or a start time and a duration? So far you've referred to the whole day as "a 24 hour span" but that's not always the case, if you're dealing with time zones that have UTC offset transitions (e.g. due to daylight saving time).

    Transitions already cause potential issues with local intervals like this - if you're working on a date where the local time "falls back" from 2am to 1am, and you've got a local time period of (say) 00:30 to 01:30, then logically that will be "true" for an hour and a half of the day:

    • 00:00-00:30: False
    • 00:30-01:30 (first time): True
    • 01:30-02:00 (first time): False
    • 01:00-01:30 (second time): True
    • 01:30-02:00 (second time): False
    • 02:00-00:00 (next day): False

    We don't really know what you're doing with the periods, but that's the sort of thing you need to be considering... likewise if you represent something as "00:00 for 24 hours" how does that work on a day which is only 23 hours long, or one that is 25 hours long? It will very much depend on exactly what you do with the data.

    I would adopt a process of:

    • Work out detailed requirements, including what you want to happen on days with UTC offset transitions in the specific time zone (and think up tests at this stage)
    • Extract the logical values from those requirements in terms of Noda Time types (with the limitation that no, we unfortunately don't support 24:00:00 as a LocalTime)
    • Represent those types in your JSON as closely as possible
    • Make your code follow your requirements documentation as closely as possible, in terms of how it handles the data