diff --git a/framework/src/Volo.Abp.Json.Abstractions/Volo/Abp/Json/AbpJsonOptions.cs b/framework/src/Volo.Abp.Json.Abstractions/Volo/Abp/Json/AbpJsonOptions.cs
index f7f5370255..043c1081d7 100644
--- a/framework/src/Volo.Abp.Json.Abstractions/Volo/Abp/Json/AbpJsonOptions.cs
+++ b/framework/src/Volo.Abp.Json.Abstractions/Volo/Abp/Json/AbpJsonOptions.cs
@@ -1,9 +1,21 @@
-namespace Volo.Abp.Json;
+using System.Collections.Generic;
+
+namespace Volo.Abp.Json;
public class AbpJsonOptions
{
///
- /// Used to set default value for the DateTimeFormat.
+ /// Formats of input JSON date, Empty string means default format.
///
- public string DefaultDateTimeFormat { get; set; }
+ public List InputDateTimeFormats { get; set; }
+
+ ///
+ /// Format of output json date, Null or empty string means default format.
+ ///
+ public string OutputDateTimeFormat { get; set; }
+
+ public AbpJsonOptions()
+ {
+ InputDateTimeFormats = new List();
+ }
}
diff --git a/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpCamelCasePropertyNamesContractResolver.cs b/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpCamelCasePropertyNamesContractResolver.cs
index a73213af6c..3e4e5d0121 100644
--- a/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpCamelCasePropertyNamesContractResolver.cs
+++ b/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpCamelCasePropertyNamesContractResolver.cs
@@ -9,12 +9,12 @@ namespace Volo.Abp.Json.Newtonsoft;
public class AbpCamelCasePropertyNamesContractResolver : CamelCasePropertyNamesContractResolver, ITransientDependency
{
- private readonly Lazy _dateTimeConverter;
+ private readonly Lazy _dateTimeConverter;
public AbpCamelCasePropertyNamesContractResolver(IServiceProvider serviceProvider)
{
- _dateTimeConverter = new Lazy(
- serviceProvider.GetRequiredService,
+ _dateTimeConverter = new Lazy(
+ serviceProvider.GetRequiredService,
true
);
@@ -28,7 +28,7 @@ public class AbpCamelCasePropertyNamesContractResolver : CamelCasePropertyNamesC
{
var property = base.CreateProperty(member, memberSerialization);
- if (AbpJsonIsoDateTimeConverter.ShouldNormalize(member, property))
+ if (AbpDateTimeConverter.ShouldNormalize(member, property))
{
property.Converter = _dateTimeConverter.Value;
}
diff --git a/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpDateTimeConverter.cs b/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpDateTimeConverter.cs
new file mode 100644
index 0000000000..3bd97f7aee
--- /dev/null
+++ b/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpDateTimeConverter.cs
@@ -0,0 +1,116 @@
+using System;
+using System.Globalization;
+using System.Linq;
+using System.Reflection;
+using Microsoft.Extensions.Options;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Converters;
+using Newtonsoft.Json.Serialization;
+using Volo.Abp.Reflection;
+using Volo.Abp.Timing;
+
+namespace Volo.Abp.Json.Newtonsoft;
+
+public class AbpDateTimeConverter : DateTimeConverterBase
+{
+ private readonly string _dateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFFK";
+ private readonly DateTimeStyles _dateTimeStyles = DateTimeStyles.RoundtripKind;
+ private readonly CultureInfo _culture = CultureInfo.InvariantCulture;
+ private readonly IClock _clock;
+ private readonly AbpJsonOptions _options;
+
+ public AbpDateTimeConverter(IClock clock, IOptions options)
+ {
+ _clock = clock;
+ _options = options.Value;
+ }
+
+ public override bool CanConvert(Type objectType)
+ {
+ return objectType == typeof(DateTime) || objectType == typeof(DateTime?);
+ }
+
+ public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
+ {
+ var nullable = Nullable.GetUnderlyingType(objectType) != null;
+ if (reader.TokenType == JsonToken.Null)
+ {
+ if (!nullable)
+ {
+ throw new JsonSerializationException($"Cannot convert null value to {objectType.FullName}.");
+ }
+
+ return null;
+ }
+
+ if (reader.TokenType == JsonToken.Date)
+ {
+ return _clock.Normalize(reader.Value.To());
+ }
+
+ if (reader.TokenType != JsonToken.String)
+ {
+ throw new JsonSerializationException($"Unexpected token parsing date. Expected String, got {reader.TokenType}.");
+ }
+
+ var dateText = reader.Value?.ToString();
+
+ if (dateText.IsNullOrEmpty() && nullable)
+ {
+ return null;
+ }
+
+ if (_options.InputDateTimeFormats.Any())
+ {
+ foreach (var format in _options.InputDateTimeFormats)
+ {
+ if (DateTime.TryParseExact(dateText, format, _culture, _dateTimeStyles, out var d1))
+ {
+ return _clock.Normalize(d1);
+ }
+ }
+ }
+
+ var date = !_dateTimeFormat.IsNullOrEmpty() ?
+ DateTime.ParseExact(dateText, _dateTimeFormat, _culture, _dateTimeStyles) :
+ DateTime.Parse(dateText, _culture, _dateTimeStyles);
+
+ return _clock.Normalize(date);
+ }
+
+ public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
+ {
+ if (value != null)
+ {
+ value = _clock.Normalize(value.To());
+ }
+
+ if (value is DateTime dateTime)
+ {
+ if ((_dateTimeStyles & DateTimeStyles.AdjustToUniversal) == DateTimeStyles.AdjustToUniversal ||
+ (_dateTimeStyles & DateTimeStyles.AssumeUniversal) == DateTimeStyles.AssumeUniversal)
+ {
+ dateTime = dateTime.ToUniversalTime();
+ }
+
+ writer.WriteValue(_options.OutputDateTimeFormat.IsNullOrWhiteSpace()
+ ? dateTime.ToString(_dateTimeFormat, _culture)
+ : dateTime.ToString(_options.OutputDateTimeFormat, _culture));
+ }
+ else
+ {
+ throw new JsonSerializationException($"Unexpected value when converting date. Expected DateTime or DateTimeOffset, got {value.GetType()}.");
+ }
+ }
+
+ internal static bool ShouldNormalize(MemberInfo member, JsonProperty property)
+ {
+ if (property.PropertyType != typeof(DateTime) &&
+ property.PropertyType != typeof(DateTime?))
+ {
+ return false;
+ }
+
+ return ReflectionHelper.GetSingleAttributeOfMemberOrDeclaringTypeOrDefault(member) == null;
+ }
+}
diff --git a/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpDefaultContractResolver.cs b/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpDefaultContractResolver.cs
index f39f6af578..131e95d4c2 100644
--- a/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpDefaultContractResolver.cs
+++ b/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpDefaultContractResolver.cs
@@ -9,12 +9,12 @@ namespace Volo.Abp.Json.Newtonsoft;
public class AbpDefaultContractResolver : DefaultContractResolver, ITransientDependency
{
- private readonly Lazy _dateTimeConverter;
+ private readonly Lazy _dateTimeConverter;
public AbpDefaultContractResolver(IServiceProvider serviceProvider)
{
- _dateTimeConverter = new Lazy(
- serviceProvider.GetRequiredService,
+ _dateTimeConverter = new Lazy(
+ serviceProvider.GetRequiredService,
true
);
}
@@ -23,7 +23,7 @@ public class AbpDefaultContractResolver : DefaultContractResolver, ITransientDep
{
var property = base.CreateProperty(member, memberSerialization);
- if (AbpJsonIsoDateTimeConverter.ShouldNormalize(member, property))
+ if (AbpDateTimeConverter.ShouldNormalize(member, property))
{
property.Converter = _dateTimeConverter.Value;
}
diff --git a/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpJsonIsoDateTimeConverter.cs b/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpJsonIsoDateTimeConverter.cs
deleted file mode 100644
index b859688a0d..0000000000
--- a/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpJsonIsoDateTimeConverter.cs
+++ /dev/null
@@ -1,60 +0,0 @@
-using System;
-using System.Reflection;
-using Microsoft.Extensions.Options;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Converters;
-using Newtonsoft.Json.Serialization;
-using Volo.Abp.DependencyInjection;
-using Volo.Abp.Reflection;
-using Volo.Abp.Timing;
-
-namespace Volo.Abp.Json.Newtonsoft;
-
-public class AbpJsonIsoDateTimeConverter : IsoDateTimeConverter, ITransientDependency
-{
- private readonly IClock _clock;
-
- public AbpJsonIsoDateTimeConverter(IClock clock, IOptions abpJsonOptions)
- {
- _clock = clock;
-
- if (abpJsonOptions.Value.DefaultDateTimeFormat != null)
- {
- DateTimeFormat = abpJsonOptions.Value.DefaultDateTimeFormat;
- }
- }
-
- public override bool CanConvert(Type objectType)
- {
- return objectType == typeof(DateTime) || objectType == typeof(DateTime?);
- }
-
- public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
- {
- var date = base.ReadJson(reader, objectType, existingValue, serializer) as DateTime?;
-
- if (date.HasValue)
- {
- return _clock.Normalize(date.Value);
- }
-
- return null;
- }
-
- public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
- {
- var date = value as DateTime?;
- base.WriteJson(writer, date.HasValue ? _clock.Normalize(date.Value) : value, serializer);
- }
-
- internal static bool ShouldNormalize(MemberInfo member, JsonProperty property)
- {
- if (property.PropertyType != typeof(DateTime) &&
- property.PropertyType != typeof(DateTime?))
- {
- return false;
- }
-
- return ReflectionHelper.GetSingleAttributeOfMemberOrDeclaringTypeOrDefault(member) == null;
- }
-}
diff --git a/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpDateTimeConverter.cs b/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpDateTimeConverter.cs
index 417037e776..366a933d13 100644
--- a/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpDateTimeConverter.cs
+++ b/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpDateTimeConverter.cs
@@ -1,5 +1,6 @@
using System;
using System.Globalization;
+using System.Linq;
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.Extensions.Options;
@@ -21,20 +22,23 @@ public class AbpDateTimeConverter : JsonConverter, ITransientDependenc
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
- if (!_options.DefaultDateTimeFormat.IsNullOrWhiteSpace())
+ if (_options.InputDateTimeFormats.Any())
{
if (reader.TokenType == JsonTokenType.String)
{
- var s = reader.GetString();
- if (DateTime.TryParseExact(s, _options.DefaultDateTimeFormat, CultureInfo.CurrentUICulture, DateTimeStyles.None, out var d1))
+ foreach (var format in _options.InputDateTimeFormats)
{
- return _clock.Normalize(d1);
+ var s = reader.GetString();
+ if (DateTime.TryParseExact(s, format, CultureInfo.CurrentUICulture, DateTimeStyles.None, out var d1))
+ {
+ return _clock.Normalize(d1);
+ }
}
-
- throw new JsonException($"'{s}' can't parse to DateTime({_options.DefaultDateTimeFormat})!");
}
-
- throw new JsonException("Reader's TokenType is not String!");
+ else
+ {
+ throw new JsonException("Reader's TokenType is not String!");
+ }
}
if (reader.TryGetDateTime(out var d3))
@@ -47,13 +51,13 @@ public class AbpDateTimeConverter : JsonConverter, ITransientDependenc
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
{
- if (_options.DefaultDateTimeFormat.IsNullOrWhiteSpace())
+ if (_options.OutputDateTimeFormat.IsNullOrWhiteSpace())
{
writer.WriteStringValue(_clock.Normalize(value));
}
else
{
- writer.WriteStringValue(_clock.Normalize(value).ToString(_options.DefaultDateTimeFormat, CultureInfo.CurrentUICulture));
+ writer.WriteStringValue(_clock.Normalize(value).ToString(_options.OutputDateTimeFormat, CultureInfo.CurrentUICulture));
}
}
}
diff --git a/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpNullableDateTimeConverter.cs b/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpNullableDateTimeConverter.cs
index 8b3459fcce..da5983250d 100644
--- a/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpNullableDateTimeConverter.cs
+++ b/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpNullableDateTimeConverter.cs
@@ -1,5 +1,6 @@
using System;
using System.Globalization;
+using System.Linq;
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.Extensions.Options;
@@ -21,20 +22,23 @@ public class AbpNullableDateTimeConverter : JsonConverter, ITransient
public override DateTime? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
- if (!_options.DefaultDateTimeFormat.IsNullOrWhiteSpace())
+ if (_options.InputDateTimeFormats.Any())
{
if (reader.TokenType == JsonTokenType.String)
{
- var s = reader.GetString();
- if (DateTime.TryParseExact(s, _options.DefaultDateTimeFormat, CultureInfo.CurrentUICulture, DateTimeStyles.None, out var d1))
+ foreach (var format in _options.InputDateTimeFormats)
{
- return _clock.Normalize(d1);
+ var s = reader.GetString();
+ if (DateTime.TryParseExact(s, format, CultureInfo.CurrentUICulture, DateTimeStyles.None, out var d1))
+ {
+ return _clock.Normalize(d1);
+ }
}
-
- throw new JsonException($"'{s}' can't parse to DateTime({_options.DefaultDateTimeFormat})!");
}
-
- throw new JsonException("Reader's TokenType is not String!");
+ else
+ {
+ throw new JsonException("Reader's TokenType is not String!");
+ }
}
if (reader.TryGetDateTime(out var d2))
@@ -53,13 +57,13 @@ public class AbpNullableDateTimeConverter : JsonConverter, ITransient
}
else
{
- if (_options.DefaultDateTimeFormat.IsNullOrWhiteSpace())
+ if (_options.OutputDateTimeFormat.IsNullOrWhiteSpace())
{
writer.WriteStringValue(_clock.Normalize(value.Value));
}
else
{
- writer.WriteStringValue(_clock.Normalize(value.Value).ToString(_options.DefaultDateTimeFormat, CultureInfo.CurrentUICulture));
+ writer.WriteStringValue(_clock.Normalize(value.Value).ToString(_options.OutputDateTimeFormat, CultureInfo.CurrentUICulture));
}
}
}
diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Json/JsonResultController_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Json/JsonResultController_Tests.cs
index 851ef88db8..e7015313cb 100644
--- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Json/JsonResultController_Tests.cs
+++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Json/JsonResultController_Tests.cs
@@ -14,7 +14,7 @@ public class JsonResultController_Tests : AspNetCoreMvcTestBase
{
services.Configure(options =>
{
- options.DefaultDateTimeFormat = "yyyy*MM*dd";
+ options.OutputDateTimeFormat = "yyyy*MM*dd";
});
base.ConfigureServices(context, services);
diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Json/JsonSerializer_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Json/JsonSerializer_Tests.cs
index 2f986c89c3..1613e4bb49 100644
--- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Json/JsonSerializer_Tests.cs
+++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Json/JsonSerializer_Tests.cs
@@ -21,7 +21,7 @@ public class JsonSerializer_Tests : AspNetCoreMvcTestBase
{
services.Configure(options =>
{
- options.DefaultDateTimeFormat = "yyyy*MM*dd";
+ options.OutputDateTimeFormat = "yyyy*MM*dd";
});
base.ConfigureServices(context, services);
diff --git a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonSerializerProvider_Tests.cs b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonSerializerProvider_Tests.cs
index f9823e7d65..f605914d6e 100644
--- a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonSerializerProvider_Tests.cs
+++ b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonSerializerProvider_Tests.cs
@@ -220,7 +220,8 @@ public class AbpSystemTextJsonSerializerProvider_DateTimeFormat_Tests : AbpSyste
{
services.Configure(options =>
{
- options.DefaultDateTimeFormat = "yyyy*MM*dd";
+ options.InputDateTimeFormats.Add("yyyy*MM*dd");
+ options.OutputDateTimeFormat = "yyyy*MM*dd HH*mm*ss";
});
}
@@ -233,8 +234,12 @@ public class AbpSystemTextJsonSerializerProvider_DateTimeFormat_Tests : AbpSyste
file.CreationTime.Month.ShouldBe(11);
file.CreationTime.Day.ShouldBe(20);
- var newJson = JsonSerializer.Serialize(file);
- newJson.ShouldBe(json);
+ json = JsonSerializer.Serialize(new FileWithDatetime()
+ {
+ Name = "abp",
+ CreationTime = new DateTime(2020, 11, 20, 12, 34, 56)
+ });
+ json.ShouldContain("\"2020*11*20 12*34*56\"");
}
[Fact]
@@ -256,8 +261,12 @@ public class AbpSystemTextJsonSerializerProvider_DateTimeFormat_Tests : AbpSyste
file.CreationTime.Value.Month.ShouldBe(11);
file.CreationTime.Value.Day.ShouldBe(20);
- var newJson = JsonSerializer.Serialize(file);
- newJson.ShouldBe(json);
+ json = JsonSerializer.Serialize(new FileWithDatetime()
+ {
+ Name = "abp",
+ CreationTime = new DateTime(2020, 11, 20, 12, 34, 56)
+ });
+ json.ShouldContain("\"2020*11*20 12*34*56\"");
}
}