簡體   English   中英

使用 Json.Net 以 dd/MM/yyyy 格式反序列化日期

[英]Deserializing dates with dd/MM/yyyy format using Json.Net

我正在嘗試將對象從 JSON 數據反序列化為 C# 類(我正在使用 Newtonsoft Json.NET)。 數據包含作為字符串值的日期,例如09/12/2013 ,格式為dd/MM/yyyy

如果我調用JsonConvert.DeserializeObject<MyObject>(data) ,日期會以MM/dd/yyyy格式加載到 C# 類的DateTime屬性中,這會導致日期值為 2013 年 9 月12 September 2013 (而不是 2013 年 12 月9 December 2013 ) .

是否可以配置JsonConvert以獲取正確格式的日期?

您可以使用IsoDateTimeConverter並指定DateTimeFormat以獲得所需的結果,例如:

MyObject obj = JsonConvert.DeserializeObject<MyObject>(jsonString, 
                   new IsoDateTimeConverter { DateTimeFormat = "dd/MM/yyyy" });

演示:

class Program
{
    static void Main(string[] args)
    {
        string json = @"{ ""Date"" : ""09/12/2013"" }";

        MyObject obj = JsonConvert.DeserializeObject<MyObject>(json, 
            new IsoDateTimeConverter { DateTimeFormat = "dd/MM/yyyy" });

        DateTime date = obj.Date;
        Console.WriteLine("day = " + date.Day);
        Console.WriteLine("month = " + date.Month);
        Console.WriteLine("year = " + date.Year);
    }
}

class MyObject
{
    public DateTime Date { get; set; }
}

輸出:

day = 9
month = 12
year = 2013

開始部分是關於 NewtownSoft 轉換器,重置是關於 .Net Core Json 序列化器,因為我第一次寫這個答案時沒有微軟序列化器

注意:NewtownSoft 和 Microsoft 有很多重疊的名稱,請確保使用正確的命名空間

Newtownsoft 序列化器:

多格式支持:

這就是我使用的:

public class CustomDateTimeConverter : IsoDateTimeConverter
{
    public CustomDateTimeConverter()
    {
        base.DateTimeFormat = "dd/MM/yyyy";
    }
}

然后你會這樣做:

public class MyObject
{
    [JsonConverter(typeof(CustomDateTimeConverter))]
    public DateTime Date {get;set;}
}

然后使用你以前做過的任何正常方式反序列化......

MyObject obj = JsonConvert.DeserializeObject<MyObject>(json);

選擇

其他方式與@pimbrouwers 所說的相同:

public class MyObject
{
    [JsonProperty("Date")] //Naturally Case Sensetive
    private string dateJson {get;set;}
    // it would be good to look at @pimbrouwers answer and use nullable
    [JsonIgnore]
    public DateTime Date
    {
        get
        {
            return DateTime.ParseExact(dateJson,"dd/MM/yyyy",CultureInfo.InvariantCulture);
        }
        set
        {
            dateJson = value.ToString("dd/MM/yyyy");
        }
    }

}

自定義日期時間轉換器

我也只是寫這個,自定義日期時間轉換器,它將匹配您的自定義超出范圍格式或日歷

public class CustomDateTimeConverterJalali : DateTimeConverterBase
{
    //I had no use for WriteJson section, i just wrote it, so i do not guarantee it working
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        if (value == null)
        {
            writer.WriteNull();
            return;
        }

        var nullableType = Nullable.GetUnderlyingType(value.GetType());
        var isNullable = nullableType != null;

        DateTime date;
        if (isNullable)
            date = ((DateTime?) value).Value;
        else
            date = (DateTime) value;


        PersianCalendar pc = new PersianCalendar();

        writer.WriteValue(pc.GetYear(date) + "/" + pc.GetMonth(date) + "/" + pc.GetDayOfMonth(date));
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        //this should likely be null, but since the provider json returned empty string, it was unavoidable... (i'm not sure what we will read using reader, if data is actually null on the json side, feel free to experiment 
        if (string.IsNullOrWhiteSpace((string) reader.Value))
        {
            return null;
        }

        var strDate = reader.Value.ToString();

        PersianCalendar pc = new PersianCalendar();
        var dateParts = strDate.Split('/');

        DateTime date = pc.ToDateTime(int.Parse(dateParts[0]), int.Parse(dateParts[1]), int.Parse(dateParts[2]),
            0, 0, 0, 0);

        return date;
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(DateTime);//DateTime=>true | DateTime?=>true
    }
}

筆記:

您提供的其他方式是一次性配置的,可能更簡單,並且在大多數情況下都可以使用,......但是在這里,提供者為我提供了一項服務,它在每個對象中提供兩種格式的日期,並且其中一個對象在不同的​​日歷中提供了兩個日期......所以很高興知道我在這里提供的這兩種方式

微軟序列化器:

[ASP.NET CORE MVC] 自定義 DateTimeConverter(通過默認 JSON 序列化程序):

請注意,JSON 轉換器的 Microsoft 實現與 NewtownSoft 實現不同。 我希望 NewtownSoft 的旗幟不會很快倒下,因為他們把所有的生命都放在了上面,但是人們傾向於使用那些當權者的圖書館,所以就在這里。

請注意,Microsoft 實現要求您分別實現每種類型的數據,包括 Nullable 和 non-Nullable。

我是這樣做的,我創建了一個包含所有共享內容的基類,然后為每個版本創建一個簡單的派生類。

基地:

using System;
using System.Buffers;
using System.Buffers.Text;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace Charter724.Helper.JsonConverter.Microsoft
{
    /// <summary>
    /// Base Custom Format DateTime Handler <br/>
    /// using System.Text.Json.Serialization;
    /// </summary>
    [SuppressMessage("ReSharper", "RedundantBaseQualifier")]
    public class MsBaseDateTimeConverter<T> : JsonConverter<T>
    {
        private const string DefaultDateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFFK";

        private readonly string _format;
        private readonly CultureInfo _culture;
        private readonly DateTimeStyles _dateTimeStyles;

        public MsBaseDateTimeConverter(string format, CultureInfo culture = null, DateTimeStyles dateTimeStyles= DateTimeStyles.RoundtripKind)
        {
            _format = format;

            if (culture == null)
            {
                _culture = CultureInfo.CurrentCulture;
            }

            _dateTimeStyles = dateTimeStyles;

        }

        public override bool CanConvert(Type typeToConvert)
        {
            if (typeToConvert == typeof(DateTime) || typeToConvert == typeof(DateTime?))
            {
                return true;
            }

            return false;
        }

        public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            bool nullable = ReflectionUtils.IsNullableType(typeToConvert);
            if (reader.TokenType == JsonTokenType.Null)
            {
                if (!nullable)
                {
                    throw new JsonException();
                }

                return default;
            }

            if (_format != null)
            {
                if (DateTime.TryParseExact(reader.GetString(), _format, _culture, _dateTimeStyles,
                    out var dtValue))
                {
                    return (T) (object) dtValue;
                }

                throw new JsonException();
            }
            else
            {
                // try to parse number directly from bytes
                ReadOnlySpan<byte> span = reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan;
                if (Utf8Parser.TryParse(span, out DateTime dtValue, out int bytesConsumed) &&
                    span.Length == bytesConsumed)
                    return (T) (object) dtValue;

                // try to parse from a string if the above failed, this covers cases with other escaped/UTF characters
                if (DateTime.TryParse(reader.GetString(), out dtValue))
                    return (T) (object) dtValue;

                return (T) (object) reader.GetDateTime();
            }
        }

        public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
        {
            if (value != null)
            {
                if (value is DateTime dateTime)
                {
                    if ((_dateTimeStyles & DateTimeStyles.AdjustToUniversal) == DateTimeStyles.AdjustToUniversal
                        || (_dateTimeStyles & DateTimeStyles.AssumeUniversal) == DateTimeStyles.AssumeUniversal)
                    {
                        dateTime = dateTime.ToUniversalTime();
                    }

                    var text = dateTime.ToString(_format ?? DefaultDateTimeFormat, _culture);
                    writer.WriteStringValue(text);
                }
                else
                {
                    throw new JsonException();
                }
                return;
            }

            writer.WriteNullValue();

        }
    }
}

不可為空的派生項:

using System;
using System.Diagnostics.CodeAnalysis;

namespace Charter724.Helper.JsonConverter.Microsoft
{
    /// <summary>
    /// Format: yyyy-MM-dd - NOT NULL <br/>
    /// Microsoft <br/>
    /// using System.Text.Json.Serialization;
    /// </summary>
    [SuppressMessage("ReSharper", "RedundantBaseQualifier")]
    public class MsCustomDateTimeConverter : MsBaseDateTimeConverter<DateTime>
    {
        public MsCustomDateTimeConverter():base("yyyy-MM-dd")
        {
            //base.DateTimeFormat = "yyyy-MM-dd";
        }
    }
}

可空值的派生值:

using System;
using System.Diagnostics.CodeAnalysis;

namespace Charter724.Helper.JsonConverter.Microsoft
{
    /// <summary>
    /// Format: yyyy-MM-dd - NULLABLE <br/>
    /// Microsoft <br/>
    /// using System.Text.Json.Serialization;
    /// </summary>
    [SuppressMessage("ReSharper", "RedundantBaseQualifier")]
    public class MsCustomDateTimeConverterNullable : MsBaseDateTimeConverter<DateTime?>
    {
        public MsCustomDateTimeConverterNullable():base("yyyy-MM-dd")
        {
            //base.DateTimeFormat = "yyyy-MM-dd";
        }
    }
}

使用詳情:

public class MyObject
{
    [System.Text.Json.Serialization.JsonConverter(typeof(MsCustomDateTimeConverter))]
    public DateTime Date { set; get; }
}

選擇:

我沒有測試 microsoft 版本是否也支持帶有 JsonProperty 的私有成員,但是由於 EF Core 在這件事上失敗了,我只想說明這件事,以防它不起作用。

public class MyObject
{
    [JsonProperty("Date")] //Naturally Case Sensetive
    private string dateJson {get;set;}
    // it would be good to look at @pimbrouwers answer and use nullable
    [JsonIgnore]
    public DateTime Date
    {
        get
        {
            return DateTime.ParseExact(dateJson,"dd/MM/yyyy",CultureInfo.InvariantCulture);
        }
        set
        {
            dateJson = value.ToString("dd/MM/yyyy");
        }
    }

}

兩種序列化方法的並行使用:

兩種環境中的轉換器(MVC 核心默認串行器和 NewtownSoft)

使用轉換器 在使用相同模型的兩個環境中,您所要做的就是應用 NewtownSoft 和 Default 序列化器的兩個屬性,這兩個不會干擾並且工作正常。 只要確保你的接口是正確的。

public class MyObject
{
    [System.Text.Json.Serialization.JsonConverter(typeof(MsCustomDateTimeConverter))]
    [Newtonsoft.Json.JsonConverter(typeof(NsCustomDateTimeConverter))]
    public DateTime Date { set; get; }
}
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

var dateTimeConverter = new IsoDateTimeConverter { DateTimeFormat = "dd/MM/yyyy" };
myObject obj = JsonConvert.DeserializeObject<myObject>(myJSONString, dateTimeConverter);

也可以在 JsonSerializer 中配置:

var serializer = new JsonSerializer
{
    DateFormatString = "dd/MM/yyyy"
};

在 WebConfig 中添加文化:

<system.web>
   <globalization culture="pt-BR" uiCulture="pt-BR" enableClientBasedCulture="true"/>
</system.web>

然后在WebApiConfig.cs文件中添加下面的代碼片段

var jsonFormatter =  GlobalConfiguration.Configuration.Formatters.JsonFormatter;
JsonSerializerSettings jSettings = new JsonSerializerSettings()
{
   Culture = System.Globalization.CultureInfo.CurrentCulture
};

jsonFormatter.SerializerSettings = jSettings;

文化pt-BR與默認的dd-MM-yyyy一起使用,如果您不想將文化放在 WebConfig 中,則可以僅為該對象創建一個實例。

根據newtonsoft ,您可以將JsonSerializerSettings 類

日期格式字符串

場地 。 我也以同樣的方式在我的項目中進行以下操作。

string json = @"[
 '7 December, 2009',
 '1 January, 2010',
 10 February, 2010'
]";

IList<DateTime> dateList = JsonConvert.DeserializeObject<IList<DateTime>>(json, new 
JsonSerializerSettings
{
    DateFormatString = "d MMMM, yyyy"
});

foreach (DateTime dateTime in dateList)
{
   Console.WriteLine(dateTime.ToLongDateString());
}
// Monday, 07 December 2009
// Friday, 01 January 2010
// Wednesday, 10 February 2010

根據我的經驗,最簡單的解決方案始終是在您的 CLR 對象 ( MyObject ) 上添加一個string屬性,以供 JSON.Net 使用。 同樣在您的對象上放置一個DateTime屬性,僅作為 getter,它將解析您使用 JSON.Net 以您期望的格式反序列化的日期時間字符串。

這使您可以使用開箱即用的反序列化器,並依靠良好的老式 c# 來完成工作。 沒有混亂,沒有大驚小怪。

public class MyObject
{
    public string dtStr { get; set; }
    public DateTime? dt
    {
        get
        {
            DateTime? d = null;

            if (!string.IsNullOrWhiteSpace(dtStr) && DateTime.TryParseExact(dtStr, "dd/mm/yyyy", CultureInfo.InvariantCultureDateTimeStyles.None, out d)
            {
                return d;
            }

            return d;
        }
    }
}

實際上,上面提到的都沒有完全解決我的問題。 我發現if any of my column data is null then NewtonSoft.JSON will suffer. 我的情況是我有一個從服務序列化並在 UI 中反序列化的數據集,但沒有提供任何設置 我所做的基本上是在服務(JsonConvert.SerializeObject)和 UI(JsonConvert.DeserializeObject)中添加以下設置

 var settings = new JsonSerializerSettings
 {
       Culture = new System.Globalization.CultureInfo("tr-TR"),
       DateFormatString = "dd.MM.yyyy",
       NullValueHandling = NullValueHandling.Ignore
 };

編輯:當我執行上述操作時, Newtonsoft將在反序列化時更改我的列順序 因此,我只是使用下面的代碼更改service層中的serialize設置,而不是這些設置,然后一切都開始按我的預期工作。

string serializedDataSet= JsonConvert.SerializeObject(dataset, Formatting.Indented, new IsoDateTimeConverter { DateTimeFormat = "dd.MM.yyyy" });

基於@pim的回答,這是我的解決方案:

void Main()
{
  var value = "{\"availableFrom\":\"2022-01-01\",\"availableTo\":\"null\"}";
  var dates = Newtonsoft.Json.JsonConvert.DeserializeObject<ItemOptionAvailablePeriod>(value);
  value.Dump();
  dates.Dump();
}

public class ItemOptionAvailablePeriod
{
  private string _format = "yyyy-MM-dd";
  
  public string AvailableFrom { get; set; }
  public string AvailableTo{ get; set; }
  public DateTime? AvailableFromDate
  {
    get
    {
      if(!string.IsNullOrEmpty(AvailableFrom) && DateTime.TryParseExact(AvailableFrom, _format, CultureInfo.InvariantCulture, DateTimeStyles.None, out var d)) {
        return d;
      }
      return null;
    }
  }
  public DateTime? AvailableToDate
  {
    get
    {
      if (!string.IsNullOrEmpty(AvailableTo) && DateTime.TryParseExact(AvailableTo, _format, CultureInfo.InvariantCulture, DateTimeStyles.None, out var d))
      {
        return d;
      }
      return null;
    }
  }
}

.Dump() 部分:

在此處輸入圖像描述

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM