57

JSON

{
   "title":"Mozilla Firefox",
   "id":24,
   "parent":2,
   "dateAdded":1356753810000000,
   "lastModified":1356753810000000,
   "type":"text/x-moz-place-container",
   "children":[]
}

C#

class Bookmark
{
    public string title;
    public string id;
    [JsonProperty(ItemConverterType = typeof(JavaScriptDateTimeConverter))]
    public DateTime dateAdded;
    [JsonProperty(ItemConverterType = typeof(JavaScriptDateTimeConverter))]
    public DateTime lastModified;
    public string type;
    public string root;
    public long parent;
    public List<Bookmark> children;
}

private static void Main(string[] args)
{
    var json = File.ReadAllText(@"T:/bookmarks-2013-11-13.json");
    var bookmarks = JsonConvert.DeserializeObject<Bookmark>(json);
}

当我尝试运行它时出现异常,

附加信息:错误读取日期。意外标记:整数。路径“添加日期”

我认为通过使用JavaScriptDateTimeConverterJSON.NET 可以弄清楚如何反序列化那些 unix 时间戳(小姐自纪元以来的μs)。最简单的方法是什么?

无法找到有关转换器的文档……如果有必要,自己编写一个文档可能不会太难。

编辑:这些实际上是微秒,而不是毫秒。

4

7 回答 7

69

我稍微清理了Cris 的解决方案WriteJson并实施了:

class Bookmark
{
    public string title;
    public long id;
    [JsonConverter(typeof(MicrosecondEpochConverter))]
    public DateTime dateAdded;
    [JsonConverter(typeof(MicrosecondEpochConverter))]
    public DateTime lastModified;
    public string type;
    public string root;
    public long parent;
    public List<Bookmark> children;
    public string uri;

    public override string ToString()
    {
        return string.Format("{0} - {1}", title, uri);
    }
}

public class MicrosecondEpochConverter : DateTimeConverterBase
{
    private static readonly DateTime _epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        writer.WriteRawValue(((DateTime)value - _epoch).TotalMilliseconds + "000");
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.Value == null) { return null; }
        return _epoch.AddMilliseconds((long)reader.Value / 1000d);
    }
}

internal class Program
{

    private static void Main(string[] args)
    {
        var jsonString = File.ReadAllText(@"T:/bookmarks-2013-11-13.json");
        var rootMark = JsonConvert.DeserializeObject<Bookmark>(jsonString);
        var ret = JsonConvert.SerializeObject(rootMark);
    }
}
于 2013-11-14T07:44:35.087 回答
51

有一种内置方法可以将 unix 时间戳转换为 DateTime,而无需编写自己的类:

[JsonConverter(typeof(UnixDateTimeConverter))]
public DateTime lastModified;

https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_Converters_UnixDateTimeConverter.htm

Cris 的答案中的注释不正确,因为JavaScriptDateTimeConverter格式Date(52231943)而不是 OP 的 Unix 时间戳。

我意识到这个问题现在已经有几年了,所以自从提出这个问题以来,很可能已经添加了这个类,但这可能会帮助遇到同样问题的任何人。

于 2018-02-26T02:38:29.427 回答
44

您可以创建自定义日期时间转换器

  var bookmarks = JsonConvert.DeserializeObject<Bookmark>(json,
                                                      new MyDateTimeConverter());

public class MyDateTimeConverter : Newtonsoft.Json.JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(DateTime);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var t = long.Parse((string)reader.Value);
        return new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddMilliseconds(t);
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

另一种方法是对类成员进行双重注释,

[JsonProperty(PropertyName="dateAdded")] 
[JsonConverter(typeof(JavaScriptDateTimeConverter))]
public DateTime dateAdded;
于 2013-11-14T07:16:46.840 回答
6

我想System.Text.Json根据接受的答案为 .Net 核心添加一个解决方案。 在撰写本文时已在 3.1 中验证。

public class UnixDateTimeConverter : JsonConverter<DateTime>
{
   public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
   {
       return DateTime.UnixEpoch.AddSeconds(reader.GetInt64());
   }

   public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
   {
       writer.WriteStringValue((value - DateTime.UnixEpoch).TotalMilliseconds + "000");
   }
}

然后,您可以使用数据注释应用它

[JsonConverter(typeof(UnixDateTimeConverter))]
public DateTime MyDateTime {get;set;}
于 2020-09-14T13:08:49.757 回答
2

嗯......棘手的一点是 DateTime 构造函数不接受时间戳作为参数。

这是本文的解决方案:如何将 Unix 时间戳转换为 DateTime,反之亦然?

public static DateTime UnixTimeStampToDateTime( double unixTimeStamp )
{
    // Unix timestamp is seconds past epoch
    System.DateTime dtDateTime = new DateTime(1970,1,1,0,0,0,0);
    dtDateTime = dtDateTime.AddSeconds( unixTimeStamp ).ToLocalTime();
    return dtDateTime;
}

你必须调用它,最好是在你的类中使用默认构造函数,或者在它的get方法中使用另一个属性来返回它。

于 2013-11-14T07:18:15.740 回答
0

与 Bryan 的回答类似,这里有一个System.Text.Json反序列化变体,它支持更多选项。

  • 以秒或毫秒为单位定义的 Unix 时间。假设:秒 < 9999 年(最大日期时间)和毫秒 > 1978。
  • 可空日期时间
public class UnixToNullableDateTimeConverter : JsonConverter<DateTime?>
{
    public override bool HandleNull => true;
    public bool? IsFormatInSeconds { get; set; } = null;

    public override DateTime? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        if (reader.TryGetInt64(out var time))
        {
            // if 'IsFormatInSeconds' is unspecified, then deduce the correct type based on whether it can be represented in the allowed .net DateTime range
            if (IsFormatInSeconds == true || IsFormatInSeconds == null && time > _unixMinSeconds && time < _unixMaxSeconds)
                return DateTimeOffset.FromUnixTimeSeconds(time).LocalDateTime;
            return DateTimeOffset.FromUnixTimeMilliseconds(time).LocalDateTime;
        }

        return null;
    }

    public override void Write(Utf8JsonWriter writer, DateTime? value, JsonSerializerOptions options) => throw new NotSupportedException();

    private static readonly long _unixMinSeconds = DateTimeOffset.MinValue.ToUnixTimeSeconds() - DateTimeOffset.UnixEpoch.ToUnixTimeSeconds(); // -62_135_596_800
    private static readonly long _unixMaxSeconds = DateTimeOffset.MaxValue.ToUnixTimeSeconds() - DateTimeOffset.UnixEpoch.ToUnixTimeSeconds(); // 253_402_300_799
}
于 2021-12-05T01:48:58.403 回答
-1

我就是这样做的,而且效果很好

在我的 ViewModel 中,我有一个 DateTime 类型的公共属性

Public DateTime TimeToBeShown {get; set;}

在我的模型中,我有 Long 类型的公共属性,它以 JSON 格式从 API 获取日期。

Public long DateThatIsComingAsJsonFormat {get; set;}
     var dateTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
     TimeToBeShown=dateTime.AddSeconds(somethingfromloop.CreatedTime).ToLocalTime();
Bind to TimeToBeShown in Xaml



于 2019-06-27T16:40:28.857 回答