Правильный способ преобразования даты 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);
}
Ответы
Ответ 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;
}
}
}