Как ISO 8601 отформатировать дату со смещением часового пояса в JavaScript?
Цель: найти local time
а также UTC time offset
затем создайте URL в следующем формате.
Пример URL: /Actions/Sleep? Duration=2002-10-10T12:00:00−05:00
Формат основан на рекомендации W3C: http://www.w3.org/TR/xmlschema11-2/
В документации сказано:
For example, 2002-10-10T12:00:00−05:00 (noon on 10 October 2002,
Central Daylight Savings Time as well as Eastern Standard Time in the U.S.)
is equal to 2002-10-10T17:00:00Z, five hours later than 2002-10-10T12:00:00Z.
Исходя из моего понимания, мне нужно найти свое местное время с помощью новой функции Date(), затем использовать функцию 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 утра, а разница с UTC составляет 7 часов (UTC на 7 часов опережает местное время)
Пока что это похоже на работу, но что, если getTimezoneOffset() возвращает отрицательное значение, например -120?
Мне интересно, как должен выглядеть формат в таком случае, потому что я не могу понять из документа W3C. Заранее спасибо.
23 ответа
Ниже должно работать правильно, и для всех браузеров (спасибо @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());
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
Это хорошо протестированное кросс-браузерное решение с множеством других полезных функций.
Я думаю, что стоит учесть, что вы можете получить запрошенную информацию с помощью всего лишь одного вызова 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()", но вы должны указать ей, чтобы она включала время с помощью параметров, иначе она просто выдаст дату.
Мой ответ - небольшая вариация для тех, кому нужна сегодняшняя дата в местном часовом поясе в формате ГГГГ-ММ-ДД.
Позвольте мне пояснить:
Моя цель: получить сегодняшнюю дату в часовом поясе пользователя, но в формате ISO8601 (ГГГГ-ММ-ДД)
Вот код:
new Date().toLocaleDateString("sv") // "2020-02-23" //
Это работает, потому что в Швеции используется формат ISO 8601.
Проверь это:
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'
Это моя функция для часового пояса клиентов, это легкий вес и просто
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;
}
Вы можете добиться этого с помощью нескольких простых методов расширения. Следующий метод расширения даты возвращает только компонент часового пояса в формате 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
для всех без указанной библиотеки.)
Просто мои два посылает сюда
Я столкнулся с этой проблемой с datetime, так что я сделал это:
const moment = require('moment-timezone')
const date = moment.tz('America/Bogota').format()
Затем сохраните дату в БД, чтобы иметь возможность сравнить ее с каким-либо запросом.
Установить moment-timezone
npm i moment-timezone
Не требуется moment.js: вот полный ответ туда и обратно из типа ввода "datetime-local", который выводит строку ISOLocal в UTCseconds в 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
- дата в строку ISO,
- с местным (компьютерным) часовым поясом,
- с миллисекундами или без них
Ссылка на ISO: https://en.wikipedia.org/wiki/ISO_8601
как использовать: toIsoLocalTime(новая дата ())
Используйте временную .
Temporal.Now.zonedDateTimeISO().toString()
// '2022-08-09T14:16:47.762797591-07:00[America/Los_Angeles]'
Чтобы опустить доли секунды и часовой пояс IANA:
Temporal.Now.zonedDateTimeISO().toString({
timeZoneName: "never",
fractionalSecondDigits: 0
})
// '2022-08-09T14:18:34-07:00'
Примечание. Temporal в настоящее время (2022 г.) доступен в виде полифилла , но вскоре будет доступен в основных браузерах.
Если вы ищете простой способ получить текущую дату в формате ISO, вот он.
const currentIsoDateString = new Date(Date.now() - new Date().getTimezoneOffset() * 60000).toISOString()
Вы можете изменить это, чтобы получить строку даты/времени ISO для других дат, заменив Date.now() целым числом даты вашей эпохи.
Вот как это работает изнутри. Date.now() возвращает текущее время в миллисекундах с эпохи 1 января 1970 года. Для меня текущая локальная дата/время — 2023-07-05 09:57:32 (например, 1688565167374), но Date.now не волнует Что касается местного времени, оно просто дает время из эпохи независимо от местного времени, поэтому нам нужно настроить.
new Date().getTimezonOffset() возвращает смещение местного часового пояса от UTC. В моем случае это 240 или 4 часа. Мы умножаем эти минуты на 60000, чтобы преобразовать их в миллисекунды, и вычитаем результат из UTC.
Затем мы можем использовать удобную встроенную функцию .toISOString(), чтобы получить красиво отформатированную строку ISO. '2023-07-05T09:58:18.119Z'
Никаких библиотек не требуется :-)
рассмотрите возможность использования момента (например , ответ Мэтта ).
Начиная с версии 2.20.0, вы можете вызывать .toISOString(true) для предотвращения преобразования UTC:
console.log(moment().toISOString(true));
// sample output: 2022-04-06T16:26:36.758+03:00
Вот функции, которые я использовал для этого:
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();
};
простой способ получить:
//using a sample date
let iso_str = '2022-06-11T01:51:59.618Z';
let d = new Date(iso_str);
let tz = 'America/Santiago'
let options = {
timeZone:tz ,
timeZoneName:'longOffset',
year: 'numeric',
month: 'numeric',
day: 'numeric',
hour: 'numeric',
minute: 'numeric',
second: 'numeric',
fractionalSecondDigits: 3
}
str_locale = d.toLocaleString("sv-SE",options);
iso_str_tz = str_locale.replace(/(\d{4})-(\d{2})-(\d{2})\s+(\d{2}):(\d{2}):(\d{2}),(\d+)\s+/,'$1-$2-$3T$4:$5:$6.$7').replace('GMT−', '-' ).replace('GMT+','+')
console.log('iso_str : ',iso_str);
console.log('str_locale : ',str_locale);
console.log('iso_str_tz : ',iso_str_tz);
console.log('iso_str_tz --> date : ',new Date(iso_str_tz));
console.log('iso_str_tz --> iso_str: ',new Date(iso_str_tz).toISOString());
Вот еще один способ преобразовать дату со смещением.
function toCustomDateString(date, offset) {
function pad(number) {
if (number < 10) {
return "0" + number;
}
return number;
}
var offsetHours = offset / 60;
var offsetMinutes = offset % 60;
var sign = (offset > 0) ? "+" : "-";
offsetHours = pad(Math.floor(Math.abs(offsetHours)));
offsetMinutes = pad(Math.abs(offsetMinutes));
return date.getFullYear() +
"-" + pad(date.getMonth() + 1) +
"-" + pad(date.getDate()) +
"T" + pad(date.getHours()) +
":" + pad(date.getMinutes()) +
":" + pad(date.getSeconds()) +
sign + offsetHours +
":" + offsetMinutes;
}
Затем вы можете использовать его следующим образом:
var date = new Date();
var offset = 330; // offset in minutes from UTC, for India it is 330 minutes ahead of UTC
var customDateString = toCustomDateString(date, offset);
console.log(customDateString);
// Output: "2023-02-09T10:29:31+05:30"
Альтернативный подход с dayjs
import dayjs from "dayjs"
const formattedDateTime = dayjs(new Date()).format()
console.log(formattedDateTime) // Prints 2022-11-09T07:49:29+03:00
С использованиемmoment.js
, вы можете использоватьkeepOffset
параметрtoISOString
:
toISOString(keepOffset?: boolean): string;
moment().toISOString(true)
let myDate = new Date(dateToBeFormatted * 1000); // depends if you have milliseconds, or seconds, then the * 1000 might be not, or required.
timeOffset = myDate.getTimezoneOffset();
myDate = new Date(myDate.getTime() - (timeOffset * 60 * 1000));
console.log(myDate.toISOString().split('T')[0]);
Вдохновленный /questions/31554836/format-javascript-data-v-gggg-mm-dd/31554853#31554853, включая комментарий о смещении часового пояса .
Использование только javascript без библиотек — это всего две строки:
var dt = new Date();
// Date in UTC and ISO format: "2021-11-30T20:33:32.222Z"
console.log(dt.toISOString());
var dtOffset = new Date(dt.setMinutes(dt.getMinutes() - dt.getTimezoneOffset()));
// Date in EST and ISO format: "2021-11-30T15:33:32.222Z"
console.log(dtOffset.toISOString());
new Date()
по умолчанию будет использоваться текущая локаль, но вы также можете указать ее напрямую, если это необходимо:
var dt = new Date(new Date().toLocaleString("en-US", {timeZone: "America/New_York"}));
function setDate(){
var now = new Date();
now.setMinutes(now.getMinutes() - now.getTimezoneOffset());
var timeToSet = now.toISOString().slice(0,16);
/*
If you have an element called "eventDate" like the following:
<input type="datetime-local" name="eventdate" id="eventdate" />
and you would like to set the current and minimum time then use the following:
*/
var elem = document.getElementById("eventDate");
elem.value = timeToSet;
elem.min = timeToSet;
}
Я нашел другое более простое решение:
let now = new Date();
// correct time zone offset for generating iso string
now.setMinutes(now.getMinutes() - now.getTimezoneOffset())
now = now.toISOString();
Я отменяю смещение часового пояса, вычитая его из текущего объекта даты. Время UTC из объекта даты теперь указывает на местное время. Это дает вам возможность получить дату iso для местного времени.