วิธีดีซีเรียลไลซ์การประทับเวลา unix (μs) เป็น DateTime จาก 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);
}

ฉันได้รับข้อยกเว้นเมื่อฉันพยายามเรียกใช้สิ่งนี้

ข้อมูลเพิ่มเติม: เกิดข้อผิดพลาดในการอ่านวันที่ โทเค็นที่ไม่คาดคิด: จำนวนเต็ม เส้นทาง 'วันที่เพิ่ม'

ฉันคิดว่าการใช้ JavaScriptDateTimeConverter ทำให้ JSON.NET สามารถหาวิธีดีซีเรียลไลซ์การประทับเวลายูนิกซ์เหล่านั้นได้ (ms μs ตั้งแต่ยุค) วิธีที่ง่ายที่สุดในการทำเช่นนี้คืออะไร?

มีปัญหาในการหาเอกสารเกี่ยวกับตัวแปลง... การเขียนด้วยตัวเองก็คงไม่ยากเกินไปหากจำเป็น

แก้ไข: จริงๆ แล้วคือหน่วยไมโครวินาที ไม่ใช่มิลลิวินาที


person mpen    schedule 14.11.2013    source แหล่งที่มา
comment
นี่เป็นคำถามที่คุ้มค่าอย่างยิ่งเนื่องจากเวลาของยูนิกซ์เป็นเพียงการนำเสนอที่ต้านทานข้อบกพร่องของ JS อย่างสมบูรณ์เกี่ยวกับเขตเวลา   -  person Peter Wone    schedule 14.11.2013


คำตอบ (6)


ฉันทำความสะอาดโซลูชันของ 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);
    }
}
person mpen    schedule 14.11.2013
comment
น่าทำความสะอาดนะ คุณยังสามารถใส่ฟิลด์ _epoch แบบคงที่เพื่อเพิ่มการใช้หน่วยความจำบิตได้ - person Charles HETIER; 18.11.2014
comment
แก้ไขโค้ดเพื่อจัดการ DateTime? AKA Nullable DateTime DateTimeConverterBase สามารถแปลงทั้ง DateTime และ DateTime ได้หรือไม่ - person Jess; 23.06.2015
comment
ขอบคุณ ขอโทษ! เช่นเดียวกับหมายเหตุเพิ่มเติมสำหรับทุกคนที่ถูกจับได้ - OP ขอตัวแปลงจาก unix MICRO วินาทีเป็น C# Datetime ฉันคิดอย่างโง่เขลาว่าเวลายุคนั้นถูกกำหนดเป็นไมโครวินาทีเสมอมาตั้งแต่ปี 1970 แต่โดยปกติจะแสดงเป็นวินาที (en.wikipedia .org/wiki/Unix_time) ดังนั้นเมื่อฉันใช้ตัวแปลงนี้ ทุกอย่างก็ผิด ทำให้ฉันสับสนอยู่พักหนึ่ง ^_^ - person Ryan; 27.01.2016
comment
@ไรอันแน่นอน PHP และภาษาอื่นๆ ส่วนใหญ่ใช้เวลาไม่กี่วินาทีนับตั้งแต่ยุค JavaScript จะใช้มิลลิวินาทีในยุค แต่ด้วยเหตุผลบางอย่าง Firefox จึงตัดสินใจจัดเก็บบุ๊กมาร์กของพวกเขาเป็นไมโครวินาทีนับตั้งแต่ยุค - person mpen; 28.01.2016
comment
@mpen - ข้อมูลของฉันเข้ามาเป็นสตริงที่แสดงถึงความยาว (จาก Instagram) Convert.ToInt64 จะดีกว่า (long)reader.Value หรือไม่ อย่างอื่นทำงานได้อย่างสมบูรณ์แบบ - person alex; 15.01.2017
comment
@alex เอ่อ ... C # ของฉันเป็นสนิมแล้วตอนนี้ ฉันคิดว่าคุณต้องแปลงมันแทนที่จะโยนมันถ้ามันมาจากสตริง - person mpen; 15.01.2017
comment
ใช้งานได้ ฉันเปลี่ยนค่าส่งคืนบน ReadJson เป็น _epoch.AddMilliseconds((long)reader.Value); เพื่อทำให้ค่าแบบยาวเป็นอนุกรมที่มาจาก Java Timestamp - person Juan; 10.12.2018
comment
@Juan หากคุณต้องการมิลลิวินาทีแทนที่จะเป็นไมโครวินาที คุณควรลบ + "000" ใน WriteJson ด้วย - person mpen; 11.12.2018
comment
หากใครสงสัยว่าเหตุใดจึงไม่ทำงาน ตรวจสอบให้แน่ใจว่าคุณใช้เนมสเปซ Newtonsoft.Json เดียวกันสำหรับคำอธิบายประกอบ [JsonConverter] ในคลาสข้อมูล - person Zoltán Barics; 27.07.2020
comment
@ ZoltánBaricsค่อนข้างแน่ใจว่าฉันไม่ได้ใช้ NewtonSoft สำหรับสิ่งนี้ ควรจะเป็น System.Text.Json.Serialization.JsonConverter - person mpen; 28.07.2020

คุณสามารถสร้างตัวแปลง 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;
person Cris    schedule 14.11.2013
comment
ดูเหมือนว่าจะใช้งานได้ แล้วคุณสมบัติที่ใช้มีอะไรบ้าง? - person mpen; 14.11.2013
comment
ItemConverterType ใช้สำหรับการแปลงรายการในอาร์เรย์ ลองใส่คำอธิบายประกอบคุณสมบัติสองครั้งด้วย JsonProperty และ JsonConverter เช่น [JsonProperty(PropertyName=dateAdded)] [JsonConverter(typeof(JavaScriptDateTimeConverter))] - person Cris; 14.11.2013
comment
ไม่จำเป็นต้องใส่คำอธิบายประกอบคู่ [JsonConverter] คือคุณลักษณะที่ฉันกำลังมองหา ขอบคุณ! (แต่ [JsonProperty] ก็ดีเหมือนกัน เพราะตอนนี้ฉันสามารถเปลี่ยนชื่อคุณสมบัติของฉันได้แล้ว) - person mpen; 14.11.2013
comment
ใช้ Convert.ToString(reader.Value) แทนการใช้อ็อบเจ็กต์เนทิฟ (string)reader.Value เพื่อให้สิ่งนี้ใช้งานได้สำหรับฉัน - person Darth Jon; 22.08.2014
comment
ฉันลองคำตอบของคุณแล้ว แต่ฉันก็ต้องการใช้การตั้งค่าเพื่อละเว้นค่า Null ฉันจะใช้ทั้งสองอย่างได้อย่างไร เมื่อฉันลองด้านล่าง ฉันได้รับข้อโต้แย้งที่ไม่ถูกต้อง JsonConvert.DeserializeObject(restResponse.Content, typeof(MyClass), new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }, new MyDateTimeConverter()); - person Neo; 18.09.2015
comment
ข้อผิดพลาดใดที่คุณได้รับที่นี่?เป็นเวลารันไทม์หรือไม่? - person Cris; 18.09.2015
comment
@DarthJon: var t = Convert.ToInt64(reader.Value); หลีกเลี่ยงการออกนอกเส้นทางทั้งหมด - person TomB; 16.09.2020

มีวิธีการแปลงจากการประทับเวลา 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

ฉันรู้ว่าคำถามนี้มีอายุไม่กี่ปีแล้ว ดังนั้นจึงมีความเป็นไปได้สูงที่ชั้นเรียนนี้จะถูกเพิ่มนับตั้งแต่มีการถามคำถามนี้ แต่นี่อาจช่วยใครก็ตามที่เจอปัญหาเดียวกัน

person Aoki Metal    schedule 26.02.2018
comment
คำถามของฉันเกี่ยวกับไมโครวินาทีตั้งแต่ยุค แต่ไม่ใช่วินาทีปกติ อย่าคิดว่า UnixDateTimeConverter ใช้ได้ผลใช่ไหม - person mpen; 26.02.2018
comment
โปรดทราบว่า UnixDateTimeConverter คือ JsonConvert v.11+ หากคุณติดอยู่ที่ 10.x หรือต่ำกว่า คุณจะต้องใช้วิธีแก้ปัญหาอื่นๆ ที่เสนอมา :) - person Frederik Struck-Schøning; 24.04.2018

ฉันต้องการเพิ่มโซลูชันสำหรับ .Net core และ System.Text.Json ตามคำตอบที่ยอมรับ ยืนยันแล้วใน 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;}
person Bryan Halterman    schedule 14.09.2020
comment
DateTime.UnixEpoch ใหม่หรือเปล่า? นี่ดูสะอาดขึ้นนิดหน่อย ขอบคุณ! - person mpen; 16.09.2020
comment
@mpen มีให้บริการใน .net มาตรฐาน 2.1, .net core 2.1 และสูงกว่า docs.microsoft.com/en-us/dotnet/api/ - person Bryan Halterman; 17.09.2020

อืม ...สิ่งที่ยุ่งยากเล็กน้อยคือตัวสร้าง 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

person Noctis    schedule 14.11.2013

นั่นคือวิธีที่ฉันทำและมันได้ผล

ใน ViewModel ของฉัน ฉันมีคุณสมบัติสาธารณะประเภท DateTime

Public DateTime TimeToBeShown {get; set;}

ใน My Model ฉันมีคุณสมบัติสาธารณะประเภท Long ซึ่งรับวันที่จาก API เป็นรูปแบบ JSON

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



person redar ismail    schedule 27.06.2019