mirror of https://github.com/abpframework/abp.git
committed by
GitHub
8 changed files with 346 additions and 138 deletions
@ -1,84 +1,43 @@ |
|||
using System; |
|||
using System.Globalization; |
|||
using System.Linq; |
|||
using System.Text.Json; |
|||
using System.Text.Json.Serialization; |
|||
using Microsoft.Extensions.Options; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.Timing; |
|||
|
|||
namespace Volo.Abp.Json.SystemTextJson.JsonConverters; |
|||
|
|||
public class AbpDateTimeConverter : JsonConverter<DateTime>, ITransientDependency |
|||
public class AbpDateTimeConverter : AbpDateTimeConverterBase<DateTime>, ITransientDependency |
|||
{ |
|||
private readonly IClock _clock; |
|||
private readonly AbpJsonOptions _options; |
|||
private bool _skipDateTimeNormalization; |
|||
|
|||
public AbpDateTimeConverter(IClock clock, IOptions<AbpJsonOptions> abpJsonOptions) |
|||
public AbpDateTimeConverter( |
|||
IClock clock, |
|||
IOptions<AbpJsonOptions> abpJsonOptions, |
|||
ICurrentTimezoneProvider currentTimezoneProvider, |
|||
ITimezoneProvider timezoneProvider) |
|||
: base(clock, abpJsonOptions, currentTimezoneProvider, timezoneProvider) |
|||
{ |
|||
_clock = clock; |
|||
_options = abpJsonOptions.Value; |
|||
} |
|||
|
|||
public virtual AbpDateTimeConverter SkipDateTimeNormalization() |
|||
{ |
|||
_skipDateTimeNormalization = true; |
|||
IsSkipDateTimeNormalization = true; |
|||
return this; |
|||
} |
|||
|
|||
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) |
|||
{ |
|||
if (_options.InputDateTimeFormats.Any()) |
|||
{ |
|||
if (reader.TokenType == JsonTokenType.String) |
|||
{ |
|||
foreach (var format in _options.InputDateTimeFormats) |
|||
{ |
|||
var s = reader.GetString(); |
|||
if (DateTime.TryParseExact(s, format, CultureInfo.CurrentUICulture, DateTimeStyles.None, out var d1)) |
|||
{ |
|||
return Normalize(d1); |
|||
} |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
throw new JsonException("Reader's TokenType is not String!"); |
|||
} |
|||
} |
|||
|
|||
if (reader.TryGetDateTime(out var d3)) |
|||
{ |
|||
return Normalize(d3); |
|||
} |
|||
|
|||
var dateText = reader.GetString(); |
|||
if (!dateText.IsNullOrWhiteSpace()) |
|||
if (Options.InputDateTimeFormats.Any() && reader.TokenType != JsonTokenType.String) |
|||
{ |
|||
if (DateTime.TryParse(dateText, CultureInfo.CurrentUICulture, DateTimeStyles.None, out var d4)) |
|||
{ |
|||
return Normalize(d4); |
|||
} |
|||
throw new JsonException("Reader's TokenType is not String!"); |
|||
} |
|||
|
|||
throw new JsonException("Can't get datetime from the reader!"); |
|||
return TryReadDateTime(ref reader, out var result) |
|||
? result |
|||
: throw new JsonException("Can't get datetime from the reader!"); |
|||
} |
|||
|
|||
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) |
|||
{ |
|||
if (_options.OutputDateTimeFormat.IsNullOrWhiteSpace()) |
|||
{ |
|||
writer.WriteStringValue(Normalize(value)); |
|||
} |
|||
else |
|||
{ |
|||
writer.WriteStringValue(Normalize(value).ToString(_options.OutputDateTimeFormat, CultureInfo.CurrentUICulture)); |
|||
} |
|||
} |
|||
|
|||
protected virtual DateTime Normalize(DateTime dateTime) |
|||
{ |
|||
return _skipDateTimeNormalization ? dateTime : _clock.Normalize(dateTime); |
|||
WriteDateTime(writer, value); |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,116 @@ |
|||
using System; |
|||
using System.Globalization; |
|||
using System.Linq; |
|||
using System.Text.Json; |
|||
using System.Text.Json.Serialization; |
|||
using Microsoft.Extensions.Logging; |
|||
using Microsoft.Extensions.Logging.Abstractions; |
|||
using Microsoft.Extensions.Options; |
|||
using Volo.Abp.Timing; |
|||
|
|||
namespace Volo.Abp.Json.SystemTextJson.JsonConverters; |
|||
|
|||
public abstract class AbpDateTimeConverterBase<T> : JsonConverter<T> |
|||
{ |
|||
public ILogger<AbpDateTimeConverterBase<T>> Logger { get; set; } |
|||
|
|||
protected IClock Clock { get; } |
|||
protected AbpJsonOptions Options { get; } |
|||
protected ICurrentTimezoneProvider CurrentTimezoneProvider { get; } |
|||
protected ITimezoneProvider TimezoneProvider { get; } |
|||
protected bool IsSkipDateTimeNormalization { get; set; } |
|||
|
|||
protected AbpDateTimeConverterBase( |
|||
IClock clock, |
|||
IOptions<AbpJsonOptions> abpJsonOptions, |
|||
ICurrentTimezoneProvider currentTimezoneProvider, |
|||
ITimezoneProvider timezoneProvider) |
|||
{ |
|||
Logger = NullLogger<AbpDateTimeConverterBase<T>>.Instance; |
|||
|
|||
Clock = clock; |
|||
CurrentTimezoneProvider = currentTimezoneProvider; |
|||
TimezoneProvider = timezoneProvider; |
|||
Options = abpJsonOptions.Value; |
|||
} |
|||
|
|||
protected bool TryReadDateTime(ref Utf8JsonReader reader, out DateTime value) |
|||
{ |
|||
value = default; |
|||
|
|||
if (Options.InputDateTimeFormats.Any()) |
|||
{ |
|||
if (reader.TokenType != JsonTokenType.String) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
var s = reader.GetString(); |
|||
foreach (var format in Options.InputDateTimeFormats) |
|||
{ |
|||
if (!DateTime.TryParseExact(s, format, CultureInfo.CurrentUICulture, DateTimeStyles.None, out var d1)) |
|||
{ |
|||
continue; |
|||
} |
|||
|
|||
value = Normalize(d1); |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
if (reader.TryGetDateTime(out var d2)) |
|||
{ |
|||
value = Normalize(d2); |
|||
return true; |
|||
} |
|||
|
|||
var dateText = reader.GetString(); |
|||
if (dateText.IsNullOrWhiteSpace()) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
if (!DateTime.TryParse(dateText, CultureInfo.CurrentUICulture, DateTimeStyles.None, out var d3)) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
value = Normalize(d3); |
|||
return true; |
|||
|
|||
} |
|||
|
|||
protected void WriteDateTime(Utf8JsonWriter writer, DateTime value) |
|||
{ |
|||
if (Options.OutputDateTimeFormat.IsNullOrWhiteSpace()) |
|||
{ |
|||
writer.WriteStringValue(Normalize(value)); |
|||
} |
|||
else |
|||
{ |
|||
writer.WriteStringValue(Normalize(value).ToString(Options.OutputDateTimeFormat, CultureInfo.CurrentUICulture)); |
|||
} |
|||
} |
|||
|
|||
protected virtual DateTime Normalize(DateTime dateTime) |
|||
{ |
|||
if (dateTime.Kind != DateTimeKind.Unspecified || |
|||
!Clock.SupportsMultipleTimezone || |
|||
CurrentTimezoneProvider.TimeZone.IsNullOrWhiteSpace()) |
|||
{ |
|||
return IsSkipDateTimeNormalization ? dateTime : Clock.Normalize(dateTime); |
|||
} |
|||
|
|||
try |
|||
{ |
|||
var timezoneInfo = TimezoneProvider.GetTimeZoneInfo(CurrentTimezoneProvider.TimeZone); |
|||
dateTime = new DateTimeOffset(dateTime, timezoneInfo.GetUtcOffset(dateTime)).UtcDateTime; |
|||
} |
|||
catch |
|||
{ |
|||
Logger.LogWarning("Could not convert DateTime with unspecified Kind using timezone '{TimeZone}'.", CurrentTimezoneProvider.TimeZone); |
|||
} |
|||
|
|||
return IsSkipDateTimeNormalization ? dateTime : Clock.Normalize(dateTime); |
|||
} |
|||
} |
|||
Loading…
Reference in new issue