Skip to content

Commit

Permalink
Issue 16053: Fix it so that SysTime's from*String supports more than …
Browse files Browse the repository at this point in the history
…7 digits.

ISO 8601 says that it's up to the application to decide how many digits
to put in the fractional seconds if they're present. SysTime.to*String
puts up to 7 (stripping trailing zeroes), because that's
hecto-nanosecond precision, and SysTime holds the time in
hecto-nanoseconds. Currently, from*String only accepts up to 7 digits in
the fractional seconds, which _does_ follow the spec in that (per the
spec) the number of digits is up to the applications. However, while we
never emit more than 7 digits, other applications do, so only accepting
7 digits makes us incompatible with them, whereas accepting them would
make us more compatible with other programs, and it would actually be
more efficient, since we'd have fewer checks in the code.

So, these changes make is so that SysTime.from*String accepts more than 7
digits in the fractional seconds, but the additional digits are
truncated (since SysTime doesn't support more than 7 digits of
precision).
  • Loading branch information
jmdavis committed May 13, 2017
1 parent d052675 commit 21c09f1
Showing 1 changed file with 46 additions and 10 deletions.
56 changes: 46 additions & 10 deletions std/datetime/systime.d
Expand Up @@ -8201,7 +8201,11 @@ public:
The exact format is exactly as described in $(D toISOString) except that
trailing zeroes are permitted - including having fractional seconds with
all zeroes. However, a decimal point with nothing following it is
invalid.
invalid. Also, while $(LREF toISOString) will never generate a string
with more than 7 digits in the fractional seconds (because that's the
limit with hecto-nanosecond precision), it will allow more than 7 digits
in order to read strings from other sources that have higher precision
(however, any digits beyond 7 will be truncated).
If there is no time zone in the string, then
$(REF LocalTime,std,datetime,timezone) is used. If the time zone is "Z",
Expand Down Expand Up @@ -8315,6 +8319,9 @@ public:
assert(SysTime.fromISOString("00000105T230959.00002") ==
SysTime(DateTime(0, 1, 5, 23, 9, 59), usecs(20)));

assert(SysTime.fromISOString("20130207T043937.000050392") ==
SysTime(DateTime(2013, 2, 7, 4, 39, 37), hnsecs(503)));

assert(SysTime.fromISOString("-00040105T000002") ==
SysTime(DateTime(-4, 1, 5, 0, 0, 2)));

Expand All @@ -8337,7 +8344,7 @@ public:
{
foreach (str; ["", "20100704000000", "20100704 000000", "20100704t000000",
"20100704T000000.", "20100704T000000.A", "20100704T000000.Z",
"20100704T000000.00000000", "20100704T000000.00000000",
"20100704T000000.0000000A", "20100704T000000.00000000A",
"20100704T000000+", "20100704T000000-", "20100704T000000:",
"20100704T000000-:", "20100704T000000+:", "20100704T000000-1:",
"20100704T000000+1:", "20100704T000000+1:0",
Expand Down Expand Up @@ -8386,6 +8393,9 @@ public:
test("19070707T121212.0", SysTime(DateTime(1907, 07, 07, 12, 12, 12)));
test("19070707T121212.0000000", SysTime(DateTime(1907, 07, 07, 12, 12, 12)));
test("19070707T121212.0000001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), hnsecs(1)));
test("20100704T000000.00000000", SysTime(Date(2010, 07, 04)));
test("20100704T000000.00000009", SysTime(Date(2010, 07, 04)));
test("20100704T000000.00000019", SysTime(DateTime(2010, 07, 04), hnsecs(1)));
test("19070707T121212.000001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), usecs(1)));
test("19070707T121212.0000010", SysTime(DateTime(1907, 07, 07, 12, 12, 12), usecs(1)));
test("19070707T121212.001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), msecs(1)));
Expand Down Expand Up @@ -8453,7 +8463,11 @@ public:
The exact format is exactly as described in $(D toISOExtString)
except that trailing zeroes are permitted - including having fractional
seconds with all zeroes. However, a decimal point with nothing following
it is invalid.
it is invalid. Also, while $(LREF toISOExtString) will never generate a
string with more than 7 digits in the fractional seconds (because that's
the limit with hecto-nanosecond precision), it will allow more than 7
digits in order to read strings from other sources that have higher
precision (however, any digits beyond 7 will be truncated).
If there is no time zone in the string, then
$(REF LocalTime,std,datetime,timezone) is used. If the time zone is "Z",
Expand Down Expand Up @@ -8554,6 +8568,9 @@ public:
assert(SysTime.fromISOExtString("0000-01-05T23:09:59.00002") ==
SysTime(DateTime(0, 1, 5, 23, 9, 59), usecs(20)));

assert(SysTime.fromISOExtString("2013-02-07T04:39:37.000050392") ==
SysTime(DateTime(2013, 2, 7, 4, 39, 37), hnsecs(503)));

assert(SysTime.fromISOExtString("-0004-01-05T00:00:02") ==
SysTime(DateTime(-4, 1, 5, 0, 0, 2)));

Expand All @@ -8578,7 +8595,7 @@ public:
"2010-07:0400:00:00", "2010-07-04 00:00:00",
"2010-07-04 00:00:00", "2010-07-04t00:00:00",
"2010-07-04T00:00:00.", "2010-07-04T00:00:00.A", "2010-07-04T00:00:00.Z",
"2010-07-04T00:00:00.00000000", "2010-07-04T00:00:00.00000000",
"2010-07-04T00:00:00.0000000A", "2010-07-04T00:00:00.00000000A",
"2010-07-04T00:00:00+", "2010-07-04T00:00:00-",
"2010-07-04T00:00:00:", "2010-07-04T00:00:00-:", "2010-07-04T00:00:00+:",
"2010-07-04T00:00:00-1:", "2010-07-04T00:00:00+1:", "2010-07-04T00:00:00+1:0",
Expand Down Expand Up @@ -8624,6 +8641,9 @@ public:
test("1907-07-07T12:12:12.0", SysTime(DateTime(1907, 07, 07, 12, 12, 12)));
test("1907-07-07T12:12:12.0000000", SysTime(DateTime(1907, 07, 07, 12, 12, 12)));
test("1907-07-07T12:12:12.0000001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), hnsecs(1)));
test("2010-07-04T00:00:00.00000000", SysTime(Date(2010, 07, 04)));
test("2010-07-04T00:00:00.00000009", SysTime(Date(2010, 07, 04)));
test("2010-07-04T00:00:00.00000019", SysTime(DateTime(2010, 07, 04), hnsecs(1)));
test("1907-07-07T12:12:12.000001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), usecs(1)));
test("1907-07-07T12:12:12.0000010", SysTime(DateTime(1907, 07, 07, 12, 12, 12), usecs(1)));
test("1907-07-07T12:12:12.001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), msecs(1)));
Expand Down Expand Up @@ -8669,7 +8689,11 @@ public:
The exact format is exactly as described in $(D toSimpleString) except
that trailing zeroes are permitted - including having fractional seconds
with all zeroes. However, a decimal point with nothing following it is
invalid.
invalid. Also, while $(LREF toSimpleString) will never generate a
string with more than 7 digits in the fractional seconds (because that's
the limit with hecto-nanosecond precision), it will allow more than 7
digits in order to read strings from other sources that have higher
precision (however, any digits beyond 7 will be truncated).
If there is no time zone in the string, then
$(REF LocalTime,std,datetime,timezone) is used. If the time zone is "Z",
Expand Down Expand Up @@ -8770,6 +8794,9 @@ public:
assert(SysTime.fromSimpleString("0000-Jan-05 23:09:59.00002") ==
SysTime(DateTime(0, 1, 5, 23, 9, 59), usecs(20)));

assert(SysTime.fromSimpleString("2013-Feb-07 04:39:37.000050392") ==
SysTime(DateTime(2013, 2, 7, 4, 39, 37), hnsecs(503)));

assert(SysTime.fromSimpleString("-0004-Jan-05 00:00:02") ==
SysTime(DateTime(-4, 1, 5, 0, 0, 2)));

Expand All @@ -8796,7 +8823,7 @@ public:
"2010-07-04T00:00:00.", "2010-07-04T00:00:00.0",
"2010-Jul-0400:00:00", "2010-Jul-04t00:00:00", "2010-Jul-04T00:00:00",
"2010-Jul-04 00:00:00.", "2010-Jul-04 00:00:00.A", "2010-Jul-04 00:00:00.Z",
"2010-Jul-04 00:00:00.00000000", "2010-Jul-04 00:00:00.00000000",
"2010-Jul-04 00:00:00.0000000A", "2010-Jul-04 00:00:00.00000000A",
"2010-Jul-04 00:00:00+", "2010-Jul-04 00:00:00-",
"2010-Jul-04 00:00:00:", "2010-Jul-04 00:00:00-:",
"2010-Jul-04 00:00:00+:", "2010-Jul-04 00:00:00-1:",
Expand Down Expand Up @@ -8842,6 +8869,9 @@ public:

test("1907-Jul-07 12:12:12.0", SysTime(DateTime(1907, 07, 07, 12, 12, 12)));
test("1907-Jul-07 12:12:12.0000000", SysTime(DateTime(1907, 07, 07, 12, 12, 12)));
test("2010-Jul-04 00:00:00.00000000", SysTime(Date(2010, 07, 04)));
test("2010-Jul-04 00:00:00.00000009", SysTime(Date(2010, 07, 04)));
test("2010-Jul-04 00:00:00.00000019", SysTime(DateTime(2010, 07, 04), hnsecs(1)));
test("1907-Jul-07 12:12:12.0000001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), hnsecs(1)));
test("1907-Jul-07 12:12:12.000001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), usecs(1)));
test("1907-Jul-07 12:12:12.0000010", SysTime(DateTime(1907, 07, 07, 12, 12, 12), usecs(1)));
Expand Down Expand Up @@ -10347,8 +10377,7 @@ if (isSomeString!S)
enforce(str[0] == '.', new DateTimeException("Invalid ISO String"));
str.popFront();

enforce(!str.empty && str.length <= 7, new DateTimeException("Invalid ISO String"));
enforce(all!isDigit(str), new DateTimeException("Invalid ISO String"));
enforce(!str.empty && all!isDigit(str), new DateTimeException("Invalid ISO String"));

dchar[7] fullISOString = void;
foreach (i, ref dchar c; fullISOString)
Expand All @@ -10373,11 +10402,13 @@ if (isSomeString!S)
assertThrown!DateTimeException(testFSInvalid("0."));
assertThrown!DateTimeException(testFSInvalid("0"));
assertThrown!DateTimeException(testFSInvalid("0000000"));
assertThrown!DateTimeException(testFSInvalid(".00000000"));
assertThrown!DateTimeException(testFSInvalid(".00000001"));
assertThrown!DateTimeException(testFSInvalid("T"));
assertThrown!DateTimeException(testFSInvalid("T."));
assertThrown!DateTimeException(testFSInvalid(".T"));
assertThrown!DateTimeException(testFSInvalid(".00000Q0"));
assertThrown!DateTimeException(testFSInvalid(".000000Q"));
assertThrown!DateTimeException(testFSInvalid(".0000000Q"));
assertThrown!DateTimeException(testFSInvalid(".0000000000Q"));

assert(fracSecsFromISOString("") == Duration.zero);
assert(fracSecsFromISOString(".0000001") == hnsecs(1));
Expand Down Expand Up @@ -10412,6 +10443,11 @@ if (isSomeString!S)
assert(fracSecsFromISOString(".00999") == hnsecs(99_900));
assert(fracSecsFromISOString(".0999000") == hnsecs(999_000));
assert(fracSecsFromISOString(".0999") == hnsecs(999_000));
assert(fracSecsFromISOString(".00000000") == Duration.zero);
assert(fracSecsFromISOString(".00000001") == Duration.zero);
assert(fracSecsFromISOString(".00000009") == Duration.zero);
assert(fracSecsFromISOString(".1234567890") == hnsecs(1_234_567));
assert(fracSecsFromISOString(".12345678901234567890") == hnsecs(1_234_567));
}


Expand Down

0 comments on commit 21c09f1

Please sign in to comment.