Skip to content

Commit

Permalink
Add serialisation compatibility of TimeSpan and DateTime (#16205)
Browse files Browse the repository at this point in the history
Co-authored-by: Mike Alhayek <[email protected]>
Co-authored-by: Hisham Bin Ateya <[email protected]>
  • Loading branch information
3 people authored Jun 11, 2024
1 parent 2cc41ce commit 3d3f172
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 1 deletion.
2 changes: 2 additions & 0 deletions src/OrchardCore/OrchardCore.Abstractions/Json/JOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ static JOptions()
Default = new JsonSerializerOptions(Base);
Default.Converters.Add(new DynamicJsonConverter());
Default.Converters.Add(new PathStringJsonConverter());
Default.Converters.Add(new TimeSpanJsonConverter());
Default.Converters.Add(new DateTimeJsonConverter());

Indented = new JsonSerializerOptions(Default)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System;
using System.Globalization;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace OrchardCore.Json.Serialization;

public class DateTimeJsonConverter : JsonConverter<DateTime>
{
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (typeToConvert != typeof(DateTime))
{
throw new ArgumentException("Unexpected type to convert.", nameof(typeToConvert));
}

if (!reader.TryGetDateTime(out DateTime value) && DateTime.TryParse(reader.GetString()!, out value))
{
return value;
}

return value;
}

public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
=> writer.WriteStringValue(value.ToString("yyyy-MM-ddTHH:mm:ssZ", CultureInfo.InvariantCulture));
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace OrchardCore.Json.Serialization;

public class TimeSpanJsonConverter : JsonConverter<TimeSpan>
{
public override TimeSpan Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType != JsonTokenType.String)
{
throw new JsonException($"Unexpected token parsing TimeSpan. Expected a string, got '{reader.TokenType}'.");
}

var stringValue = reader.GetString();

if (TimeSpan.TryParse(stringValue, out var timeSpan))
{
return timeSpan;
}

throw new JsonException($"Unable to convert '{stringValue}' to TimeSpan.");
}

public override void Write(Utf8JsonWriter writer, TimeSpan value, JsonSerializerOptions options)
=> writer.WriteStringValue(value.ToString());
}
48 changes: 47 additions & 1 deletion test/OrchardCore.Tests/Data/ContentItemTests.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,58 @@
using System.Text.Json;
using System.Text.Json.Dynamic;
using System.Text.Json.Nodes;
using OrchardCore.ContentFields.Fields;
using OrchardCore.ContentManagement;
using OrchardCore.Json.Serialization;

namespace OrchardCore.Tests.Data
{
public class ContentItemTests
{
/// <summary>
/// To validate <see cref="DateTimeJsonConverter"/>
/// and <seealso cref="TimeSpanJsonConverter"/>
/// </summary>
[Fact]
public void JsonNode_WhenParseCalled_ConvertShortTimeFormatToTimeField()
{
// Arrange
var jsonStr = """
{
"TimeFieldTest": {
"Value": "13:05"
},
"DateTimeFieldTest": {
"Value": "2024-5-31 13:05"
},
"TimezoneDateTimeFieldTest": {
"Value": "2022-12-13T21:02:18.399-05:00"
},
"DateFieldTest": {
"Value": "2024-5-31"
}
}
""";

// Act
var jobject = JsonNode.Parse(jsonStr);
var timeField = jobject.SelectNode("TimeFieldTest").ToObject<TimeField>();
var dateField = jobject.SelectNode("DateFieldTest").ToObject<DateField>();
var dateTimeField = jobject.SelectNode("DateTimeFieldTest").ToObject<DateTimeField>();
var timezoneDateTimeFieldTest = jobject.SelectNode("TimezoneDateTimeFieldTest").ToObject<DateTimeField>();

// Assert
Assert.Equal("13:05:00", timeField.Value.Value.ToString());
Assert.Equal("2024-05-31", dateField.Value.Value.ToString("yyyy-MM-dd"));
Assert.Equal("2024-05-31 13:05", dateTimeField.Value.Value.ToString("yyyy-MM-dd HH:mm"));
Assert.Equal("13:05:00", JObject.FromObject(timeField).SelectNode("Value").ToString());
Assert.Equal("2024-05-31T00:00:00Z", JObject.FromObject(dateField).SelectNode("Value").ToString());
Assert.Equal("2024-05-31T13:05:00Z", JObject.FromObject(dateTimeField).SelectNode("Value").ToString());

var utcTime = TimeZoneInfo.ConvertTimeToUtc(timezoneDateTimeFieldTest.Value.Value);
Assert.Equal("2022-12-14 02:02:18", utcTime.ToString("yyyy-MM-dd HH:mm:ss"));
}

[Fact]
public void ShouldSerializeContent()
{
Expand Down Expand Up @@ -163,7 +209,7 @@ public void ContentShouldStoreDateTimeFields()

var json = JConvert.SerializeObject(contentItem);

Assert.Contains(@"""MyPart"":{""Text"":""test"",""myField"":{""Value"":""2024-01-01T10:42:00""}}", json);
Assert.Contains(@"""MyPart"":{""Text"":""test"",""myField"":{""Value"":""2024-01-01T10:42:00Z""}}", json);
}

[Fact]
Expand Down

0 comments on commit 3d3f172

Please sign in to comment.