@@ -435,19 +435,27 @@ String Time::toISO8601 (bool includeDividerCharacters) const
435435 + getUTCOffsetString (includeDividerCharacters);
436436}
437437
438- static int parseFixedSizeIntAndSkip (String::CharPointerType& t, int numChars, char charToSkip) noexcept
438+ static int parseVariableSizeIntAndSkip (String::CharPointerType& t,
439+ int minNumChars,
440+ int targetNumChars,
441+ char charToSkip) noexcept
439442{
440443 int n = 0 ;
441444
442- for (int i = numChars; --i >= 0 ; )
445+ for (int i = 0 ; i < targetNumChars; ++i )
443446 {
444- auto digit = (int ) (*t - ' 0' );
447+ n *= 10 ;
448+ const auto digit = (int ) (*t - ' 0' );
445449
446- if (! isPositiveAndBelow (digit, 10 ))
450+ if (isPositiveAndBelow (digit, 10 ))
451+ {
452+ n += digit;
453+ ++t;
454+ }
455+ else if (i < minNumChars)
456+ {
447457 return -1 ;
448-
449- ++t;
450- n = n * 10 + digit;
458+ }
451459 }
452460
453461 if (charToSkip != 0 && *t == (juce_wchar) charToSkip)
@@ -456,6 +464,11 @@ static int parseFixedSizeIntAndSkip (String::CharPointerType& t, int numChars, c
456464 return n;
457465}
458466
467+ static int parseFixedSizeIntAndSkip (String::CharPointerType& t, int numChars, char charToSkip) noexcept
468+ {
469+ return parseVariableSizeIntAndSkip (t, numChars, numChars, charToSkip);
470+ }
471+
459472Time Time::fromISO8601 (StringRef iso)
460473{
461474 auto t = iso.text ;
@@ -515,13 +528,16 @@ Time Time::fromISO8601 (StringRef iso)
515528 if (*t == ' .' || *t == ' ,' )
516529 {
517530 ++t;
518- milliseconds = parseFixedSizeIntAndSkip (t, 3 , 0 );
531+ milliseconds = parseVariableSizeIntAndSkip (t, 1 , 3 , 0 );
519532
520533 if (milliseconds < 0 )
521534 {
522535 jassertfalse;
523536 return {};
524537 }
538+
539+ // skip to the next non-digit character
540+ while (t.isDigit ()) { ++t; }
525541 }
526542
527543 milliseconds += 1000 * seconds;
@@ -701,6 +717,46 @@ class TimeTests final : public UnitTest
701717 expect (Time::fromISO8601 (" 20160216T150357.999-0230" ) == Time (2016 , 1 , 16 , 17 , 33 , 57 , 999 , false ));
702718 expect (Time::fromISO8601 (" 20160216T150357,999-0230" ) == Time (2016 , 1 , 16 , 17 , 33 , 57 , 999 , false ));
703719
720+ expect (Time::fromISO8601 (" 2016-02-16T15:03:57.9+00:00" ) == Time (2016 , 1 , 16 , 15 , 3 , 57 , 900 , false ));
721+ expect (Time::fromISO8601 (" 20160216T150357.9+0000" ) == Time (2016 , 1 , 16 , 15 , 3 , 57 , 900 , false ));
722+ expect (Time::fromISO8601 (" 2016-02-16T15:03:57.9Z" ) == Time (2016 , 1 , 16 , 15 , 3 , 57 , 900 , false ));
723+ expect (Time::fromISO8601 (" 2016-02-16T15:03:57,9Z" ) == Time (2016 , 1 , 16 , 15 , 3 , 57 , 900 , false ));
724+ expect (Time::fromISO8601 (" 20160216T150357.9Z" ) == Time (2016 , 1 , 16 , 15 , 3 , 57 , 900 , false ));
725+ expect (Time::fromISO8601 (" 20160216T150357,9Z" ) == Time (2016 , 1 , 16 , 15 , 3 , 57 , 900 , false ));
726+
727+ expect (Time::fromISO8601 (" 2016-02-16T15:03:57.9-02:30" ) == Time (2016 , 1 , 16 , 17 , 33 , 57 , 900 , false ));
728+ expect (Time::fromISO8601 (" 2016-02-16T15:03:57,9-02:30" ) == Time (2016 , 1 , 16 , 17 , 33 , 57 , 900 , false ));
729+ expect (Time::fromISO8601 (" 20160216T150357.9-0230" ) == Time (2016 , 1 , 16 , 17 , 33 , 57 , 900 , false ));
730+ expect (Time::fromISO8601 (" 20160216T150357,9-0230" ) == Time (2016 , 1 , 16 , 17 , 33 , 57 , 900 , false ));
731+
732+ expect (Time::fromISO8601 (" 2016-02-16T15:03:57.99+00:00" ) == Time (2016 , 1 , 16 , 15 , 3 , 57 , 990 , false ));
733+ expect (Time::fromISO8601 (" 20160216T150357.99+0000" ) == Time (2016 , 1 , 16 , 15 , 3 , 57 , 990 , false ));
734+ expect (Time::fromISO8601 (" 2016-02-16T15:03:57.99Z" ) == Time (2016 , 1 , 16 , 15 , 3 , 57 , 990 , false ));
735+ expect (Time::fromISO8601 (" 2016-02-16T15:03:57,99Z" ) == Time (2016 , 1 , 16 , 15 , 3 , 57 , 990 , false ));
736+ expect (Time::fromISO8601 (" 20160216T150357.99Z" ) == Time (2016 , 1 , 16 , 15 , 3 , 57 , 990 , false ));
737+ expect (Time::fromISO8601 (" 20160216T150357,99Z" ) == Time (2016 , 1 , 16 , 15 , 3 , 57 , 990 , false ));
738+
739+ expect (Time::fromISO8601 (" 2016-02-16T15:03:57.99-02:30" ) == Time (2016 , 1 , 16 , 17 , 33 , 57 , 990 , false ));
740+ expect (Time::fromISO8601 (" 2016-02-16T15:03:57,99-02:30" ) == Time (2016 , 1 , 16 , 17 , 33 , 57 , 990 , false ));
741+ expect (Time::fromISO8601 (" 20160216T150357.99-0230" ) == Time (2016 , 1 , 16 , 17 , 33 , 57 , 990 , false ));
742+ expect (Time::fromISO8601 (" 20160216T150357,99-0230" ) == Time (2016 , 1 , 16 , 17 , 33 , 57 , 990 , false ));
743+
744+ // The 8601 standard appears to support any number of fractional digits.
745+ // The fractional part should either be rounded or truncated.
746+ // The Time class stores time with millisecond precision.
747+ // Most implementations appear to truncate so that's what we test for too.
748+ expect (Time::fromISO8601 (" 2016-02-16T15:03:57.9999+00:00" ) == Time (2016 , 1 , 16 , 15 , 3 , 57 , 999 , false ));
749+ expect (Time::fromISO8601 (" 20160216T150357.999999999+0000" ) == Time (2016 , 1 , 16 , 15 , 3 , 57 , 999 , false ));
750+ expect (Time::fromISO8601 (" 2016-02-16T15:03:57.999999999Z" ) == Time (2016 , 1 , 16 , 15 , 3 , 57 , 999 , false ));
751+ expect (Time::fromISO8601 (" 2016-02-16T15:03:57,999999999Z" ) == Time (2016 , 1 , 16 , 15 , 3 , 57 , 999 , false ));
752+ expect (Time::fromISO8601 (" 20160216T150357.9999999999999Z" ) == Time (2016 , 1 , 16 , 15 , 3 , 57 , 999 , false ));
753+ expect (Time::fromISO8601 (" 20160216T150357,9999999999999Z" ) == Time (2016 , 1 , 16 , 15 , 3 , 57 , 999 , false ));
754+
755+ expect (Time::fromISO8601 (" 2016-02-16T15:03:57.9999-02:30" ) == Time (2016 , 1 , 16 , 17 , 33 , 57 , 999 , false ));
756+ expect (Time::fromISO8601 (" 2016-02-16T15:03:57,9999-02:30" ) == Time (2016 , 1 , 16 , 17 , 33 , 57 , 999 , false ));
757+ expect (Time::fromISO8601 (" 20160216T150357.999999999-0230" ) == Time (2016 , 1 , 16 , 17 , 33 , 57 , 999 , false ));
758+ expect (Time::fromISO8601 (" 20160216T150357,999999999-0230" ) == Time (2016 , 1 , 16 , 17 , 33 , 57 , 999 , false ));
759+
704760 expect (Time (1970 , 0 , 1 , 0 , 0 , 0 , 0 , false ) == Time (0 ));
705761 expect (Time (2106 , 1 , 7 , 6 , 28 , 15 , 0 , false ) == Time (4294967295000 ));
706762 expect (Time (2007 , 10 , 7 , 1 , 7 , 20 , 0 , false ) == Time (1194397640000 ));
0 commit comments