我在c#中使用Json.net 7.0.1来使用rest API。问题在于API在其JSON响应中使用的日期格式。它看起来像这样:
/Date(1445301615000-0700)/
表示UTC时间2015-10-19 17:40:15
如果将1445301615000插入历元时间转换器,您会看到它是2015-10-2000: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
属性来表示预期的日期字符串格式。但是我找不到合适的格式字符串字符来表示这个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有一种本地方法来处理这种类型的日期字符串。
/日期(1445301615000 - 0700)/
表示UTC时间2015-10-19 17:40:15
对不起,这是错误的。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<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解释偏移量并应用默认行为,这通常不是期望的行为。
-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
}