Skip to content

Commit

Permalink
BigInteger Json Converter
Browse files Browse the repository at this point in the history
  • Loading branch information
lucasteles committed Mar 23, 2023
1 parent feadfdf commit 05a50d8
Show file tree
Hide file tree
Showing 6 changed files with 193 additions and 143 deletions.
25 changes: 22 additions & 3 deletions src/DateTimeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,24 @@ public static class DateTimeExtensions
public static string ToJsonString(this DateTime dateTime) =>
JsonSerializer.Serialize(dateTime)[1..^1];

/// <summary>
/// Initializes a new instance of the DateTimeOffset structure using the specified DateTime value and offset
/// </summary>
public static DateTimeOffset WithOffset(this DateTime dateTime, TimeSpan offset) =>
new(dateTime, offset);

/// <summary>
/// Returns the number of seconds that have elapsed since 1970-01-01T00:00:00Z
/// </summary>
public static long ToUnixTimeSeconds(this DateTime dateTime) =>
new DateTimeOffset(dateTime).ToUnixTimeSeconds();

/// <summary>
/// Returns the number of seconds that have elapsed since 1970-01-01T00:00:00Z
/// </summary>
public static long ToUnixTimeSeconds(this DateOnly dateTime) =>
new DateTimeOffset(dateTime.ToDateTime()).ToUnixTimeSeconds();

/// <summary>
/// DateOnly string Invariant IS8601 string
/// </summary>
Expand All @@ -37,11 +55,12 @@ public static class DateTimeExtensions
public static TimeOnly ToTimeOnly(this DateTime dateTime) =>
TimeOnly.FromDateTime(dateTime);


/// <summary>
/// Returns a DateTime instance with the specified input kind that is set to the date of this DateOnly instance and the time at 00:00AM.
/// </summary>
public static DateTime
ToDateTime(this DateOnly dateOnly, DateTimeKind kind = DateTimeKind.Utc) =>
dateOnly.ToDateTime(new(), kind);
ToDateTime(this DateOnly dateOnly,
TimeOnly time = default,
DateTimeKind kind = DateTimeKind.Utc) =>
dateOnly.ToDateTime(time, kind);
}
35 changes: 35 additions & 0 deletions src/JsonConverters/BigIntegerJsonConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System.Globalization;
using System.Numerics;

namespace System.Text.Json.Serialization;

/// <summary>
/// Json converter for System.Numerics.BigInteger
/// </summary>
public class BigIntegerJsonConverter : JsonConverter<BigInteger>
{
/// <inheritdoc />
public override BigInteger Read(ref Utf8JsonReader reader, Type typeToConvert,
JsonSerializerOptions options)
{
if (reader.TokenType is not (JsonTokenType.Number or JsonTokenType.String))
throw new JsonException(
$"Found token {reader.TokenType} but expected token {JsonTokenType.Number}");

using var doc = JsonDocument.ParseValue(ref reader);
var value = reader.TokenType == JsonTokenType.String
? doc.RootElement.GetString() ?? "0"
: doc.RootElement.GetRawText();

var bigInteger = BigInteger.Parse(value, NumberFormatInfo.InvariantInfo);
return bigInteger;
}

/// <inheritdoc />
public override void Write(Utf8JsonWriter writer, BigInteger value,
JsonSerializerOptions options)
{
var result = value.ToString(NumberFormatInfo.InvariantInfo);
writer.WriteRawValue(result);
}
}
88 changes: 0 additions & 88 deletions src/TryParse.cs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using System.Numerics;
using System.Text.Json.Serialization;

namespace CSharpPlus.Tests.JsonConverters;

using System.Text.Json;
using static System.Text.Json.JsonSerializer;

public class BigIntegerJsonConverterTests : BaseTest
{
readonly JsonSerializerOptions options = new()
{
Converters =
{
new BigIntegerJsonConverter()
}
};

record TestDate(BigInteger Data);

[Test]
public void ShouldParseLong()
{
var expected = faker.Random.Long();
var value = Deserialize<TestDate>($@"{{""Data"": ""{expected}""}}", options)!.Data;

value.Should().Be(expected);
}

[Test]
public void ShouldParseBigNum()
{
var bigNum = faker.Random.ReplaceNumbers(new('#', 100));
var value = Deserialize<TestDate>($@"{{""Data"": ""{bigNum}""}}", options)!.Data;

var expected = BigInteger.Parse(bigNum);
value.Should().Be(expected);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
using System.Text.Json.Serialization;

namespace CSharpPlus.Tests.JsonConverters;

using System.Text.Json;
using static System.Text.Json.JsonSerializer;

public class DateTimeTests
{
readonly JsonSerializerOptions options = new()
{
Converters =
{
new DateTimeUtcOnlyJsonConverter()
}
};

record TestDate(DateTime Data);

DateTime Parse(string isoDate) =>
Deserialize<TestDate>($@"{{""Data"": ""{isoDate}""}}", options)!.Data;

[Test]
public void ShouldNotChangeOnReadISO8601UtcDate()
{
var expected = new DateTime(2022, 07, 2, 10, 30, 20, DateTimeKind.Utc);
var isoDate = "2022-07-02T10:30:20Z";
Parse(isoDate).Should().Be(expected)
.And.Subject!.Value.Kind.Should().Be(DateTimeKind.Utc);
}

[Test]
public void ShouldSetUTCAndNotChangeOnReadISO8601UnspecifiedKindDate()
{
var expected = new DateTime(2022, 7, 2, 10, 30, 20, DateTimeKind.Utc);
var isoDate = "2022-07-02T10:30:20";

DateTime.Parse(isoDate).Kind.Should().Be(DateTimeKind.Unspecified);
var parsed = Parse(isoDate);
parsed.Should().Be(expected).And.Subject!.Value.Kind.Should().Be(DateTimeKind.Utc);
}

[Test]
public void ShouldSetUnspecifiedKindUtcConvertingFromTimeZone()
{
var expected = new DateTime(2022, 7, 2, 10, 30, 20, DateTimeKind.Utc);
var isoDate = "2022-07-02T07:30:20";
DateTime.Parse(isoDate).Kind.Should().Be(DateTimeKind.Unspecified);

var timeZone = TimeZoneInfo.FindSystemTimeZoneById("America/Sao_Paulo");

var parsed = Deserialize<TestDate>(
$@"{{""Data"": ""{isoDate}""}}",
new JsonSerializerOptions
{
Converters =
{
new DateTimeUtcOnlyJsonConverter(timeZone)
}
})!.Data;

parsed.Should().Be(expected).And.Subject!.Value.Kind.Should().Be(DateTimeKind.Utc);
}

[Test]
public void ShouldSetUnspecifiedKindUtcConvertingFromOffset()
{
var expected = new DateTime(2022, 7, 2, 10, 30, 20, DateTimeKind.Utc);
var isoDate = "2022-07-02T13:30:20";
DateTime.Parse(isoDate).Kind.Should().Be(DateTimeKind.Unspecified);

var offset = TimeSpan.FromHours(3);

var parsed = Deserialize<TestDate>(
$@"{{""Data"": ""{isoDate}""}}",
new JsonSerializerOptions
{
Converters =
{
new DateTimeUtcOnlyJsonConverter(offset)
}
})!.Data;

parsed.Should().Be(expected).And.Subject!.Value.Kind.Should().Be(DateTimeKind.Utc);
}

[Test]
public void ShouldChangeLocalDateToUtc()
{
var expected = new DateTime(2022, 7, 2, 10, 30, 20, DateTimeKind.Utc);
var isoDate = "2022-07-02T07:30:20-03:00";

DateTime.Parse(isoDate).Kind.Should().Be(DateTimeKind.Local);
var parsed = Parse(isoDate);
parsed.Should().Be(expected).And.Subject!.Value.Kind.Should().Be(DateTimeKind.Utc);
}
}
52 changes: 0 additions & 52 deletions tests/CSharpPlus.Tests/TryParseTests.cs

This file was deleted.

0 comments on commit 05a50d8

Please sign in to comment.