c# - 为什么即使日期是 JSON 中的 UTC,ServiceStack 也会发出本地时间?

标签 c# servicestack servicestack-text

长话短说 - 通过 ServiceStack.Text 的 JSON 解析器往返的日期丢失了时区信息。奇怪的是,DateTimeSerializerTests.DateTime_Is_Serialized_As_Utc_and_Deserialized_as_local()似乎期望这种行为,并且 DateTimeSerializer.Prepare()明确调用 ToLocalTime()在每个被解析为 UTC 的日期时间对象上!

这是一个示例测试用例(MSTest,但很容易在任何情况下运行)。本地传递,但 UTC 和 Unspecified 不传递 - DateTime 对象返回的类型始终是“本地”。

[TestMethod]
public void TestParseSingleDateTime_UTC()
{
    // In canonical UTC format
    var date = "2014-06-03T14:26:20.0030000Z";
    var raw = new DateTime(2014, 6, 3, 14, 26, 20, 3, DateTimeKind.Utc);
    var value = DateTimeSerializer.ParseShortestXsdDateTime(date);
    Assert.AreEqual(DateTimeKind.Utc, value.Kind);
    Assert.AreEqual(raw, value);
}

[TestMethod]
public void TestParseSingleDateTime_Local()
{
    // In local time zone
    var date = "2014-06-02T11:15:49.1480000-05:00";
    var raw = new DateTime(2014, 6, 2, 11, 15, 49, 148, DateTimeKind.Local);
    var value = DateTimeSerializer.ParseShortestXsdDateTime(date);
    Assert.AreEqual(DateTimeKind.Local, value.Kind);
    Assert.AreEqual(raw, value);
}

[TestMethod]
public void TestParseSingleDateTime_Unspecified()
{
    // Unspecified time zone, as we would parse from Excel cells with dates
    var date = "2012-01-06T00:00:00.0000000";
    var raw = new DateTime(2012, 1, 6, 0, 0, 0, DateTimeKind.Unspecified);
    var value = DateTimeSerializer.ParseShortestXsdDateTime(date);
    Assert.AreEqual(DateTimeKind.Unspecified, value.Kind);
    Assert.AreEqual(raw, value);
}

为什么这是默认行为?使用 JsConfig.AlwaysUseUtc在这里不是一个好的解决方法,因为那样我也无法将本地时间戳解析为本地。

最佳答案

如果有人发现这个,虽然它很旧,但这个逻辑应该能够通过 JSON 解析器的配置完全控制,作为 JsConfig 全局可用。

下面的例子(虽然未经测试)应该大致涵盖我上面理解的场景:

// Formats to use for the different date kinds
string utcTimeFormat = "yyyy-MM-dd'T'HH:mm:ss.fffffff'Z'";
string localTimeFormat = "yyyy-MM-dd'T'HH:mm:ss.fffffff";

// Serialization function
// Check if specified as UTC otherwise treat as local. 
JsConfig<DateTime>.SerializeFn = datetime =>
{
    switch (datetime.Kind)
    {
        case DateTimeKind.Utc:
            return datetime.ToString(utcTimeFormat);
        default: //DateTimeKind.Unspecified and DateTimeKind.Local
            return datetime.ToString(localTimeFormat);
    }
};

// Deserialization function
// Check which format provided, attempt to parse as datetime or return minValue.
JsConfig<DateTime>.DeSerializeFn = datetimeStr =>
{
    if (string.IsNullOrWhiteSpace(datetimeStr))
    {
        return DateTime.MinValue;
    }

    if (datetimeStr.EndsWith("Z") && 
        DateTime.TryParseExact(datetimeStr, utcTimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out DateTime resultUtc))
    {
        return resultUtc;
    }
    else if (!datetimeStr.EndsWith("Z") && 
        DateTime.TryParseExact(datetimeStr, localTimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out DateTime resultLocal))
    {
        return resultLocal;
    }

    return DateTime.MinValue;
};

为什么会发生这种情况,要么是设计选择,要么是疏忽,我无法评论。

关于c# - 为什么即使日期是 JSON 中的 UTC,ServiceStack 也会发出本地时间?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24021235/

相关文章:

ServiceStack:在与 Google 进行身份验证时从身份验证 session 中获取电子邮件

asp.net-mvc - ServiceStack 和 MVC4 未接线

csv - 无法将 CSV 转换为 Poco

c# - 如何使用 OLEDB 从 excel 文件(2007 格式)中读取超过 256 列

c# - 使 Gridview 的一个字段成为选择链接?

Servicestack 注册因泛型类型而崩溃

c# - ServiceStack反序列化xml到对象

C# TcpClient ReadAsync 读取大消息

c# - 有没有办法在 C# 中捕获调试消息,然后将它们输出到单独的窗口?

javascript - 如何将 JavaScript 对象 (JSON) 转换为 JSV 格式?