public System.Text.Json.JsonElement.ObjectEnumerator EnumerateObject() { throw null; }
public int GetArrayLength() { throw null; }
public bool GetBoolean() { throw null; }
+ public DateTime GetDateTime() { throw null; }
+ public DateTimeOffset GetDateTimeOffset() { throw null; }
public decimal GetDecimal() { throw null; }
public double GetDouble() { throw null; }
public int GetInt32() { throw null; }
[System.CLSCompliantAttribute(false)]
public ulong GetUInt64() { throw null; }
public override string ToString() { throw null; }
+ public bool TryGetDateTime(out DateTime value) { throw null; }
+ public bool TryGetDateTimeOffset(out DateTimeOffset value) { throw null; }
public bool TryGetDecimal(out decimal value) { throw null; }
public bool TryGetDouble(out double value) { throw null; }
public bool TryGetInt32(out int value) { throw null; }
<Compile Include="System\Text\Json\JsonCommentHandling.cs" />
<Compile Include="System\Text\Json\JsonConstants.cs" />
<Compile Include="System\Text\Json\JsonHelpers.cs" />
+ <Compile Include="System\Text\Json\JsonHelpers.Date.cs" />
<Compile Include="System\Text\Json\JsonTokenType.cs" />
<Compile Include="System\Text\Json\ThrowHelper.cs" />
<Compile Include="System\Text\Json\ThrowHelper.Serialization.cs" />
<Compile Include="System\Text\Json\Reader\ConsumeTokenResult.cs" />
<Compile Include="System\Text\Json\Reader\JsonReaderException.cs" />
<Compile Include="System\Text\Json\Reader\JsonReaderHelper.cs" />
- <Compile Include="System\Text\Json\Reader\JsonReaderHelper.Date.cs" />
<Compile Include="System\Text\Json\Reader\JsonReaderHelper.Unescaping.cs" />
<Compile Include="System\Text\Json\Reader\JsonReaderOptions.cs" />
<Compile Include="System\Text\Json\Reader\JsonReaderState.cs" />
/// <summary>
/// This is an implementation detail and MUST NOT be called by source-package consumers.
/// </summary>
+ internal bool TryGetValue(int index, out DateTime value)
+ {
+ CheckNotDisposed();
+
+ DbRow row = _parsedData.Get(index);
+
+ CheckExpectedType(JsonTokenType.String, row.TokenType);
+
+ ReadOnlySpan<byte> data = _utf8Json.Span;
+ ReadOnlySpan<byte> segment = data.Slice(row.Location, row.SizeOrLength);
+
+ if (JsonHelpers.TryParseAsISO(segment, out DateTime tmp, out int bytesConsumed) &&
+ segment.Length == bytesConsumed)
+ {
+ value = tmp;
+ return true;
+ }
+
+ value = default;
+ return false;
+ }
+
+ /// <summary>
+ /// This is an implementation detail and MUST NOT be called by source-package consumers.
+ /// </summary>
+ internal bool TryGetValue(int index, out DateTimeOffset value)
+ {
+ CheckNotDisposed();
+
+ DbRow row = _parsedData.Get(index);
+
+ CheckExpectedType(JsonTokenType.String, row.TokenType);
+
+ ReadOnlySpan<byte> data = _utf8Json.Span;
+ ReadOnlySpan<byte> segment = data.Slice(row.Location, row.SizeOrLength);
+
+ if (JsonHelpers.TryParseAsISO(segment, out DateTimeOffset tmp, out int bytesConsumed) &&
+ segment.Length == bytesConsumed)
+ {
+ value = tmp;
+ return true;
+ }
+
+ value = default;
+ return false;
+ }
+
+ /// <summary>
+ /// This is an implementation detail and MUST NOT be called by source-package consumers.
+ /// </summary>
internal string GetRawValueAsString(int index)
{
ReadOnlyMemory<byte> segment = GetRawValue(index, includeQuotes: true);
}
/// <summary>
+ /// Attempts to represent the current JSON string as a <see cref="DateTime"/>.
+ /// </summary>
+ /// <param name="value">Receives the value.</param>
+ /// <remarks>
+ /// This method does not create a DateTime representation of values other than JSON strings.
+ /// </remarks>
+ /// <returns>
+ /// <see langword="true"/> if the string can be represented as a <see cref="DateTime"/>,
+ /// <see langword="false"/> otherwise.
+ /// </returns>
+ /// <exception cref="InvalidOperationException">
+ /// This value's <see cref="Type"/> is not <see cref="JsonValueType.String"/>.
+ /// </exception>
+ /// <exception cref="ObjectDisposedException">
+ /// The parent <see cref="JsonDocument"/> has been disposed.
+ /// </exception>
+ public bool TryGetDateTime(out DateTime value)
+ {
+ CheckValidInstance();
+
+ return _parent.TryGetValue(_idx, out value);
+ }
+
+ /// <summary>
+ /// Gets the value of the element as a <see cref="DateTime"/>.
+ /// </summary>
+ /// <remarks>
+ /// This method does not create a DateTime representation of values other than JSON strings.
+ /// </remarks>
+ /// <returns>The value of the element as a <see cref="DateTime"/>.</returns>
+ /// <exception cref="InvalidOperationException">
+ /// This value's <see cref="Type"/> is not <see cref="JsonValueType.String"/>.
+ /// </exception>
+ /// <exception cref="ObjectDisposedException">
+ /// The parent <see cref="JsonDocument"/> has been disposed.
+ /// </exception>
+ /// <seealso cref="ToString"/>
+ public DateTime GetDateTime()
+ {
+ if (TryGetDateTime(out DateTime value))
+ {
+ return value;
+ }
+
+ throw new FormatException();
+ }
+
+ /// <summary>
+ /// Attempts to represent the current JSON string as a <see cref="DateTimeOffset"/>.
+ /// </summary>
+ /// <param name="value">Receives the value.</param>
+ /// <remarks>
+ /// This method does not create a DateTimeOffset representation of values other than JSON strings.
+ /// </remarks>
+ /// <returns>
+ /// <see langword="true"/> if the string can be represented as a <see cref="DateTimeOffset"/>,
+ /// <see langword="false"/> otherwise.
+ /// </returns>
+ /// <exception cref="InvalidOperationException">
+ /// This value's <see cref="Type"/> is not <see cref="JsonValueType.String"/>.
+ /// </exception>
+ /// <exception cref="ObjectDisposedException">
+ /// The parent <see cref="JsonDocument"/> has been disposed.
+ /// </exception>
+ public bool TryGetDateTimeOffset(out DateTimeOffset value)
+ {
+ CheckValidInstance();
+
+ return _parent.TryGetValue(_idx, out value);
+ }
+
+ /// <summary>
+ /// Gets the value of the element as a <see cref="DateTimeOffset"/>.
+ /// </summary>
+ /// <remarks>
+ /// This method does not create a DateTimeOffset representation of values other than JSON strings.
+ /// </remarks>
+ /// <returns>The value of the element as a <see cref="DateTimeOffset"/>.</returns>
+ /// <exception cref="InvalidOperationException">
+ /// This value's <see cref="Type"/> is not <see cref="JsonValueType.String"/>.
+ /// </exception>
+ /// <exception cref="ObjectDisposedException">
+ /// The parent <see cref="JsonDocument"/> has been disposed.
+ /// </exception>
+ /// <seealso cref="ToString"/>
+ public DateTimeOffset GetDateTimeOffset()
+ {
+ if (TryGetDateTimeOffset(out DateTimeOffset value))
+ {
+ return value;
+ }
+
+ throw new FormatException();
+ }
+
+ /// <summary>
/// This is an implementation detail and MUST NOT be called by source-package consumers.
/// </summary>
internal string GetPropertyName()
namespace System.Text.Json
{
- internal static partial class JsonReaderHelper
+ internal static partial class JsonHelpers
{
public static bool TryParseAsISO(ReadOnlySpan<byte> source, out DateTime value, out int bytesConsumed)
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsInRangeInclusive(JsonTokenType value, JsonTokenType lowerBound, JsonTokenType upperBound)
=> (value - lowerBound) <= (upperBound - lowerBound);
+
+ /// <summary>
+ /// Returns <see langword="true"/> iff <paramref name="value"/> is in the range [0..9].
+ /// Otherwise, returns <see langword="false"/>.
+ /// </summary>
+ public static bool IsDigit(byte value) => (uint)(value - '0') <= '9' - '0';
}
}
}
}
- // A digit is valid if it is in the range: [0..9]
- // Otherwise, return false.
- public static bool IsDigit(byte nextByte) => (uint)(nextByte - '0') <= '9' - '0';
-
// Returns true if the TokenType is a primitive "value", i.e. String, Number, True, False, and Null
// Otherwise, return false.
public static bool IsTokenTypePrimitive(JsonTokenType tokenType) =>
}
else
{
- if (JsonReaderHelper.IsDigit(first) || first == '-')
+ if (JsonHelpers.IsDigit(first) || first == '-')
{
if (!TryGetNumberMultiSegment(_buffer.Slice(_consumed), out int numberOfBytes))
{
{
StartArray();
}
- else if (JsonReaderHelper.IsDigit(marker) || marker == '-')
+ else if (JsonHelpers.IsDigit(marker) || marker == '-')
{
return ConsumeNumberMultiSegment();
}
}
nextByte = data[i];
- if (!JsonReaderHelper.IsDigit(nextByte))
+ if (!JsonHelpers.IsDigit(nextByte))
{
ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.RequiredDigitNotFoundAfterSign, nextByte);
}
for (; i < data.Length; i++)
{
nextByte = data[i];
- if (!JsonReaderHelper.IsDigit(nextByte))
+ if (!JsonHelpers.IsDigit(nextByte))
{
break;
}
for (; i < data.Length; i++)
{
nextByte = data[i];
- if (!JsonReaderHelper.IsDigit(nextByte))
+ if (!JsonHelpers.IsDigit(nextByte))
{
break;
}
data = _buffer;
}
byte nextByte = data[i];
- if (!JsonReaderHelper.IsDigit(nextByte))
+ if (!JsonHelpers.IsDigit(nextByte))
{
ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.RequiredDigitNotFoundAfterDecimal, nextByte);
}
nextByte = data[i];
}
- if (!JsonReaderHelper.IsDigit(nextByte))
+ if (!JsonHelpers.IsDigit(nextByte))
{
ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.RequiredDigitNotFoundAfterSign, nextByte);
}
}
ReadOnlySpan<byte> span = HasValueSequence ? ValueSequence.ToArray() : ValueSpan;
- return JsonReaderHelper.TryParseAsISO(span, out value, out int bytesConsumed) && span.Length == bytesConsumed;
+ return JsonHelpers.TryParseAsISO(span, out value, out int bytesConsumed) && span.Length == bytesConsumed;
}
/// <summary>
}
ReadOnlySpan<byte> span = HasValueSequence ? ValueSequence.ToArray() : ValueSpan;
- return JsonReaderHelper.TryParseAsISO(span, out value, out int bytesConsumed) && span.Length == bytesConsumed;
+ return JsonHelpers.TryParseAsISO(span, out value, out int bytesConsumed) && span.Length == bytesConsumed;
}
}
}
// Create local copy to avoid bounds checks.
ReadOnlySpan<byte> localBuffer = _buffer;
- if (JsonReaderHelper.IsDigit(first) || first == '-')
+ if (JsonHelpers.IsDigit(first) || first == '-')
{
if (!TryGetNumber(localBuffer.Slice(_consumed), out int numberOfBytes))
{
{
StartArray();
}
- else if (JsonReaderHelper.IsDigit(marker) || marker == '-')
+ else if (JsonHelpers.IsDigit(marker) || marker == '-')
{
return ConsumeNumber();
}
}
nextByte = data[i];
- if (!JsonReaderHelper.IsDigit(nextByte))
+ if (!JsonHelpers.IsDigit(nextByte))
{
_bytePositionInLine += i;
ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.RequiredDigitNotFoundAfterSign, nextByte);
for (; i < data.Length; i++)
{
nextByte = data[i];
- if (!JsonReaderHelper.IsDigit(nextByte))
+ if (!JsonHelpers.IsDigit(nextByte))
{
break;
}
return ConsumeNumberResult.NeedMoreData;
}
byte nextByte = data[i];
- if (!JsonReaderHelper.IsDigit(nextByte))
+ if (!JsonHelpers.IsDigit(nextByte))
{
_bytePositionInLine += i;
ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.RequiredDigitNotFoundAfterDecimal, nextByte);
nextByte = data[i];
}
- if (!JsonReaderHelper.IsDigit(nextByte))
+ if (!JsonHelpers.IsDigit(nextByte))
{
_bytePositionInLine += i;
ThrowHelper.ThrowJsonReaderException(ref this, ExceptionResource.RequiredDigitNotFoundAfterSign, nextByte);
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using Xunit;
+
+namespace System.Text.Json.Tests
+{
+ internal class JsonDateTimeTestData
+ {
+ // Test string, Argument to DateTime(Offset).Parse(Exact)
+ public static IEnumerable<object[]> ValidISO8601Tests()
+ {
+ yield return new object[] { "\"0997-07-16\"", "0997-07-16" };
+ yield return new object[] { "\"1997-07-16\"", "1997-07-16" };
+ yield return new object[] { "\"1997-07-16T19:20\"", "1997-07-16T19:20" };
+ yield return new object[] { "\"1997-07-16T19:20:30\"", "1997-07-16T19:20:30" };
+ yield return new object[] { "\"1997-07-16T19:20:30.45\"", "1997-07-16T19:20:30.45" };
+ yield return new object[] { "\"1997-07-16T19:20:30.4555555\"", "1997-07-16T19:20:30.4555555" };
+
+ // Skip test T24:00 till #35830 is fixed.
+ // yield return new object[] { "\"1997-07-16T24:00\"", "1997-07-16T24:00" };
+
+ // Test fractions.
+ yield return new object[] { "\"1997-07-16T19:20:30.0\"", "1997-07-16T19:20:30" };
+ yield return new object[] { "\"1997-07-16T19:20:30.000\"", "1997-07-16T19:20:30" };
+ yield return new object[] { "\"1997-07-16T19:20:30.0000000\"", "1997-07-16T19:20:30" };
+ yield return new object[] { "\"1997-07-16T19:20:30.01\"", "1997-07-16T19:20:30.01" };
+ yield return new object[] { "\"1997-07-16T19:20:30.0001\"", "1997-07-16T19:20:30.0001" };
+ yield return new object[] { "\"1997-07-16T19:20:30.0000001\"", "1997-07-16T19:20:30.0000001" };
+ yield return new object[] { "\"1997-07-16T19:20:30.0000323\"", "1997-07-16T19:20:30.0000323" };
+ yield return new object[] { "\"1997-07-16T19:20:30.1\"", "1997-07-16T19:20:30.1" };
+ yield return new object[] { "\"1997-07-16T19:20:30.22\"", "1997-07-16T19:20:30.22" };
+ yield return new object[] { "\"1997-07-16T19:20:30.333\"", "1997-07-16T19:20:30.333" };
+ yield return new object[] { "\"1997-07-16T19:20:30.4444\"", "1997-07-16T19:20:30.4444" };
+ yield return new object[] { "\"1997-07-16T19:20:30.55555\"", "1997-07-16T19:20:30.55555" };
+ yield return new object[] { "\"1997-07-16T19:20:30.666666\"", "1997-07-16T19:20:30.666666" };
+ yield return new object[] { "\"1997-07-16T19:20:30.7777777\"", "1997-07-16T19:20:30.7777777" };
+ yield return new object[] { "\"1997-07-16T19:20:30.1000000\"", "1997-07-16T19:20:30.1" };
+ yield return new object[] { "\"1997-07-16T19:20:30.2200000\"", "1997-07-16T19:20:30.22" };
+ yield return new object[] { "\"1997-07-16T19:20:30.3330000\"", "1997-07-16T19:20:30.333" };
+ yield return new object[] { "\"1997-07-16T19:20:30.4444000\"", "1997-07-16T19:20:30.4444" };
+ yield return new object[] { "\"1997-07-16T19:20:30.5555500\"", "1997-07-16T19:20:30.55555" };
+ yield return new object[] { "\"1997-07-16T19:20:30.6666660\"", "1997-07-16T19:20:30.666666" };
+
+ // Test fraction truncation.
+ yield return new object[] { "\"1997-07-16T19:20:30.0000000000000\"", "1997-07-16T19:20:30" };
+ yield return new object[] { "\"1997-07-16T19:20:30.00000001\"", "1997-07-16T19:20:30" };
+ yield return new object[] { "\"1997-07-16T19:20:30.00000000000001\"", "1997-07-16T19:20:30" };
+ yield return new object[] { "\"1997-07-16T19:20:30.77777770\"", "1997-07-16T19:20:30.7777777" };
+ yield return new object[] { "\"1997-07-16T19:20:30.777777700\"", "1997-07-16T19:20:30.7777777" };
+ yield return new object[] { "\"1997-07-16T19:20:30.45555554\"", "1997-07-16T19:20:30.45555554" };
+ // We expect the parser to truncate. `DateTime(Offset).Parse` will round up to 7dp in these cases,
+ // so we pass a string representing the Datetime(Offset) we expect to the `Parse` method.
+ yield return new object[] { "\"1997-07-16T19:20:30.45555555\"", "1997-07-16T19:20:30.4555555" };
+ yield return new object[] { "\"1997-07-16T19:20:30.4555555555555555555\"", "1997-07-16T19:20:30.4555555" };
+
+ // Test Non-UTC timezone designator (TZD).
+ yield return new object[] { "\"1997-07-16T19:20+01:00\"", "1997-07-16T19:20+01:00" };
+ yield return new object[] { "\"1997-07-16T19:20-01:00\"", "1997-07-16T19:20-01:00" };
+ yield return new object[] { "\"1997-07-16T19:20:30+01:00\"", "1997-07-16T19:20:30+01:00" };
+ yield return new object[] { "\"1997-07-16T19:20:30-01:00\"", "1997-07-16T19:20:30-01:00" };
+ yield return new object[] { "\"1997-07-16T19:20:30.4555555+01:00\"", "1997-07-16T19:20:30.4555555+01:00" };
+ yield return new object[] { "\"1997-07-16T19:20:30.4555555-01:00\"", "1997-07-16T19:20:30.4555555-01:00" };
+ yield return new object[] { "\"1997-07-16T19:20:30.4555555+04:30\"", "1997-07-16T19:20:30.4555555+04:30" };
+ yield return new object[] { "\"1997-07-16T19:20:30.4555555-04:30\"", "1997-07-16T19:20:30.4555555-04:30" };
+ yield return new object[] { "\"1997-07-16T19:20:30.4555555+0100\"", "1997-07-16T19:20:30.4555555+01:00" };
+ yield return new object[] { "\"1997-07-16T19:20:30.4555555-0100\"", "1997-07-16T19:20:30.4555555-01:00" };
+ yield return new object[] { "\"1997-07-16T19:20:30.4555555+0430\"", "1997-07-16T19:20:30.4555555+04:30" };
+ yield return new object[] { "\"1997-07-16T19:20:30.4555555-0430\"", "1997-07-16T19:20:30.4555555-04:30" };
+ // Test Non-UTC TZD without minute.
+ yield return new object[] { "\"1997-07-16T19:20:30.4555555+01\"", "1997-07-16T19:20:30.4555555+01:00" };
+ yield return new object[] { "\"1997-07-16T19:20:30.4555555-01\"", "1997-07-16T19:20:30.4555555-01:00" };
+ // Test Non-UTC TZD with max UTC offset hour.
+ yield return new object[] { "\"1997-07-16T19:20:30.4555555+14:00\"", "1997-07-16T19:20:30.4555555+14:00" };
+ yield return new object[] { "\"1997-07-16T19:20:30.4555555-14:00\"", "1997-07-16T19:20:30.4555555-14:00" };
+ yield return new object[] { "\"1997-07-16T19:20:30.4555555+1400\"", "1997-07-16T19:20:30.4555555+14:00" };
+ yield return new object[] { "\"1997-07-16T19:20:30.4555555-1400\"", "1997-07-16T19:20:30.4555555-14:00" };
+ yield return new object[] { "\"1997-07-16T19:20:30.4555555+14\"", "1997-07-16T19:20:30.4555555+14:00" };
+ yield return new object[] { "\"1997-07-16T19:20:30.4555555-14\"", "1997-07-16T19:20:30.4555555-14:00" };
+ // Test February 29 on a leap year
+ yield return new object[] { "\"2020-02-29T19:20:30.4555555+10:00\"", "2020-02-29T19:20:30.4555555+10:00" };
+ }
+
+ // UTC TZD tests are separate because `DateTime.Parse` for strings with `Z` TZD will return
+ // a `DateTime` with `DateTimeKind.Local` i.e `+00:00` which does not equal our expected result,
+ // a `DateTime` with `DateTimeKind.Utc` i.e `Z`.
+ // Instead, we need to use `DateTime.ParseExact` which returns a DateTime Utc `DateTimeKind`.
+ //
+ // Test string, Argument to DateTime(Offset).Parse(Exact)
+ public static IEnumerable<object[]> ValidISO8601TestsWithUtcOffset()
+ {
+ yield return new object[] { "\"1997-07-16T19:20Z\"", "1997-07-16T19:20:00.0000000Z" };
+ yield return new object[] { "\"1997-07-16T19:20:30Z\"", "1997-07-16T19:20:30.0000000Z" };
+ yield return new object[] { "\"1997-07-16T19:20:30.4555555Z\"", "1997-07-16T19:20:30.4555555Z" };
+ }
+
+ public static IEnumerable<object[]> InvalidISO8601Tests()
+ {
+ // Invalid YYYY-MM-DD
+ yield return new object[] { "\"0997 07-16\"" };
+ yield return new object[] { "\"0997-0a-16\"" };
+ yield return new object[] { "\"0997-07 16\"" };
+ yield return new object[] { "\"0997-07-160997-07-16\"" };
+ yield return new object[] { "\"0997-07-16abc\"" };
+ yield return new object[] { "\"0997-07-16 \"" };
+ yield return new object[] { "\"0997-07-16,0997-07-16\"" };
+ yield return new object[] { "\"1997-07-16T19:20abc\"" };
+ yield return new object[] { "\"1997-07-16T19:20, 123\"" };
+ yield return new object[] { "\"997-07-16\"" };
+ yield return new object[] { "\"1997-07\"" };
+ yield return new object[] { "\"1997-7-06\"" };
+ yield return new object[] { "\"1997-07-16T\"" };
+ yield return new object[] { "\"1997-07-6\"" };
+ yield return new object[] { "\"1997-07-6T01\"" };
+ yield return new object[] { "\"1997-07-16Z\"" };
+ yield return new object[] { "\"1997-07-16+01:00\"" };
+ yield return new object[] { "\"19970716\"" };
+ yield return new object[] { "\"0997-07-166\"" };
+ yield return new object[] { "\"1997-07-1sdsad\"" };
+ yield return new object[] { "\"1997-07-16T19200\"" };
+
+ // Invalid YYYY-MM-DDThh:mm
+ yield return new object[] { "\"1997-07-16T1\"" };
+ yield return new object[] { "\"1997-07-16Ta0:00\"" };
+ yield return new object[] { "\"1997-07-16T19: 20:30\"" };
+ yield return new object[] { "\"1997-07-16 19:20:30\"" };
+ yield return new object[] { "\"1997-07-16T19:2030\"" };
+
+ // Invalid YYYY-MM-DDThh:mm:ss
+ yield return new object[] { "\"1997-07-16T19:20:3a\"" };
+ yield return new object[] { "\"1997-07-16T19:20:30a\"" };
+ yield return new object[] { "\"1997-07-16T19:20:3045\"" };
+ yield return new object[] { "\"1997-07-16T19:20:304555555\"" };
+
+ // Invalid fractions.
+ yield return new object[] { "\"1997-07-16T19:20:30,45\"" };
+ yield return new object[] { "\"1997-07-16T19:20:30.\"" };
+ yield return new object[] { "\"1997-07-16T19:20:30 .\"" };
+ yield return new object[] { "\"abc1997-07-16T19:20:30.000\"" };
+ yield return new object[] { "\"1997-07-16T19:20:30.4555555+\"" };
+
+ // Invalid TZD.
+ yield return new object[] { "\"1997-07-16T19:20:30.4555555+-Z\"" };
+ yield return new object[] { "\"1997-07-16T19:20:30.4555555Z \"" };
+ yield return new object[] { "\"1997-07-16T19:20:30.4555555+01Z\"" };
+ yield return new object[] { "\"1997-07-16T19:20:30.4555555+01:\"" };
+ yield return new object[] { "\"1997-07-16T19:20:30.4555555 +01:00\"" };
+ yield return new object[] { "\"1997-07-16T19:20:30.4555555+01:\"" };
+ yield return new object[] { "\"1997-07-16T19:20:30.4555555- 01:00\"" };
+ yield return new object[] { "\"1997-07-16T19:20:30.4555555+04 :30\"" };
+ yield return new object[] { "\"1997-07-16T19:20:30.4555555-04: 30\"" };
+ yield return new object[] { "\"1997-07-16T19:20:30.4555555+0100 \"" };
+ yield return new object[] { "\"1997-07-16T19:20:30.4555555-010\"" };
+ yield return new object[] { "\"1997-07-16T19:20:30.4555555+430\"" };
+ yield return new object[] { "\"1997-07-16T19:20:30.4555555--0430\"" };
+ yield return new object[] { "\"1997-07-16T19:20:30.4555555+0\"" };
+ yield return new object[] { "\"1997-07-16T19:20:30.4555555-01005\"" };
+ yield return new object[] { "\"1997-07-16T19:20:30.4555555+14:00a\"" };
+ yield return new object[] { "\"1997-07-16T19:20:30.4555555-14:0\"" };
+ yield return new object[] { "\"1997-07-16T19:20:30.4555555-14:00 \"" };
+ yield return new object[] { "\"1997-07-16T19:20:30.4555555+14 00\"" };
+
+ // Proper format but invalid calendar date, time, or time zone designator fields
+ yield return new object[] { "\"1997-00-16T19:20:30.4555555\"" };
+ yield return new object[] { "\"1997-07-16T25:20:30.4555555\"" };
+ yield return new object[] { "\"1997-00-16T19:20:30.4555555Z\"" };
+ yield return new object[] { "\"1997-07-16T25:20:30.4555555Z\"" };
+ yield return new object[] { "\"1997-07-16T19:20:30.4555555+14:30\"" };
+ yield return new object[] { "\"1997-07-16T19:20:30.4555555-14:30\"" };
+ yield return new object[] { "\"1997-07-16T19:20:30.4555555+15:00\"" };
+ yield return new object[] { "\"1997-07-16T19:20:30.4555555-15:00\"" };
+ yield return new object[] { "\"1997-00-16T19:20:30.4555555+10:00\"" };
+ yield return new object[] { "\"1997-07-16T25:20:30.4555555+10:00\"" };
+ yield return new object[] { "\"1997-07-16T19:60:30.4555555+10:00\"" };
+ yield return new object[] { "\"1997-07-16T19:20:60.4555555+10:00\"" };
+ yield return new object[] { "\"1997-07-16T19:20:30.4555555+10:60\"" };
+ yield return new object[] { "\"0000-07-16T19:20:30.4555555+10:00\"" };
+ yield return new object[] { "\"2019-02-29T19:20:30.4555555+10:00\"" };
+ yield return new object[] { "\"9999-12-31T23:59:59.9999999-01:00\"" }; // This date spills over to year 10_000.
+ }
+ }
+}
using System.Buffers;
using System.Collections;
+using System.Globalization;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Collections.Generic;
}
Assert.Throws<InvalidOperationException>(() => root.GetString());
+ Assert.Throws<InvalidOperationException>(() => root.GetDateTime());
+ Assert.Throws<InvalidOperationException>(() => root.GetDateTimeOffset());
Assert.Throws<InvalidOperationException>(() => root.GetArrayLength());
Assert.Throws<InvalidOperationException>(() => root.EnumerateArray());
Assert.Throws<InvalidOperationException>(() => root.EnumerateObject());
}
Assert.Throws<InvalidOperationException>(() => root.GetString());
+ Assert.Throws<InvalidOperationException>(() => root.GetDateTime());
+ Assert.Throws<InvalidOperationException>(() => root.GetDateTimeOffset());
Assert.Throws<InvalidOperationException>(() => root.GetArrayLength());
Assert.Throws<InvalidOperationException>(() => root.EnumerateArray());
Assert.Throws<InvalidOperationException>(() => root.EnumerateObject());
Assert.Equal(value, root.GetUInt64());
Assert.Throws<InvalidOperationException>(() => root.GetString());
+ Assert.Throws<InvalidOperationException>(() => root.GetDateTime());
+ Assert.Throws<InvalidOperationException>(() => root.GetDateTimeOffset());
Assert.Throws<InvalidOperationException>(() => root.GetArrayLength());
Assert.Throws<InvalidOperationException>(() => root.EnumerateArray());
Assert.Throws<InvalidOperationException>(() => root.EnumerateObject());
Assert.Throws<FormatException>(() => root.GetUInt64());
Assert.Throws<InvalidOperationException>(() => root.GetString());
+ Assert.Throws<InvalidOperationException>(() => root.GetDateTime());
+ Assert.Throws<InvalidOperationException>(() => root.GetDateTimeOffset());
Assert.Throws<InvalidOperationException>(() => root.GetArrayLength());
Assert.Throws<InvalidOperationException>(() => root.EnumerateArray());
Assert.Throws<InvalidOperationException>(() => root.EnumerateObject());
}
}
+ [Theory]
+ [MemberData(nameof(JsonDateTimeTestData.ValidISO8601Tests), MemberType = typeof(JsonDateTimeTestData))]
+ public static void ReadDateTimeAndDateTimeOffset(string jsonString, string expectedString)
+ {
+ byte[] dataUtf8 = Encoding.UTF8.GetBytes(jsonString);
+
+ using (JsonDocument doc = JsonDocument.Parse(dataUtf8, default))
+ {
+ JsonElement root = doc.RootElement;
+
+ DateTime expectedDateTime = DateTime.Parse(expectedString);
+ DateTimeOffset expectedDateTimeOffset = DateTimeOffset.Parse(expectedString);
+
+ Assert.Equal(JsonValueType.String, root.Type);
+
+ Assert.True(root.TryGetDateTime(out DateTime DateTimeVal));
+ Assert.Equal(expectedDateTime, DateTimeVal);
+
+ Assert.True(root.TryGetDateTimeOffset(out DateTimeOffset DateTimeOffsetVal));
+ Assert.Equal(expectedDateTimeOffset, DateTimeOffsetVal);
+
+ Assert.Equal(expectedDateTime, root.GetDateTime());
+ Assert.Equal(expectedDateTimeOffset, root.GetDateTimeOffset());
+
+ Assert.Throws<InvalidOperationException>(() => root.GetInt32());
+ Assert.Throws<InvalidOperationException>(() => root.GetUInt32());
+ Assert.Throws<InvalidOperationException>(() => root.GetInt64());
+ Assert.Throws<InvalidOperationException>(() => root.GetUInt64());
+ Assert.Throws<InvalidOperationException>(() => root.GetArrayLength());
+ Assert.Throws<InvalidOperationException>(() => root.EnumerateArray());
+ Assert.Throws<InvalidOperationException>(() => root.EnumerateObject());
+ Assert.Throws<InvalidOperationException>(() => root.GetBoolean());
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(JsonDateTimeTestData.ValidISO8601TestsWithUtcOffset), MemberType = typeof(JsonDateTimeTestData))]
+ public static void ReadDateTimeAndDateTimeOffset_WithUtcOffset(string jsonString, string expectedString)
+ {
+ byte[] dataUtf8 = Encoding.UTF8.GetBytes(jsonString);
+
+ using (JsonDocument doc = JsonDocument.Parse(dataUtf8, default))
+ {
+ JsonElement root = doc.RootElement;
+
+ DateTime expectedDateTime = DateTime.ParseExact(expectedString, "O", CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind);
+ DateTimeOffset expectedDateTimeOffset = DateTimeOffset.ParseExact(expectedString, "O", CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind);
+
+ Assert.Equal(JsonValueType.String, root.Type);
+
+ Assert.True(root.TryGetDateTime(out DateTime DateTimeVal));
+ Assert.Equal(expectedDateTime, DateTimeVal);
+
+ Assert.True(root.TryGetDateTimeOffset(out DateTimeOffset DateTimeOffsetVal));
+ Assert.Equal(expectedDateTimeOffset, DateTimeOffsetVal);
+
+ Assert.Equal(expectedDateTime, root.GetDateTime());
+ Assert.Equal(expectedDateTimeOffset, root.GetDateTimeOffset());
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(JsonDateTimeTestData.InvalidISO8601Tests), MemberType = typeof(JsonDateTimeTestData))]
+ public static void ReadDateTimeAndDateTimeOffset_InvalidTests(string jsonString)
+ {
+ byte[] dataUtf8 = Encoding.UTF8.GetBytes(jsonString);
+
+ using (JsonDocument doc = JsonDocument.Parse(dataUtf8, default))
+ {
+ JsonElement root = doc.RootElement;
+
+ Assert.Equal(JsonValueType.String, root.Type);
+
+ Assert.False(root.TryGetDateTime(out DateTime DateTimeVal));
+ Assert.False(root.TryGetDateTimeOffset(out DateTimeOffset DateTimeOffsetVal));
+
+ Assert.Throws<FormatException>(() => root.GetDateTime());
+ Assert.Throws<FormatException>(() => root.GetDateTimeOffset());
+ }
+ }
+
public static IEnumerable<object[]> NonIntegerCases
{
get
Assert.Throws<FormatException>(() => root.GetUInt64());
Assert.Throws<InvalidOperationException>(() => root.GetString());
+ Assert.Throws<InvalidOperationException>(() => root.GetDateTime());
+ Assert.Throws<InvalidOperationException>(() => root.GetDateTimeOffset());
Assert.Throws<InvalidOperationException>(() => root.GetArrayLength());
Assert.Throws<InvalidOperationException>(() => root.EnumerateArray());
Assert.Throws<InvalidOperationException>(() => root.EnumerateObject());
Assert.Throws<FormatException>(() => root.GetUInt64());
Assert.Throws<InvalidOperationException>(() => root.GetString());
+ Assert.Throws<InvalidOperationException>(() => root.GetDateTime());
+ Assert.Throws<InvalidOperationException>(() => root.GetDateTimeOffset());
Assert.Throws<InvalidOperationException>(() => root.GetArrayLength());
Assert.Throws<InvalidOperationException>(() => root.EnumerateArray());
Assert.Throws<InvalidOperationException>(() => root.EnumerateObject());
Assert.Throws<InvalidOperationException>(() => root.GetUInt64());
Assert.Throws<InvalidOperationException>(() => root.TryGetUInt64(out ulong _));
Assert.Throws<InvalidOperationException>(() => root.GetString());
+ Assert.Throws<InvalidOperationException>(() => root.GetDateTime());
+ Assert.Throws<InvalidOperationException>(() => root.GetDateTimeOffset());
Assert.Throws<InvalidOperationException>(() => root.EnumerateObject());
Assert.Throws<InvalidOperationException>(() => root.GetBoolean());
}
Assert.Throws<InvalidOperationException>(() => root.GetUInt64());
Assert.Throws<InvalidOperationException>(() => root.TryGetUInt64(out ulong _));
Assert.Throws<InvalidOperationException>(() => root.GetString());
+ Assert.Throws<InvalidOperationException>(() => root.GetDateTime());
+ Assert.Throws<InvalidOperationException>(() => root.GetDateTimeOffset());
Assert.Throws<InvalidOperationException>(() => root.GetBoolean());
Assert.Throws<InvalidOperationException>(() => root.GetRawText());
}
<Compile Include="BufferSegment.cs" />
<Compile Include="FixedSizedBufferWriter.cs" />
<Compile Include="InvalidBufferWriter.cs" />
+ <Compile Include="JsonDateTimeTestData.cs" />
<Compile Include="JsonDocumentTests.cs" />
<Compile Include="JsonNumberTestData.cs" />
<Compile Include="JsonReaderStateAndOptionsTests.cs" />
{
public static partial class Utf8JsonReaderTests
{
- // Test string, Argument to DateTime(Offset).Parse(Exact)
- public static IEnumerable<object[]> ValidISO8601Tests()
- {
- yield return new object[] { "\"0997-07-16\"", "0997-07-16" };
- yield return new object[] { "\"1997-07-16\"", "1997-07-16" };
- yield return new object[] { "\"1997-07-16T19:20\"", "1997-07-16T19:20" };
- yield return new object[] { "\"1997-07-16T19:20:30\"", "1997-07-16T19:20:30" };
- yield return new object[] { "\"1997-07-16T19:20:30.45\"", "1997-07-16T19:20:30.45" };
- yield return new object[] { "\"1997-07-16T19:20:30.4555555\"", "1997-07-16T19:20:30.4555555" };
-
- // Skip test T24:00 till #35830 is fixed.
- // yield return new object[] { "\"1997-07-16T24:00\"", "1997-07-16T24:00" };
-
- // Test fractions.
- yield return new object[] { "\"1997-07-16T19:20:30.0\"", "1997-07-16T19:20:30" };
- yield return new object[] { "\"1997-07-16T19:20:30.000\"", "1997-07-16T19:20:30" };
- yield return new object[] { "\"1997-07-16T19:20:30.0000000\"", "1997-07-16T19:20:30" };
- yield return new object[] { "\"1997-07-16T19:20:30.01\"", "1997-07-16T19:20:30.01" };
- yield return new object[] { "\"1997-07-16T19:20:30.0001\"", "1997-07-16T19:20:30.0001" };
- yield return new object[] { "\"1997-07-16T19:20:30.0000001\"", "1997-07-16T19:20:30.0000001" };
- yield return new object[] { "\"1997-07-16T19:20:30.0000323\"", "1997-07-16T19:20:30.0000323" };
- yield return new object[] { "\"1997-07-16T19:20:30.1\"", "1997-07-16T19:20:30.1" };
- yield return new object[] { "\"1997-07-16T19:20:30.22\"", "1997-07-16T19:20:30.22" };
- yield return new object[] { "\"1997-07-16T19:20:30.333\"", "1997-07-16T19:20:30.333" };
- yield return new object[] { "\"1997-07-16T19:20:30.4444\"", "1997-07-16T19:20:30.4444" };
- yield return new object[] { "\"1997-07-16T19:20:30.55555\"", "1997-07-16T19:20:30.55555" };
- yield return new object[] { "\"1997-07-16T19:20:30.666666\"", "1997-07-16T19:20:30.666666" };
- yield return new object[] { "\"1997-07-16T19:20:30.7777777\"", "1997-07-16T19:20:30.7777777" };
- yield return new object[] { "\"1997-07-16T19:20:30.1000000\"", "1997-07-16T19:20:30.1" };
- yield return new object[] { "\"1997-07-16T19:20:30.2200000\"", "1997-07-16T19:20:30.22" };
- yield return new object[] { "\"1997-07-16T19:20:30.3330000\"", "1997-07-16T19:20:30.333" };
- yield return new object[] { "\"1997-07-16T19:20:30.4444000\"", "1997-07-16T19:20:30.4444" };
- yield return new object[] { "\"1997-07-16T19:20:30.5555500\"", "1997-07-16T19:20:30.55555" };
- yield return new object[] { "\"1997-07-16T19:20:30.6666660\"", "1997-07-16T19:20:30.666666" };
-
- // Test fraction truncation.
- yield return new object[] { "\"1997-07-16T19:20:30.0000000000000\"", "1997-07-16T19:20:30" };
- yield return new object[] { "\"1997-07-16T19:20:30.00000001\"", "1997-07-16T19:20:30" };
- yield return new object[] { "\"1997-07-16T19:20:30.00000000000001\"", "1997-07-16T19:20:30" };
- yield return new object[] { "\"1997-07-16T19:20:30.77777770\"", "1997-07-16T19:20:30.7777777" };
- yield return new object[] { "\"1997-07-16T19:20:30.777777700\"", "1997-07-16T19:20:30.7777777" };
- yield return new object[] { "\"1997-07-16T19:20:30.45555554\"", "1997-07-16T19:20:30.45555554" };
- // We expect the parser to truncate. `DateTime(Offset).Parse` will round up to 7dp in these cases,
- // so we pass a string representing the Datetime(Offset) we expect to the `Parse` method.
- yield return new object[] { "\"1997-07-16T19:20:30.45555555\"", "1997-07-16T19:20:30.4555555" };
- yield return new object[] { "\"1997-07-16T19:20:30.4555555555555555555\"", "1997-07-16T19:20:30.4555555" };
-
- // Test Non-UTC timezone designator (TZD).
- yield return new object[] { "\"1997-07-16T19:20+01:00\"", "1997-07-16T19:20+01:00" };
- yield return new object[] { "\"1997-07-16T19:20-01:00\"", "1997-07-16T19:20-01:00" };
- yield return new object[] { "\"1997-07-16T19:20:30+01:00\"", "1997-07-16T19:20:30+01:00" };
- yield return new object[] { "\"1997-07-16T19:20:30-01:00\"", "1997-07-16T19:20:30-01:00" };
- yield return new object[] { "\"1997-07-16T19:20:30.4555555+01:00\"", "1997-07-16T19:20:30.4555555+01:00" };
- yield return new object[] { "\"1997-07-16T19:20:30.4555555-01:00\"", "1997-07-16T19:20:30.4555555-01:00" };
- yield return new object[] { "\"1997-07-16T19:20:30.4555555+04:30\"", "1997-07-16T19:20:30.4555555+04:30" };
- yield return new object[] { "\"1997-07-16T19:20:30.4555555-04:30\"", "1997-07-16T19:20:30.4555555-04:30" };
- yield return new object[] { "\"1997-07-16T19:20:30.4555555+0100\"", "1997-07-16T19:20:30.4555555+01:00" };
- yield return new object[] { "\"1997-07-16T19:20:30.4555555-0100\"", "1997-07-16T19:20:30.4555555-01:00" };
- yield return new object[] { "\"1997-07-16T19:20:30.4555555+0430\"", "1997-07-16T19:20:30.4555555+04:30" };
- yield return new object[] { "\"1997-07-16T19:20:30.4555555-0430\"", "1997-07-16T19:20:30.4555555-04:30" };
- // Test Non-UTC TZD without minute.
- yield return new object[] { "\"1997-07-16T19:20:30.4555555+01\"", "1997-07-16T19:20:30.4555555+01:00" };
- yield return new object[] { "\"1997-07-16T19:20:30.4555555-01\"", "1997-07-16T19:20:30.4555555-01:00" };
- // Test Non-UTC TZD with max UTC offset hour.
- yield return new object[] { "\"1997-07-16T19:20:30.4555555+14:00\"", "1997-07-16T19:20:30.4555555+14:00" };
- yield return new object[] { "\"1997-07-16T19:20:30.4555555-14:00\"", "1997-07-16T19:20:30.4555555-14:00" };
- yield return new object[] { "\"1997-07-16T19:20:30.4555555+1400\"", "1997-07-16T19:20:30.4555555+14:00" };
- yield return new object[] { "\"1997-07-16T19:20:30.4555555-1400\"", "1997-07-16T19:20:30.4555555-14:00" };
- yield return new object[] { "\"1997-07-16T19:20:30.4555555+14\"", "1997-07-16T19:20:30.4555555+14:00" };
- yield return new object[] { "\"1997-07-16T19:20:30.4555555-14\"", "1997-07-16T19:20:30.4555555-14:00" };
- // Test February 29 on a leap year
- yield return new object[] { "\"2020-02-29T19:20:30.4555555+10:00\"", "2020-02-29T19:20:30.4555555+10:00" };
- }
-
- // UTC TZD tests are separate because `DateTime.Parse` for strings with `Z` TZD will return
- // a `DateTime` with `DateTimeKind.Local` i.e `+00:00` which does not equal our expected result,
- // a `DateTime` with `DateTimeKind.Utc` i.e `Z`.
- // Instead, we need to use `DateTime.ParseExact` which returns a DateTime Utc `DateTimeKind`.
- //
- // Test string, Argument to DateTime(Offset).Parse(Exact)
- public static IEnumerable<object[]> ValidISO8601TestsWithUtcOffset()
- {
- yield return new object[] { "\"1997-07-16T19:20Z\"", "1997-07-16T19:20:00.0000000Z" };
- yield return new object[] { "\"1997-07-16T19:20:30Z\"", "1997-07-16T19:20:30.0000000Z" };
- yield return new object[] { "\"1997-07-16T19:20:30.4555555Z\"", "1997-07-16T19:20:30.4555555Z" };
- }
-
- public static IEnumerable<object[]> InvalidISO8601Tests()
- {
- // Invalid YYYY-MM-DD
- yield return new object[] { "\"0997 07-16\"" };
- yield return new object[] { "\"0997-0a-16\"" };
- yield return new object[] { "\"0997-07 16\"" };
- yield return new object[] { "\"0997-07-160997-07-16\"" };
- yield return new object[] { "\"0997-07-16abc\"" };
- yield return new object[] { "\"0997-07-16 \"" };
- yield return new object[] { "\"0997-07-16,0997-07-16\"" };
- yield return new object[] { "\"1997-07-16T19:20abc\"" };
- yield return new object[] { "\"1997-07-16T19:20, 123\"" };
- yield return new object[] { "\"997-07-16\"" };
- yield return new object[] { "\"1997-07\"" };
- yield return new object[] { "\"1997-7-06\"" };
- yield return new object[] { "\"1997-07-16T\"" };
- yield return new object[] { "\"1997-07-6\"" };
- yield return new object[] { "\"1997-07-6T01\"" };
- yield return new object[] { "\"1997-07-16Z\"" };
- yield return new object[] { "\"1997-07-16+01:00\"" };
- yield return new object[] { "\"19970716\"" };
- yield return new object[] { "\"0997-07-166\"" };
- yield return new object[] { "\"1997-07-1sdsad\"" };
- yield return new object[] { "\"1997-07-16T19200\"" };
-
- // Invalid YYYY-MM-DDThh:mm
- yield return new object[] { "\"1997-07-16T1\"" };
- yield return new object[] { "\"1997-07-16Ta0:00\"" };
- yield return new object[] { "\"1997-07-16T19: 20:30\"" };
- yield return new object[] { "\"1997-07-16 19:20:30\"" };
- yield return new object[] { "\"1997-07-16T19:2030\"" };
-
- // Invalid YYYY-MM-DDThh:mm:ss
- yield return new object[] { "\"1997-07-16T19:20:3a\"" };
- yield return new object[] { "\"1997-07-16T19:20:30a\"" };
- yield return new object[] { "\"1997-07-16T19:20:3045\"" };
- yield return new object[] { "\"1997-07-16T19:20:304555555\"" };
-
- // Invalid fractions.
- yield return new object[] { "\"1997-07-16T19:20:30,45\"" };
- yield return new object[] { "\"1997-07-16T19:20:30.\"" };
- yield return new object[] { "\"1997-07-16T19:20:30 .\"" };
- yield return new object[] { "\"abc1997-07-16T19:20:30.000\"" };
- yield return new object[] { "\"1997-07-16T19:20:30.4555555+\"" };
-
- // Invalid TZD.
- yield return new object[] { "\"1997-07-16T19:20:30.4555555+-Z\"" };
- yield return new object[] { "\"1997-07-16T19:20:30.4555555Z \"" };
- yield return new object[] { "\"1997-07-16T19:20:30.4555555+01Z\"" };
- yield return new object[] { "\"1997-07-16T19:20:30.4555555+01:\"" };
- yield return new object[] { "\"1997-07-16T19:20:30.4555555 +01:00\"" };
- yield return new object[] { "\"1997-07-16T19:20:30.4555555+01:\"" };
- yield return new object[] { "\"1997-07-16T19:20:30.4555555- 01:00\"" };
- yield return new object[] { "\"1997-07-16T19:20:30.4555555+04 :30\"" };
- yield return new object[] { "\"1997-07-16T19:20:30.4555555-04: 30\"" };
- yield return new object[] { "\"1997-07-16T19:20:30.4555555+0100 \"" };
- yield return new object[] { "\"1997-07-16T19:20:30.4555555-010\"" };
- yield return new object[] { "\"1997-07-16T19:20:30.4555555+430\"" };
- yield return new object[] { "\"1997-07-16T19:20:30.4555555--0430\"" };
- yield return new object[] { "\"1997-07-16T19:20:30.4555555+0\"" };
- yield return new object[] { "\"1997-07-16T19:20:30.4555555-01005\"" };
- yield return new object[] { "\"1997-07-16T19:20:30.4555555+14:00a\"" };
- yield return new object[] { "\"1997-07-16T19:20:30.4555555-14:0\"" };
- yield return new object[] { "\"1997-07-16T19:20:30.4555555-14:00 \"" };
- yield return new object[] { "\"1997-07-16T19:20:30.4555555+14 00\"" };
-
- // Proper format but invalid calendar date, time, or time zone designator fields
- yield return new object[] { "\"1997-00-16T19:20:30.4555555\"" };
- yield return new object[] { "\"1997-07-16T25:20:30.4555555\"" };
- yield return new object[] { "\"1997-00-16T19:20:30.4555555Z\"" };
- yield return new object[] { "\"1997-07-16T25:20:30.4555555Z\"" };
- yield return new object[] { "\"1997-07-16T19:20:30.4555555+14:30\"" };
- yield return new object[] { "\"1997-07-16T19:20:30.4555555-14:30\"" };
- yield return new object[] { "\"1997-07-16T19:20:30.4555555+15:00\"" };
- yield return new object[] { "\"1997-07-16T19:20:30.4555555-15:00\"" };
- yield return new object[] { "\"1997-00-16T19:20:30.4555555+10:00\"" };
- yield return new object[] { "\"1997-07-16T25:20:30.4555555+10:00\"" };
- yield return new object[] { "\"1997-07-16T19:60:30.4555555+10:00\"" };
- yield return new object[] { "\"1997-07-16T19:20:60.4555555+10:00\"" };
- yield return new object[] { "\"1997-07-16T19:20:30.4555555+10:60\"" };
- yield return new object[] { "\"0000-07-16T19:20:30.4555555+10:00\"" };
- yield return new object[] { "\"2019-02-29T19:20:30.4555555+10:00\"" };
- yield return new object[] { "\"9999-12-31T23:59:59.9999999-01:00\"" }; // This date spills over to year 10_000.
- }
-
[Fact]
public static void TestingNumbers_TryGetMethods()
{
}
[Theory]
- [MemberData(nameof(ValidISO8601Tests))]
+ [MemberData(nameof(JsonDateTimeTestData.ValidISO8601Tests), MemberType = typeof(JsonDateTimeTestData))]
public static void TestingStringsConversionToDateTime(string jsonString, string expectedString)
{
byte[] dataUtf8 = Encoding.UTF8.GetBytes(jsonString);
}
[Theory]
- [MemberData(nameof(ValidISO8601Tests))]
+ [MemberData(nameof(JsonDateTimeTestData.ValidISO8601Tests), MemberType = typeof(JsonDateTimeTestData))]
public static void TestingStringsConversionToDateTimeOffset(string jsonString, string expectedString)
{
byte[] dataUtf8 = Encoding.UTF8.GetBytes(jsonString);
}
[Theory]
- [MemberData(nameof(ValidISO8601TestsWithUtcOffset))]
+ [MemberData(nameof(JsonDateTimeTestData.ValidISO8601TestsWithUtcOffset), MemberType = typeof(JsonDateTimeTestData))]
public static void TestingStringsWithUTCOffsetToDateTime(string jsonString, string expectedString)
{
byte[] dataUtf8 = Encoding.UTF8.GetBytes(jsonString);
}
[Theory]
- [MemberData(nameof(ValidISO8601TestsWithUtcOffset))]
+ [MemberData(nameof(JsonDateTimeTestData.ValidISO8601TestsWithUtcOffset), MemberType = typeof(JsonDateTimeTestData))]
public static void TestingStringsWithUTCOffsetToDateTimeOffset(string jsonString, string expectedString)
{
byte[] dataUtf8 = Encoding.UTF8.GetBytes(jsonString);
}
[Theory]
- [MemberData(nameof(InvalidISO8601Tests))]
+ [MemberData(nameof(JsonDateTimeTestData.InvalidISO8601Tests), MemberType = typeof(JsonDateTimeTestData))]
public static void TestingStringsInvalidConversionToDateTime(string jsonString)
{
byte[] dataUtf8 = Encoding.UTF8.GetBytes(jsonString);
}
[Theory]
- [MemberData(nameof(InvalidISO8601Tests))]
+ [MemberData(nameof(JsonDateTimeTestData.InvalidISO8601Tests), MemberType = typeof(JsonDateTimeTestData))]
public static void TestingStringsInvalidConversionToDateTimeOffset(string jsonString)
{
byte[] dataUtf8 = Encoding.UTF8.GetBytes(jsonString);