Skip to content

Commit 3719053

Browse files
committed
Fix Iso8601 format with varying fractional values
Relates: #4910 The PR introduced a fix to support basic offset formats when deserializing Iso8601, but the fix would only work with 7 fractional second values. This commit fixes the implementation to support any number of fractional second values. (cherry picked from commit f176653)
1 parent db95308 commit 3719053

File tree

2 files changed

+129
-22
lines changed

2 files changed

+129
-22
lines changed

src/Elasticsearch.Net/Utf8Json/Formatters/DateTimeFormatter.cs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -359,16 +359,15 @@ public DateTime Deserialize(ref JsonReader reader, IJsonFormatterResolver format
359359
}
360360
else if (i < to && array[i] == '-' || array[i] == '+')
361361
{
362-
if (len != 30 && len != 32 && len != 33) goto ERROR;
363-
362+
var offLen = to - i;
363+
if (offLen != 3 && offLen != 5 && offLen != 6) goto ERROR;
364364
kind = DateTimeKind.Local;
365365
var minus = array[i++] == '-';
366-
367366
var h = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0');
368367
var m = 0;
369368
if (i < to)
370369
{
371-
if (len == 33)
370+
if (offLen == 6)
372371
{
373372
if (array[i] != ':') goto ERROR;
374373
i++;
@@ -713,15 +712,14 @@ public DateTimeOffset Deserialize(ref JsonReader reader, IJsonFormatterResolver
713712

714713
if (i < to && array[i] == '-' || array[i] == '+')
715714
{
716-
if (len != 30 && len != 32 && len != 33) goto ERROR;
717-
715+
var offLen = to - i;
716+
if (offLen != 3 && offLen != 5 && offLen != 6) goto ERROR;
718717
var minus = array[i++] == '-';
719-
720718
var h = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0');
721719
var m = 0;
722720
if (i < to)
723721
{
724-
if (len == 33)
722+
if (offLen == 6)
725723
{
726724
if (array[i] != ':') goto ERROR;
727725
i++;

tests/Tests.Reproduce/GitHubIssue4876.cs

Lines changed: 123 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,58 +19,167 @@ public class GitHubIssue4876
1919

2020
[U]
2121
public void CanDeserializeExtendedFormatOffsetIso8601DateTime() =>
22-
AssertDateTime("{\"timestamp\":\"2020-07-31T12:29:29.4425068+10:00\"}");
22+
AssertDateTime("2020-07-31T12:29:29.4425068+10:00", 637317593694425068);
2323

2424
[U]
2525
public void CanDeserializeBasicFormatOffsetWithMinutesIso8601DateTime() =>
26-
AssertDateTime("{\"timestamp\":\"2020-07-31T12:29:29.4425068+1000\"}");
26+
AssertDateTime("2020-07-31T12:29:29.4425068+1000", 637317593694425068);
2727

2828
[U]
2929
public void CanDeserializeBasicFormatOffsetIso8601DateTime() =>
30-
AssertDateTime("{\"timestamp\":\"2020-07-31T12:29:29.4425068+10\"}");
30+
AssertDateTime("2020-07-31T12:29:29.4425068+10", 637317593694425068);
3131

3232
[U]
3333
public void ThrowExceptionWhenInvalidBasicFormatOffset()
3434
{
35-
Action action = () => AssertDateTime("{\"timestamp\":\"2020-07-31T12:29:29.4425068+100\"}");
35+
Action action = () => AssertDateTime("2020-07-31T12:29:29.4425068+100", 637317593694425068);
3636
action.Should().Throw<InvalidOperationException>();
3737
}
3838

3939
[U]
4040
public void ThrowExceptionWhenInvalidBasicFormatOffset2()
4141
{
42-
Action action = () => AssertDateTime("{\"timestamp\":\"2020-07-31T12:29:29.4425068-10000\"}");
42+
Action action = () => AssertDateTime("2020-07-31T12:29:29.4425068-10000", 637317593694425068);
4343
action.Should().Throw<InvalidOperationException>();
4444
}
4545

4646
[U]
4747
public void CanDeserializeExtendedFormatOffsetIso8601DateTimeOffset() =>
48-
AssertDateTimeOffset("{\"timestamp\":\"2020-07-31T12:29:29.4425068+10:00\"}");
48+
AssertDateTimeOffset("2020-07-31T12:29:29.4425068+10:00", 637317593694425068);
4949

5050
[U]
5151
public void CanDeserializeBasicFormatOffsetWithMinutesIso8601DateTimeOffset() =>
52-
AssertDateTimeOffset("{\"timestamp\":\"2020-07-31T12:29:29.4425068+1000\"}");
52+
AssertDateTimeOffset("2020-07-31T12:29:29.4425068+1000", 637317593694425068);
5353

5454
[U]
5555
public void CanDeserializeBasicFormatOffsetIso8601DateTimeOffset() =>
56-
AssertDateTimeOffset("{\"timestamp\":\"2020-07-31T12:29:29.4425068+10\"}");
56+
AssertDateTimeOffset("2020-07-31T12:29:29.4425068+10", 637317593694425068);
5757

58-
private void AssertDateTime(string json)
58+
[U]
59+
public void CanDeserializeNoFractionalSeconds()
60+
{
61+
var ticks = 637321081960000000;
62+
AssertDateTime("2020-08-04T13:23:16+10:00", ticks);
63+
AssertDateTime("2020-08-04T13:23:16+1000", ticks);
64+
AssertDateTime("2020-08-04T13:23:16+10", ticks);
65+
AssertDateTimeOffset("2020-08-04T13:23:16+10:00", ticks);
66+
AssertDateTimeOffset("2020-08-04T13:23:16+1000", ticks);
67+
AssertDateTimeOffset("2020-08-04T13:23:16+10", ticks);
68+
}
69+
70+
[U]
71+
public void CanDeserializeOneFractionalSecond()
72+
{
73+
var ticks = 637321081967000000;
74+
AssertDateTime("2020-08-04T13:23:16.7+10:00", ticks);
75+
AssertDateTime("2020-08-04T13:23:16.7+1000", ticks);
76+
AssertDateTime("2020-08-04T13:23:16.7+10", ticks);
77+
AssertDateTimeOffset("2020-08-04T13:23:16.7+10:00", ticks);
78+
AssertDateTimeOffset("2020-08-04T13:23:16.7+1000", ticks);
79+
AssertDateTimeOffset("2020-08-04T13:23:16.7+10", ticks);
80+
}
81+
82+
[U]
83+
public void CanDeserializeTwoFractionalSeconds()
84+
{
85+
var ticks = 637321081967200000;
86+
AssertDateTime("2020-08-04T13:23:16.72+10:00", ticks);
87+
AssertDateTime("2020-08-04T13:23:16.72+1000", ticks);
88+
AssertDateTime("2020-08-04T13:23:16.72+10", ticks);
89+
AssertDateTimeOffset("2020-08-04T13:23:16.72+10:00", ticks);
90+
AssertDateTimeOffset("2020-08-04T13:23:16.72+1000", ticks);
91+
AssertDateTimeOffset("2020-08-04T13:23:16.72+10", ticks);
92+
}
93+
94+
[U]
95+
public void CanDeserializeThreeFractionalSeconds()
96+
{
97+
var ticks = 637321081967220000;
98+
AssertDateTime("2020-08-04T13:23:16.722+10:00", ticks);
99+
AssertDateTime("2020-08-04T13:23:16.722+1000", ticks);
100+
AssertDateTime("2020-08-04T13:23:16.722+10", ticks);
101+
AssertDateTimeOffset("2020-08-04T13:23:16.722+10:00", ticks);
102+
AssertDateTimeOffset("2020-08-04T13:23:16.722+1000", ticks);
103+
AssertDateTimeOffset("2020-08-04T13:23:16.722+10", ticks);
104+
}
105+
106+
[U]
107+
public void CanDeserializeFourFractionalSeconds()
108+
{
109+
var ticks = 637321081967220000;
110+
AssertDateTime("2020-08-04T13:23:16.7220+10:00", ticks);
111+
AssertDateTime("2020-08-04T13:23:16.7220+1000", ticks);
112+
AssertDateTime("2020-08-04T13:23:16.7220+10", ticks);
113+
AssertDateTimeOffset("2020-08-04T13:23:16.7220+10:00", ticks);
114+
AssertDateTimeOffset("2020-08-04T13:23:16.7220+1000", ticks);
115+
AssertDateTimeOffset("2020-08-04T13:23:16.7220+10", ticks);
116+
}
117+
118+
[U]
119+
public void CanDeserializeFiveFractionalSeconds()
120+
{
121+
var ticks = 637321081967220100;
122+
AssertDateTime("2020-08-04T13:23:16.72201+10:00", ticks);
123+
AssertDateTime("2020-08-04T13:23:16.72201+1000", ticks);
124+
AssertDateTime("2020-08-04T13:23:16.72201+10", ticks);
125+
AssertDateTimeOffset("2020-08-04T13:23:16.72201+10:00", ticks);
126+
AssertDateTimeOffset("2020-08-04T13:23:16.72201+1000", ticks);
127+
AssertDateTimeOffset("2020-08-04T13:23:16.72201+10", ticks);
128+
}
129+
130+
[U]
131+
public void CanDeserializeSixFractionalSeconds()
132+
{
133+
var ticks = 637321081967220110;
134+
AssertDateTime("2020-08-04T13:23:16.722011+10:00", ticks);
135+
AssertDateTime("2020-08-04T13:23:16.722011+1000", ticks);
136+
AssertDateTime("2020-08-04T13:23:16.722011+10", ticks);
137+
AssertDateTimeOffset("2020-08-04T13:23:16.722011+10:00", ticks);
138+
AssertDateTimeOffset("2020-08-04T13:23:16.722011+1000", ticks);
139+
AssertDateTimeOffset("2020-08-04T13:23:16.722011+10", ticks);
140+
}
141+
142+
[U]
143+
public void CanDeserializeSevenFractionalSeconds()
144+
{
145+
var ticks = 637321081967220111;
146+
AssertDateTime("2020-08-04T13:23:16.7220111+10:00", ticks);
147+
AssertDateTime("2020-08-04T13:23:16.7220111+1000", ticks);
148+
AssertDateTime("2020-08-04T13:23:16.7220111+10", ticks);
149+
AssertDateTimeOffset("2020-08-04T13:23:16.7220111+10:00", ticks);
150+
AssertDateTimeOffset("2020-08-04T13:23:16.7220111+1000", ticks);
151+
AssertDateTimeOffset("2020-08-04T13:23:16.7220111+10", ticks);
152+
}
153+
154+
[U]
155+
public void CanDeserializeMoreThanSevenFractionalSeconds()
156+
{
157+
var ticks = 637321081967220111;
158+
var digits = new Random().Next();
159+
AssertDateTime($"2020-08-04T13:23:16.7220111{digits}+10:00", ticks);
160+
AssertDateTime($"2020-08-04T13:23:16.7220111{digits}+1000", ticks);
161+
AssertDateTime($"2020-08-04T13:23:16.7220111{digits}+10", ticks);
162+
AssertDateTimeOffset($"2020-08-04T13:23:16.7220111{digits}+10:00", ticks);
163+
AssertDateTimeOffset($"2020-08-04T13:23:16.7220111{digits}+1000", ticks);
164+
AssertDateTimeOffset($"2020-08-04T13:23:16.7220111{digits}+10", ticks);
165+
}
166+
167+
private void AssertDateTime(string json, long expectedTicks)
59168
{
60-
var stream = new MemoryStream(Encoding.UTF8.GetBytes(json));
169+
var stream = new MemoryStream(Encoding.UTF8.GetBytes($"{{\"timestamp\":\"{json}\"}}"));
61170
var document = _client.SourceSerializer.Deserialize<Document>(stream);
62171

63172
document.Timestamp.Should().Be(
64-
new DateTime(637317593694425068, DateTimeKind.Utc).ToLocalTime());
173+
new DateTime(expectedTicks, DateTimeKind.Utc).ToLocalTime());
65174
}
66175

67-
private void AssertDateTimeOffset(string json)
176+
private void AssertDateTimeOffset(string json, long expectedTicks)
68177
{
69-
var stream = new MemoryStream(Encoding.UTF8.GetBytes(json));
178+
var stream = new MemoryStream(Encoding.UTF8.GetBytes($"{{\"timestamp\":\"{json}\"}}"));
70179
var document = _client.SourceSerializer.Deserialize<Document2>(stream);
71180

72181
document.Timestamp.Should().Be(
73-
new DateTimeOffset(637317593694425068, TimeSpan.Zero));
182+
new DateTimeOffset(expectedTicks, TimeSpan.Zero));
74183
}
75184

76185
public class Document

0 commit comments

Comments
 (0)