Формат даты ASP.NET MVC JsonResult - PullRequest
226 голосов
/ 07 апреля 2009

У меня есть действие контроллера, которое фактически просто возвращает JsonResult моей модели. Итак, в моем методе у меня есть что-то вроде следующего:

return new JsonResult(myModel);

Это работает хорошо, за исключением одной проблемы. В модели есть свойство date, которое, по-видимому, возвращается в результате Json:

"\/Date(1239018869048)\/"

Как мне обращаться с датами, чтобы они возвращались в нужном мне формате? Или как мне обработать этот формат выше в сценарии?

Ответы [ 23 ]

184 голосов
/ 07 апреля 2009

Просто чтобы расширить ответ casperOne .

Спецификация JSON не учитывает значения даты. 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 ()

94 голосов
/ 20 ноября 2009

Вот мое решение в Javascript - очень похожее на JPot, но короче (и, возможно, чуть-чуть быстрее):

value = new Date(parseInt(value.substr(6)));

"value.substr (6)" убирает часть "/ Date ("), а функция parseInt игнорирует нечисловые символы, встречающиеся в конце.

РЕДАКТИРОВАТЬ: я намеренно пропустил основание (2-й аргумент для parseInt); см. мой комментарий ниже . Кроме того, обратите внимание, что даты ISO-8601 предпочтительнее этого старого формата - поэтому этот формат обычно не следует использовать для новой разработки. См. Превосходную библиотеку Json.NET для прекрасной альтернативы, которая сериализует даты, используя формат ISO-8601.

Для дат JSON в формате ISO-8601 просто передайте строку в конструктор Date:

var date = new Date(jsonDate); //no ugly parsing needed; full timezone support
63 голосов
/ 16 февраля 2012

Существует довольно много ответов для обработки на стороне клиента, но вы можете изменить сторону сервера вывода, если хотите.

Есть несколько способов подойти к этому, я начну с основ. Вам придется создать подкласс класса 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(); } };
}

Дополнительные кредиты: Джеймс Ньютон-Кинг

30 голосов
/ 05 ноября 2012

Moment.js - обширная библиотека datetime, которая также поддерживает это. http://momentjs.com/docs/#/parsing/asp-net-json-dates/

например: момент ("/ Дата (1198908717056-0700) /")

Это может помочь. выход плунжера

19 голосов
/ 27 декабря 2010

Использование jQuery для автоматического преобразования дат с $.parseJSON

Примечание : этот ответ предоставляет расширение jQuery, которое добавляет автоматическую поддержку формата ISO и .net даты.

Так как вы используете Asp.net MVC, я подозреваю, что вы используете jQuery на стороне клиента. Я предлагаю вам прочитать это сообщение в блоге , в котором есть код, как использовать $.parseJSON для автоматического преобразования дат для вас.

Код поддерживает даты в формате Asp.net, такие как упомянутые вами, а также даты в формате ISO. Все даты будут автоматически отформатированы для вас с помощью $.parseJSON().

17 голосов
/ 09 марта 2015

Я обнаружил, что создание нового 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.

11 голосов
/ 10 октября 2014

Ajax-связь между клиентом и сервером часто включает данные в формате JSON. Хотя JSON хорошо работает со строками, числами и логическими значениями, он может создавать некоторые трудности для дат из-за того, как ASP.NET их сериализует. Поскольку он не имеет специального представления для дат, они сериализуются в виде простых строк. В качестве решения механизм сериализации по умолчанию ASP.NET Web Forms и MVC сериализует даты в специальной форме - / Date (ticks) / -, где ticks - это количество миллисекунд с 1 января 1970 года.

Эту проблему можно решить двумя способами:

на стороне клиента

Преобразовать полученную строку даты в число и создать объект даты, используя конструктор класса даты с галочками в качестве параметра.

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();

}

на стороне сервера

Предыдущее решение использует скрипт на стороне клиента для преобразования даты в объект JavaScript Date. Вы также можете использовать код на стороне сервера, который сериализует экземпляры .NET DateTime в выбранном вами формате. Для выполнения этой задачи вам нужно создать собственный ActionResult, а затем сериализовать данные так, как вы хотите.

ссылка: http://www.developer.com/net/dealing-with-json-dates-in-asp.net-mvc.html

7 голосов
/ 11 марта 2010

У меня была та же проблема, и вместо возврата фактического значения даты я просто использовал ToString ("dd MMM yyyy") для него. Затем в моем javascript я использовал новую дату (datevalue), где datevalue может быть «01.01.2009».

4 голосов
/ 07 апреля 2009

Смотрите эту тему:

http://forums.asp.net/p/1038457/1441866.aspx#1441866

По сути, хотя формат Date() является допустимым javascript, он НЕ является действительным JSON (есть разница). Если вы хотите использовать старый формат, вам, вероятно, придется создать фасад и трансформировать значение самостоятельно, либо найти способ получить сериализатор для вашего типа в JsonResult и использовать его в пользовательском формате для дат.

2 голосов
/ 11 января 2010

Не самый элегантный способ, но у меня это сработало:

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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...