web-dev-qa-db-fra.com

Format de date ASP.NET MVC JsonResult

J'ai une action de contrôleur qui renvoie simplement un résultat JsonResult de mon modèle. Donc, dans ma méthode, j'ai quelque chose comme:

return new JsonResult(myModel);

Cela fonctionne bien, sauf pour un problème. Il y a une propriété de date dans le modèle et cela semble être retourné dans le résultat Json comme ceci:

"\/Date(1239018869048)\/"

Comment dois-je gérer les dates afin qu'elles soient renvoyées dans le format requis? Ou comment gérer ce format ci-dessus dans un script?

231
Jon Archway

Juste pour développer réponse de casperOne .

Le spécification JSON ne prend pas en compte les valeurs de date. MS devait passer un appel et le chemin choisi était d’exploiter une petite astuce dans la représentation javascript des chaînes: le littéral chaîne "/" est identique à "\ /" et une chaîne littérale sera ne jamais être sérialisé vers "\ /" (même "\ /" doit être mappé sur "\\ /").

Voir http://msdn.Microsoft.com/en-us/library/bb299886.aspx#intro_to_json_topic2 pour une meilleure explication (faites défiler jusqu'à "Des littéraux JavaScript à JSON").

L’un des points sensibles de JSON est l’absence de littéral date/heure. Beaucoup de gens sont surpris et déçus d'apprendre cela lorsqu'ils rencontrent JSON pour la première fois. L’explication simple (consoler ou non) de l’absence d’un littéral date/heure est que JavaScript n’en a jamais eu non plus: le support des valeurs de date et heure en JavaScript est entièrement fourni via l’objet Date. Par conséquent, la plupart des applications utilisant JSON comme format de données ont généralement tendance à utiliser une chaîne ou un nombre pour exprimer les valeurs de date et d'heure. Si une chaîne est utilisée, vous pouvez généralement vous attendre à ce qu'elle soit au format ISO 8601. Si un nombre est utilisé, la valeur est généralement utilisée pour désigner le nombre de millisecondes en temps coordonné universel (UTC) depuis Epoch, où Epoch est défini comme étant minuit le 1er janvier 1970 (UTC). Encore une fois, ceci est une simple convention et ne fait pas partie de la norme JSON. Si vous échangez des données avec une autre application, vous devrez vérifier sa documentation pour voir comment elle encode les valeurs de date et d'heure dans un littéral JSON. Par exemple, ASP.NET AJAX de Microsoft n'utilise aucune des conventions décrites. Au lieu de cela, il code les valeurs .NET DateTime en tant que chaîne JSON, où le contenu de la chaîne est/Date (ticks)/et où ticks représente des millisecondes depuis Epoch (UTC). Ainsi, le 29 novembre 1989 à 4:55:30 du matin, en UTC, le code "\/Date (628318530718)\/" est codé.

Une solution serait simplement de l’analyser:

value = new Date(parseInt(value.replace("/Date(", "").replace(")/",""), 10));

Cependant, j'ai entendu dire qu'il existe un paramètre permettant au sérialiseur de générer des objets DateTime avec la syntaxe new Date(xxx). Je vais essayer de creuser ça.


Le deuxième paramètre de JSON.parse() accepte une fonction reviver, qui spécifie comment la valeur produite à l'origine par, avant d'être renvoyée.

Voici un exemple pour la date:

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

Voir la documentation de JSON.parse ()

188
JPot

Voici ma solution en Javascript - très semblable à celle de JPot, mais plus courte (et peut-être un peu plus rapide):

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

"value.substr (6)" supprime la partie "/ Date (") et la fonction parseInt ignore les caractères non numériques qui apparaissent à la fin.

EDIT: j'ai volontairement laissé de côté la base (le deuxième argument à analyser); voir mon commentaire ci-dessous . Veuillez également noter que les dates ISO-8601 sont préférables à cet ancien format. Ce format ne doit donc généralement pas être utilisé pour de nouveaux développements. Voir l'excellente bibliothèque Json.NET pour une excellente alternative qui sérialise les dates à l'aide du format ISO-8601.

Pour les dates JSON formatées ISO-8601, il suffit de passer la chaîne dans le constructeur Date:

var date = new Date(jsonDate); //no ugly parsing needed; full timezone support
94
Roy Tinker

Il y a pas mal de réponses pour gérer le côté client, mais vous pouvez modifier le côté serveur de sortie si vous le souhaitez.

Il y a plusieurs façons d'aborder cela, je vais commencer par les bases. Vous devrez sous-classer la classe JsonResult et substituer la méthode ExecuteResult. À partir de là, vous pouvez adopter différentes approches pour modifier la sérialisation.

Approche 1: L'implémentation par défaut utilise le JsonScriptSerializer . Si vous consultez la documentation, vous pouvez utiliser la méthode RegisterConverters pour ajouter un paramètre personnalisé JavaScriptConverters . Il existe toutefois quelques problèmes avec ceci: JavaScriptConverter sérialise dans un dictionnaire, c’est-à-dire qu’il prend un objet et se sérialise dans un dictionnaire Json. Pour que l'objet soit sérialisé en chaîne, un peu de piratage est nécessaire, voir post . Ce hack va également échapper à la chaîne.

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

Approche 2 (recommandée): La deuxième approche consiste à commencer avec le JsonResult surchargé et à utiliser un autre sérialiseur Json, dans mon cas le Json .NET sérialiseur. Cela ne nécessite pas le piratage de l'approche 1. Voici ma mise en œuvre de la sous-classe 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));
        }
    }
}

Exemple d'utilisation:

[HttpGet]
public ActionResult Index() {
    return new CustomJsonResult { Data = new { users=db.Users.ToList(); } };
}

Crédits supplémentaires: James Newton-King

63
Perishable Dave

Moment.js est une bibliothèque datetime étendue qui prend également en charge cette fonctionnalité. http://momentjs.com/docs/#/parsing/asp-net-json-dates/

ex: moment ("/ Date (1198908717056-0700) /")

Cela pourrait aider. sortie du plongeur

30
Eric

Utilisation de jQuery pour convertir automatiquement les dates avec $.parseJSON

Note : cette réponse fournit une extension jQuery qui ajoute un ISO automatique et Prise en charge du format de date .net

Puisque vous utilisez Asp.net MVC, je suppose que vous utilisez jQuery côté client. Je vous suggère de lire cet article de blog qui a du code comment utiliser $.parseJSON pour convertir automatiquement les dates pour vous.

Code prend en charge les dates au format Asp.net telles que celles que vous avez mentionnées, ainsi que les dates au format ISO. Toutes les dates seront automatiquement formatées pour vous en utilisant $.parseJSON().

19
Robert Koritnik

J'ai trouvé que créer une nouvelle JsonResult et renvoyer cela n'est pas satisfaisant - devoir remplacer tous les appels à return Json(obj) par return new MyJsonResult { Data = obj } est une tâche pénible.


Alors j'ai pensé, pourquoi ne pas juste détourner le JsonResult en utilisant un 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));
            }
        }
    }
}

Ceci peut être appliqué à toute méthode renvoyant un JsonResult pour utiliser JSON.Net à la place:

[JsonNetFilter]
public ActionResult GetJson()
{
    return Json(new { hello = new Date(2015, 03, 09) }, JsonRequestBehavior.AllowGet)
}

qui répondra avec

{"hello":"2015-03-09T00:00:00+00:00"}

comme voulu!


Vous pouvez, si cela ne vous dérange pas d’appeler la comparaison is à chaque demande, l’ajouter à votre FilterConfig:

// ...
filters.Add(new JsonNetFilterAttribute());

et tous vos JSON seront maintenant sérialisés avec JSON.Net au lieu du JavaScriptSerializer intégré.

18
dav_i

La communication Ajax entre le client et le serveur implique souvent des données au format JSON. Bien que JSON fonctionne bien pour les chaînes, les nombres et les booléens, il peut poser certaines difficultés pour les dates en raison de la façon dont ASP.NET les sérialise. Comme il n'y a pas de représentation particulière pour les dates, elles sont sérialisées en tant que chaînes simples. En guise de solution, le mécanisme de sérialisation par défaut de ASP.NET Web Forms et de MVC sérialise les dates sous une forme spéciale -/Date (ticks)/-, où ticks correspond au nombre de millisecondes depuis le 1er janvier 1970.

Ce problème peut être résolu de 2 manières:

côté client

Convertissez la chaîne de date reçue en un nombre et créez un objet de date à l'aide du constructeur de la classe de date avec les graduations en paramètre.

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

}

côté serveur

La solution précédente utilise un script côté client pour convertir la date en objet Date JavaScript. Vous pouvez également utiliser un code côté serveur qui sérialise les instances .NET DateTime au format de votre choix. Pour accomplir cette tâche, vous devez créer votre propre ActionResult, puis sérialiser les données comme vous le souhaitez.

référence: http://www.developer.com/net/dealing-with-json-dates-in-asp.net-mvc.html

11
Mischa

J'ai eu le même problème et au lieu de renvoyer la valeur de date réelle, je viens d'utiliser ToString ("jj MMM aaaa"). Ensuite, dans mon javascript, j'ai utilisé new Date (datevalue), datevalue pouvant être "01 janv. 2009".

7
Joe

Voir ce fil:

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

Fondamentalement, bien que le format Date() soit valide javascript, ce n'est pas valide JSON (il y a une différence). Si vous voulez l'ancien format, vous devrez probablement créer une façade et transformer la valeur vous-même, ou trouver un moyen d'obtenir le sérialiseur de votre type dans JsonResult et lui faire utiliser un format personnalisé pour les dates.

4
casperOne

La meilleure façon de gérer les dates dans knockoutjs est d'utiliser la bibliothèque de moments et de gérer les dates comme Boss. Vous pouvez facilement traiter des dates telles que/Date (-62135578800000) /. Pas besoin de vous soucier de la façon dont vous sérialisez la date dans le contrôleur.

function jsonToDate(date,format) {
   return moment(date).format(format);
}

l'utiliser comme

var formattedDate = jsonToDate(date,'MM/DD/YYYY')

momentjs prend en charge de nombreux formats de date et heure ainsi que des fonctions utilitaires sur les dates.

2
Ajay Kelkar

Pas la manière la plus élégante mais cela a fonctionné pour moi:

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;
}
2
Gabe

J'ai travaillé sur une solution à ce problème car aucune des réponses ci-dessus ne m'a vraiment aidé. Je travaillais avec le calendrier de la semaine jQuery et j'avais besoin de dates pour avoir des informations de fuseau horaire sur le serveur et localement sur la page. Après avoir fouillé un peu, j'ai trouvé une solution qui pourrait aider les autres.

J'utilise asp.net 3.5, vs 2008, asp.net MVC 2 et le calendrier de la semaine jQuery,

Premièrement, j'utilise une bibliothèque écrite par Steven Levithan qui aide à gérer les dates côté client, la bibliothèque de dates de Steven Levithan . Le format isoUtcDateTime est parfait pour ce dont j'avais besoin. Dans mon appel jquery AJAX, j'utilise la fonction de format fournie avec la bibliothèque avec le format isoUtcDateTime et lorsque l'appel ajax touche ma méthode d'action, le type datetime est défini sur local et reflète l'heure du serveur.

Lorsque j'envoie des dates sur ma page via AJAX, je les envoie sous forme de chaînes de texte en les formatant avec "jj, jj MMM aaaa HH ':' mm ':' ss 'GMT'zzzz". Ce format est facilement converti côté client en utilisant

var myDate = new Date(myReceivedDate);

Voici ma solution complète moins la source de Steve Levithan, que vous pouvez télécharger:

Manette:

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>

J'espère que cet exemple rapide aidera d'autres personnes dans la même situation que celle dans laquelle je me trouvais. À l'heure actuelle, il semble très bien fonctionner avec la sérialisation JSON de Microsoft et maintient mes dates exactes dans les fuseaux horaires.

2
Jesse

Formatez la date dans la requête.

var _myModel = from _m in model.ModelSearch(Word)
    select new { date = ((DateTime)_m.Date).ToShortDateString() };

Le seul problème avec cette solution est que vous n'obtiendrez aucun résultat si AUCUNE des valeurs de date n'est nulle. Pour contourner ce problème, vous pouvez soit insérer des instructions conditionnelles dans votre requête AVANT de sélectionner la date qui ignore les dates nulles, soit configurer une requête pour obtenir tous les résultats, puis parcourir toutes ces informations à l'aide d'une boucle foreach et attribuer une valeur. à toutes les dates nulles AVANT de faire votre nouvelle commande SELECT.

Exemple des deux:

var _test = from _t in adc.ItemSearchTest(Word)
                        where _t.Date != null
                        select new { date = ((DateTime)_t.Date).ToShortDateString() };

La deuxième option nécessite entièrement une autre requête afin que vous puissiez affecter des valeurs à toutes les valeurs nulles. Cette boucle et la boucle foreach doivent être AVANT votre requête qui sélectionne les valeurs.

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");
                }
            }

Juste une idée que j'ai trouvée plus facile que tous les exemples en javascript.

1
Chad

Vous pouvez utiliser cette méthode:

String.prototype.jsonToDate = function(){
    try{
        var date;
        eval(("date = new " + this).replace(/\//g,''));
        return date;
    } 
    catch(e){
        return new Date(0);
    }
};
1
eladmat

Il retourne le format de date du serveur. Vous devez définir votre propre fonction.

function jsonDateFormat(jsonDate) {

// Changed data format;
return (new Date(parseInt(jsonDate.substr(6)))).format("mm-dd-yyyy / h:MM tt");

};

0
Manish Kundu

ajoute le plugin jquery ui dans votre page.

function JsonDateFormate(dateFormate, jsonDateTime) {
    return $.datepicker.formatDate(dateFormate, eval('new ' + jsonDateTime.slice(1, -1)));
};
0
Thulasiram

J'ai trouvé que c'était le moyen le plus simple de changer le côté serveur.

using System.Collections.Generic;
using System.Web.Mvc;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;

namespace Website
{
    /// <summary>
    /// This is like MVC5's JsonResult but it uses CamelCase and date formatting.
    /// </summary>
    public class MyJsonResult : ContentResult
    {
        private static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
        {
            ContractResolver = new CamelCasePropertyNamesContractResolver(),
            Converters = new List<JsonConverter> { new StringEnumConverter() }
        };

        public FindersJsonResult(object obj)
        {
            this.Content = JsonConvert.SerializeObject(obj, Settings);
            this.ContentType = "application/json";
        }
    }
}
0

Voici du code JavaScript que j'ai écrit qui définit une valeur <input type="date"> à partir d'une date passée à partir d'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);
    }
};

Vous appelez cette fonction comme suit:

setDate('#productCommissionStartDate', data.commissionStartDate);

Où commissionStartDate est la date JSON transmise par MVC.

0
Tribal Coder

Ennuyant, n'est-ce pas?

Ma solution a été de changer mon service WCF pour qu'il retourne DateTimes dans un format plus lisible (non Microsoft). Notez ci-dessous, le "UpdateDateOriginal", qui est le format de date par défaut de WCF, et mon "UpdateDate", qui est formaté de manière à être plus lisible.

enter image description here

Voici comment le faire:

Modification du format de date WCF

J'espère que cela t'aides.

0
Mike Gledhill

Pas pour rien, mais il y a un autre moyen. Commencez par construire votre requête LINQ. Ensuite, créez une requête du résultat énuméré et appliquez le type de mise en forme qui vous convient.

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") };

Je dois dire que l'étape supplémentaire est ennuyeuse, mais cela fonctionne bien.

0
skrile

Remplacez les contrôleurs Json/JsonResult pour renvoyer JSON.Net:

Cela fonctionne un régal

0
Ian

Ce qui a fonctionné pour moi a été de créer un modèle de vue contenant la propriété date sous forme de chaîne. Affectation de la propriété DateTime à partir du modèle de domaine et appel de la propriété .ToString () sur la propriété date lors de l'attribution de la valeur à viewmodel.

Un résultat JSON d'une méthode d'action MVC renverra la date dans un format compatible avec la vue.

Voir le modèle

public class TransactionsViewModel
{
    public string DateInitiated { get; set; }
    public string DateCompleted { get; set; }
}

Modèle de domaine

public class Transaction{
   public DateTime? DateInitiated {get; set;}
   public DateTime? DateCompleted {get; set;}
}

Méthode d'action du contrôleur

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);
}
0
Oladipo Olasemo