Как инициализировать дату 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, интериоризовать британское время. Надеюсь, что это поможет!