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?
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 ()
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
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
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
$.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()
.
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é.
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
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".
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.
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.
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;
}
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.
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.
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);
}
};
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");
};
ajoute le plugin jquery ui dans votre page.
function JsonDateFormate(dateFormate, jsonDateTime) {
return $.datepicker.formatDate(dateFormate, eval('new ' + jsonDateTime.slice(1, -1)));
};
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";
}
}
}
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.
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.
Voici comment le faire:
Modification du format de date WCF
J'espère que cela t'aides.
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.
Remplacez les contrôleurs Json/JsonResult pour renvoyer JSON.Net:
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.
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);
}