Time parsing seems a bit broken

Given the following code, I’m seeing various discrepancies (using Windows/VS2026 and VS2022):

    auto testTime = [] (const Time& timeToTest)
    {
        const auto millis = timeToTest.toMilliseconds();
        DBG (millis);
        DBG (timeToTest.toISO8601 (true));
        DBG (timeToTest.toString (true, true, true, true));
        DBG (timeToTest.getHours());

        jassert (1455635037100 == millis);
        jassert (2016 == timeToTest.getYear());
        jassert (1 == timeToTest.getMonth());
        jassert (16 == timeToTest.getDayOfMonth());
        jassert (15 == timeToTest.getHours());
        jassert (3 == timeToTest.getMinutes());
        jassert (57 == timeToTest.getSeconds());
        jassert (100 == timeToTest.getMilliseconds());
    };

For this first scenario, the output is as such:

testTime (Time (2016, 1, 16, 15, 3, 57, 100, false));
1455635037100
2016-02-16T10:03:57.100-05:00
16 Feb 2016 10:03:57
10

The problem here is that the hours I’m getting back are wrong: I provided 15 and received 10.

Edit: I’m realising this is likely due to the machine tz, Ottawa/:canada: , being accounted for… It’s a bit awkward because I expected to get back what I put in due to my setting the useLocalTime to false.


For this second scenario - using the same time via the ISO8601 API - this is what I get:

testTime (Time::fromISO8601 ("2016-02-16T15:03:57.1Z"));
0
1969-12-31T19:00:00.000-05:00
31 Dec 1969 19:00:00
19

ISTM that the milliseconds parsing is what’s broken, specifically the fact that 3 digits appear required for millis by the API even though ISO8601 supports varied amounts of digits.

        if (*t == '.' || *t == ',')
        {
            ++t;
            milliseconds = parseFixedSizeIntAndSkip (t, 3, 0);

            if (milliseconds < 0)
                return {};
        }

Both should be the same time. Here’s some supporting external validation:

1 Like

What’s happening is the time you have passed in is treated as UTC, that is it is 15:03 UTC (rather than 15:03 local time which I would be 10:03 UTC in your example), but toString(), the getX() methods, and toISO8601() all print the stored time as a local time, it doesn’t look like we currently have a way to ask for the time back as UTC.

Seems like you’re right the last unit can have a variable number of digits, it just seems like it’s not very common. I don’t think that would be hard to add if you think it would be helpful?

I remember this fell on my foot before when parsing timestamps from a Django server, so I guess it’s not that uncommon. Also I think it would be cool if the parser could deal with all valid ISO8601 strings properly.

I’m echoing @hugoderwolf ‘s experience - it would be helpful.

To further take this by a bit, I think it’d be better to not return a valid Time if the parsing failed; instead, it might be worth considering an std::optional<Time> . Obviously I’m unsure of the effects this may have on users…

Otherwise, some jassert would be helpful (X marks the spot for where it failed).

1 Like

Thanks for reporting we’ve added support for a variable number of fractional digits and we’ve added some asserts in to help debug issues. You can also check if the Time returned is equal to juce::Time{} which is a good indication that something has gone wrong.

1 Like

Roger roger. Thanks!