Формат даты ASP.NET MVC JsonResult
У меня есть действие контроллера, которое эффективно просто возвращает JsonResult моей модели. Итак, в моем методе у меня есть что-то вроде следующего:
return new JsonResult(myModel);
Это хорошо работает, за исключением одной проблемы. В модели есть свойство date, и это, по-видимому, возвращается в результате Json так:
"\/Date(1239018869048)\/"
Как я должен иметь дело с датами, чтобы они были возвращены в требуемом формате? Или как мне обрабатывать этот формат выше в script?
Ответы
Ответ 1
Просто чтобы расширить ответ casperOne.
Спецификация JSON не учитывает значения Date. MS пришлось сделать вызов, и путь, который они выбрали, заключался в использовании небольшого трюка в представлении строк в javascript: строковый литерал "/" совпадает с "\/", а строковый литерал никогда не будет сериализован для "\/" (даже "\/" должно быть сопоставлено с "\\/" ).
См. http://msdn.microsoft.com/en-us/library/bb299886.aspx#intro_to_json_topic2 для лучшего объяснения (прокрутите вниз до "Из литералов JavaScript в JSON" )
Одной из проблемных точек JSON является отсутствие лимита даты/времени. Многие люди удивлены и разочарованы узнать это, когда они сначала встретиться с JSON. Простое объяснение (утешение или нет) за отсутствие литерал даты/времени - это то, что JavaScript никогда не было ни одного: поддержка значения даты и времени в JavaScript полностью предоставлено через Дату объект. Большинство приложений, использующих JSON как формат данных, следовательно, в целом имеют тенденцию использовать либо строку, либо номер для указания даты и времени значения. Если используется строка, вы можете обычно ожидайте, что это будет в ISO 8601. Если используется число, вместо этого значение обычно принято считать числом миллисекунды в универсальном скоординированном Время (UTC) с эпохи, где эпоха определенная как полночь 1 января 1970 г. (УНИВЕРСАЛЬНОЕ ГЛОБАЛЬНОЕ ВРЕМЯ). Опять же, это просто конвенция, а не часть JSON стандарт. Если вы обмениваетесь данными с другим приложением вы будете необходимо проверить свою документацию, чтобы увидеть как он кодирует значения даты и времени в литературе JSON. Например, Microsoft ASP.NET AJAX не использует ни описанных конвенций. Скорее, он кодирует значения .NET DateTime как JSON, где содержимое строка/Дата (тики)/и где тики представляют миллисекунды с тех пор эпоха (UTC). Итак, 29 ноября 1989 года, 4:55:30, в UTC кодируется как "\/Дата (628318530718) \/".
Решение состоит в том, чтобы просто проанализировать его:
value = new Date(parseInt(value.replace("/Date(", "").replace(")/",""), 10));
Однако я слышал, что есть параметр где-то, чтобы заставить сериализатор выводить объекты DateTime
с синтаксисом new Date(xxx)
. Я попытаюсь выкопать это.
Второй параметр JSON.parse()
принимает функцию reviver
, где предписывает, как значение, изначально созданное, перед возвратом.
Вот пример даты:
var parsed = JSON.parse(data, function(key, value) {
if (typeof value === 'string') {
var d = /\/Date\((\d*)\)\//.exec(value);
return (d) ? new Date(+d[1]) : value;
}
return value;
});
Смотрите документы JSON.parse()
Ответ 2
Здесь мое решение в Javascript - очень похоже на JPot, но короче (и, возможно, немного быстрее):
value = new Date(parseInt(value.substr(6)));
"value.substr(6)" вынимает функцию "/Date (" part ", а функция parseInt игнорирует символы без номера, которые встречаются в конце.
EDIT: Я намеренно упустил radix (второй аргумент parseInt); см. мой комментарий ниже. Кроме того, обратите внимание, что даты ISO-8601 предпочтительнее этого старого формата, поэтому этот формат обычно не должен использоваться для новой разработки. См. Превосходную библиотеку Json.NET для отличной альтернативы, которая сериализует даты с использованием формата ISO-8601.
Для ISO-8601 отформатированных дат JSON просто передайте строку в конструктор Date:
var date = new Date(jsonDate); //no ugly parsing needed; full timezone support
Ответ 3
Существует довольно много ответов для обработки клиентской части, но вы можете изменить выходную серверную сторону, если хотите.
Есть несколько способов приблизиться к этому, я начну с основ. Вам придется подклассифицировать класс JsonResult и переопределить метод ExecuteResult. Оттуда вы можете использовать несколько разных подходов для изменения сериализации.
Подход 1:
Реализация по умолчанию использует JsonScriptSerializer. Если вы посмотрите на документацию, вы можете использовать метод RegisterConverters для добавления пользовательских JavaScriptConverters. Есть несколько проблем с этим: JavaScriptConverter сериализуется в словаре, то есть он берет объект и сериализуется в Json-словаре. Чтобы сделать сериализацию объекта строкой, он требует немного хакера, см. post. Этот конкретный хак также удалит строку.
public class CustomJsonResult : JsonResult
{
private const string _dateFormat = "yyyy-MM-dd HH:mm:ss";
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
HttpResponseBase response = context.HttpContext.Response;
if (!String.IsNullOrEmpty(ContentType))
{
response.ContentType = ContentType;
}
else
{
response.ContentType = "application/json";
}
if (ContentEncoding != null)
{
response.ContentEncoding = ContentEncoding;
}
if (Data != null)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
// Use your custom JavaScriptConverter subclass here.
serializer.RegisterConverters(new JavascriptConverter[] { new CustomConverter });
response.Write(serializer.Serialize(Data));
}
}
}
Подход 2 (рекомендуется):
Второй подход - начать с переопределенного JsonResult и пойти с другим сериализатором Json, в моем случае Json.NET сериализатору. Это не требует взлома подхода 1. Вот моя реализация подкласса JsonResult:
public class CustomJsonResult : JsonResult
{
private const string _dateFormat = "yyyy-MM-dd HH:mm:ss";
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
HttpResponseBase response = context.HttpContext.Response;
if (!String.IsNullOrEmpty(ContentType))
{
response.ContentType = ContentType;
}
else
{
response.ContentType = "application/json";
}
if (ContentEncoding != null)
{
response.ContentEncoding = ContentEncoding;
}
if (Data != null)
{
// Using Json.NET serializer
var isoConvert = new IsoDateTimeConverter();
isoConvert.DateTimeFormat = _dateFormat;
response.Write(JsonConvert.SerializeObject(Data, isoConvert));
}
}
}
Пример использования:
[HttpGet]
public ActionResult Index() {
return new CustomJsonResult { Data = new { users=db.Users.ToList(); } };
}
Дополнительные кредиты:
Джеймс Ньютон-Кинг
Ответ 4
Moment.js - обширная библиотека datetime, которая также поддерживает это. http://momentjs.com/docs/#/parsing/asp-net-json-dates/
ex: moment ( "/Date (1198908717056-0700)/" )
Это может помочь. вывод плунжера
Ответ 5
Использование jQuery для автоматического преобразования дат с помощью $.parseJSON
Примечание: этот ответ предоставляет расширение jQuery, которое добавляет автоматическую поддержку формата даты в формате ISO и .net.
Поскольку вы используете Asp.net MVC, я подозреваю, что вы используете jQuery на стороне клиента. Я предлагаю вам прочитать этот пост в блоге, в котором есть код, как использовать $.parseJSON
для автоматического преобразования дат для вас.
Код поддерживает даты форматирования Asp.net, такие как те, которые вы упомянули, а также даты в формате ISO. Все даты будут автоматически отформатированы для вас, используя $.parseJSON()
.
Ответ 6
Я обнаружил, что создание нового JsonResult
и возвращение неудовлетворительное - замена всех вызовов на return Json(obj)
на return new MyJsonResult { Data = obj }
является болью.
Итак, я понял, почему бы не просто захватить JsonResult
с помощью ActionFilter
:
public class JsonNetFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (filterContext.Result is JsonResult == false)
{
return;
}
filterContext.Result = new JsonNetResult(
(JsonResult)filterContext.Result);
}
private class JsonNetResult : JsonResult
{
public JsonNetResult(JsonResult jsonResult)
{
this.ContentEncoding = jsonResult.ContentEncoding;
this.ContentType = jsonResult.ContentType;
this.Data = jsonResult.Data;
this.JsonRequestBehavior = jsonResult.JsonRequestBehavior;
this.MaxJsonLength = jsonResult.MaxJsonLength;
this.RecursionLimit = jsonResult.RecursionLimit;
}
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
var isMethodGet = string.Equals(
context.HttpContext.Request.HttpMethod,
"GET",
StringComparison.OrdinalIgnoreCase);
if (this.JsonRequestBehavior == JsonRequestBehavior.DenyGet
&& isMethodGet)
{
throw new InvalidOperationException(
"GET not allowed! Change JsonRequestBehavior to AllowGet.");
}
var response = context.HttpContext.Response;
response.ContentType = string.IsNullOrEmpty(this.ContentType)
? "application/json"
: this.ContentType;
if (this.ContentEncoding != null)
{
response.ContentEncoding = this.ContentEncoding;
}
if (this.Data != null)
{
response.Write(JsonConvert.SerializeObject(this.Data));
}
}
}
}
Это может быть применено к любому методу, возвращающему JsonResult
вместо JSON.Net:
[JsonNetFilter]
public ActionResult GetJson()
{
return Json(new { hello = new Date(2015, 03, 09) }, JsonRequestBehavior.AllowGet)
}
который будет отвечать
{"hello":"2015-03-09T00:00:00+00:00"}
по желанию!
Вы можете, если не возражать при вызове сравнения is
при каждом запросе, добавьте это в свой FilterConfig
:
// ...
filters.Add(new JsonNetFilterAttribute());
и все ваши JSON теперь будут сериализованы с помощью JSON.Net вместо встроенного JavaScriptSerializer
.
Ответ 7
Ajax-связь между клиентом и сервером часто включает данные в формате JSON. В то время как JSON хорошо работает для строк, чисел и логических значений, он может создавать определенные трудности для дат из-за того, как они преобразуются в ASP.NET. Поскольку у них нет специального представления для дат, они сериализуются как простые строки.
В качестве решения механизм сериализации по умолчанию ASP.NET Web Forms и MVC сериализует даты в специальной форме -/Date (ticks)/- где тики - это количество миллисекунд с 1 января 1970 года.
Эта проблема может быть решена двумя способами:
клиентская сторона
Преобразовать полученную строку даты в число и создать объект даты с использованием конструктора класса даты с параметрами ticks как.
function ToJavaScriptDate(value) {
var pattern = /Date\(([^)]+)\)/;
var results = pattern.exec(value);
var dt = new Date(parseFloat(results[1]));
return (dt.getMonth() + 1) + "/" + dt.getDate() + "/" + dt.getFullYear();
}
серверная сторона
Предыдущее решение использует клиентскую сторону script для преобразования даты в объект JavaScript Date. Вы также можете использовать код на стороне сервера, который сериализует экземпляры .NET DateTime в выбранном вами формате.
Для выполнения этой задачи вам необходимо создать свой собственный ActionResult и затем сериализовать данные так, как вы хотите.
ссылка:
http://www.developer.com/net/dealing-with-json-dates-in-asp.net-mvc.html
Ответ 8
У меня была такая же проблема, и вместо того, чтобы возвращать фактическое значение даты, я просто использовал ToString ( "dd MMM yyyy" ). Затем в моем javascript я использовал новую Date (datevalue), где datevalue может быть "01 января 2009".
Ответ 9
Смотрите эту тему:
http://forums.asp.net/p/1038457/1441866.aspx#1441866
По сути, хотя формат Date()
является допустимым javascript, он НЕ является действительным JSON (есть разница). Если вы хотите использовать старый формат, вам, вероятно, придется создать фасад и трансформировать значение самостоятельно или найти способ получить сериализатор для вашего типа в JsonResult
и использовать его в настраиваемом формате для дат.
Ответ 10
Не самый элегантный способ, но это сработало для меня:
var ms = date.substring(6, date.length - 2);
var newDate = formatDate(ms);
function formatDate(ms) {
var date = new Date(parseInt(ms));
var hour = date.getHours();
var mins = date.getMinutes() + '';
var time = "AM";
// find time
if (hour >= 12) {
time = "PM";
}
// fix hours format
if (hour > 12) {
hour -= 12;
}
else if (hour == 0) {
hour = 12;
}
// fix minutes format
if (mins.length == 1) {
mins = "0" + mins;
}
// return formatted date time string
return date.getMonth() + 1 + "/" + date.getDate() + "/" + date.getFullYear() + " " + hour + ":" + mins + " " + time;
}
Ответ 11
Я работаю над решением этой проблемы, так как ни один из вышеперечисленных ответов мне не помог. Я работаю с календарем недели jquery и нуждаюсь в моих датах, чтобы иметь информацию о часовом поясе на сервере и локально на странице. После довольно много рывка вокруг, я выяснил решение, которое может помочь другим.
Я использую asp.net 3.5, vs 2008, asp.net MVC 2 и календарь недели jquery,
Во-первых, я использую библиотеку, написанную Стивеном Левитаном, которая помогает справляться с датами на стороне клиента, Датой регистрации Стивена Левитана. Формат isoUtcDateTime идеально подходит для того, что мне нужно. В моем вызове jQuery AJAX я использую функцию формата, предоставляемую библиотекой с форматом isoUtcDateTime, и когда вызов ajax вызывает мой метод действия, datetime Kind установлен в локальный и отражает время сервера.
Когда я отправляю даты на свою страницу через AJAX, я отправляю их в виде текстовых строк, форматируя даты, используя "ddd, dd MMM yyyy HH": 'mm': 'ss' GMT'zzzz. Этот формат легко конвертируется с помощью
var myDate = new Date(myReceivedDate);
Вот мое полное решение минус источник Стива Левитана, который вы можете скачать:
Контроллер:
public class HomeController : Controller
{
public const string DATE_FORMAT = "ddd, dd MMM yyyy HH':'mm':'ss 'GMT'zzzz";
public ActionResult Index()
{
ViewData["Message"] = "Welcome to ASP.NET MVC!";
return View();
}
public ActionResult About()
{
return View();
}
public JsonResult GetData()
{
DateTime myDate = DateTime.Now.ToLocalTime();
return new JsonResult { Data = new { myDate = myDate.ToString(DATE_FORMAT) } };
}
public JsonResult ReceiveData(DateTime myDate)
{
return new JsonResult { Data = new { myDate = myDate.ToString(DATE_FORMAT) } };
}
}
JavaScript:
<script type="text/javascript">
function getData() {
$.ajax({
url: "/Home/GetData",
type: "POST",
cache: "false",
dataType: "json",
success: function(data) {
alert(data.myDate);
var newDate = cleanDate(data.myDate);
alert(newDate);
sendData(newDate);
}
});
}
function cleanDate(d) {
if (typeof d == 'string') {
return new Date(d) || Date.parse(d) || new Date(parseInt(d));
}
if (typeof d == 'number') {
return new Date(d);
}
return d;
}
function sendData(newDate) {
$.ajax({
url: "/Home/ReceiveData",
type: "POST",
cache: "false",
dataType: "json",
data:
{
myDate: newDate.format("isoUtcDateTime")
},
success: function(data) {
alert(data.myDate);
var newDate = cleanDate(data.myDate);
alert(newDate);
}
});
}
// bind myButton click event to call getData
$(document).ready(function() {
$('input#myButton').bind('click', getData);
});
</script>
Надеюсь, этот быстрый пример поможет другим в той же ситуации, в которой я был. В настоящее время он отлично работает с Microsoft JSON Serialization и сохраняет мои даты правильными во времени.
Ответ 12
Лучший способ обработки дат в knockoutjs - использовать библиотеку времени и обрабатывать даты, такие как босс. Вы можете легко иметь дело с датами типа /Date (-62135578800000)/. Не нужно беспокоиться о том, как ваша дата сериализации в контроллере.
function jsonToDate(date,format) {
return moment(date).format(format);
}
используйте его как
var formattedDate = jsonToDate(date,'MM/DD/YYYY')
momentjs поддерживает множество дат и форматов функций в датах.
Ответ 13
Отформатируйте дату в запросе.
var _myModel = from _m in model.ModelSearch(word)
select new { date = ((DateTime)_m.Date).ToShortDateString() };
Единственная проблема с этим решением заключается в том, что вы не получите никаких результатов, если ANY из значений даты равно null. Чтобы обойти это, вы можете либо поставить условные операторы в свой запрос, прежде чем вы выбираете дату, которая игнорирует дату null, или вы можете настроить запрос для получения всех результатов, а затем пропустить всю эту информацию с помощью цикла foreach и присвоить значение ко всем датам, которые являются нулевыми до того, как вы сделаете свой новый SELECT.
Пример обоих:
var _test = from _t in adc.ItemSearchTest(word)
where _t.Date != null
select new { date = ((DateTime)_t.Date).ToShortDateString() };
Второй вариант требует другого запроса, поэтому вы можете назначать значения всем нулям. Это и цикл foreach должны быть перед вашим запросом, который выбирает значения.
var _testA = from _t in adc.ItemSearchTest(word)
select _i;
foreach (var detail in _testA)
{
if (detail.Date== null)
{
detail.Date= Convert.ToDateTime("1/1/0001");
}
}
Просто идея, которую я нашел легче, чем все примеры javascript.
Ответ 14
Вы можете использовать этот метод:
String.prototype.jsonToDate = function(){
try{
var date;
eval(("date = new " + this).replace(/\//g,''));
return date;
}
catch(e){
return new Date(0);
}
};
Ответ 15
добавить jquery ui плагин на вашей странице.
function JsonDateFormate(dateFormate, jsonDateTime) {
return $.datepicker.formatDate(dateFormate, eval('new ' + jsonDateTime.slice(1, -1)));
};
Ответ 16
Он возвращает формат даты сервера. Вам нужно определить свою собственную функцию.
function jsonDateFormat(jsonDate) {
// Changed data format;
return (new Date(parseInt(jsonDate.substr(6)))).format("mm-dd-yyyy / h:MM tt");
};
Ответ 17
Вот код JavaScript, который я написал, который устанавливает значение <input type="date">
из даты, переданной из ASP.NET MVC.
var setDate = function (id, d) {
if (d !== undefined && d !== null) {
var date = new Date(parseInt(d.replace("/Date(", "").replace(")/", ""), 10));
var day = ('0' + date.getDate()).slice(-2);
var month = ('0' + (date.getMonth() + 1)).slice(-2);
var parsedDate = date.getFullYear() + "-" + (month) + "-" + (day);
$(id).val(parsedDate);
}
};
Вы вызываете эту функцию следующим образом:
setDate('#productCommissionStartDate', data.commissionStartDate);
Где CommissionStartDate - дата JSON, переданная MVC.
Ответ 18
Не зря, но есть другой способ. Сначала создайте запрос LINQ. Затем создайте запрос результата Enumerated и примените любой тип форматирования для вас.
var query = from t in db.Table select new { t.DateField };
var result = from c in query.AsEnumerable() select new { c.DateField.toString("dd MMM yyy") };
Я должен сказать, что дополнительный шаг раздражает, но он работает хорошо.
Ответ 19
Что сработало для меня, так это создать модель представления, содержащую свойство date в виде строки. Присвоение свойства DateTime из модели домена и вызов .ToString() в свойстве date при присвоении значения модели viewmodel.
Результат JSON из метода действия MVC вернет дату в формате, совместимом с представлением.
Просмотреть модель
public class TransactionsViewModel
{
public string DateInitiated { get; set; }
public string DateCompleted { get; set; }
}
Модель домена
public class Transaction{
public DateTime? DateInitiated {get; set;}
public DateTime? DateCompleted {get; set;}
}
Метод действия контроллера
public JsonResult GetTransactions(){
var transactions = _transactionsRepository.All;
var model = new List<TransactionsViewModel>();
foreach (var transaction in transactions)
{
var item = new TransactionsViewModel
{
...............
DateInitiated = transaction.DateInitiated.ToString(),
DateCompleted = transaction.DateCompleted.ToString(),
};
model.Add(item);
}
return Json(model, JsonRequestBehavior.AllowGet);
}
Ответ 20
Переопределите контроллеры Json/JsonResult для возврата JSON.Net:
Это работает.
Ответ 21
Раздражает, не так ли?
Мое решение состояло в том, чтобы изменить мою службу WCF, чтобы вернуть DateTimes в более читаемый (не Microsoft) формат. Обратите внимание: "UpdateDateOriginal
", который представляет собой формат дат даты по умолчанию для WCF, и мой "UpdateDate
", который отформатирован на что-то более читаемое.
Вот как это сделать:
Изменение формата даты WCF
Надеюсь, что это поможет.
Ответ 22
eval (JSON.stringify(object).replace(//Date ((\ d+))//gi, function (a, b, c) {return new Date (parseInt (b))}))
Ответ 23
Самый простой:
var milisegundos = parseInt (data.replace("/Date (", "").replace(")/", ""));
Var newDate = новая дата (milisegundos). toLocaleDateString ("en-UE");