¿Cómo envío una cadena con formato ISO 8601 en JavaScript?


247

Tengo un Dateobjeto ¿Cómo renderizo la titleporción del siguiente fragmento?

<abbr title="2010-04-02T14:12:07">A couple days ago</abbr>

Tengo la porción de "tiempo relativo en palabras" de otra biblioteca.

He intentado lo siguiente:

function isoDate(msSinceEpoch) {

   var d = new Date(msSinceEpoch);
   return d.getUTCFullYear() + '-' + (d.getUTCMonth() + 1) + '-' + d.getUTCDate() + 'T' +
          d.getUTCHours() + ':' + d.getUTCMinutes() + ':' + d.getUTCSeconds();

}

Pero eso me da:

"2010-4-2T3:19"

Respuestas:


453

Ya hay una función llamada toISOString():

var date = new Date();
date.toISOString(); //"2011-12-19T15:28:46.493Z"

Si, de alguna manera, estás en un navegador que no lo admite, te tengo cubierto:

if ( !Date.prototype.toISOString ) {
  ( function() {

    function pad(number) {
      var r = String(number);
      if ( r.length === 1 ) {
        r = '0' + r;
      }
      return r;
    }

    Date.prototype.toISOString = function() {
      return this.getUTCFullYear()
        + '-' + pad( this.getUTCMonth() + 1 )
        + '-' + pad( this.getUTCDate() )
        + 'T' + pad( this.getUTCHours() )
        + ':' + pad( this.getUTCMinutes() )
        + ':' + pad( this.getUTCSeconds() )
        + '.' + String( (this.getUTCMilliseconds()/1000).toFixed(3) ).slice( 2, 5 )
        + 'Z';
    };

  }() );
}

1
.toISOString () definitivamente devuelve la fecha en UTC?
Jon Wells

new Date("xx").toISOString()produce NaN-NaN-NaNTNaN:NaN:NaN.NZLa implementación nativa arroja RangeException.
Joseph Lennox

Si desea pasar un objeto de fecha a un servicio de telenovelas ... ¡esa es la forma! :) Gracias.
thinklinux

1
En la muestra proporcionada por el OP, no hay milisegundos ni zona horaria.
Dan Dascalescu

Todas esas llamadas a funciones como "getUTCFullYear" fallan porque no se conocen en el modo de documento de IE 5.
Elaskanator

63

Vea el último ejemplo en la página https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference:Global_Objects:Date :

/* Use a function for the exact format desired... */
function ISODateString(d) {
    function pad(n) {return n<10 ? '0'+n : n}
    return d.getUTCFullYear()+'-'
         + pad(d.getUTCMonth()+1)+'-'
         + pad(d.getUTCDate())+'T'
         + pad(d.getUTCHours())+':'
         + pad(d.getUTCMinutes())+':'
         + pad(d.getUTCSeconds())+'Z'
}

var d = new Date();
console.log(ISODateString(d)); // Prints something like 2009-09-28T19:03:12Z

1
La muestra proporcionada por el OP ( <abbr title="2010-04-02T14:12:07">) no tiene zona horaria. Tal vez querían la hora local, lo que tendría sentido para una cadena de tiempo de UI?
Dan Dascalescu

60

Casi todos los métodos to-ISO en la web eliminan la información de la zona horaria aplicando una conversión a "Z" ulu time (UTC) antes de generar la cadena. El .toISOString () nativo del navegador también elimina la información de la zona horaria.

Esto descarta información valiosa, ya que el servidor o el destinatario siempre pueden convertir una fecha ISO completa a la hora de Zulu o la zona horaria que requiera, al tiempo que obtienen la información de la zona horaria del remitente.

La mejor solución que he encontrado es usar la biblioteca de JavaScript Moment.js y usar el siguiente código:

Para obtener la hora ISO actual con información de zona horaria y milisegundos

now = moment().format("YYYY-MM-DDTHH:mm:ss.SSSZZ")
// "2013-03-08T20:11:11.234+0100"

now = moment().utc().format("YYYY-MM-DDTHH:mm:ss.SSSZZ")
// "2013-03-08T19:11:11.234+0000"

now = moment().utc().format("YYYY-MM-DDTHH:mm:ss") + "Z"
// "2013-03-08T19:11:11Z" <- better use the native .toISOString() 

Para obtener la hora ISO de un objeto JavaScript Date nativo con información de zona horaria pero sin milisegundos

var current_time = Date.now();
moment(current_time).format("YYYY-MM-DDTHH:mm:ssZZ")

Esto se puede combinar con Date.js para obtener funciones como Date.today () cuyo resultado se puede pasar al momento.

Una cadena de fecha con este formato es compatible con JSON y se presta bien para almacenarse en una base de datos. A Python y C # parece gustarles.


21
No llenes cosas con gente de citas. Solo usa moment.js y salva tu cabello.
Valamas

1
En realidad, en Python y DB resultó ser un dolor. db usa UTC (sin problema, ya que puede convertir fácilmente al lado del servidor UTC), por lo que si desea mantener la información de desplazamiento, necesita otro campo. Y Python prefiere el uso de nanosegundos en lugar de los milisegundos de JavaScript, que generalmente son suficientes y preferibles en segundos. En python, solo dateutil.parser.parse lo analiza correctamente, y para escribir milisegundos, el ISO requiere un "_when = when.strftime ("% Y-% m-% dT% H:% M:% S.% f% z "); devuelve _when [: - 8] + _when [-5:]" para convertir los nanos a millis. eso no es agradable.
Daniel F

3
Usted puede simplemente omitir el formato de este modo: moment(new Date()).format(). "A partir de la versión 1.5.0, el formato de momento de llamada # sin formato será predeterminado en ... el formato ISO8601 YYYY-MM-DDTHH:mm:ssZ". Doc: desplácese hacia arriba desde momentjs.com/docs/#/displaying/fromnow
user193130

1
Buen punto @ user193130 pero realmente debes tener cuidado porque la salida difiere del método nativo. moment().format() "2015-03-04T17:16:05+03:00" (new Date()).toISOString() "2015-03-04T14:16:24.555Z"
Olga

1
Tal vez sea exigente, pero estos ejemplos devuelven el desplazamiento actual de UTC, no la zona horaria. Una zona horaria es una región geográfica comúnmente expresada como, por ejemplo, "América / Toronto". Muchas zonas horarias cambian su compensación UTC dos veces al año y la zona horaria no puede (siempre) determinarse a partir de la compensación UTC actual ... por lo tanto, esta respuesta también está eliminando la información de la zona horaria :-)
Martin Fido

27

La pregunta que se hizo fue el formato ISO con precisión reducida. Voila

 new Date().toISOString().slice(0, 19) + 'Z'
 // '2014-10-23T13:18:06Z'

Suponiendo que se quiere el Z final, de lo contrario, simplemente omítalo.


14

Más corto, pero no compatible con Internet Explorer 8 y versiones anteriores:

new Date().toJSON()

12

Si no necesita admitir IE7, el siguiente es un gran truco conciso:

JSON.parse(JSON.stringify(new Date()))

para IE7, esta decisión también es adecuada si se incluye json3-library ( bestiejs.github.io/json3 ). Gracias :)
vladimir

También falla en IE8. ("'JSON' no está definido")
Cees Timmerman el

1
El viaje redondo a través de JSON es feo, especialmente si su objetivo declarado es la concisión; use el toJSONmétodo de la fecha en su lugar. JSON.stringifylo está usando debajo de las sábanas de todos modos.
Mark Amery

@CeesTimmerman IE8 admite el JSONobjeto, aunque no en algunos modos de compatibilidad. Ver stackoverflow.com/questions/4715373/…
Mark Amery

3
¿De qué manera es esto mejor que .toISOString()?
Martin

7

Por lo general, no quiero mostrar una fecha UTC ya que a los clientes no les gusta hacer la conversión en su cabeza. Para mostrar una fecha ISO local , uso la función:

function toLocalIsoString(date, includeSeconds) {
    function pad(n) { return n < 10 ? '0' + n : n }
    var localIsoString = date.getFullYear() + '-'
        + pad(date.getMonth() + 1) + '-'
        + pad(date.getDate()) + 'T'
        + pad(date.getHours()) + ':'
        + pad(date.getMinutes()) + ':'
        + pad(date.getSeconds());
    if(date.getTimezoneOffset() == 0) localIsoString += 'Z';
    return localIsoString;
};

La función anterior omite la información de desplazamiento de zona horaria (excepto si la hora local es UTC), por lo que utilizo la siguiente función para mostrar el desplazamiento local en una sola ubicación. También puede agregar su salida a los resultados de la función anterior si desea mostrar el desplazamiento cada vez:

function getOffsetFromUTC() {
    var offset = new Date().getTimezoneOffset();
    return ((offset < 0 ? '+' : '-')
        + pad(Math.abs(offset / 60), 2)
        + ':'
        + pad(Math.abs(offset % 60), 2))
};

toLocalIsoStringusos pad. Si es necesario, funciona como casi cualquier función de pad, pero en aras de la integridad, esto es lo que uso:

// Pad a number to length using padChar
function pad(number, length, padChar) {
    if (typeof length === 'undefined') length = 2;
    if (typeof padChar === 'undefined') padChar = '0';
    var str = "" + number;
    while (str.length < length) {
        str = padChar + str;
    }
    return str;
}

3

Falta un '+' después de la 'T'

isoDate: function(msSinceEpoch) {
  var d = new Date(msSinceEpoch);
  return d.getUTCFullYear() + '-' + (d.getUTCMonth() + 1) + '-' + d.getUTCDate() + 'T'
         + d.getUTCHours() + ':' + d.getUTCMinutes() + ':' + d.getUTCSeconds();
}

Deberías hacerlo.

Para los ceros iniciales, puede usar esto desde aquí :

function PadDigits(n, totalDigits) 
{ 
    n = n.toString(); 
    var pd = ''; 
    if (totalDigits > n.length) 
    { 
        for (i=0; i < (totalDigits-n.length); i++) 
        { 
            pd += '0'; 
        } 
    } 
    return pd + n.toString(); 
} 

Usándolo así:

PadDigits(d.getUTCHours(),2)

Gran captura! Sin embargo, no aborda los "0" faltantes.
James A. Rosen

1
Escriba una función para convertir un entero en una cadena de 2 caracteres (anteponiendo un '0' si el argumento es menor que 10), y llámelo para cada parte de la fecha / hora.
dan04

3
function timeStr(d) { 
  return ''+
    d.getFullYear()+
    ('0'+(d.getMonth()+1)).slice(-2)+
    ('0'+d.getDate()).slice(-2)+
    ('0'+d.getHours()).slice(-2)+
    ('0'+d.getMinutes()).slice(-2)+
    ('0'+d.getSeconds()).slice(-2);
}

1
En el modo IE5 tuve que seguir esta ruta ya que todas las otras respuestas aquí usaban funciones que no existen.
Elaskanator

3

El problema con toISOString es que solo da fecha y hora como "Z".

ISO-8601 también define la fecha y hora con la diferencia de zona horaria en horas y minutos, en formas como 2016-07-16T19: 20: 30 + 5: 30 (cuando la zona horaria está por delante UTC) y 2016-07-16T19: 20: 30-01 : 00 (cuando la zona horaria está detrás de UTC).

No creo que sea una buena idea usar otro complemento, moment.js para una tarea tan pequeña, especialmente cuando puede obtenerlo con unas pocas líneas de código.



    var timezone_offset_min = new Date().getTimezoneOffset(),
        offset_hrs = parseInt(Math.abs(timezone_offset_min/60)),
        offset_min = Math.abs(timezone_offset_min%60),
        timezone_standard;

    if(offset_hrs < 10)
        offset_hrs = '0' + offset_hrs;

    if(offset_min > 10)
        offset_min = '0' + offset_min;

    // getTimezoneOffset returns an offset which is positive if the local timezone is behind UTC and vice-versa.
    // So add an opposite sign to the offset
    // If offset is 0, it means timezone is UTC
    if(timezone_offset_min < 0)
        timezone_standard = '+' + offset_hrs + ':' + offset_min;
    else if(timezone_offset_min > 0)
        timezone_standard = '-' + offset_hrs + ':' + offset_min;
    else if(timezone_offset_min == 0)
        timezone_standard = 'Z';

    // Timezone difference in hours and minutes
    // String such as +5:30 or -6:00 or Z
    console.log(timezone_standard); 

Una vez que haya compensado la zona horaria en horas y minutos, puede agregar una cadena de fecha y hora.

Escribí una publicación de blog sobre él: http://usefulangle.com/post/30/javascript-get-date-time-with-offset-hours-minutes



2

Pude llegar por debajo de la salida con muy menos código.

var ps = new Date('2010-04-02T14:12:07')  ;
ps = ps.toDateString() + " " + ps.getHours() + ":"+ ps.getMinutes() + " hrs";

Salida:

Fri Apr 02 2010 19:42 hrs

0
function getdatetime() {
    d = new Date();
    return (1e3-~d.getUTCMonth()*10+d.toUTCString()+1e3+d/1)
        .replace(/1(..)..*?(\d+)\D+(\d+).(\S+).*(...)/,'$3-$1-$2T$4.$5Z')
        .replace(/-(\d)T/,'-0$1T');
}

Encontré lo básico sobre Stack Overflow en alguna parte (creo que era parte de otro código de golf de Stack Exchange), y lo mejoré para que también funcione en Internet Explorer 10 o anterior. Es feo, pero hace el trabajo.


0

Para extender la gran y concisa respuesta de Sean con algo de azúcar y sintaxis moderna:

// date.js

const getMonthName = (num) => {
  const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Oct', 'Nov', 'Dec'];
  return months[num];
};

const formatDate = (d) => {
  const date = new Date(d);
  const year = date.getFullYear();
  const month = getMonthName(date.getMonth());
  const day = ('0' + date.getDate()).slice(-2);
  const hour = ('0' + date.getHours()).slice(-2);
  const minutes = ('0' + date.getMinutes()).slice(-2);

  return `${year} ${month} ${day}, ${hour}:${minutes}`;
};

module.exports = formatDate;

Entonces, por ejemplo.

import formatDate = require('./date');

const myDate = "2018-07-24T13:44:46.493Z"; // Actual value from wherever, eg. MongoDB date
console.log(formatDate(myDate)); // 2018 Jul 24, 13:44
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.