El formato de fecha JSON "correcto"

1138

He visto muchos estándares diferentes para el formato de fecha JSON:

"\"\\/Date(1335205592410)\\/\""         .NET JavaScriptSerializer
"\"\\/Date(1335205592410-0500)\\/\""    .NET DataContractJsonSerializer
"2012-04-23T18:25:43.511Z"              JavaScript built-in JSON object
"2012-04-21T18:25:43-05:00"             ISO 8601

¿Cuál es la correcta? O mejor? ¿Hay algún tipo de estándar en esto?

Kamyar Nazeri
fuente
75
No hay formato de fecha en JSON, solo hay cadenas que un des / serializador decide asignar a valores de fecha.
11
strings, numbers, true, false, null, objectsYarrays
Russ Cam
12
Sin embargo, el objeto JSON incorporado de JavaScript y el ISO8601 contienen toda la información para ser entendida por humanos y computadoras y no se basa en el comienzo de la era de las computadoras (1970-1-1).
poussma

Respuestas:

1850

JSON enno especifica cómo se deben representar las fechas, pero JavaScript sí.

Usted debe utilizar el formato emitido por Date's toJSONmétodo:

2012-04-23T18:25:43.511Z

Este es el por qué:

  1. Es legible para los humanos pero también sucinto

  2. Se ordena correctamente

  3. Incluye segundos fraccionarios, que pueden ayudar a restablecer la cronología.

  4. Cumple con ISO 8601

  5. ISO 8601 ha sido bien establecido internacionalmente por más de una década

  6. ISO 8601 está avalado por W3C , RFC3339 y XKCD

Dicho esto , cada biblioteca de fechas jamás escrita puede comprender "milisegundos desde 1970". Entonces, para una fácil portabilidad, ThiefMaster tiene razón.

funroll
fuente
32
Esta es también la representación preferida de acuerdo con ECMA :JSON.stringify({'now': new Date()}) "{"now":"2013-10-21T13:28:06.419Z"}"
Steven
11
Añadiría otra razón importante a la lista: es independiente de la configuración regional. Si tuviera una fecha como 02-03-2014, necesitaría información adicional para saber si se refiere al 3 de febrero o al 2 de marzo. Depende de si se utiliza el formato de EE. UU. U otro formato.
Juanal
107
Voto por mencionar y vincular xkcd: D @ajorquera Usualmente utilizo momentjs para esto. También he visto problemas con IE a este respecto
fholzer
54
Con respecto al segundo punto, no se clasifica correctamente después del año 10000. Sin embargo, tenemos casi 8000 años para encontrar un nuevo formato, por lo que probablemente no sea un problema.
Erfa
77
En realidad, @Erfa, como -viene antes de los dígitos ASCII, se ordenará muy bien hasta el año 100,000. ; P
Ben Leggiero
128

JSON no sabe nada sobre fechas. Lo que hace .NET es un hack / extensión no estándar.

Usaría un formato que se pueda convertir fácilmente en un Dateobjeto en JavaScript, es decir, uno al que se pueda pasar new Date(...). El formato más fácil y probablemente más portátil es la marca de tiempo que contiene milisegundos desde 1970.

ThiefMaster
fuente
3
stackoverflow.com/questions/10286385/… - veamos si alguien sabe por qué FF se comporta así.
ThiefMaster
11
Si sigue esta ruta, asegúrese de no tener que lidiar con fechas anteriores a 1970.
Ben Dolman
8
Como dijo @BenDolman, esta "solución" no trata adecuadamente con fechas anteriores al 1 de enero de 1970 (Época). Además, hay una razón por la cual ISO8601 existe en primer lugar. Aquí en la Tierra tenemos cosas llamadas "zonas horarias". ¿Dónde está eso en milisegundos? JSON no puede tener un estándar para las fechas, pero existen fechas fuera de JSON, y no es un estándar para eso. La respuesta de funroll es la correcta (ver también: xkcd.com/1179 ).
JoeLinux
55
Quizás también valga la pena mencionar que (mili) segundos desde 1970 no son predecibles para fechas en el futuro porque tenemos segundos bisiestos . Por lo tanto, no lo usaría para la comunicación entre procesos y el almacenamiento de datos. Sin embargo, es agradable usarlo internamente en un programa, ya que puede almacenarse en un solo entero, lo que le brinda algunos beneficios de rendimiento.
Brodie Garnet
55
La marca de tiempo de Unix siempre es UTC, convierte desde su zona horaria local antes de generar la marca de tiempo, y de nuevo a la zona horaria local en la pantalla, no hay ambigüedad allí.
lkraider
46

No hay un formato correcto ; La especificación JSON no especifica un formato para intercambiar fechas, razón por la cual hay tantas formas diferentes de hacerlo.

El mejor formato es posiblemente una fecha representada en formato ISO 8601 ( ver Wikipedia ); Es un formato muy conocido y ampliamente utilizado y puede manejarse en muchos idiomas diferentes, lo que lo hace muy adecuado para la interoperabilidad. Si tiene control sobre el json generado, por ejemplo, proporciona datos a otros sistemas en formato json, eligiendo 8601 como formato de intercambio de fechas es una buena opción.

Si no tiene control sobre el json generado, por ejemplo, es el consumidor de json de varios sistemas existentes diferentes, la mejor manera de manejar esto es tener una función de utilidad de análisis de fechas para manejar los diferentes formatos esperados.

Russ Cam
fuente
2
@mlissner, pero esa es una opinión sobre cuál es el mejor. ISO-8601 es un estándar, pero no es el estándar para JSON (aunque me inclinaría a usarlo); por ejemplo, Microsoft decidió no usarlo ( msdn.microsoft.com/en-us/library/… ). La mejor práctica es seguir una convención (sensata), sea lo que sea. Como dije en la respuesta, la mejor manera de manejar esto es definir una función de utilidad de análisis de fechas que pueda manejar los formatos esperados. Si se integra con sistemas que utilizan diferentes formatos, la función debe manejar cada caso.
Russ Cam
1
@RussCam, podemos ir y venir, pero si alguien está preguntando la mejor manera de codificar fechas en JSON, está preguntando cómo formatear las fechas cuando hacen JSON (y la respuesta es generalmente ISO-8601). Estás respondiendo la pregunta opuesta: cómo consumir fechas JSON una vez que ya están hechas (aunque tu consejo es correcto).
mlissner
1
La especificación del esquema JSON en realidad dice que las fechas que son verificadas por un esquema deben estar en formato 8601.
gnasher729
3
@ gnasher729 ¿tienes un enlace?
Russ Cam
@vallismortis: es un borrador de especificación para definir un esquema para una estructura json dada intercambiada entre partes, no el formato para las fechas en la especificación json. Voy a revisar mi respuesta según los comentarios, no parece que lo haya dejado suficientemente claro
Russ Cam
27

Desde RFC 7493 (El formato de mensaje I-JSON) :

I-JSON significa JSON de Internet o JSON interoperable, dependiendo de a quién le pregunte.

Los protocolos a menudo contienen elementos de datos diseñados para contener marcas de tiempo o duraciones de tiempo. Se RECOMIENDA que todos estos elementos de datos se expresen como valores de cadena en formato ISO 8601, como se especifica en RFC 3339 , con las restricciones adicionales de que se utilicen letras mayúsculas en lugar de minúsculas, que la zona horaria se incluya no predeterminada y que los segundos finales opcionales se incluirá incluso cuando su valor sea "00". También se RECOMIENDA que todos los elementos de datos que contengan duraciones de tiempo se ajusten a la producción de "duración" en el Apéndice A de RFC 3339, con las mismas restricciones adicionales.

Bryan Larsen
fuente
2
Este es también el formato producido por Date().toISOString()y Date().toJSON(), con la limitación de que Dateno rastrea un valor de zona horaria y, por lo tanto, siempre emite las marcas de tiempo en la Zzona horaria UTC ( ). El valor se puede analizar con new Date("...")y Date.parseDate.
Søren Løvborg
15

Solo como referencia, he visto este formato utilizado:

Date.UTC(2017,2,22)

Funciona con JSONP, que es compatible con la $.getJSON()función. No estoy seguro de que iría tan lejos como para recomendar este enfoque ... simplemente lanzándolo como una posibilidad porque la gente lo está haciendo de esta manera.

FWIW: nunca use segundos desde epoch en un protocolo de comunicación, ni milisegundos desde epoch, porque estos están llenos de peligro gracias a la implementación aleatoria de segundos bisiestos (no tiene idea si el emisor y el receptor implementan correctamente los segundos bisiestos UTC).

Una especie de odio a las mascotas, pero muchas personas creen que UTC es solo el nuevo nombre de GMT, ¡mal! Si su sistema no implementa segundos intercalares, entonces está utilizando GMT (a menudo llamado UTC a pesar de ser incorrecto). Si implementa completamente los segundos bisiestos, realmente está utilizando UTC. Los segundos de salto futuros no se pueden conocer; IERS los publica según sea necesario y requieren actualizaciones constantes. Si está ejecutando un sistema que intenta implementar segundos intercalares pero contiene una tabla de referencia desactualizada (más común de lo que podría pensar), entonces no tiene GMT ni UTC, tiene un sistema inestable que finge ser UTC.

Estos contadores de fecha solo son compatibles cuando se expresan en un formato desglosado (a, m, d, etc.). NUNCA son compatibles en un formato de época. Mantenlo en mente.

Tel
fuente
44
No usaría ese formato, pero el resto de la información que proporcionó es muy útil, ¡gracias!
Robert Mikes
9

En caso de duda, simplemente vaya a la consola web javascript de un navegador moderno presionando F12 (Ctrl + K en Firefox) y escriba lo siguiente:

new Date().toISOString()

Saldrá:

"2019-07-04T13: 33: 03.969Z"

Ta-da !!

Shayan Ahmad
fuente
3

Creo que el mejor formato para la interoperabilidad universal no es la cadena ISO-8601, sino el formato utilizado por EJSON:

{ "myDateField": { "$date" : <ms-since-epoch> } }

Como se describe aquí: https://docs.meteor.com/api/ejson.html

Beneficios

  1. Análisis del rendimiento: si almacena fechas como cadenas ISO-8601, esto es excelente si espera un valor de fecha en ese campo en particular, pero si tiene un sistema que debe determinar los tipos de valores sin contexto, está analizando cada cadena para un formato de fecha.
  2. No es necesario validar la fecha : no debe preocuparse por la validación y verificación de la fecha. Incluso si una cadena coincide con el formato ISO-8601, puede que no sea una fecha real; Esto nunca puede suceder con una fecha EJSON.
  3. Declaración de tipo inequívoca: en lo que respecta a los sistemas de datos genéricos, si desea almacenar una cadena ISO como una cadena en un caso, y una fecha real del sistema en otro, los sistemas genéricos que adopten el formato de cadena ISO-8601 no lo permitirán, mecánicamente (sin trucos de escape o soluciones horribles similares).

Conclusión

Entiendo que un formato legible por humanos (cadena ISO-8601) es útil y más conveniente para el 80% de los casos de uso, y de hecho a nadie se le debe decir que no almacene sus fechas como cadenas ISO-8601 si eso es lo que hacen sus aplicaciones entender, pero para un formato de transporte universalmente aceptado que debe garantizar a ciertos valores para asegurarse de que las fechas, ¿cómo podemos permitir la ambigüedad y la necesidad de que tanto la validación?

Ciabaros
fuente
Vea esta respuesta anteriormente en el hilo de por qué milisegundos desde la época tiene advertencias tales como el cálculo incorrecto de los segundos bisiestos, etc.: stackoverflow.com/a/42480073/190476
Sudhanshu Mishra
@SudhanshuMishra Las advertencias a las que hace referencia son problemas generales para las preocupaciones extremadamente académicas de las marcas de tiempo de Unix, en su mayoría relacionadas con la generación de marcas de tiempo. Esto es aún menos preocupante con la resolución de milisegundos. Como se mencionó en otro comentario, la mayoría de las fechas de la computadora se representan internamente como marcas de tiempo unix, incluso si están expuestas y formateadas de otra manera. Sin embargo, no hay nada de malo con la representación en milisegundos de una fecha y hora dada, especialmente cuando se compara con otros enfoques, que pueden verse afectados fácilmente por las mismas advertencias de nano-impacto bajo el capó.
Ciabaros
Solo para agregar con respecto a las preocupaciones de fechas "fuera de rango" para las marcas de tiempo de Unix: esos son problemas de almacenamiento del sistema, que se abordarán en un contexto mucho más amplio que el formato de transporte. Por ejemplo, este formato no necesita limitarse a números enteros que se ajusten a 32 bits, ni debe ser números estrictamente positivos, pero nadie va a resolver el "problema del año 2038" colocando marcas de tiempo en un nivel de sistema / arquitectura ; solo necesitan expandirse (por ejemplo, a 64 bits o más), y esto no afecta este formato de transporte propuesto.
Ciabaros
3

JSON en sí no tiene formato de fecha, no le importa cómo alguien almacene las fechas. Sin embargo, dado que esta pregunta está etiquetada con JavaScript, supongo que desea saber cómo almacenar las fechas de JavaScript en JSON. Simplemente puede pasar una fecha al JSON.stringifymétodo, y usará Date.prototype.toJSONde forma predeterminada, que a su vez usa Date.prototype.toISOString( MDN en Date.toJSON ):

const json = JSON.stringify(new Date());
const parsed = JSON.parse(json); //2015-10-26T07:46:36.611Z
const date = new Date(parsed); // Back to date object

También me pareció útil usar el reviverparámetro JSON.parse( MDN en JSON.parse ) para convertir automáticamente las cadenas ISO a fechas de JavaScript cada vez que leía cadenas JSON.

const isoDatePattern = new RegExp(/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z)/);

const obj = {
 a: 'foo',
 b: new Date(1500000000000) // Fri Jul 14 2017, etc...
}
const json = JSON.stringify(obj);

// Convert back, use reviver function:
const parsed = JSON.parse(json, (key, value) => {
    if (typeof value === 'string' &&  value.match(isoDatePattern)){
        return new Date(value); // isostring, so cast to js date
    }
    return value; // leave any other value as-is
});
console.log(parsed.b); // // Fri Jul 14 2017, etc...
Justus Romijn
fuente
2

La forma preferida es usar 2018-04-23T18:25:43.511Z...

La siguiente imagen muestra por qué esta es la forma preferida:

Fecha JSON

Como puede ver, Date tiene un método nativo toJSON, que returnen este formato se puede convertir fácilmente de Datenuevo ...

Alireza
fuente
2
¡Correcto! La sintaxis de intercambio de datos JSON no especifica el estándar: ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf, pero en la práctica, los formatos compatibles con ISO 8601 son más deseables en todas las plataformas, incluido el tiempo de ejecución de JavaScript.
Kamyar Nazeri
1

En Sharepoint 2013, al obtener datos en JSON no hay formato para convertir la fecha en formato de fecha solamente, porque en esa fecha debe estar en formato ISO

yourDate.substring(0,10)

Esto puede ser útil para usted.

raghava arr
fuente
0

"2014-01-01T23: 28: 56.782Z"

La fecha se representa en un formato estándar y ordenable que representa una hora UTC (indicada por la Z). ISO 8601 también admite zonas horarias al reemplazar la Z con el valor + o - para el desplazamiento de la zona horaria:

"2014-02-01T09: 28: 56.321-10: 00"

Existen otras variaciones de la codificación de zona horaria en la especificación ISO 8601, pero el formato –10: 00 es el único formato TZ que admiten los analizadores JSON actuales. En general, es mejor usar el formato basado en UTC (Z) a menos que tenga una necesidad específica de averiguar la zona horaria en la que se produjo la fecha (posible solo en la generación del lado del servidor).

NB: fecha var = nueva fecha (); console.log (fecha); // Mié 01 Ene 2014 13:28:56 GMT- 1000 (Hora estándar de Hawai)

var json = JSON.stringify(date);
console.log(json);  // "2014-01-01T23:28:56.782Z"

para decirte que esa es la forma preferida a pesar de que JavaScript no tiene un formato estándar para ello

// JSON encoded date
var json = "\"2014-01-01T23:28:56.782Z\"";

var dateStr = JSON.parse(json);  
console.log(dateStr); // 2014-01-01T23:28:56.782Z
Pedro JR
fuente
0

Si está utilizando Kotlin, esto resolverá su problema. (Formato MS Json)

val dataString = "/Date(1586583441106)/"
val date = Date(Long.parseLong(dataString.substring(6, dataString.length - 2)))
suhas sasuke
fuente
-3

es trabajo para mí con el servidor de análisis

{
    "ContractID": "203-17-DC0101-00003-10011",
    "Supplier":"Sample Co., Ltd",
    "Value":12345.80,
    "Curency":"USD",
    "StartDate": {
                "__type": "Date",
                "iso": "2017-08-22T06:11:00.000Z"
            }
}
Kemal Karadag
fuente
-6

Solo hay una respuesta correcta a esto y la mayoría de los sistemas se equivocan. Número de milisegundos desde la época, también conocido como un entero de 64 bits. La zona horaria es una preocupación de UI y no tiene negocios en la capa de aplicación o en la capa de base de datos. ¿Por qué a tu db le importa qué zona horaria es algo? Cuando sabes que lo almacenará como un entero de 64 bits, haz los cálculos de transformación.

Elimine los bits extraños y simplemente trate las fechas como números hasta la interfaz de usuario. Puede usar operadores aritméticos simples para hacer consultas y lógica.

Chad Wilson
fuente
Los comentarios se han movido al chat .
Jon Clements
55
Ahora tiene 2 problemas: ¿qué época debe elegir y qué milisegundos debe contar? Probablemente la opción más común es el tiempo Unix (1970-01-01T00: 00: 00 UTC y SI milisegundos, excepto los que caen en un segundo bisiesto), pero, por supuesto, eso hace que los tiempos futuros sean indefinidos.
aij
2
Entonces, ¿cómo representas microsegundos? RFC3339 funciona bien con cualquier precisión, tendrá un lector que analiza la zona horaria y le da la marca de tiempo correcta, y es información adicional. Las aplicaciones de calendario generalmente se preocupan por las zonas horarias.
gnasher729
11
La zona horaria no es una preocupación de UI, a menos que no le importe perder su próximo vuelo. Los vuelos se publican en la hora local y siguen reglas específicas para los cambios de horario de verano. Perder la compensación significa perder información comercial importante
Panagiotis Kanavos
1
Algunos argumentos en contra adicionales incluyen la capacidad de representar tiempos anteriores a 1970 (asumiendo esa época en particular), y la tendencia de los JSON a ser algo legible para los humanos.
Timo
-8

El siguiente código me ha funcionado. Este código imprimirá la fecha en formato DD-MM-AAAA .

DateValue=DateValue.substring(6,8)+"-"+DateValue.substring(4,6)+"-"+DateValue.substring(0,4);

de lo contrario, también puede usar:

DateValue=DateValue.substring(0,4)+"-"+DateValue.substring(4,6)+"-"+DateValue.substring(6,8);
Aniket Kumar Shrivastava
fuente
-19

Creo que eso realmente depende del caso de uso. En muchos casos, podría ser más beneficioso usar un modelo de objeto adecuado (en lugar de representar la fecha en una cadena), de esta manera:

{
"person" :
      {
 "name" : {
   "first": "Tom",
   "middle": "M",
  ...
}
 "dob" :  {
         "year": 2012,
         "month": 4,
         "day": 23,
         "hour": 18,
         "minute": 25,
         "second": 43,
         "timeZone": "America/New_York"
    }   
   }
}

Es cierto que esto es más detallado que RFC 3339 pero:

  • es legible por humanos también
  • implementa un modelo de objeto adecuado (como en OOP, siempre que JSON lo permita)
  • admite zonas horarias (no solo el desplazamiento UTC en la fecha y hora indicadas)
  • puede soportar unidades más pequeñas como milisegundos, nanosegundos, ... o simplemente segundos fraccionarios
  • no requiere un paso de análisis por separado (para analizar la cadena de fecha y hora), el analizador JSON hará todo por usted
  • Creación fácil con cualquier marco de fecha-hora o implementación en cualquier idioma
  • se puede ampliar fácilmente para admitir otras escalas de calendario (hebreo, chino, islámico ...) y eras (AD, BC, ...)
  • es seguro para el año 10000 ;-) (RFC 3339 no lo es)
  • admite fechas de todo el día y tiempos flotantes (Javascript Date.toJSON()no)

No creo que la clasificación correcta (como lo señala funroll para RFC 3339) sea una característica realmente necesaria cuando se serializa una fecha en JSON. Además, eso solo es cierto para las fechas y horas que tienen el mismo desplazamiento de zona horaria.

Marta
fuente
77
Dudo que alguien esté usando json en el año 10000, o incluso que para ese momento el año 10000 seguirá siendo el año 10000. Pero si ambas cosas siguen siendo ciertas para entonces, el formato puede simplemente expandirse para contener un dígito de 3 dígitos. componente del siglo. Entonces, diría que la gente puede seguir con seguridad con RFC 3339, al menos hasta el año 9900
recuerdo de un sueño
8
@downvoters: según ¿Por qué es importante votar? deberías votar si a post contains wrong information, is poorly researched, or fails to communicate information. Explique por cuál de estos motivos ha rechazado esta respuesta.
Marten
55
@Marten Dos cosas. 1. Nunca se te debe una explicación de los votos negativos, aunque entiendo que puede ser útil. 2. No desestimé tu respuesta, pero supongo que a la gente no le gusta tu respuesta porque piensan que es la forma incorrecta de hacerlo. Eso lo calificaría como "Información incorrecta" ya que la pregunta está buscando la mejor manera de hacer algo
Kevin Wells
77
No te rechacé, pero ciertamente puedo entender cómo "inventar otro formato mal especificado" (que es básicamente lo que estás diciendo) sería visto como incorrecto o mal investigado.
aij
2
@ Phil, UTC no es realmente una zona horaria (no hay lugar en la tierra que use "UTC" como su zona horaria oficial), es un estándar de tiempo . Además, las compensaciones de zona horaria son bastante impredecibles. No hay forma de decir si en 2025 "12:00 hora de Moscú" sigue siendo "9:00 UTC" como lo es hoy, se ha cambiado un par de veces durante los últimos 30 años . Si desea expresar una hora local futura, necesita zonas horarias reales.
Marten