Подтвердить что ты не робот

Правильный способ преобразования даты JSON в .NET DateTime во время десериализации

У меня есть функция javascript, которая вызывает MVC-контроллер с данными JSON:

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

На стороне сервера, внутри контроллера, я не могу пропустить эту ошибку:

/Дата (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);
    }

Я занимаюсь поиском в Интернете, и приведенный выше код - моя последняя попытка сделать эту работу (используя TimeSpanJsonConverter от здесь). Другие подходы показывают отправку только даты на сервер, но у меня есть список объектов, у которых есть даты как некоторые свойства.

Есть ли элегантный, общепринятый подход к решению этого вопроса, или нам все еще нужна какая-то уродливая работа? Какой правильный способ решить эту проблему?

=================== Конец оригинального вопроса ===================


Изменить - РЕШИТЬ путем сериализации с использованием JsonConvert

См. ниже мой ответ


Изменить - Crappy work-around

Я создал 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 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);
    }
4b9b3361

Ответ 1

Я нашел простой ответ. В моем javascript я сериализовал данные с помощью JavaScriptSerializer. После многого поиска я нашел эту статью которая показывает, как сериализоваться с помощью JsonConvert, что приводит к использованию более удобного для .NET DateTime.

Старый:

var specs = @Html.Raw(new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(ViewBag.JobSpecEquipment))

Даты выглядят так: Date(1348017917565)

New:

var specs = @Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(ViewBag.JobSpecEquipment));

Даты выглядят так: 2012-09-18T21:27:31.1285861-04:00

Таким образом, проблема была в самом деле в том, как я сериализуюсь в первую очередь. Как только я использовал JsonConvert, десериализация на заднем конце просто работала.

Ответ 2

Я нашел этот фрагмент кода в Интернете. Это работало как прелесть для меня...

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

Ответ 3

Одна вещь, которая часто улавливает людей с переходом между датами Javascript и различными серверными языками, заключается в том, что, хотя обе стороны могут понимать значение времени в стиле unix, JS использует метку времени с микросекундной точностью, тогда как в большинстве других Языки. Значение временной метки по умолчанию относится ко второй.

Другими словами, 1347993132851 в Javascript необходимо разделить на 1000, чтобы быть распознанным как временная метка unix на других языках.

В качестве альтернативы, если ваша платформа может принимать форматированные строки даты, используйте объект Javascript Date() для преобразования значения временной метки в форматированную дату для отправки на сервер. Или еще лучше, используйте вспомогательную библиотеку, такую ​​как Date.js или Moment. JS.

Ответ 4

JavaScript (ну, EcmaScript) определяет формат строкового обмена DateTime на основе упрощения стандарта ISO-8601.

XML Schema также определяет формат строкового обмена DateTime на основе ISO-8601.

Я нашел удобным использовать .NET class System.Runtime.Remoting.Metadata.W3cXsd2001.SoapDateTime для обработки преобразования значений .NET DateTime в форматы XML и обратно.

Поскольку JavaScript основан на том же стандарте ISO-8601, возможно, он будет работать и для вашего дела JSON.

Ответ 5

Я взял @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 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;
        }
    }
}