使用JSON.NET解析格式为Date(epochTime-offset)的json日期

我在C#中使用Json.net 7.0.1来使用rest API。 问题在于API在其JSON响应中使用的日期格式。 它看起来像这样:

/Date(1445301615000-0700)/ 

这意味着代表2015-10-19 17:40:15的UTC时间

如果将1445301615000插入纪元时间转换器 ,您会看到它是2015-10- 20 00:40:15。 所以比UTC提前7个小时。 然后他们包括-0700可能是为了抵消回到UTC。 所以,为了给我一个UTC时间,他们发给我UTC + 7-0700。 为什么他们这样做我不知道,但我不能改变它。

我的问题是,如何最好地使Json.NET解析该日期字符串并提出2015-10-19 17:40:15 UTC的DateTime。 我可以编写一个自定义JsonConverter来劫持该值并手动操作它,但我想知道是否有更原生的方法。

我已经尝试将JsonSerializerSettings DateTimeZoneHandling属性更改JsonSerializerSettings DateTimeZoneHandling所有不同的值。 将它设置为Utc只是忽略时区偏移,产生2015-10-20 00:40:15 。 将其设置为Local,Unspecified或2015-10-19 20:40:15都会产生2015-10-19 20:40:15 ,我认为这是因为我的本地时区是UTC-4,所以它试图将该调整应用于2015年的主要日期值-10-20 00:40

我还考虑使用DateFormatString属性来表示预期的日期字符串格式。 但我找不到正确的格式字符串字符来表示这个epochtime-offset格式。

这是一个简化的例子:

 Person person; string json = @"{ 'Name': 'John', 'LastSeen':'/Date(1445301615000-0700)/' }"; // 1445301615000 = 2015-10-20 00:40:15 person = JsonConvert.DeserializeObject(json); Console.WriteLine(person.LastSeen); // 10/19/2015 8:40:15 PM Kind = Local person = JsonConvert.DeserializeObject(json, new JsonSerializerSettings { DateFormatHandling = DateFormatHandling.MicrosoftDateFormat }); Console.WriteLine(person.LastSeen); // 10/19/2015 8:40:15 PM Kind = Local person = JsonConvert.DeserializeObject(json, new JsonSerializerSettings { DateTimeZoneHandling = DateTimeZoneHandling.Utc }); Console.WriteLine(person.LastSeen); // 10/20/2015 00:40:15 PM Kind = Utc // In all three, the -0700 portion is being ignored. I'd like person.LastSeen to be 10/19/2015 17:40:15. 

再一次,我可以知道API将给我UTC + 7并自己进行调整以获得真实的UTC。 但我想知道Json.NET是否有一种本地方式来处理这种类型的日期字符串。

/日期(1445301615000-0700)/

这意味着代表2015-10-19 17:40:15的UTC时间

对不起,那是不对的。 UTC时间是2015-10-20 00:45:15 。 您的值对应于当时时间区域,当时时间区域的偏移量为-07:00

在这种棘手的格式中 ,时间戳部分仍然仅基于UTC。 偏移量是额外信息。 它不会更改时间戳。 您可以给出不同的偏移量,或者完全省略它,它仍然是同一时刻。

关于时间点,以下所有内容都是等效的。

 /Date(1445301615000-0700)/ /Date(1445301615000)/ 2015-10-20T00:40:15Z 2015-10-19T17:40:15-07:00 

请注意,在ISO格式中,偏移确实会更改值,但在MS格式中则不会。

如果你没有使用这种格式,那将是最好的,因为ISO8601是一个更加理智的JSON选择。 但是如果你坚持使用它,那么最好不要将它反序列化为DateTime 。 而是使用DateTimeOffset

考虑:

 string s = "\"/Date(1445301615000-0700)/\""; DateTime dt = JsonConvert.DeserializeObject(s); Console.WriteLine(dt.Kind); // Local 

那不好。 基本上,如果有任何偏移,它认为它是你的本地时区,它可能是,但它可能不是。

 string s = "\"/Date(1445301615000)/\""; DateTime dt = JsonConvert.DeserializeObject(s); Console.WriteLine(dt.Kind); // Utc 

这没关系,但你已经忘记了那个当地时间。

 string s = "\"/Date(1445301615000-0700)/\""; DateTimeOffset dto = JsonConvert.DeserializeObject(s); Console.WriteLine(dto); // 10/19/2015 5:40:15 PM -07:00 

那好多了。 如果你确实想要一个UTC DateTime ,那么:

 string s = "\"/Date(1445301615000-0700)/\""; DateTimeOffset dto = JsonConvert.DeserializeObject(s); DateTime utc = dto.UtcDateTime; Console.WriteLine(utc); // 10/20/2015 12:40:15 AM 

因此,关键的教训是,无论格式如何,如果数据中存在时区偏移信息,则反序列化为DateTimeOffset 。 虽然在某些情况下使用DateTime 可能会起作用,但是您要求.NET解释偏移并应用默认行为,这通常不是所需的行为。

-hhmm表示本地时间已序列化,而不是UTC时间。 与许多其他平台一样,.NET认识到时区的概念。 例如,在.NET中, DateTime类有一个属性,指示您正在处理的日期/时间类型。 您可以明确地构建不同种类的日期/时间。 调试器很糟糕,因为没有指出这一点,但您可以使用以下代码查看它。

 var dt1 = new DateTime(2015, 01, 01, 00, 00, 00); // defaults to DateTimeKind.Unspecified var dt2 = new DateTime(2015, 01, 01, 00, 00, 00, DateTimeKind.Local); var dt3 = new DateTime(2015, 01, 01, 00, 00, 00, DateTimeKind.Utc); var dt4 = new DateTime(2015, 01, 01, 00, 00, 00, DateTimeKind.Unspecified); Debug.WriteLine(dt1.Kind); // writes "Unspecified" Debug.WriteLine(dt2.Kind); // writes "Local" Debug.WriteLine(dt3.Kind); // writes "Utc" Debug.WriteLine(dt4.Kind); // writes "Unspecified" 

然后,您可以使用以下内容查看DateTimeKind对Json的影响

 // local time -- default datetime handling from JSON.NET { var dateTime = DateTime.Now; var jsonObject = new JObject {["dateTime"] = dateTime}; var jsonString = jsonObject.ToString(); Debug.WriteLine(jsonString); // uses "2015-10-19T18:13:53.4698565-04:00" form } // UTC time -- default datetime handling from JSON.NET { var dateTime = DateTime.Now.ToUniversalTime(); var jsonObject = new JObject {["dateTime"] = dateTime }; var jsonString = jsonObject.ToString(); Debug.WriteLine(jsonString); // uses "2015-10-19T22:13:53.5166571Z" form } // local time -- Microsoft-like datetime handling from JSON.NET { var dateTime = DateTime.Now; var jsonObject = new JObject {["dateTime"] = dateTime }; var jsonString = JsonConvert.SerializeObject(jsonObject, new JsonSerializerSettings { DateFormatHandling = DateFormatHandling.MicrosoftDateFormat }); Debug.WriteLine(jsonString); // uses "/Date(1445292833516-0400)/" format } // local time -- Microsoft-like datetime handling from JSON.NET { var dateTime = DateTime.Now.ToUniversalTime(); var jsonObject = new JObject {["dateTime"] = dateTime }; var jsonString = JsonConvert.SerializeObject(jsonObject, new JsonSerializerSettings { DateFormatHandling = DateFormatHandling.MicrosoftDateFormat }); Debug.WriteLine(jsonString); // uses "/Date(1445292833579)/" form }