.net JavaScriptSerializer UTC DateTime 问题
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17069460/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
JavaScriptSerializer UTC DateTime issues
提问by JustAMartin
Our client wanted to show the date and time values in the browser exactly as they are in the database, and we are storing them as UTC in the database.
我们的客户希望在浏览器中显示与数据库中完全相同的日期和时间值,我们将它们作为 UTC 存储在数据库中。
At first we had some problems with the serialization and Javascript side. The DateTime values got shifted twice - at first to match the local time zone of the machine and then to match the time zone in the browser. We fixed it by adding a custom Converter to the JavaScriptSerializer. We marked the DateTime to be of DateTimeKind.Utc in the Serialize override. It was a bit hard to feed the data back from the Serialize but we found some Uri hack which helped to return DateTime values in the same JavaScriptSerializer /Date(286769410010)/ format but without shifting to the local time. On the Javascript side we patched the KendoUI JS library to offset the constructed Date() objects so they appear as if they are UTC.
起初我们在序列化和 Javascript 方面遇到了一些问题。DateTime 值移动了两次 - 首先匹配机器的本地时区,然后匹配浏览器中的时区。我们通过向 JavaScriptSerializer 添加自定义转换器来修复它。我们在 Serialize 覆盖中将 DateTime 标记为 DateTimeKind.Utc。从 Serialize 返回数据有点困难,但我们发现了一些 Uri hack,它有助于以相同的 JavaScriptSerializer /Date(286769410010)/ 格式返回 DateTime 值,但不会转换到本地时间。在 Javascript 方面,我们修补了 KendoUI JS 库以抵消构造的 Date() 对象,使它们看起来好像是 UTC。
Then we started to work on the other side, deserialization. Again, we had to adjust our code to use a custom stringify instead of JSON.stringify, which again offsets the data when converting from the local time to UTC. Everything seemed good so far.
然后我们开始在另一边工作,反序列化。同样,我们必须调整我们的代码以使用自定义 stringify 而不是 JSON.stringify,这在从本地时间转换为 UTC 时再次偏移数据。到目前为止,一切似乎都很好。
But look at this test:
但是看看这个测试:
public void DeserialiseDatesTest()
{
var dateExpected = new DateTime(1979, 2, 2,
2, 10, 10, 10, DateTimeKind.Utc);
// this how the Dates look like after serializing
// anothe issue, unrelated to the core problem, is that the "\" might get stripped out when dates come back from the browser
// so I have to add missing "\" or else Deserialize will break
string s = "\"\/Date(286769410010)\/\"";
// this get deserialized to UTC date by default
JavaScriptSerializer js = new JavaScriptSerializer();
var dateActual = js.Deserialize<DateTime>(s);
Assert.AreEqual(dateExpected, dateActual);
Assert.AreEqual(DateTimeKind.Utc, dateActual.Kind);
// but some Javascript components (like KendoUI) sometimes use JSON.stringify
// for Javascript Date() object, thus producing the following:
s = "\"1979-02-02T02:10:10Z\"";
dateActual = js.Deserialize<DateTime>(s);
// If your local computer time is not UTC, this will FAIL!
Assert.AreEqual(dateExpected, dateActual);
// and the following fails always
Assert.AreEqual(DateTimeKind.Utc, dateActual.Kind);
}
Why does JavaScriptSerializer deserialize \/Date(286769410010)\/strings to UTC time but 1979-02-02T02:10:10Zto local time?
为什么 JavaScriptSerializer 将\/Date(286769410010)\/字符串反序列化为UTC 时间而不是1979-02-02T02:10:10Z本地时间?
We tried to add a Deserialize method to our custom JavascriptConverterbut the problem is that the Deserialize is never called if our JavascriptConverter has the following types:
我们尝试向我们的自定义添加一个 Deserialize 方法,JavascriptConverter但问题是如果我们的 JavascriptConverter 具有以下类型,则永远不会调用 Deserialize:
public override IEnumerable<Type> SupportedTypes
{
get { return new List<Type>() { typeof(DateTime), typeof(DateTime?) }; }
}
I guess, Deserialize would be called only if SupportedTypescontained types of some complex entities which have DateTime fields.
我猜,只有当SupportedTypes包含一些具有 DateTime 字段的复杂实体的类型时,才会调用反序列化。
So, JavaScriptSerializerand JavascriptConverterhave two inconsistencies:
所以,JavaScriptSerializer和JavascriptConverter有两个矛盾:
- Serialize takes into account simple types in SupportedTypes for every data item, but Deserialize ignores it for simple types
- Deserialize deserializes some dates as UTC and some - as local time.
- Serialize 考虑了 SupportedTypes 中每个数据项的简单类型,但 Deserialize 忽略了简单类型
- 反序列化将一些日期反序列化为 UTC,将一些日期反序列化为本地时间。
Is there any simple way to fix these issues?
We are a bit afraid to replace JavaScriptSerializerwith some other serializer because maybe some of the 3rd party libraries we are using, are relying upon some certain "features/bugs" of JavaScriptSerializer.
有什么简单的方法可以解决这些问题吗?我们有点害怕JavaScriptSerializer用其他一些序列化程序替换,因为也许我们正在使用的某些 3rd 方库依赖于JavaScriptSerializer.
回答by Matt Johnson-Pint
JavaScriptSerializer, and DataContractJsonSerializerare riddled with bugs. Use json.netinstead. Even Microsoft has made this switch in ASP.Net MVC4 and other recent projects.
JavaScriptSerializer,并且DataContractJsonSerializer充满了错误。改用json.net。甚至微软也在 ASP.Net MVC4 和其他最近的项目中进行了这种转换。
The /Date(286769410010)/format is proprietary and made up by Microsoft. It has problems, and is not widely supported. You should use the 1979-02-02T02:10:10Zformat everywhere. This is defined in ISO8601and RF3339. It is both machine and human readable, lexically sortable, culture invariant, and unambiguous.
该/Date(286769410010)/格式是专有的,由 Microsoft 制作。它有问题,并且没有得到广泛支持。您应该在1979-02-02T02:10:10Z任何地方使用该格式。这在ISO8601和RF3339 中定义。它既是机器可读的,又是人类可读的,在词汇上可排序的,文化不变的,而且是明确的。
In JavaScript, if you can guarantee you will be running on newer browsers, then use:
在 JavaScript 中,如果你能保证你将在较新的浏览器上运行,那么使用:
date.toISOString()
参考这里。
If you want full cross-browser and older-browser support, use moment.jsinstead.
如果您想要完整的跨浏览器和旧浏览器支持,请改用moment.js。
UPDATE
更新
As an aside, if you really want to keep using JavaScriptSerializer, you could deserialize to a DateTimeOffset, which would preserve the correct time. You could then get the UTC DateTimefrom there, as follows:
JavaScriptSerializer顺便说一句,如果您真的想继续使用,您可以反序列化为 a DateTimeOffset,这将保留正确的时间。然后您可以DateTime从那里获取 UTC ,如下所示:
// note, you were missing the milliseconds in your example, I added them here.
s = "\"1979-02-02T02:10:10.010Z\"";
dateActual = js.Deserialize<DateTimeOffset>(s).UtcDateTime;
Your test will now pass.
您的测试现在将通过。

