¿Cómo analizar JSON para recibir un objeto Date en JavaScript?

117

Tengo una siguiente pieza de JSON:

\/Date(1293034567877)\/

que es el resultado de este código .NET:

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

Ahora, el problema al que me enfrento es cómo crear un objeto Date a partir de esto en JavaScript. Todo lo que pude encontrar fue una increíble solución de expresiones regulares (muchas contenían errores).

Es difícil creer que no hay una solución elegante ya que todo esto está en JavaScrip, me refiero al código JavaScript que intenta leer JSON (notación de objetos JavaScript) que se supone que es un código JavaScript y en este momento resulta que no es porque JavaScript no puede haz un buen trabajo aquí.

También he visto algunas soluciones de evaluación que no pude hacer funcionar (además de ser señaladas como una amenaza para la seguridad).

¿Realmente no hay forma de hacerlo de una manera elegante?

Pregunta similar sin respuesta real:
Cómo analizar el formato de fecha JSON de ASP.NET con GWT

Piotr Owsiak
fuente
2
Puede simplemente pasar la marca de tiempo al cliente e invocarla new Date().
jAndy
Si tuviera una marca de tiempo, podría, pero tengo JSON que JavaScript aparentemente no entiende [¡sic!]
Piotr Owsiak

Respuestas:

51

No hay una representación JSON estándar de fechas. Debes hacer lo que sugirió @jAndy y no serializar DateTimeen absoluto; simplemente envíe una cadena de fecha RFC 1123 ToString("r")o un número de segundos de Unix-epoch, o algo más que pueda usar en JavaScript para construir un Date.

Jacob
fuente
3
Gracias, estaba yendo por un camino muerto, fuiste el primero en señalar que JSON no admite el tipo de fecha.
Piotr Owsiak
3
JSON admite números, cadenas, objetos, matrices y los literales verdadero, falso y nulo. Dado que Date no es ninguno de esos, es un tipo complejo que debe almacenarse como un objeto, en lugar de una cadena, por lo que puede incluir información de tipo como el nombre del tipo en miembros especiales como "$ type" que nunca se resolvería como un miembro de objeto real. Estos metamiembros se pueden usar para revivir el objeto JSON a un objeto de tiempo de ejecución fuertemente tipado más adelante. Creo que la práctica de pegar una fecha en una cadena es estúpida, porque crea innecesariamente patrones de cadena reservados e intenta hacerlos coincidir en cada cadena.
Triynko
4
Ahora hay un formato de fecha JSON estándar. tools.ietf.org/html/rfc7493#section-4.3
Bryan Larsen
128

La JSON.parsefunción acepta una función de reactivación de fecha y hora opcional. Puedes usar una función como esta:

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

Luego llame

JSON.parse(somejsonstring, dateTimeReviver);

Y tus citas saldrán bien.

Tim
fuente
1
Bien visto, bastante útil.
noup
5
Esta práctica de codificar datos con tipos no primitivos en un tipo primitivo (cadena) es una locura. Codifique fechas en un objeto JSON con propiedades significativas, o para ir aún más lejos, incluya una propiedad "$ type" en el objeto JSON para que la rutina de análisis / deserialización pueda revivir el tipo de manera apropiada e incluso usar convertidores personalizados si desea empaquetar todo la información en un único valor de propiedad como "ticks" o "ms_since_epoch".
Triynko
7
Tuve que modificar la expresión regular de esta manera / \ / Date ((-? \ D *)) \ // para que también pudiera manejar números negativos. Los números negativos aparecen cuando tiene un DateTime muy antiguo (antes de Epoch) que fue convertido por .NET a JSON.
ClearCloud8
@ ClearCloud8: Se pierden las barras diagonales inversas: / \ / Date \ ((-? \ D *) \) \ //
Además,
1
Nunca supe sobre esta función, ¡es muy útil!
Keldar
50

Esta respuesta de Roy Tinker aquí :

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

Como él dice: La función substr saca la parte "/ Date (", y la función parseInt obtiene el número entero e ignora el ") /" al final. El número resultante se pasa al constructor Date.

Otra opción es simplemente formatear su información correctamente en el lado ASP de modo que JavaScript pueda leerla fácilmente. Considere hacer esto para sus citas:

DateTime.Now()

Que debería devolver un formato como este:

7/22/2008 12:11:04 PM

Si pasa esto a un Dateconstructor de JavaScript como este:

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

La variable dateahora tiene este valor:

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

Naturalmente, puede formatear este DateTimeobjeto en cualquier tipo de cadena / int que Dateacepte el constructor JS .

cara de árbol
fuente
Gracias treeface, esta respuesta me ayudó con algo recientemente.
Malicia
4
Nunca, nunca, confíe en los formatos de conversión de cadenas de fecha <-> predeterminados. Usar milisegundos desde Epoch, que permanece en el dominio de tipos numéricos, es mucho más simple y confiable.
Johan Boulé
2
Esta respuesta presenta dos soluciones: la primera es correcta (el parseInt) y la segunda es incorrecta, por lo que no estoy seguro de si votar a favor o en contra. El problema con la salida simplemente como una cadena es que la fecha puede retroceder fácilmente si el servidor está en un país, por ejemplo, EE.UU. y el navegador en otro, por ejemplo, Reino Unido.
Mike Nelson
La primera respuesta para darme algún tipo de pista
Nick.McDermaid
Una respuesta correcta hasta " Considere hacer esto para sus citas ... ". Sugerir un formato no estándar que presente problemas de zona horaria y análisis dependientes de la implementación no es una buena idea. El formato OP es preferible (aunque no ideal).
RobG
21

si usa la fecha ISO8601 de estilo JavaScript en JSON, puede usar esto, de MDN

var jsonDate = (new Date()).toJSON();
var backToDate = new Date(jsonDate);
console.log(jsonDate); //2015-10-26T07:46:36.611Z
LeeGee
fuente
2
En mi opinión, esta es la respuesta más elegante y debería ser la aceptada.
Juan
1
Muy elegante de hecho, pero esto no se relaciona con el formato de fecha específico que se mencionó en la pregunta.
asiop
@aslop: si el usuario no puede convertir una fecha a / desde ISO, entonces JSON es el menor de los problemas.
LeeGee
7

Puede convertir JSON Date al formato de fecha normal en JavaScript.

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

Qué hay de malo en:

new Date(1293034567877);

Esto me devuelve "Miércoles 22 de diciembre de 2010 16:16:07 GMT + 0000 (hora estándar GMT)".

¿O necesitas sacar el número del json?

Psytronic
fuente
3
¿Qué hay de malo en tu solución? Bueno, el 1293034567877 no es el JSON que tengo, ¿verdad? Además, no necesito obtener el número del JSON, necesito obtener la fecha del JSON. Espero un poco más de JavaScript que solo poder hacer todo con expresiones regulares. Necesito que mi código sea legible y no se vea como una maldición de dibujos animados.
Piotr Owsiak
7
Culparía a .NET por producir una serialización de un objeto de fecha en un formato tan extraño como \/Date(1293034567877)\/. Si estuviera cuerdo, solo generaría un tiempo de época y podría inicializar un objeto Date con eso.
Quentin
2
@treeface: si JSON no es JavaScript, entonces creo que los tutoriales y los libros son los culpables de este malentendido común. De todos modos, me corrijo con mucho gusto, de verdad. En cuanto a su sugerencia de que la fecha se puede representar como una cadena, puedo decir que todo se puede representar como una cadena, ¿verdad? Pero esto no facilitaría nuestro trabajo, sino que sería terriblemente doloroso e infernal. Supongo que mi problema se debe al hecho de que consideré JSON como un formato de serialización (anunciado para tomar menos ancho de banda y funcionar mejor con JavaScript que XML). Resulta que no lo es, al menos no indoloro.
Piotr Owsiak
1
@treeface: Hice en Google tu afirmación sobre JSON y descubrí que JSON es JavaScript, en realidad es un subconjunto de JavaScript. Consulte RFC # 4627 "El tipo de medio application / json para la notación de objetos JavaScript (JSON)" y busque una declaración: "Los objetivos de diseño de JSON eran que fuera mínimo, portátil, textual y un subconjunto de JavaScript". Ahora, cuando lo pienso, parece obvio, ya que puedes llamar a eval () en JSON.
Piotr Owsiak
1
@David Dorward: Prefiero que la complejidad adicional se implemente en las bibliotecas (ya sea .NET, Java, Ruby, Python o cualquier lenguaje / plataforma en el que se encuentre) en lugar de dejar que el programador maneje los detalles. También tenga en cuenta que no necesita soporte de tipos de datos booleanos y enteros en JSON, puede simplemente ponerlos en cadenas, ¿verdad? ¿Te imaginas lo terrible que sería obtener algo de JSON entonces?
Piotr Owsiak
2

Sé que este es un hilo muy antiguo, pero deseo publicarlo para ayudar a aquellos que se encuentran con esto como lo hice yo.

Si no le importa usar un script de terceros, puede usar moment, js Luego puede usar .format () para formatearlo a lo que quiera.

Eman
fuente
2

Las citas siempre son una pesadilla. Respondiendo a tu vieja pregunta, quizás esta sea la forma más elegante:

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

Con eval convertimos nuestra cadena a código javascript. Luego eliminamos la "/", en la función de reemplazo hay una expresión regular. Cuando comenzamos con nuevo, nuestras oraciones superarán esto:

new Date(1455418800000)

Ahora, una cosa que comencé a usar hace mucho tiempo, son los valores largos que están representados en ticks ... ¿por qué? bueno, localización y deja de pensar en cómo se configura la fecha en cada servidor o en cada cliente. De hecho, también lo uso en bases de datos.

Quizás sea bastante tarde para esta respuesta, pero puede ayudar a cualquiera por aquí.

Gabriel Andrés Brancolini
fuente
Por cierto, mi inglés con los años se está volviendo peor que nunca ... pero supongo que me hice entender.
Gabriel Andrés Brancolini
Tu respuesta funciona muy bien, me ayudó a salir de un apuro. Gracias.
BoredBsee
1

AngularJS tampoco pudo analizar la /Date(xxxxxxxxxxxxx)/cadena de fecha JSON de .NET .

Dejé de lado este problema formateando la fecha a su representación de cadena ISO 8601 en lugar de descargar el Dateobjeto directamente ...

Aquí hay una muestra de código ASP.NET MVC.

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

Lo intenté RFC 1123pero no funciona. Angular trata esto como una cadena en lugar de Date.

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

No he usado .Net para cosas como esta. Si pudo hacer que imprima algo como lo siguiente, debería funcionar.

Tenga en cuenta que, a menos que esté analizando esa cadena JSON por algún otro medio o solo espere que los usuarios tengan navegadores modernos con un analizador JSON integrado, debe usar un marco JS o JSON2 para analizar la cadena JSON generada por el servidor en un JSON real. objeto.

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

Enlace Wiki

Los navegadores modernos, como Firefox 3.5 e Internet Explorer 8, incluyen funciones especiales para analizar JSON. Dado que la compatibilidad con el navegador nativo es más eficiente y segura que eval (), se espera que la compatibilidad con JSON nativo se incluya en el próximo estándar ECMAScript. [6]


Enlace al archivo JSON2

Ejemplo en vivo

calmar
fuente
Lo entiendo, pero mi problema con JSON y el tipo de fecha es que necesito hacer explícitamente "nueva fecha (" que es a) trabajo adicional b) conocimiento adicional que debe comunicarse al consumidor. Estoy realmente decepcionado de descubrir cómo se maneja esto y básicamente lo considero un error en la especificación JSON.
Piotr Owsiak
0

La respuesta a esta pregunta es, use nuget para obtener JSON.NET y luego use esto dentro de su JsonResultmétodo:

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

dentro de su vista simple haga esto en javascript:

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

Si es una llamada 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 vez que JSON.parsese ha llamado, puede poner la fecha JSON en una new Dateinstancia porque JsonConvertcrea una instancia de tiempo ISO adecuada

Callum Linington
fuente
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
fuente
0

Como mencionó Callum, para mí, la mejor manera es cambiar el método Controller a string en lugar de JsonResult ".

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

Desde el método ajax puedes hacer algo como esto

 $.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
fuente
0

El uso de la función eval funciona solo tiene que eliminar la barra inclinada en la parte delantera y trasera.

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

produce el jueves 01 de enero de 1970 00:00:00 GMT-0700 (hora estándar de las montañas de EE. UU.)

vernmico
fuente
0

Me encontré con un problema con la API externa que proporciona fechas en este formato, algunas veces incluso con información de diferencia UTC como /Date(123232313131+1000)/. Pude convertirlo en un Dateobjeto js con el siguiente código

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);
  }
}
Martín Vich
fuente
-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
fuente
2
No está devolviendo un objeto de fecha, por lo que entiendo el código.
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 esta función

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