在反序列化期间将JSON日期转换为.NET DateTime的正确方法

时间:2012-09-18 18:29:14

标签: c# javascript json stringify

我有一个用JSON数据调用MVC控制器的javascript函数:

var specsAsJson = JSON.stringify(specs);
$.post('/Home/Save', { jsonData: specsAsJson });

在服务器端,在控制器内,我似乎无法通过此错误:

  

/ Date(1347992529530)/不是DateTime的有效值。

当我调用Deserialize()(下面的方法中的第三行)时会发生异常:

    public ActionResult Save(string jsonData)
    {
        var serializer = new JavaScriptSerializer();
        serializer.RegisterConverters(new[] { new TimeSpanJsonConverter() });
        var specs = serializer.Deserialize<List<EquipmentSpecWithParameterlessConstructor>>(jsonData);

        return View("Index", _allTrackerJobs);
    }

我一直在做一些谷歌搜索,上面的代码是我最近的尝试(使用来自here的TimeSpanJsonConverter)。其他方法显示只向服务器发送日期,但我有一个对象列表,其中日期为某些属性。

是否有一种优雅的,普遍接受的方法来解决这个问题,还是我们还需要某种丑陋的解决方法?解决这个问题的正确方法是什么?

===================原始问题结束===================


编辑 - 通过使用JsonConvert序列化解决

请参阅下面的回答(不是这个问题中糟糕的解决办法)。


编辑 - 糟糕的解决方法

我使用与域对象完全相同的字段创建了一个DTO,不同之处在于我将日期字段设置为字符串,以便反序列化。现在我可以反序列化它,我将努力将日期转换为有效格式,以便我可以从我的DTO创建域对象。

public class EquipmentSpecDto
{
    public string StartTime { get; set; }
    public string EndTime { get; set; }
    // more properties here
}

我只是使用DTO进行反序列化:

var specs = serializer.Deserialize<List<EquipmentSpecDto>>(jsonData);

编辑2 - 将JavaScript日期转换为.NET

为了完整性,并希望我将其他人保存一小时,这就是我能够转换javascript日期的方式:

    foreach (EquipmentSpecDto specDto in specDtos)
    {
        // JavaScript uses the unix epoch of 1/1/1970. Note, it's important to call ToLocalTime()
        // after doing the time conversion, otherwise we'd have to deal with daylight savings hooey.
        DateTime unixEpoch       = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
        Double startMilliseconds = Convert.ToDouble(specDto.StartTime.Substring(6, 13));
        Double endMilliseconds   = Convert.ToDouble(specDto.EndTime.Substring(6, 13));
        DateTime startTime       = unixEpoch.AddMilliseconds(startMilliseconds).ToLocalTime();
        DateTime endTime         = unixEpoch.AddMilliseconds(endMilliseconds).ToLocalTime();
        EquipmentSpec spec       = new EquipmentSpec(startTime, endTime, specDto.Equipment);

        specs.Add(spec);
    }

5 个答案:

答案 0 :(得分:6)

我在互联网上找到了这段代码。 它对我来说就像一个魅力......

function customJSONstringify(obj) {
    return JSON.stringify(obj).replace(/\/Date/g, "\\\/Date").replace(/\)\//g, "\)\\\/")
}

答案 1 :(得分:3)

通过在Javascript日期和各种服务器端语言之间进行转换,经常捕获人们的一件事是,尽管双方都能够理解unix样式的时间戳值,但JS使用的是微秒精度时间戳,而在大多数其他时间戳中语言默认时间戳精度是第二个。

换句话说,Javascript中的1347993132851需要除以1000才能被识别为其他语言的unix时间戳。

或者,如果您的平台可以接受格式化日期字符串,请使用Javascript Date()对象将时间戳值转换为格式化日期以发送到服务器。或者更好的是,使用辅助库,例如Date.jsMoment.js

答案 2 :(得分:1)

JavaScript(以及EcmaScript)基于ISO-8601标准的简化来定义其DateTime字符串交换格式。

XML Schema也定义了基于ISO-8601的DateTime字符串交换格式。

我发现使用.NET类System.Runtime.Remoting.Metadata.W3cXsd2001.SoapDateTime来处理从.NET DateTime值到XML格式的转换以及返回它都很方便。

由于JavaScript基于相同的ISO-8601标准,因此它也可能适用于您的JSON案例。

答案 3 :(得分:1)

我接受了@Bob Horn的回答,但它并没有为我工作。我的REST服务使用的是Javascritpt日期。我将推荐的答案改编为扩展方法。


using System;

namespace Mediatel.Framework
{
    public static class JsonDate
    {
        public static DateTime ConvertToDateTime(this string jsonDate)
        {
            // JavaScript uses the unix epoch of 1/1/1970. Note, it's important to call ToLocalTime()
            // after doing the time conversion, otherwise we'd have to deal with daylight savings hooey.
            DateTime unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
            Double milliseconds = Convert.ToDouble(jsonDate);
            DateTime dateTime = unixEpoch.AddMilliseconds(milliseconds).ToLocalTime();

            return dateTime;
        }
    }
}

答案 4 :(得分:1)

修复错误

  

/ Date(1347992529530)/不是DateTime的有效值。

使用此替换对我有用。

var data = ko.toJSON({ objext: obj});
$.ajax({
    url: "/API/API.asmx/SaveObject",
    type: "POST",
    dataType: "json",
    contentType: "application/json; char-utf8;",
    data: data.replace(/\/Date/g, "\\\/Date").replace(/\)\//g, "\)\\\/"),
    success: function (r) {},
    error: function (e) {},
    complete: function () {}
});