Как десериализовать метку времени Unix (мкс) в DateTime из JSON?
JSON
{
"title":"Mozilla Firefox",
"id":24,
"parent":2,
"dateAdded":1356753810000000,
"lastModified":1356753810000000,
"type":"text/x-moz-place-container",
"children":[]
}
С#
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);
}
Я получаю исключение, когда пытаюсь запустить это,
Дополнительная информация: Ошибка чтения даты. Неожиданный токен: Integer. Путь 'dateAdded'
Я подумал, что с помощью JavaScriptDateTimeConverter
JSON.NET сможет выяснить, как десериализовать эти временные метки Unix ( Миз мкс с эпохи). Какой самый простой способ сделать это?
Возникли проблемы с поиском документации по конвертерам... вероятно, было бы не сложно написать ее самостоятельно, если это необходимо.
Изменить: Это на самом деле микросекунды, а не миллисекунды.
Ответы
Ответ 1
Я очистил решение 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);
}
}
Ответ 2
Вы можете создать настраиваемый конвертер DateTime
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;
Ответ 3
Существует встроенный способ преобразования метки времени 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)
, а не метки времени Unix из OP.
Я понимаю, что этому вопросу уже несколько лет, поэтому весьма вероятно, что этот класс был добавлен после того, как этот вопрос был задан, но это может помочь любому, кто сталкивается с той же проблемой.
Ответ 4
Хммм... сложный бит заключается в том, что конструктор 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
.
Ответ 5
Вот как я это сделал и это сработало
задавать;}
В моей модели у меня есть открытое свойство типа Long, которое получает дату из API в формате JSON. set;} var dateTime = new DateTime (1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); TimeToBeShown = dateTime.AddSeconds(somethingfromloop.CreatedTime).ToLocalTime(); Привязка к TimeToBeShow в Xaml