1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-09 23:34:20 +00:00

Time: Add support for variable number of millisecond digits in ISO8601 format

This commit is contained in:
Anthony Nicholls 2025-10-13 12:19:14 +01:00 committed by Anthony Nicholls
parent ea37e71f87
commit 4212720f7d

View file

@ -435,19 +435,27 @@ String Time::toISO8601 (bool includeDividerCharacters) const
+ getUTCOffsetString (includeDividerCharacters);
}
static int parseFixedSizeIntAndSkip (String::CharPointerType& t, int numChars, char charToSkip) noexcept
static int parseVariableSizeIntAndSkip (String::CharPointerType& t,
int minNumChars,
int targetNumChars,
char charToSkip) noexcept
{
int n = 0;
for (int i = numChars; --i >= 0;)
for (int i = 0; i < targetNumChars; ++i)
{
auto digit = (int) (*t - '0');
n *= 10;
const auto digit = (int) (*t - '0');
if (! isPositiveAndBelow (digit, 10))
if (isPositiveAndBelow (digit, 10))
{
n += digit;
++t;
}
else if (i < minNumChars)
{
return -1;
++t;
n = n * 10 + digit;
}
}
if (charToSkip != 0 && *t == (juce_wchar) charToSkip)
@ -456,6 +464,11 @@ static int parseFixedSizeIntAndSkip (String::CharPointerType& t, int numChars, c
return n;
}
static int parseFixedSizeIntAndSkip (String::CharPointerType& t, int numChars, char charToSkip) noexcept
{
return parseVariableSizeIntAndSkip (t, numChars, numChars, charToSkip);
}
Time Time::fromISO8601 (StringRef iso)
{
auto t = iso.text;
@ -515,13 +528,16 @@ Time Time::fromISO8601 (StringRef iso)
if (*t == '.' || *t == ',')
{
++t;
milliseconds = parseFixedSizeIntAndSkip (t, 3, 0);
milliseconds = parseVariableSizeIntAndSkip (t, 1, 3, 0);
if (milliseconds < 0)
{
jassertfalse;
return {};
}
// skip to the next non-digit character
while (t.isDigit()) { ++t; }
}
milliseconds += 1000 * seconds;
@ -701,6 +717,46 @@ public:
expect (Time::fromISO8601 ("20160216T150357.999-0230") == Time (2016, 1, 16, 17, 33, 57, 999, false));
expect (Time::fromISO8601 ("20160216T150357,999-0230") == Time (2016, 1, 16, 17, 33, 57, 999, false));
expect (Time::fromISO8601 ("2016-02-16T15:03:57.9+00:00") == Time (2016, 1, 16, 15, 3, 57, 900, false));
expect (Time::fromISO8601 ("20160216T150357.9+0000") == Time (2016, 1, 16, 15, 3, 57, 900, false));
expect (Time::fromISO8601 ("2016-02-16T15:03:57.9Z") == Time (2016, 1, 16, 15, 3, 57, 900, false));
expect (Time::fromISO8601 ("2016-02-16T15:03:57,9Z") == Time (2016, 1, 16, 15, 3, 57, 900, false));
expect (Time::fromISO8601 ("20160216T150357.9Z") == Time (2016, 1, 16, 15, 3, 57, 900, false));
expect (Time::fromISO8601 ("20160216T150357,9Z") == Time (2016, 1, 16, 15, 3, 57, 900, false));
expect (Time::fromISO8601 ("2016-02-16T15:03:57.9-02:30") == Time (2016, 1, 16, 17, 33, 57, 900, false));
expect (Time::fromISO8601 ("2016-02-16T15:03:57,9-02:30") == Time (2016, 1, 16, 17, 33, 57, 900, false));
expect (Time::fromISO8601 ("20160216T150357.9-0230") == Time (2016, 1, 16, 17, 33, 57, 900, false));
expect (Time::fromISO8601 ("20160216T150357,9-0230") == Time (2016, 1, 16, 17, 33, 57, 900, false));
expect (Time::fromISO8601 ("2016-02-16T15:03:57.99+00:00") == Time (2016, 1, 16, 15, 3, 57, 990, false));
expect (Time::fromISO8601 ("20160216T150357.99+0000") == Time (2016, 1, 16, 15, 3, 57, 990, false));
expect (Time::fromISO8601 ("2016-02-16T15:03:57.99Z") == Time (2016, 1, 16, 15, 3, 57, 990, false));
expect (Time::fromISO8601 ("2016-02-16T15:03:57,99Z") == Time (2016, 1, 16, 15, 3, 57, 990, false));
expect (Time::fromISO8601 ("20160216T150357.99Z") == Time (2016, 1, 16, 15, 3, 57, 990, false));
expect (Time::fromISO8601 ("20160216T150357,99Z") == Time (2016, 1, 16, 15, 3, 57, 990, false));
expect (Time::fromISO8601 ("2016-02-16T15:03:57.99-02:30") == Time (2016, 1, 16, 17, 33, 57, 990, false));
expect (Time::fromISO8601 ("2016-02-16T15:03:57,99-02:30") == Time (2016, 1, 16, 17, 33, 57, 990, false));
expect (Time::fromISO8601 ("20160216T150357.99-0230") == Time (2016, 1, 16, 17, 33, 57, 990, false));
expect (Time::fromISO8601 ("20160216T150357,99-0230") == Time (2016, 1, 16, 17, 33, 57, 990, false));
// The 8601 standard appears to support any number of fractional digits.
// The fractional part should either be rounded or truncated.
// The Time class stores time with millisecond precision.
// Most implementations appear to truncate so that's what we test for too.
expect (Time::fromISO8601 ("2016-02-16T15:03:57.9999+00:00") == Time (2016, 1, 16, 15, 3, 57, 999, false));
expect (Time::fromISO8601 ("20160216T150357.999999999+0000") == Time (2016, 1, 16, 15, 3, 57, 999, false));
expect (Time::fromISO8601 ("2016-02-16T15:03:57.999999999Z") == Time (2016, 1, 16, 15, 3, 57, 999, false));
expect (Time::fromISO8601 ("2016-02-16T15:03:57,999999999Z") == Time (2016, 1, 16, 15, 3, 57, 999, false));
expect (Time::fromISO8601 ("20160216T150357.9999999999999Z") == Time (2016, 1, 16, 15, 3, 57, 999, false));
expect (Time::fromISO8601 ("20160216T150357,9999999999999Z") == Time (2016, 1, 16, 15, 3, 57, 999, false));
expect (Time::fromISO8601 ("2016-02-16T15:03:57.9999-02:30") == Time (2016, 1, 16, 17, 33, 57, 999, false));
expect (Time::fromISO8601 ("2016-02-16T15:03:57,9999-02:30") == Time (2016, 1, 16, 17, 33, 57, 999, false));
expect (Time::fromISO8601 ("20160216T150357.999999999-0230") == Time (2016, 1, 16, 17, 33, 57, 999, false));
expect (Time::fromISO8601 ("20160216T150357,999999999-0230") == Time (2016, 1, 16, 17, 33, 57, 999, false));
expect (Time (1970, 0, 1, 0, 0, 0, 0, false) == Time (0));
expect (Time (2106, 1, 7, 6, 28, 15, 0, false) == Time (4294967295000));
expect (Time (2007, 10, 7, 1, 7, 20, 0, false) == Time (1194397640000));