我在C#中使用Json.net 7.0.1来使用rest API。问题在于API在其JSON响应中使用的日期格式。它看起来像这样:
/Date(1445301615000-0700)/
这意味着代表2015-10-19 17:40:15的UTC时间
如果您将1445301615000插入epoch time converter,您会看到它是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
属性更改为其所有不同的值。将其设置为Utc只会忽略时区偏移,产生2015-10-20 00:40:15
。将其设置为Local,Unspecified或RoundtripKind都会产生2015-10-19 20:40:15
,我认为这是因为我的本地时区是UTC-4,所以它试图将该调整应用于2015-10-20 00的主日期值:40
我还考虑使用DateFormatString
属性来表示预期的日期字符串格式。但我找不到合适的format string characters来表示这个epochtime-offset格式。
这是一个简化的例子:
Person person;
string json = @"{ 'Name': 'John',
'LastSeen':'/Date(1445301615000-0700)/' }"; // 1445301615000 = 2015-10-20 00:40:15
person = JsonConvert.DeserializeObject<Person>(json);
Console.WriteLine(person.LastSeen); // 10/19/2015 8:40:15 PM Kind = Local
person = JsonConvert.DeserializeObject<Person>(json, new JsonSerializerSettings { DateFormatHandling = DateFormatHandling.MicrosoftDateFormat });
Console.WriteLine(person.LastSeen); // 10/19/2015 8:40:15 PM Kind = Local
person = JsonConvert.DeserializeObject<Person>(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是否有一种本地方式来处理这种类型的日期字符串。
答案 0 :(得分:6)
/日期(1445301615000-0700)/
这意味着代表2015-10-19 17:40:15的UTC时间
抱歉,这不正确。 UTC时间为2015-10-20 00:45:15
。您的值对应于本地时间,在该时刻有-07:00
偏移量的时区。
在此screwy format中,时间戳部分仍然仅基于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<DateTime>(s);
Console.WriteLine(dt.Kind); // Local
那不好。基本上,如果有任何偏移量,它认为它是你的本地时区,它可能是,但它可能不是。
string s = "\"/Date(1445301615000)/\"";
DateTime dt = JsonConvert.DeserializeObject<DateTime>(s);
Console.WriteLine(dt.Kind); // Utc
这没关系,但你已经忘记了当地的时间。
string s = "\"/Date(1445301615000-0700)/\"";
DateTimeOffset dto = JsonConvert.DeserializeObject<DateTimeOffset>(s);
Console.WriteLine(dto); // 10/19/2015 5:40:15 PM -07:00
那要好得多。如果您确实想要UTC DateTime
,那么:
string s = "\"/Date(1445301615000-0700)/\"";
DateTimeOffset dto = JsonConvert.DeserializeObject<DateTimeOffset>(s);
DateTime utc = dto.UtcDateTime;
Console.WriteLine(utc); // 10/20/2015 12:40:15 AM
因此,关键的教训是,无论格式如何,如果数据中存在时区偏移信息,则反序列化为DateTimeOffset
。虽然在某些情况下使用DateTime
可能工作,但您要求.NET解释偏移并应用默认行为,这通常不是所需的行为。
答案 1 :(得分:3)
-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
}