Как инициализировать дату JavaScript для определенного часового пояса
У меня есть дата в конкретном часовом поясе в виде строки, и я хочу преобразовать ее в локальное время. Но я не знаю, как установить часовой пояс в объекте Date.
Например, у меня есть Feb 28 2013 7:00 PM ET,
, тогда я могу
var mydate = new Date();
mydate.setFullYear(2013);
mydate.setMonth(02);
mydate.setDate(28);
mydate.setHours(7);
mydate.setMinutes(00);
Насколько я знаю, я могу установить время UTC или местное время. Но как установить время в другой часовой пояс?
Я попытался использовать добавление/вычитание смещения с UTC, но я не знаю, как противостоять дневному сбережению. Не уверен, что я направляюсь в правильном направлении.
Как я могу перевести время из другого часового пояса в локальное время в javascript?
Ответы
Ответ 1
Фон
JavaScript-объект Date
отслеживает внутреннее время в формате UTC, но обычно принимает ввод и вывод по местному времени компьютера, на котором он работает. Он не имеет никаких средств для работы со временем в других часовых поясах. Он может анализировать и выводить даты в формате UTC или Local, но не может напрямую работать с другими часовыми поясами.
Чтобы быть абсолютно точным, внутреннее представление объекта Date
представляет собой одно число, представляющее количество миллисекунд, прошедших с 1970-01-01 00:00:00 UTC
, без учета високосных секунд. В самом объекте Date нет часового пояса или формата строки. Когда используются различные функции объекта Date
, локальный часовой пояс компьютера применяется к внутреннему представлению. Если функция создает строку, то информация о локали компьютера может быть принята во внимание, чтобы определить, как создать эту строку. Детали варьируются в зависимости от функции, а некоторые зависят от реализации.
Библиотеки
К счастью, есть библиотеки, которые можно использовать для работы с часовыми поясами. Хотя они по-прежнему не могут заставить объект Date
вести себя по-другому, они обычно реализуют стандартную базу данных часовых поясов Olson/IANA и предоставляют функции для ее использования в JavaScript. Некоторые из них имеют накладные расходы, если вы работаете в веб-браузере, так как база данных может стать немного больше, если вы хотите всего этого. К счастью, многие из этих библиотек позволяют вам выборочно выбирать зоны, которые вы хотите поддерживать, делая размер данных намного более приемлемым. Также некоторые используют современные функции для получения данных о часовых поясах из Intl
API вместо того, чтобы отправлять их самостоятельно.
Для этого есть несколько библиотек:
Luxon - это, пожалуй, самая безопасная ставка для всего современного использования, и это самый легкий вес, поскольку он использует Intl
API для своих данных о часовых поясах.
Moment-timezone является расширением для Moment.js и предоставляет собственные данные о часовых поясах.
js-joda - это реализация JavaScript Joda-Time API (из Java), включающая поддержку часовых поясов через отдельный модуль.
date-fns-tz - это расширение для date-fns 2.x. date-fns-timezone является расширением для date-fns 1.x.
BigEasy/TimeZone также, кажется, находится на правильном пути.
У WallTime-js закончился срок эксплуатации, и владельцы мигрируют в зону времени и времени.
TimeZoneJS был самым длинным, но, как известно, имеет некоторые давние ошибки, особенно при переходах на летнее время. Надеюсь, они будут исправлены в будущем.
tz.js также был в течение некоторого времени, но не очень хорошо задокументирован, IMHO.
Вы должны оценить эти библиотеки, чтобы увидеть, какие из них будут соответствовать вашим потребностям. Если не уверены, перейдите с моментом/моментом-часовым поясом.
Нативная поддержка в современных условиях
Если вы можете ограничить использование в современных средах, теперь вы можете делать следующее без каких-либо специальных библиотек:
new Date().toLocaleString("en-US", {timeZone: "America/New_York"})
Это не комплексное решение, но оно работает для многих сценариев, которые требуют только преобразования выходных данных (из UTC или локального времени в определенный часовой пояс, но не в другом направлении). Это часть API интернационализации ECMAScript (ECMA-402). Смотрите этот пост для более подробной информации. Эта таблица совместимости отслеживает, какие версии поддерживаются. Это API-интерфейс Intl
упомянутый выше, который в настоящее время используются некоторыми библиотеками.
(Для ясности, это не инициализирует объект Date
, но может использоваться для применения часового пояса при создании строкового представления для конкретной локали.)
Будущие предложения
Целью временного предложения TC39 является предоставление нового набора стандартных объектов для работы с датами и временем на самом языке JavaScript. Это будет включать поддержку объекта, осведомленного о часовом поясе.
Ответ 2
Как сказал Мэтт Джонсон
Если вы можете ограничить свое использование современными веб-браузерами, теперь вы можете сделать следующие без каких-либо специальных библиотек:
new Date().toLocaleString("en-US", {timeZone: "America/New_York"})
Это не комплексное решение, но оно работает для многих сценариев которые требуют только выходного преобразования (из UTC или локального времени в определенный часовой пояс, но не другое направление).
Таким образом, хотя браузер не может считывать часовые пояса IANA при создании даты или имеет какие-либо методы для изменения часовых поясов в существующем объекте Date, кажется, что есть взлом:
function changeTimezone(date, ianatz) {
// suppose the date is 12:00 UTC
var invdate = new Date(date.toLocaleString('en-US', {
timeZone: ianatz
}));
// then invdate will be 07:00 in Toronto
// and the diff is 5 hours
var diff = date.getTime() - invdate.getTime();
// so 12:00 in Toronto is 17:00 UTC
return new Date(date.getTime() + diff);
}
// E.g.
var there = new Date();
var here = changeTimezone(there, "America/Toronto");
console.log('Here: ${here.toString()}\nToronto: ${there.toString()}');
Ответ 3
Вы можете указать смещение часового пояса на new Date()
, например:
new Date('Feb 28 2013 19:00:00 EST')
или
new Date('Feb 28 2013 19:00:00 GMT-0500')
Так как Date
сохраняет время UTC (т.е. getTime
возвращается в UTC), javascript будет преобразовывать время в UTC, а когда вы вызываете такие вещи, как toString
, javascript будет преобразовывать время UTC в локальный часовой пояс браузера и возвращать строка в локальном часовом поясе, т.е. если я использую UTC+8
:
> new Date('Feb 28 2013 19:00:00 GMT-0500').toString()
< "Fri Mar 01 2013 08:00:00 GMT+0800 (CST)"
Также вы можете использовать обычный метод getHours/Minute/Second
:
> new Date('Feb 28 2013 19:00:00 GMT-0500').getHours()
< 8
(Этот 8
означает, что после того, как время будет преобразовано в мое местное время - UTC+8
, число часов 8
.)
Ответ 4
Я знаю его 3 года слишком поздно, но, возможно, он может помочь кому-то другому, потому что я нашел что-то подобное, за исключением библиотеки времени и времени, что не совсем то же самое, что и просьба здесь.
ive сделал что-то подобное для немецкого часового пояса,
это немного сложно из-за летнего времени и високосных лет, когда у вас есть 366 дней.
может потребоваться небольшая работа с функцией "isDaylightSavingTimeInGermany", в то время как разные временные часы меняются в разное время перехода на летнее время.
в любом случае, ознакомьтесь с этой страницей:
https://github.com/zerkotin/german-timezone-converter/wiki
основными методами являются:
convertLocalDateToGermanTimezone
convertGermanDateToLocalTimezone
ive прилагает усилия к документированию, поэтому он не будет настолько запутанным.
Ответ 5
У меня возникла аналогичная проблема с модульными тестами (особенно в шутку, когда модульные тесты запускаются локально для создания моментальных снимков, а затем сервер CI запускает (потенциально) другой часовой пояс, что приводит к сбою сравнения моментальных снимков). Я издевался над нашими Date
и некоторыми вспомогательными методами:
describe('...', () => {
let originalDate;
beforeEach(() => {
originalDate = Date;
Date = jest.fn(
(d) => {
let newD;
if (d) {
newD = (new originalDate(d));
} else {
newD = (new originalDate('2017-05-29T10:00:00z'));
}
newD.toLocaleString = () => {
return (new originalDate(newD.valueOf())).toLocaleString("en-US", {timeZone: "America/New_York"});
};
newD.toLocaleDateString = () => {
return (new originalDate(newD.valueOf())).toLocaleDateString("en-US", {timeZone: "America/New_York"});
};
newD.toLocaleTimeString = () => {
return (new originalDate(newD.valueOf())).toLocaleTimeString("en-US", {timeZone: "America/New_York"});
};
return newD;
}
);
Date.now = () => { return (Date()); };
});
afterEach(() => {
Date = originalDate;
});
});
Ответ 6
Я нашел наиболее поддерживаемый способ сделать это, не беспокоясь о сторонних библиотеках, - использовать getTimezoneOffset
для вычисления соответствующей метки времени или обновить время, а затем использовать обычные методы для получения необходимой даты и времени.
var mydate = new Date();
mydate.setFullYear(2013);
mydate.setMonth(02);
mydate.setDate(28);
mydate.setHours(7);
mydate.setMinutes(00);
// ET timezone offset in hours.
var timezone = -5;
// Timezone offset in minutes + the desired offset in minutes, converted to ms.
// This offset should be the same for ALL date calculations, so you should only need to calculate it once.
var offset = (mydate.getTimezoneOffset() + (timezone * 60)) * 60 * 1000;
// Use the timestamp and offset as necessary to calculate min/sec etc, i.e. for countdowns.
var timestamp = mydate.getTime() + offset,
seconds = Math.floor(timestamp / 1000) % 60,
minutes = Math.floor(timestamp / 1000 / 60) % 60,
hours = Math.floor(timestamp / 1000 / 60 / 60);
// Or update the timestamp to reflect the timezone offset.
mydate.setTime(mydate.getTime() + offset);
// Then Output dates and times using the normal methods.
var date = mydate.getDate(),
hour = mydate.getHours();
РЕДАКТИРОВАТЬ
Ранее я использовал методы UTC
при выполнении преобразований даты, что было неправильно. При добавлении смещения ко времени локальные функции get
вернут желаемые результаты.
Ответ 7
Попробуйте использовать ctoc из npm. https://www.npmjs.com/package/ctoc_timezone
Он имеет простую функциональность для изменения часовых поясов (большинство часовых поясов около 400) и всех пользовательских форматов, которые вы хотите отобразить.
Ответ 8
Попробуйте: date-from-timezone, он разрешает ожидаемую дату с помощью изначально доступных Intl.DateTimeFormat
.
Я использовал этот метод в одном из своих проектов уже несколько лет, но теперь я решил опубликовать его как небольшой проект ОС:)
Ответ 9
Основываясь на ответах выше, я использую эту собственную строку для преобразования длинной строки часового пояса в строку из трех букв:
var longTz = 'America/Los_Angeles';
var shortTz = new Date().
toLocaleString("en", {timeZoneName: "short", timeZone: longTz}).
split(' ').
pop();
Это даст PDT или PST в зависимости от предоставленной даты. В моем конкретном случае использования на базе Salesforce (Aura/Lightning) мы можем получить часовой пояс пользователя в длинном формате из бэкэнда.
Ответ 10
Это должно решить вашу проблему, пожалуйста, не стесняйтесь предлагать исправления. Этот метод также учитывает переход на летнее время для указанной даты.
dateWithTimeZone = (timeZone, year, month, day, hour, minute, second) => {
let date = new Date(Date.UTC(year, month, day, hour, minute, second));
let utcDate = new Date(date.toLocaleString('en-US', { timeZone: "UTC" }));
let tzDate = new Date(date.toLocaleString('en-US', { timeZone: timeZone }));
let offset = utcDate.getTime() - tzDate.getTime();
date.setTime( date.getTime() + offset );
return date;
};
Как использовать с часовым поясом и местным временем:
dateWithTimeZone("America/Los_Angeles",2019,8,8,0,0,0)
Ответ 11
Столкнулся с одной и той же проблемой, использовал этот
Console.log(Date.parse("13 июня 2018 10:50:39 GMT + 1"));
Он вернет миллисекунды, на которые вы можете проверить, есть ли +100 timzone, интериоризовать британское время. Надеюсь, что это поможет!