Comment analyser JSON pour recevoir un objet Date en JavaScript?

117

J'ai un morceau suivant de JSON:

\/Date(1293034567877)\/

qui est le résultat de ce code .NET:

var obj = DateTime.Now;
var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
serializer.Serialize(obj).Dump();

Maintenant, le problème auquel je suis confronté est de savoir comment créer un objet Date à partir de cela en JavaScript. Tout ce que j'ai pu trouver, c'était une incroyable solution regex (beaucoup contenant des bogues).

Il est difficile de croire qu'il n'y a pas de solution élégante car tout cela est en JavaScrip, je veux dire du code JavaScript essayant de lire JSON (JavaScript Object Notation) qui est censé être un code JavaScript et pour le moment, il s'avère que ce n'est pas parce que JavaScript ne peut pas faites du bon travail ici.

J'ai également vu des solutions d'évaluation que je ne pouvais pas faire fonctionner (en plus d'être signalé comme une menace pour la sécurité).

N'y a-t-il vraiment aucun moyen de le faire de manière élégante?

Question similaire sans vraie réponse:
Comment analyser le format de date JSON ASP.NET avec GWT

Piotr Owsiak
la source
2
Vous pouvez simplement transmettre l'horodatage au client et l'appeler new Date().
jAndy
Si j'avais un horodatage, je pourrais, mais j'ai JSON que JavaScript ne comprend apparemment pas [sic!]
Piotr Owsiak

Réponses:

51

Il n'y a pas de représentation JSON standard des dates. Vous devriez faire ce que @jAndy a suggéré et ne pas sérialiser DateTimedu tout un; envoyez simplement une chaîne de date RFC 1123 ToString("r")ou un nombre de secondes à partir de l'époque Unix, ou quelque chose d'autre que vous pouvez utiliser dans le JavaScript pour construire un fichier Date.

Jacob
la source
3
Merci d'avoir emprunté un chemin mort, vous avez été le premier à souligner que JSON ne prend pas en charge le type Date.
Piotr Owsiak
3
JSON prend en charge les nombres, les chaînes, les objets, les tableaux et les littéraux true, false et null. Étant donné que Date n'est aucun de ceux-ci, il s'agit d'un type complexe qui doit être stocké en tant qu'objet, plutôt que sous forme de chaîne, vous pouvez donc inclure des informations de type telles que le nom du type dans des membres spéciaux tels que "$ type" qui ne se résoudraient jamais en un membre réel de l'objet. Ces méta-membres peuvent être utilisés pour faire revivre l'objet JSON en un objet d'exécution fortement typé ultérieurement. Je pense que la pratique consistant à coller une date dans une chaîne est stupide, car elle crée inutilement des modèles de chaîne réservés et essaie de les faire correspondre sur chaque chaîne.
Triynko
4
Il existe désormais un format de date JSON standard. tools.ietf.org/html/rfc7493#section-4.3
Bryan Larsen
128

La JSON.parsefonction accepte une fonction de relance DateTime facultative. Vous pouvez utiliser une fonction comme celle-ci:

dateTimeReviver = function (key, value) {
    var a;
    if (typeof value === 'string') {
        a = /\/Date\((\d*)\)\//.exec(value);
        if (a) {
            return new Date(+a[1]);
        }
    }
    return value;
}

Puis appelez

JSON.parse(somejsonstring, dateTimeReviver);

Et vos dates sortiront correctement.

Tim
la source
1
Bien repéré, assez utile.
noup
5
Cette pratique de codage de données typées non primitives dans un type primitif (chaîne) est insensée. Encodez les dates dans un objet JSON avec des propriétés significatives, ou pour aller encore plus loin, incluez une propriété "$ type" dans l'objet JSON afin que la routine d'analyse / désérialisation puisse raviver le type de manière appropriée et même utiliser des convertisseurs personnalisés si vous souhaitez tout emballer les informations en une seule valeur de propriété comme "ticks" ou "ms_since_epoch".
Triynko
7
J'ai dû modifier l'expression rationnelle comme ceci / \ / Date ((-? \ D *)) \ // afin qu'il puisse également gérer les nombres négatifs. Les nombres négatifs apparaissent lorsque vous avez un très ancien DateTime (avant l'époque) qui a été converti par .NET en JSON.
ClearCloud8
@ ClearCloud8: Vous manquez des barres obliques inverses: / \ / Date \ ((-? \ D *) \) \ //
Jerther
1
Je n'ai jamais connu cette fonction - c'est tellement utile!
keldar
50

Cette réponse de Roy Tinker ici :

var date = new Date(parseInt(jsonDate.substr(6)));

Comme il le dit: La fonction substr prend la partie "/ Date (", et la fonction parseInt obtient l'entier et ignore le ") /" à la fin. Le nombre résultant est passé dans le constructeur Date.

Une autre option consiste simplement à formater correctement vos informations du côté ASP afin que JavaScript puisse les lire facilement. Pensez à faire ceci pour vos dates:

DateTime.Now()

Ce qui devrait renvoyer un format comme celui-ci:

7/22/2008 12:11:04 PM

Si vous passez ceci dans un Dateconstructeur JavaScript comme celui-ci:

var date = new Date('7/22/2008 12:11:04 PM');

La variable datecontient maintenant cette valeur:

Tue Jul 22 2008 12:11:04 GMT-0700 (Pacific Daylight Time)

Naturellement, vous pouvez formater cet DateTimeobjet dans n'importe quelle sorte de chaîne / int acceptée par le Dateconstructeur JS .

face d'arbre
la source
Merci treeface, cette réponse m'a aidé avec quelque chose récemment!
Malice
4
Ne vous fiez jamais, jamais, aux formats de conversion de chaîne de date <-> par défaut. Utiliser les millisecondes depuis Epoch, qui reste dans le domaine des types numériques, est beaucoup plus simple et fiable.
Johan Boulé
2
Cette réponse présente deux solutions - la première est correcte (le parseInt) et la seconde est fausse, donc pas sûr de savoir s'il faut voter pour ou contre! Le problème avec la simple sortie sous forme de chaîne est que la date peut facilement revenir en arrière si le serveur est dans un pays, par exemple les États-Unis et le navigateur dans un autre, par exemple au Royaume-Uni.
mike nelson
La première réponse pour me donner une sorte d'indice
Nick.McDermaid
Une réponse OK jusqu'à " Pensez à faire ceci pour vos dates… ". Suggérer un format non standard qui introduit des problèmes d'analyse et de fuseau horaire dépendants de l'implémentation n'est pas une bonne idée. Le format OP est préférable (mais pas idéal).
RobG
21

si vous utilisez la date ISO8601 de style JavaScript dans JSON, vous pouvez l'utiliser, à partir de MDN

var jsonDate = (new Date()).toJSON();
var backToDate = new Date(jsonDate);
console.log(jsonDate); //2015-10-26T07:46:36.611Z
LeeGee
la source
2
imo c'est la réponse la plus élégante et devrait être celle acceptée.
John
1
Très élégant en effet, mais cela ne concerne pas le format de date spécifique qui a été mentionné dans la question.
asiop le
@aslop - si l'utilisateur ne peut pas convertir une date vers / depuis ISO, alors JSON est le moindre des problèmes.
LeeGee
7

Vous pouvez convertir la date JSON au format de date normal en JavaScript.

var date = new Date(parseInt(jsonDate.substr(6)));
ViPuL5
la source
6

Quel est le problème avec:

new Date(1293034567877);

Cela me renvoie "Wed Dec 22 2010 16:16:07 GMT + 0000 (GMT Standard Time)".

Ou avez-vous besoin de sortir le numéro du json?

Psytronique
la source
3
Quel est le problème avec votre solution? Eh bien, le 1293034567877 n'est pas le JSON que j'ai, non? De plus, je n'ai pas besoin de sortir le numéro du JSON, j'ai besoin de sortir la date du JSON. J'attends un peu plus de JavaScript que de pouvoir tout faire avec regex. J'ai besoin que mon code soit lisible et ne ressemble pas à une malédiction de dessin animé.
Piotr Owsiak
7
Je blâmerais .NET d'avoir produit une sérialisation d'un objet date dans un format aussi étrange que \/Date(1293034567877)\/. Si c'était sain d'esprit, cela afficherait simplement l'heure de l'époque et vous pourriez initialiser un objet Date avec cela.
Quentin
2
@treeface: Si JSON n'est pas JavaScript, je pense que les tutoriels et les livres sont à blâmer pour ce malentendu courant. Quoi qu'il en soit, je suis volontiers corrigé, vraiment. Quant à votre suggestion que la date peut être représentée sous forme de chaîne, je peux dire que tout peut être représenté sous forme de chaîne, non? Mais cela ne rendrait pas notre travail plus facile, mais terriblement pénible et infernal. Je suppose que mon problème vient du fait que j'ai considéré JSON comme un format de sérialisation (annoncé pour prendre moins de bande passante et mieux fonctionner avec JavaScript que XML). Il s'avère que ce n'est pas, du moins pas indolore.
Piotr Owsiak
1
@treeface: J'ai cherché sur Google votre réclamation sur JSON et j'ai découvert que JSON est JavaScript, en fait c'est un sous-ensemble de JavaScript. Voir RFC # 4627 "Le type de média application / json pour la notation d'objet JavaScript (JSON)" et recherchez une déclaration: "Les objectifs de conception de JSON étaient qu'il soit minimal, portable, textuel et un sous-ensemble de JavaScript.". Maintenant, quand j'y pense, cela semble évident car vous pouvez appeler eval () sur JSON.
Piotr Owsiak
1
@David Dorward: Je préférerais que la complexité supplémentaire soit implémentée au plus profond des bibliothèques (soit .NET, Java, Ruby, Python ou quel que soit le langage / plate-forme sur lequel vous êtes) plutôt que de laisser les détails à gérer par le programmeur. Notez également que vous n'avez pas besoin de la prise en charge des types de données booléens et entiers dans JSON, vous pouvez simplement les mettre dans des chaînes, non? Pouvez-vous imaginer à quel point ce serait horrible d'obtenir quoi que ce soit de JSON alors?
Piotr Owsiak
2

Je sais que c'est un très vieux fil de discussion, mais je souhaite le publier pour aider ceux qui se heurtent à cela comme je l'ai fait.

si vous ne vous souciez pas d'utiliser un script tiers, vous pouvez utiliser moment, js. Ensuite, vous pouvez utiliser .format () pour le formater en tout ce que vous voulez.

Eman
la source
2

Les dates sont toujours un cauchemar. Pour répondre à votre ancienne question, c'est peut-être la manière la plus élégante:

eval(("new " + "/Date(1455418800000)/").replace(/\//g,""))

Avec eval, nous convertissons notre chaîne en code javascript. Ensuite, nous supprimons le "/", dans la fonction de remplacement est une expression régulière. Au fur et à mesure que nous commençons avec du nouveau, nos phrases vont exécuter ceci:

new Date(1455418800000)

Maintenant, une chose que j'ai commencé à utiliser il y a longtemps, ce sont les valeurs longues qui sont représentées par des graduations ... pourquoi? Eh bien, la localisation et arrêtez de penser à la façon dont la date est configurée dans chaque serveur ou chaque client. En fait, je l'utilise aussi dans les bases de données.

Il est peut-être assez tard pour cette réponse, mais peut aider n'importe qui ici.

Gabriel Andrés Brancolini
la source
Btw, mon anglais avec des années devient pire que jamais ... mais je suppose que je me suis fait comprendre.
Gabriel Andrés Brancolini
Votre réponse fonctionne très bien, m'a aidé à sortir d'un bourrage. Merci.
BoredBsee
1

AngularJS n'a pas non plus pu analyser la /Date(xxxxxxxxxxxxx)/chaîne de date .NET JSON .

J'ai résolu ce problème en formatant la date en sa représentation sous forme de chaîne ISO 8601 au lieu de vider l' Dateobjet directement ...

Voici un exemple de code ASP.NET MVC.

return Json(new { 
  date : DateTime.Now.ToString("O") //ISO 8601 Angular understands this format
});

J'ai essayé RFC 1123mais cela ne fonctionne pas. Angular traite cela comme une chaîne au lieu de Date.

return Json(new { 
  date : DateTime.Now.ToString("R") //RFC 1123 Angular won't parse this
});
Rosdi Kasim
la source
0

Je n'ai pas utilisé .Net pour des choses comme ça. Si vous parvenez à le faire imprimer quelque chose comme ce qui suit, cela devrait fonctionner.

Notez que, sauf si vous analysez cette chaîne JSON par d'autres moyens ou que vous vous attendez uniquement à ce que les utilisateurs aient des navigateurs modernes avec un analyseur JSON intégré, vous devez utiliser un framework JS ou JSON2 pour analyser la chaîne JSON sortie par le serveur dans un vrai JSON objet.

// JSON received from server is in string format
var jsonString = '{"date":1251877601000}';

//use JSON2 or some JS library to parse the string
var jsonObject =  JSON.parse( jsonString );

//now you have your date!
alert( new Date(jsonObject.date) );

Lien Wiki

Les navigateurs modernes, tels que Firefox 3.5 et Internet Explorer 8, incluent des fonctionnalités spéciales pour analyser JSON. La prise en charge native des navigateurs étant plus efficace et sécurisée que eval (), on s'attend à ce que la prise en charge native de JSON soit incluse dans la prochaine norme ECMAScript. [6]


Lien vers le fichier JSON2

Exemple en direct

brouiller
la source
Je comprends, mais mon problème avec le type JSON et Date est que je dois explicitement faire "nouvelle date (" qui est a) un travail supplémentaire b) une information supplémentaire qui doit être communiquée au consommateur. Je suis vraiment déçu de savoir comment cela est géré et je le considère fondamentalement comme une erreur dans les spécifications JSON.
Piotr Owsiak
0

La réponse à cette question est, utilisez nuget pour obtenir JSON.NET, puis utilisez ceci dans votre JsonResultméthode:

JsonConvert.SerializeObject(/* JSON OBJECT TO SEND TO VIEW */);

dans votre vue, faites-le simplement dans javascript:

JSON.parse(/* Converted JSON object */)

S'il s'agit d'un appel ajax:

var request = $.ajax({ url: "@Url.Action("SomeAjaxAction", "SomeController")", dataType: "json"});
request.done(function (data, result) { var safe = JSON.parse(data); var date = new Date(safe.date); });

Une fois JSON.parseappelé, vous pouvez mettre la date JSON dans une new Dateinstance car JsonConvertcrée une instance d'heure ISO appropriée

Callum Linington
la source
0
function parseJsonDate(jsonDate) {

    var fullDate = new Date(parseInt(jsonDate.substr(6)));
    var twoDigitMonth = (fullDate.getMonth() + 1) + ""; if (twoDigitMonth.length == 1) twoDigitMonth = "0" + twoDigitMonth;

    var twoDigitDate = fullDate.getDate() + ""; if (twoDigitDate.length == 1) twoDigitDate = "0" + twoDigitDate;
    var currentDate = twoDigitMonth + "/" + twoDigitDate + "/" + fullDate.getFullYear();

    return currentDate;
};
Muzafar
la source
0

Comme Callum l'a mentionné, pour moi, le meilleur moyen est de changer la méthode Controller en string au lieu de JsonResult ".

public string GetValues()
{
  MyObject.DateFrom = DateTime.Now;
  return JsonConvert.SerializeObject(MyObject);
}

À partir de la méthode ajax, vous pouvez faire quelque chose comme ça

 $.ajax({
 url: "/MyController/GetValues",
 type: "post",
 success: function (data) {
 var validData = JSON.parse(data);
//if you are using datepicker and you want set a format
$("#DateFrom").val($.datepicker.formatDate("dd/mm/yy", new Date(validData.DateFrom)));                                      
// if you want the date as returned
$("#DateFrom").val(new Date(validData.DateFrom))
}
});
onixpam
la source
0

en utilisant la fonction eval fonctionne, il suffit de supprimer la barre oblique à l'avant et à l'arrière.

var date1 = "/Date(25200000)/"
eval("new " + date1.substring(1, date1.length - 1));

donne Thu Jan 01 1970 00:00:00 GMT-0700 (US Mountain Standard Time)

vernmique
la source
0

J'ai rencontré un problème avec l'API externe fournissant des dates dans ce format, parfois même avec des informations de différence UTC comme /Date(123232313131+1000)/. J'ai pu le transformer en Dateobjet js avec le code suivant

var val = '/Date(123232311-1000)/';
var pattern = /^\/Date\([0-9]+((\+|\-)[0-9]+)?\)\/$/;
var date = null;

// Check that the value matches /Date(123232311-1000)/ format
if (pattern.test(val)) {
  var number = val.replace('/Date(', '',).replace(')/', '');
  if (number.indexOf('+') >= 0) {
    var split = number.split('+');
    number = parseInt(split[0]) + parseInt(split[1]);
  } else if (number.indexOf('-') >= 0) {
    var split = number.split('-');
    number = parseInt(split[0]) - parseInt(split[1]);
  } else {
    number = parseInt(number);
    date = new Date(number);
  }
}
Martin Vich
la source
-1
//
// formats a .net date into a javascript compatible date
//
function FormatJsonDate(jsonDt) 
{              
    var MIN_DATE = -62135578800000; // const

    var date = new Date(parseInt(jsonDt.substr(6, jsonDt.length-8)));                                                       
    return date.toString() == new Date(MIN_DATE).toString() ? "" : (date.getMonth() + 1) + "\\" + date.getDate() + "\\" + date.getFullYear(); 
}
sunil
la source
2
Vous ne renvoyez pas un objet de date, pour autant que je comprends le code.
Johan Boulé
-1
function parseJsonDate(jsonDate) {

    var fullDate = new Date(parseInt(jsonDate.substr(6)));
    var twoDigitMonth = (fullDate.getMonth() + 1) + ""; if (twoDigitMonth.length == 1) twoDigitMonth = "0" + twoDigitMonth;

    var twoDigitDate = fullDate.getDate() + ""; if (twoDigitDate.length == 1) twoDigitDate = "0" + twoDigitDate;
    var currentDate = twoDigitMonth + "/" + twoDigitDate + "/" + fullDate.getFullYear();

    return currentDate;
};

// Utilisez cette fonction

var objDate=parseJsonDate("\/Date(1443812400000)\/");
alert(objDate);
Muzafar Hasan
la source