Come analizzare JSON per ricevere un oggetto Date in JavaScript?


117

Ho un seguente pezzo di JSON:

\/Date(1293034567877)\/

che è il risultato di questo codice .NET:

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

Ora il problema che sto affrontando è come creare un oggetto Date da questo in JavaScript. Tutto quello che ho trovato è stata un'incredibile soluzione regex (molte contenenti bug).

È difficile credere che non ci sia una soluzione elegante poiché è tutto in JavaScrip, intendo il codice JavaScript che cerca di leggere JSON (JavaScript Object Notation) che dovrebbe essere un codice JavaScript e in questo momento si scopre che non è perché JavaScript non può fai un buon lavoro qui.

Ho anche visto alcune soluzioni di valutazione che non sono riuscito a far funzionare (oltre ad essere indicato come minaccia alla sicurezza).

Non c'è davvero modo di farlo in modo elegante?

Domanda simile senza una risposta reale:
come analizzare il formato della data JSON di ASP.NET con GWT


2
Puoi semplicemente passare il timestamp al client e chiamarlo new Date().
jAndy

Se avessi il timestamp potrei, ma ho JSON che a quanto pare JavaScript non comprende [sic!]
Piotr Owsiak

Risposte:


51

Non esiste una rappresentazione JSON standard delle date. Dovresti fare ciò che @jAndy ha suggerito e non serializzare affatto un DateTime; invia semplicemente una stringa di data RFC 1123 ToString("r")o un numero di secondi da Unix-epoch, o qualcos'altro che puoi usare in JavaScript per costruire un file Date.


3
Grazie stavo percorrendo un sentiero morto, sei stato il primo a sottolineare che JSON non supporta il tipo di data.
Piotr Owsiak

3
JSON supporta numeri, stringhe, oggetti, matrici e i valori letterali true, false e null. Poiché Date non è nessuno di questi, è un tipo complesso che dovrebbe essere memorizzato come un oggetto, piuttosto che una stringa, quindi puoi includere informazioni sul tipo come il nome del tipo in membri speciali come "$ type" che non si risolveranno mai in un membro oggetto reale. Tali meta-membri possono essere utilizzati per rianimare l'oggetto JSON in un oggetto runtime fortemente tipizzato in un secondo momento. Penso che la pratica di inserire una data in una stringa sia stupida, perché crea inutilmente schemi di stringhe riservati e cerca di abbinarli su ogni stringa.
Triynko

4
Ora è disponibile un formato di data JSON standard. tools.ietf.org/html/rfc7493#section-4.3
Bryan Larsen

128

La JSON.parsefunzione accetta una funzione di ripristino DateTime opzionale. Puoi usare una funzione come questa:

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

Allora chiama

JSON.parse(somejsonstring, dateTimeReviver);

E le tue date verranno fuori bene.


1
Ben individuato, abbastanza utile.
noup

5
Questa pratica di codificare dati tipizzati non primitivi in ​​un tipo primitivo (stringa) è folle. Codifica le date in un oggetto JSON con proprietà significative o, per andare oltre, includi una proprietà "$ type" nell'oggetto JSON in modo che la routine di analisi / deserializzazione possa rianimare il tipo in modo appropriato e persino utilizzare convertitori personalizzati se desideri comprimere tutto le informazioni in un singolo valore di proprietà come "tick" o "ms_since_epoch".
Triynko

7
Ho dovuto modificare la regex in questo modo / \ / Date ((-? \ D *)) \ // in modo che fosse in grado di gestire anche i numeri negativi. I numeri negativi vengono visualizzati quando hai un DateTime molto vecchio (prima di Epoch) che è stato convertito da .NET in JSON.
ClearCloud8

@ ClearCloud8: Ti mancano le barre all'indietro: / \ / Date \ ((-? \ D *) \) \ //
Jerther

1
Non ho mai saputo di questa funzione: è così utile!
keldar

50

Questa risposta di Roy Tinker qui :

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

Come dice lui: la funzione substr estrae la parte "/ Date (" e la funzione parseInt ottiene il numero intero e ignora ") /" alla fine. Il numero risultante viene passato al costruttore Date.

Un'altra opzione è semplicemente formattare le informazioni correttamente sul lato ASP in modo che JavaScript possa leggerle facilmente. Considera di farlo per le tue date:

DateTime.Now()

Che dovrebbe restituire un formato come questo:

7/22/2008 12:11:04 PM

Se lo passi a un Datecostruttore JavaScript come questo:

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

La variabile dateora contiene questo valore:

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

Naturalmente, puoi formattare questo DateTimeoggetto in qualsiasi tipo di stringa / int Dateaccettato dal costruttore JS .


Grazie treeface, questa risposta mi ha aiutato con qualcosa di recente!
Malice

4
Mai, mai, fare affidamento sui formati di conversione della stringa data <-> predefinita. L'uso dei millisecondi da Epoch, che rimane nel dominio dei tipi numerici, è molto più semplice e affidabile.
Johan Boulé

2
Questa risposta presenta due soluzioni: la prima è corretta (il parseInt) e la seconda sbagliata, quindi non sono sicuro se votare verso l'alto o verso il basso! Il problema con il semplice output come stringa è che la data può facilmente capovolgere all'indietro se il server si trova in un paese, ad esempio, negli Stati Uniti e il browser in un altro, ad esempio nel Regno Unito.
mike nelson

La prima risposta per darmi qualsiasi tipo di indizio
Nick.McDermaid

Una risposta OK fino a quando " Considera di farlo per le date ... ". Suggerire un formato non standard che introduca analisi dipendenti dall'implementazione e problemi di fuso orario non è una buona idea. Il formato OP è preferibile (sebbene non ideale).
RobG

21

se utilizzi la data ISO8601 in stile JavaScript in JSON, puoi utilizzarla, da MDN

var jsonDate = (new Date()).toJSON();
var backToDate = new Date(jsonDate);
console.log(jsonDate); //2015-10-26T07:46:36.611Z

2
imo questa è la risposta più elegante e dovrebbe essere quella accettata.
Giovanni

1
Davvero molto elegante, ma questo non si riferisce al formato specifico della data menzionato nella domanda.
asiop

@aslop: se l'utente non può convertire una data in / da ISO, JSON è l'ultimo dei problemi.
LeeGee

7

Puoi convertire la data JSON nel normale formato della data in JavaScript.

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

6

Cosa c'è di sbagliato in:

new Date(1293034567877);

Questo restituisce per me "Wed Dec 22 2010 16:16:07 GMT + 0000 (GMT Standard Time)".

O hai bisogno di ottenere il numero dal JSON?


3
Cosa c'è di sbagliato nella tua soluzione? Ebbene il 1293034567877 non è il JSON che ho, giusto? Inoltre non ho bisogno di estrarre il numero dal JSON, ho bisogno di ottenere la data dal JSON. Mi aspetto un po 'di più da JavaScript che essere in grado di fare tutto con regex. Ho bisogno che il mio codice sia leggibile e non sembri una maledizione dei cartoni animati.
Piotr Owsiak

7
Incolperei .NET per aver prodotto una serializzazione di un oggetto data in un formato strano come \/Date(1293034567877)\/. Se fosse sano, restituirebbe solo l'ora dell'epoca e con quello potresti inizializzare un oggetto Date.
Quentin

2
@treeface: se JSON non è JavaScript, penso che i tutorial e i libri debbano essere incolpati di questo comune malinteso. Comunque mi correggo volentieri, davvero. Per quanto riguarda il tuo suggerimento che la data possa essere rappresentata come stringa, posso dire che tutto può essere rappresentato come stringa, giusto? Ma questo non renderebbe il nostro lavoro più facile, ma terribilmente doloroso e infernale. Immagino che il mio problema derivi dal fatto che ho considerato JSON come un formato di serializzazione (pubblicizzato per prendere meno larghezza di banda e funzionare meglio con JavaScript che XML). A quanto pare non lo è, almeno non indolore.
Piotr Owsiak

1
@treeface: ho cercato su Google la tua affermazione su JSON e ho scoperto che JSON è JavaScript, in realtà è un sottoinsieme di JavaScript. Vedere RFC # 4627 "The application / json Media Type for JavaScript Object Notation (JSON)" e cercare una dichiarazione: "Gli obiettivi di progettazione di JSON erano che fosse minimo, portabile, testuale e un sottoinsieme di JavaScript.". Ora, quando ci penso, sembra ovvio come puoi chiamare eval () su JSON.
Piotr Owsiak

1
@David Dorward: Preferirei che la complessità aggiuntiva fosse implementata in profondità all'interno delle librerie (.NET, Java, Ruby, Python o qualsiasi lingua / piattaforma su cui ti trovi) piuttosto che lasciare che i dettagli siano gestiti dal programmatore. Tieni inoltre presente che non è necessario il supporto per i tipi di dati booleani e interi in JSON, puoi semplicemente inserirli in stringhe, giusto? Riesci a immaginare quanto sarebbe orribile ottenere qualcosa da JSON allora?
Piotr Owsiak

2

So che questo è un thread molto vecchio ma desidero postarlo per aiutare coloro che si imbattono in questo come ho fatto io.

se non ti interessa usare uno script di terze parti, puoi usare moment, js Quindi puoi usare .format () per formattarlo in qualsiasi cosa tu voglia.


2

Le date sono sempre un incubo. Rispondendo alla tua vecchia domanda, forse questo è il modo più elegante:

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

Con eval convertiamo la nostra stringa in codice javascript. Quindi rimuoviamo la "/", nella funzione di sostituzione è un'espressione regolare. Quando iniziamo con nuovo, le nostre frasi eseguiranno questo:

new Date(1455418800000)

Ora, una cosa che ho iniziato a usare molto tempo fa, sono i valori lunghi rappresentati in zecche ... perché? bene, localizzazione e smetti di pensare a come è configurata la data in ogni server o ogni client. In effetti, lo uso anche nei database.

Forse è abbastanza tardi per questa risposta, ma può aiutare chiunque qui intorno.


A proposito, il mio inglese con gli anni sta peggiorando che mai ... ma credo di essermi fatto capire.
Gabriel Andrés Brancolini

La tua risposta funziona alla grande, mi ha aiutato a uscire da una marmellata. Grazie.
BoredBsee

1

AngularJS non è in grado di analizzare la /Date(xxxxxxxxxxxxx)/stringa della data JSON .NET ..

Ho risolto il problema formattando la data sulla sua rappresentazione di stringa ISO 8601 invece di scaricare Datedirettamente l' oggetto ...

Ecco un esempio di codice ASP.NET MVC.

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

Ho provato RFC 1123ma non funziona .. Angular lo tratta come una stringa invece di una data.

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

0

Non ho usato .Net per cose come questa. Se sei riuscito a farlo stampare qualcosa come il seguente, dovrebbe funzionare.

Nota, a meno che tu non stia analizzando quella stringa JSON con altri mezzi o ti aspetti che gli utenti abbiano solo browser moderni con un parser JSON integrato, devi utilizzare un framework JS o JSON2 per analizzare la stringa JSON emessa dal server in un vero JSON oggetto.

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

Wiki Link

I browser moderni, come Firefox 3.5 e Internet Explorer 8, includono funzionalità speciali per l'analisi di JSON. Poiché il supporto del browser nativo è più efficiente e sicuro di eval (), si prevede che il supporto JSON nativo sarà incluso nel prossimo standard ECMAScript. [6]


Collegamento al file JSON2

Esempio dal vivo


Ho capito, ma il mio problema con JSON e il tipo di data è che devo fare esplicitamente "nuova data (" che è un) lavoro extra b) ulteriore conoscenza che deve essere comunicata al consumatore. Sono davvero deluso di scoprire come viene gestito e fondamentalmente lo considero un errore nelle specifiche JSON.
Piotr Owsiak

0

La risposta a questa domanda è: usa nuget per ottenere JSON.NET, quindi usa questo nel tuo JsonResultmetodo:

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

all'interno della tua vista semplice fai questo in javascript:

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

Se è una chiamata 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); });

Una volta JSON.parsechiamato, puoi inserire la data JSON in new Dateun'istanza perché JsonConvertcrea un'istanza temporale ISO appropriata


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

0

Come ha detto Callum, per me, il modo migliore è cambiare il metodo Controller in stringa invece di JsonResult ".

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

Dal metodo ajax puoi fare qualcosa del genere

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

0

utilizzando la funzione eval funziona basta rimuovere la barra in avanti davanti e dietro.

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

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


0

Ho riscontrato un problema con l'API esterna che fornisce date in questo formato, alcune volte anche con informazioni sulla differenza UTC come /Date(123232313131+1000)/. Sono stato in grado di trasformarlo in Dateoggetto js con il seguente codice

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

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

2
Non stai restituendo un oggetto data, per quanto ho capito il codice.
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;
};

// Usa questa funzione

var objDate=parseJsonDate("\/Date(1443812400000)\/");
alert(objDate);
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.