Як вивести рядок у форматі ISO 8601?


247

У мене є 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"

Відповіді:


453

Уже функція називається 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
У вибірці, наданій ОП, немає ні мілісекунд, ні часового поясу.
Дан Даскалеску

Усі ці виклики функцій на кшталт "getUTCFullYear" не вдається, оскільки їм невідомий документ IE в режимі 5.
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

1
Зразок, наданий OP ( <abbr title="2010-04-02T14:12:07">), не має часового поясу. Можливо, вони хотіли місцевого часу, який мав би сенс для часового рядка інтерфейсу?
Дан Даскалеску

60

Практично кожен метод ISO в Інтернеті відкидає інформацію про часовий пояс, застосовуючи перетворення в "Z" час улу (UTC) перед виведенням рядка. Народний .toISOString () браузера також відкидає інформацію про часовий пояс.

Це відкидає цінну інформацію, оскільки сервер чи одержувач завжди можуть перетворити повну дату ISO на час зулу чи в той часовий пояс, який він вимагає, отримуючи інформацію про відправника про часовий пояс.

Найкраще рішення, з яким я зіткнувся, - це використання бібліотеки 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 з інформацією про часовий пояс, але без мілісекунд

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
насправді, на python і db's це виявилося болем. db використовує UTC (ніякої проблеми, оскільки ви можете легко перетворити на UTC серверну сторону), тому якщо ви хочете зберегти інформацію про зміщення, вам потрібно інше поле. А Python вважає за краще використовувати наносекунди замість мілісекунд javascript, яких, як правило, достатньо і переважніше за звичайні секунди. На python правильно розбирає його тільки dateutil.parser.parse , а для написання мілісекундного ISO потрібне "_when = when.strearch ("% Y-% m-% dT% H:% M:% S.% f% z "); повернути _when [: - 8] + _when [-5:]", щоб перетворити нанос у міліс. це не гарно.
Даніель Ф

3
Ви можете на самому справі просто опускаєте формат наступним чином: moment(new Date()).format(). "Починаючи з версії 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 ... таким чином, ця відповідь також видаляє інформацію про часовий пояс :-)
Мартін Фідо

27

Поставлене запитання було форматом ISO зі зниженою точністю. Вуаля:

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

Якщо припустити, що Z є потрібним, інакше просто опустіть.


14

Найкоротший, але не підтримується Internet Explorer 8 і новіших версій:

new Date().toJSON()

12

Якщо вам не потрібно підтримувати IE7, наступним є чудовий, короткий злом:

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

для IE7 це рішення також підходить, якщо було включено json3-бібліотеку ( bestiejs.github.io/json3 ). Дякую :)
vladimir

Також виходить з ладу в IE8. ("'JSON' не визначено")
Cees Timmerman

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

Після "T" пропущено "+"

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)

Чудовий улов! Однак він не стосується відсутніх "0" s.
Джеймс А. Росен

1
Напишіть функцію для перетворення цілого числа у двоцифровий рядок (попередньо перед «0», якщо аргумент менший за 10), і викличте його для кожної частини дати / часу.
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
У режимі 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.