我们的客户希望在浏览器中显示与数据库中完全相同的日期和时间值,而我们在数据库中将它们存储为UTC。
起初,我们在序列化和JavaScript方面遇到了一些问题。DateTime值被移动了两次-首先匹配机器的本地时区,然后匹配浏览器中的时区。我们通过向JavaScriptSerializer添加自定义转换器来解决此问题。我们在Serialize重写中将DateTime标记为DateTimeKind.Utc。尽管从Serialize反馈数据有点困难,但我们找到了一些URI技巧,有助于以相同的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
反序列化为本地时间?我们尝试向自定义
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对于简单类型则忽略它
- Deserialize将某些日期反序列化为UTC时间,而将另一些日期反序列化为本地时间。
有没有简单的方法来解决这些问题?
我们有点担心用其他序列化程序替代JavaScriptSerializer
,因为我们使用的某些第三方库可能依赖于JavaScriptSerializer
的某些“功能/缺陷”。