Как вывести строку в формате ISO 8601 в JavaScript?

248

У меня есть Dateобъект. Как отобразить titleчасть следующего фрагмента?

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

У меня есть часть "относительного времени в словах" из другой библиотеки.

Я пробовал следующее:

function isoDate(msSinceEpoch) {

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

}

Но это дает мне:

"2010-4-2T3:19"
Джеймс А. Розен
источник

Ответы:

454

Уже есть функция с именем toISOString():

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

Если вы каким-то образом пользуетесь браузером, который его не поддерживает, я расскажу вам:

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 () определенно возвращает дату в UTC?
Джон Уэллс
new Date("xx").toISOString()выдает NaN-NaN-NaNTNaN:NaN:NaN.NZнативную реализацию выдает RangeException.
Джозеф Леннокс
Если вы хотите передать объект даты в мыльный сервис ... это путь! :) Спасибо.
thinklinux
1
В примере, предоставленном OP, нет ни миллисекунд, ни часового пояса.
Дан Даскалеску
Все эти вызовы функций, такие как «getUTCFullYear», терпят неудачу, потому что они не известны в режиме 5 документа IE.
Elaskanator
63

См. Последний пример на странице 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
dev-null-dweller
источник
1
Образец, предоставленный OP ( <abbr title="2010-04-02T14:12:07">), не имеет часового пояса. Возможно, они хотели местное время, которое имело бы смысл для строки времени пользовательского интерфейса?
Дэн Даскалеску
60

Почти каждый метод to-ISO в сети сбрасывает информацию о часовом поясе, применяя преобразование к «Z» ulu time (UTC) перед выводом строки. Родной .toISOString () браузера также удаляет информацию о часовом поясе.

Это исключает ценную информацию, так как сервер или получатель всегда могут преобразовать полную дату ISO в время Zulu или в любой часовой пояс, который ему требуется, при этом получая информацию о часовом поясе отправителя.

Лучшее решение, с которым я столкнулся, - это использовать библиотеку JavaScript Moment.js и использовать следующий код:

Чтобы получить текущее время ISO с информацией о часовом поясе и миллисекундами

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

Чтобы получить время ISO собственного объекта JavaScript Date с информацией о часовом поясе, но без миллисекунд

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

Это может быть объединено с Date.js для получения функций, таких как Date.today (), результат которых затем может быть передан в данный момент.

Строка даты, отформатированная таким образом, является JSON-компилятором и хорошо подходит для хранения в базе данных. Python и C #, похоже, это нравится.

Даниэль Ф
источник
21
не балуйтесь с людьми свиданий. Просто используйте moment.js и сохраните свои волосы.
Валамас
1
на самом деле, на питоне и дб это оказалось болью. БД использует UTC (без проблем, так как вы можете легко конвертировать в серверную часть UTC), поэтому, если вы хотите сохранить информацию о смещении, вам нужно другое поле. А Python предпочитает использовать наносекунды вместо миллисекунд javascript, которые обычно достаточно и предпочтительнее простых секунд. На python только dateutil.parser.parse анализирует его правильно, и для записи ISO в миллисекундах требуется "_when = when.strftime ("% Y-% m-% dT% H:% M:% S.% f% z "); вернуть _when [: - 8] + _when [-5:]", чтобы преобразовать нанос в миллис. это не приятно.
Даниэль Ф
3
Вы можете на самом деле просто опускаете формат следующим образом: moment(new Date()).format(). Msgstr "Начиная с версии 1.5.0, формат момента вызова # без формата по умолчанию будет ... формат ISO8601 YYYY-MM-DDTHH:mm:ssZ". Док. Прокрутите вверх с сайта momentjs.com/docs/#/displaying/fromnow
user193130,
1
Хороший вопрос @ user193130, но вам действительно нужно быть осторожным, потому что вывод отличается от нативного метода. moment().format() "2015-03-04T17:16:05+03:00" (new Date()).toISOString() "2015-03-04T14:16:24.555Z"
Ольга
1
Может быть, требователен, но эти примеры возвращают текущее смещение от UTC, а не часовой пояс. Часовой пояс - это географический регион, обычно обозначаемый, например, как «Америка / Торонто». Многие часовые пояса меняют свое смещение UTC дважды в год, и часовой пояс не может (всегда) быть определен из текущего смещения UTC ... таким образом, этот ответ также отбрасывает информацию о часовом поясе :-)
Martin Fido
27

Был задан вопрос о формате ISO с пониженной точностью. Вуаля:

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

Предполагая, что завершающий Z требуется, в противном случае просто опустите.

arcseldon
источник
14

Самый короткий, но не поддерживается Internet Explorer 8 и более ранними версиями:

new Date().toJSON()
younes0
источник
12

Если вам не нужна поддержка IE7, это хороший и лаконичный хак:

JSON.parse(JSON.stringify(new Date()))
Рассел Дэвис
источник
для IE7 это решение тоже подходит, если была включена json3-библиотека ( bestiejs.github.io/json3 ). Спасибо :)
Владимир
Также не работает в IE8. («JSON» не определен »)
Сиз Тиммерман
1
Обход по JSON уродлив, особенно если ваша заявленная цель - краткость; toJSONвместо этого используйте метод даты . JSON.stringifyв любом случае использует его под одеялом.
Марк Амери
@CeesTimmerman IE8 поддерживает JSONобъект, хотя не в некоторых режимах совместимости. См. Stackoverflow.com/questions/4715373/…
Марк Эмери
3
Чем это лучше чем .toISOString()?
Мартин,
7

Обычно я не хочу отображать дату в формате UTC, так как клиенты не любят делать преобразования в своей голове. Чтобы отобразить локальную дату ISO, я использую функцию:

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

Приведенная выше функция пропускает информацию о смещении часового пояса (кроме случаев, когда местное время указано в формате UTC), поэтому я использую приведенную ниже функцию, чтобы показать локальное смещение в одном месте. Вы также можете добавить его вывод к результатам из вышеприведенной функции, если хотите показывать смещение каждый раз:

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

toLocalIsoStringиспользует pad. При необходимости он работает почти как любая функция пэда, но для полноты картины я использую:

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

После «Т» отсутствует знак «+»

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

должен сделать это.

Для ведущих нулей вы можете использовать это здесь :

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

Используя это так:

PadDigits(d.getUTCHours(),2)
kaiz.net
источник
Отличный улов! Это не относится к отсутствующим "0", хотя.
Джеймс А. Розен
1
Напишите функцию для преобразования целого числа в двухсимвольную строку (с добавлением «0», если аргумент меньше 10) и вызовите ее для каждой части даты / времени.
2010
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
В режиме IE5 мне пришлось идти по этому пути, так как все остальные ответы здесь использовали функции, которые не существуют.
Эласканатор
3

Проблема с toISOString заключается в том, что он дает дату и время только как "Z".

ISO-8601 также определяет дату и время с разницей в часовом поясе в часах и минутах в таких формах, как 2016-07-16T19: 20: 30 + 5: 30 (когда часовой пояс впереди UTC) и 2016-07-16T19: 20: 30-01 : 00 (когда часовой пояс отстает от UTC).

Я не думаю, что было бы хорошей идеей использовать другой плагин, moment.js для такой маленькой задачи, особенно когда вы можете получить его с помощью нескольких строк кода.



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

Как только у вас будет смещение часового пояса в часах и минутах, вы можете добавить строку даты и времени.

Я написал пост в блоге: http://usefulangle.com/post/30/javascript-get-date-time-with-offset-hours-minutes

Полезный угол
источник
2

Я смог получить результат ниже с очень меньшим количеством кода.

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

Вывод:

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

Я где-то нашел основы Stack Overflow (я думаю, что это было частью какого-то другого игры в Stack Exchange) и улучшил его, чтобы он работал и в Internet Explorer 10 или более ранней версии. Это некрасиво, но это делает работу.

Йонас Быстрём
источник
0

Чтобы расширить великолепный и лаконичный ответ Шона, добавив немного сахара и современный синтаксис:

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

Тогда, например.

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
Юха Унтинен
источник