【问题标题】:Deserializing dates with dd/MM/yyyy format using Json.Net使用 Json.Net 以 dd/MM/yyyy 格式反序列化日期
【发布时间】:2014-01-21 10:58:22
【问题描述】:

我正在尝试将 JSON 数据中的对象反序列化为 C# 类(我使用的是 Newtonsoft Json.NET)。数据包含日期为字符串值,如09/12/2013,格式为dd/MM/yyyy。

如果我打电话给JsonConvert.DeserializeObject<MyObject>(data), 日期以MM/dd/yyyy 格式加载到C# 类的DateTime 属性,这会导致日期值为12 September 2013(而不是9 December 2013)。

是否可以配置JsonConvert 以获取正确格式的日期?

【问题讨论】:

    标签: c# json json.net


    【解决方案1】:

    您可以使用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
    

    【讨论】:

      【解决方案2】:

      开始部分是关于 NewtownSoft 转换器,重置是关于 .Net Core Json Serializer,因为我第一次写这个答案时没有 Microsoft 序列化器

      注意: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 的旗帜不会很快倒下,因为他们把所有的生命都放在了上面,但是人们倾向于使用那些当权者的图书馆,所以就在这里。

      注意另外,微软的实现要求您分别实现包括 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 在这件事上失败了,我只是想指出这件事,以防它不起作用。 em>

      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; }
      }
      

      【讨论】:

        【解决方案3】:
        using Newtonsoft.Json;
        using Newtonsoft.Json.Converters;
        
        var dateTimeConverter = new IsoDateTimeConverter { DateTimeFormat = "dd/MM/yyyy" };
        myObject obj = JsonConvert.DeserializeObject<myObject>(myJSONString, dateTimeConverter);
        

        【讨论】:

          【解决方案4】:

          也可以在JsonSerializer中配置:

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

          【讨论】:

          • 多亏了这个,我来了:public static T FromJSON&lt;T&gt;(this string str) { var serializer = new JsonSerializer {DateFormatString = "dd-MM-yyyy"}; return serializer.Deserialize&lt;T&gt;(new JsonTextReader(new StringReader(str))); }
          【解决方案5】:

          在 WebConfig 中添加文化:

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

          然后在WebApiConfig.cs文件中添加下面的代码sn-p

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

          文化pt-BR 与默认的dd-MM-yyyy 一起使用,如果您不想将文化放入WebConfig,您可以仅为该对象创建一个实例。

          【讨论】:

            【解决方案6】:

            根据newtonsoft,您可以将JsonSerializerSettings Class 与

            日期格式字符串

            字段。我也在我的项目中以同样的方式进行。

            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
            

            【讨论】:

              【解决方案7】:

              根据我的经验,最简单和最简单的解决方案始终是在您的 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;
                      }
                  }
              }
              

              【讨论】:

                【解决方案8】:

                其实上面提到的都没有完全解决我的问题。我发现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" });
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2016-01-02
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多