我们的客户希望在浏览器中显示与数据库中完全相同的日期和时间值,我们将它们作为 UTC 存储在数据库中。
起初,我们在序列化和 Javascript 方面遇到了一些问题。DateTime 值移动了两次——首先匹配机器的本地时区,然后匹配浏览器中的时区。我们通过向 JavaScriptSerializer 添加自定义转换器来修复它。我们在 Serialize 覆盖中将 DateTime 标记为 DateTimeKind.Utc。从 Serialize 反馈数据有点困难,但我们发现了一些 Uri hack,它有助于以相同的 JavaScriptSerializer /Date(286769410010)/ 格式返回 DateTime 值,但无需转换到本地时间。在 Javascript 方面,我们修补了 KendoUI JS 库以偏移构造的 Date() 对象,使它们看起来好像是 UTC。
然后我们开始在另一边工作,反序列化。同样,我们必须调整我们的代码以使用自定义 stringify 而不是 JSON.stringify,这在从本地时间转换为 UTC 时再次偏移数据。到目前为止,一切似乎都很好。
但是看看这个测试:
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);
}
为什么 JavaScriptSerializer 将\/Date(286769410010)\/
字符串反序列化为 UTC 时间而不是1979-02-02T02:10:10Z
本地时间?
我们尝试向自定义添加 Deserialize 方法,JavascriptConverter
但问题是如果我们的 JavascriptConverter 具有以下类型,则永远不会调用 Deserialize:
public override IEnumerable<Type> SupportedTypes
{
get { return new List<Type>() { typeof(DateTime), typeof(DateTime?) }; }
}
SupportedTypes
我猜,只有在包含某些具有 DateTime 字段的复杂实体的类型时才会调用 Deserialize 。
所以,JavaScriptSerializer
有JavascriptConverter
两个不一致的地方:
- Serialize 为每个数据项考虑 SupportedTypes 中的简单类型,但 Deserialize 对于简单类型忽略它
- 反序列化将一些日期反序列化为 UTC 和一些 - 作为本地时间。
有什么简单的方法可以解决这些问题吗?我们有点害怕JavaScriptSerializer
用其他序列化程序替换,因为可能我们正在使用的一些 3rd 方库依赖于JavaScriptSerializer
.