Як ISO 8601 відформатувати дату із зміщенням часової зони в JavaScript?


100

Мета: Знайдіть, local timeа UTC time offsetпотім побудуйте URL-адресу в наступному форматі.

Приклад URL: / Дії / Сон? Тривалість = 2002-10-10T12: 00: 00−05: 00

Формат заснований на рекомендації W3C: http://www.w3.org/TR/xmlschema11-2/#dateTime

Документація говорить:

Наприклад, 2002-10-10T12: 00: 00–05: 00 (опівдні 10 жовтня 2002 року, центральний час в літній час, а також східний стандартний час у США) дорівнює 2002-10-10T17: 00: 00Z, на п'ять годин пізніше 2002-10-10T12: 00: 00Z.

Отже, виходячи з мого розуміння, мені потрібно знайти свій місцевий час за новою датою (), а потім використовувати функцію getTimezoneOffset () для обчислення різниці, а потім приєднати її до кінця рядка.

1.Отримайте місцевий час з форматом

var local = new Date().format("yyyy-MM-ddThh:mm:ss"); //today (local time)

вихід

2013-07-02T09:00:00

2.Отримайте UTC за часом, зміщеним за годиною

var offset = local.getTimezoneOffset() / 60;

вихід

7

3.Будуйте URL-адресу (лише часова частина)

var duration = local + "-" + offset + ":00";

вихід:

2013-07-02T09:00:00-7:00

Вищенаведений висновок означає, що мій місцевий час - 2013/07/02 9:00, а різниця від UTC - 7 годин (UTC на місцевий час на 7 годин)

Поки що це, здається, працює, але що робити, якщо getTimezoneOffset () повертає негативне значення, наприклад -120?

Мені цікаво, як повинен виглядати формат у такому випадку, оскільки я не можу зрозуміти з документа W3C. Заздалегідь спасибі.

Відповіді:


174

Наведене нижче має працювати належним чином і для всіх браузерів (завдяки @MattJohnson за пораду)

Date.prototype.toIsoString = function() {
    var tzo = -this.getTimezoneOffset(),
        dif = tzo >= 0 ? '+' : '-',
        pad = function(num) {
            var norm = Math.floor(Math.abs(num));
            return (norm < 10 ? '0' : '') + norm;
        };
    return this.getFullYear() +
        '-' + pad(this.getMonth() + 1) +
        '-' + pad(this.getDate()) +
        'T' + pad(this.getHours()) +
        ':' + pad(this.getMinutes()) +
        ':' + pad(this.getSeconds()) +
        dif + pad(tzo / 60) +
        ':' + pad(tzo % 60);
}

var dt = new Date();
console.log(dt.toIsoString());


2
Знак вказує на зміщення місцевого часу від GMT
Steven Moseley

1
@ masato-san Ви повинні перевернути знак, ознайомтеся з означенням на developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
bfavaretto

2
Тут функція pad повертає належний рядок для кожного розділу дати, крім мілісекунд. Наприклад, за 5 мс як вхід повернеться 05, що повинно бути 005. Ось посилання на мінімально модифіковану версію тієї ж функції jsbin
Safique Ahmed Faruque

9
Зверніть увагу: у цій відповіді є тонка помилка. Зсув часового поясу не буде розраховано правильно, якщо зона мала зміщення хвилин і була негативною (наприклад, -09: 30), як-от певні місця у Франції та Канаді. Mod повертає від’ємне число, тому підлога () перед abs () ненароком зробила компенсацію БІЛЬШЕ від’ємник. Щоб виправити цю помилку, так abs () і THEN floor (). Намагався редагувати відповідь, але, мабуть, "Ця редакція мала на меті адресу автора автора публікації і не має сенсу як редагування".
tytk

5
@tytk - Чудовий улов! Це, справді, тонко. Я додав ваше виправлення у відповідь. Дякуємо за коментар!
Стівен Мозелі

67

getTimezoneOffset() повертає протилежний знак формату, необхідний специфікації, на яку ви посилалися.

Цей формат також відомий як ISO8601 , а точніше як RFC3339 .

У цьому форматі UTC представлений з деяким Zчасом, а всі інші формати представлені зміщенням від UTC. Сенс такий самий, як у JavaScript, але порядок віднімання інвертований, тому результат має протилежний знак.

Крім того, на рідному Dateоб'єкті не існує методу, який називається format, тому ваша функція в №1 буде відмовлена, якщо ви не використовуєте бібліотеку для цього. Зверніться до цієї документації .

Якщо ви шукаєте бібліотеку, яка може безпосередньо працювати з цим форматом, рекомендую спробувати moment.js . Насправді це формат за замовчуванням, тому ви можете просто зробити це:

var m = moment();    // get "now" as a moment
var s = m.format();  // the ISO format is the default so no parameters are needed

// sample output:   2013-07-01T17:55:13-07:00

Це добре перевірене крос-браузерне рішення та має багато інших корисних функцій.


Використання toISOString () не буде працювати. Формат +01: 00 вимагає, щоб частина часу була місцевим часом. toISOString () дасть часовий рядок UTC.
Остін Франс

1
@AustinFrance - Ти маєш рацію! Я здивований, що в цей час я допустив цю помилку, оскільки часто виправляю інших. Вибачте, що я не бачив ваш коментар два роки тому! Відповідь відредаговано.
Метт Джонсон-Пінт

9

Я думаю, що варто врахувати, що ви можете отримати запитувану інформацію лише одним викликом API до стандартної бібліотеки ...

new Date().toLocaleString( 'sv', { timeZoneName: 'short' } );

// produces "2019-10-30 15:33:47 GMT−4"

Вам потрібно буде зробити заміну тексту, якщо ви хочете додати роздільник "T", видалити "GMT-" або додати ": 00" до кінця.

Але тоді ви можете легко пограти з іншими варіантами, якщо хочете, наприклад. використовувати час на 12 годин або пропустити секунди і т.д.

Зауважте, що я використовую Швецію як локальну, оскільки це одна з країн, яка використовує формат ISO 8601. Я думаю, що більшість країн ISO використовують цей формат 'GMT-4' для зміщення часового поясу, крім Канади, яка використовує абревіатуру часового поясу, наприклад. "EDT" для східного дня.

Ви можете отримати те ж саме з нової стандартної функції i18n "Intl.DateTimeFormat ()", але вам потрібно сказати, щоб вона включала час за допомогою параметрів, інакше вона просто дасть дату.


1
Хм, для sv, я фактично отримую "CET", а для літньої дати "CEST" ... Але спасибі за вхід, стандартний API мені достатній (потрібно додати повідомлення журналу з датою). Якби я хотів серйозно зайнятись часом та
часовими поясами

4

Це моя функція для часового поясу клієнтів, це легка вага і проста

  function getCurrentDateTimeMySql() {        
      var tzoffset = (new Date()).getTimezoneOffset() * 60000; //offset in milliseconds
      var localISOTime = (new Date(Date.now() - tzoffset)).toISOString().slice(0, 19).replace('T', ' ');
      var mySqlDT = localISOTime;
      return mySqlDT;
  }

@tsh, ви впевнені? Ви отримуєте поточне зміщення часу, яке згодом використовується для імітації місцевого часу. Можливо, на той момент компенсація була іншою, але це не має значення, тому що ви просто хвилюєтесь зараз.
Андрій

2

Перевір це:

function dateToLocalISO(date) {
    const off    = date.getTimezoneOffset()
    const absoff = Math.abs(off)
    return (new Date(date.getTime() - off*60*1000).toISOString().substr(0,23) +
            (off > 0 ? '-' : '+') + 
            (absoff / 60).toFixed(0).padStart(2,'0') + ':' + 
            (absoff % 60).toString().padStart(2,'0'))
}

// Test it:
d = new Date()

dateToLocalISO(d)
// ==> '2019-06-21T16:07:22.181-03:00'

// Is similar to:

moment = require('moment')
moment(d).format('YYYY-MM-DDTHH:mm:ss.SSSZ') 
// ==> '2019-06-21T16:07:22.181-03:00'

1

Не потрібно moment.js: Ось повний відповідь на зворотній шлях від типу введення "datetime-local", який виводить рядок ISOLocal до UTCсекунд у GMT та назад:

<input type="datetime-local" value="2020-02-16T19:30">

isoLocal="2020-02-16T19:30"
utcSeconds=new Date(isoLocal).getTime()/1000

//here you have 1581899400 for utcSeconds

let isoLocal=new Date(utcSeconds*1000-new Date().getTimezoneOffset()*60000).toISOString().substring(0,16)
2020-02-16T19:30

0

Просто мої двоє відправляють сюди

Я зіткнувся з цією проблемою з датами, так що я зробив це:

const moment = require('moment-timezone')

const date = moment.tz('America/Bogota').format()

Потім збережіть дату в db, щоб мати можливість порівняти її з деяким запитом.


Щоб встановити moment-timezone

npm i moment-timezone

0

Моя відповідь є незначним варіантом для тих, хто просто хоче сьогоднішньої дати у місцевому часовому поясі у форматі YYYY-MM-DD.

Дозвольте мені зрозуміти:

Моя мета: отримати сьогоднішню дату у часовому поясі користувача, але відформатовану як ISO8601 (РРРР-MM-DD)

Ось код:

new Date().toLocaleDateString("sv") // "2020-02-23" // 

Це працює тому, що в локальному регіоні Швеції використовується формат ISO 8601.


Невірна відповідь, це відповідає, але інше запитання ... Цю відповідь можна легко знайти в ТАК.
PsychoX

0

Ось функції, які я використовував для цього:

function localToGMTStingTime(localTime = null) {
    var date = localTime ? new Date(localTime) : new Date();
    return new Date(date.getTime() + (date.getTimezoneOffset() * 60000)).toISOString();
};

function GMTToLocalStingTime(GMTTime = null) {
    var date = GMTTime ? new Date(GMTTime) : new Date();;
    return new Date(date.getTime() - (date.getTimezoneOffset() * 60000)).toISOString();
};

0

Домогтися цього можна кількома простими методами розширення. Наступний метод розширення дати повертає просто компонент часового поясу у форматі ISO, тоді ви можете визначити іншу для частини дата / час та об'єднати їх для повного рядка зсуву дати та часу.

Date.prototype.getISOTimezoneOffset = function () {
    const offset = this.getTimezoneOffset();
    return (offset < 0 ? "+" : "-") + Math.floor(Math.abs(offset / 60)).leftPad(2) + ":" + (Math.abs(offset % 60)).leftPad(2);
}

Date.prototype.toISOLocaleString = function () {
    return this.getFullYear() + "-" + (this.getMonth() + 1).leftPad(2) + "-" +
        this.getDate().leftPad(2) + "T" + this.getHours().leftPad(2) + ":" +
        this.getMinutes().leftPad(2) + ":" + this.getSeconds().leftPad(2) + "." +
        this.getMilliseconds().leftPad(3);
}

Number.prototype.leftPad = function (size) {
    var s = String(this);
    while (s.length < (size || 2)) {
        s = "0" + s;
    }
    return s;
}

Приклад використання:

var date = new Date();
console.log(date.toISOLocaleString() + date.getISOTimezoneOffset());
// Prints "2020-08-05T16:15:46.525+10:00"

Я знаю, що це 2020 рік, і більшість людей, напевно, зараз використовують Moment.js, але просте копіювальне та пасивне рішення все ще іноді зручно мати.

(Причина, за якою я розділяю дату / час та методи зсуву, полягає в тому, що я використовую стару бібліотеку Datejs, яка вже забезпечує гнучкий toStringметод із спеціальними специфікаторами формату, але просто не включає зміщення часового поясу. Отже, я додав toISOLocaleStringдля тих, хто без згадана бібліотека.)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.