Альтернатива приведению даты UTC в Javascript? - PullRequest
2 голосов
/ 11 марта 2019

Я хочу создать новую дату в JS, но она будет приведена как время UTC.Например, предположим, что castAsUTC() производит следующий желаемый эффект:

var x = new Date('2019-01-01T00:00:00') // In local time (PST)
castAsUTC(x).toISOString(); // => '2019-01-01T00:00:00Z'
// x.toISOString() gives us '2019-01-01T08:00:00Z', which is undesired

В настоящее время моя функция выглядит следующим образом:

function castAsUTC(date) {
  return new Date(x.toLocaleString() + '+00:00');
}

Есть ли более чистый / приятный способ производства того же самогоэффект?Заранее спасибо!

РЕДАКТИРОВАТЬ: Чтобы быть более точным, я заинтересован в преобразовании часового пояса даты, не меняя ее фактическое значение с как можно меньшим арифметическим.Таким образом, при вызове .toISOString() будет получена та же дата, что и по местному времени.

В настоящее время я использую библиотеку moment-timezone, но я не могу добиться желаемого эффекта, используя это.Я бы определенно принял ответ, который использует Moment.js

Ответы [ 3 ]

2 голосов
/ 11 марта 2019

Вы можете переключить экземпляр момента в UTC, используя функцию utc .Затем просто используйте format, чтобы получить любой конкретный вывод, который вы хотите от него.

1 голос
/ 11 марта 2019

tl; dr;

Вы неправильно отформатировали дату.Добавьте букву «Z» в конец строки даты, и она будет рассматриваться как UTC.

var x = new Date('2019-01-01T00:00:00Z')    // Jan 1, 2019 12 AM UTC

Этими проблемами форматирования легче управлять с помощью библиотеки, например momentjs (utc и formatфункции), как описано в других ответах.Если вы хотите использовать vanilla javascript, вам необходимо вычесть смещение часового пояса перед вызовом toISOString (см. Предупреждения в более длинном ответе ниже).

Подробности

Date вJavascript имеет дело с часовыми поясами в несколько противоречащем интуитивном ключе.Внутри дата хранится в виде количества миллисекунд с начала Unix (1 января 1970 г.).Это число, которое вы получаете, когда звоните getTime(), и это число, которое используется для математики и сравнений.

Однако - когда вы используете стандартные функции форматирования строк (toString, toTimeString, toDateStringи т. д.) javascript автоматически применяет смещение часового пояса для локальных компьютеров часового пояса перед форматированием.В браузере это означает, что он будет применять смещение для компьютера конечного пользователя, а не для сервера.Функции toISOString и toUTCString не будут применять смещение - они печатают фактическое значение UTC, сохраненное в Date.Вероятно, это все равно будет выглядеть «неправильно», потому что оно не будет соответствовать значению, которое вы видите в консоли или при вызове toString.

Вот где вещи действительно становятся интересными.Вы можете создать Date в javascript, указав количество миллисекунд с начала Unix, используя new Date(milliseconds), или используя синтаксический анализатор с new Date(dateString).С помощью метода миллисекунд не нужно беспокоиться о часовом поясе - он определяется как UTC.Вопрос в том, как с помощью метода синтаксического анализа javascript определяет, какой часовой пояс вы намеревались?До ES5 (выпущенный в 2009 году) ответ был другим в зависимости от браузера !Пост ES5, ответ зависит от , как вы форматируете строку !Если вы используете упрощенную версию ISO 8601 (только с датой, без времени), javascript считает эту дату UTC.В противном случае, если вы указываете время в формате ISO 8601 или используете формат, «читаемый человеком», он считает дату местным часовым поясом. Проверьте MDN для получения дополнительной информации.

Некоторые примеры.Я указал для каждого, рассматривает ли javascript его как UTC или локальную дату.В UTC значение будет 1 января 1970 года в полночь.В местном это зависит от часового пояса.Для OP в указанное время (UTC-8) значение UTC будет 1 января 1970 года в 8 часов утра.

new Date(0)                    // UTC (milliseconds is always UTC)
new Date("1/1/1970");          // Local - (human readable string)
new Date("1970-1-1");          // Local (invalid ISO 8601 - missing leading zeros on the month and day)
new Date("1970-01-01");        // UTC (valid simplified ISO 8601)
new Date("1970-01-01T00:00");  // Local (valid ISO 8601 with time and no timezone)
new Date("1970-01-01T00:00Z"); // UTC (valid ISO 8601 with UTC specified)

Вы не можете изменить это поведение - но вы можете быть педантичнымо форматах, которые вы используете для разбора дат.В вашем случае проблема заключалась в том, что вы предоставили строку ISO-8601 с компонентом времени, но без часового пояса.Добавление буквы «Z» к концу вашей строки или удаление времени будет работать для вас.

Или всегда используйте библиотеку, например моменты, чтобы избежать этих сложностей.

Vanilla JSОбходной путь

Как уже говорилось, настоящей проблемой здесь является знание того, будет ли дата рассматриваться как локальная или по Гринвичу.Вы не можете "кастовать" с локального на UTC, потому что все Date уже UTC - это просто форматирование.Однако, если вы уверены, что дата была проанализирована как локальная, и она действительно должна быть в формате UTC, вы можете обойти ее, вручную отрегулировав смещение часового пояса.Это называется «смена эпох» (спасибо @MattJohnson за термин!), И это опасно.Вы фактически создаете совершенно новую дату , которая относится к другому моменту времени!Если вы используете его в других частях вашего кода, вы можете получить неправильные значения!

Вот пример метода смены эпох (для ясности переименован в castAsUtc).Сначала получите смещение часового пояса от объекта, затем вычтите его и создайте новую дату с новым значением.Если вы объедините это с toISOString, вы получите отформатированную вами дату.

function epochShiftToUtc(date) {
    var timezoneOffsetMinutes = date.getTimezoneOffset();
    var timezoneOffsetMill = timezoneOffsetMinutes * 1000 * 60;
    var buffer = new Date(date.getTime() - timezoneOffsetMill);

    return buffer;
}

epochShiftToUtc(date).toUTCString();
0 голосов
/ 12 марта 2019

Если действительно строка, которая у вас есть, похожа на показанную, то проще всего будет добавить Z для обозначения UTC.

var input = '2019-01-01T00:00:00';
var date = new Date(input + 'Z');
var output = date.toISOString();

Или, если вы хотите использовать Moment.js, сделайте следующее:

var input = '2019-01-01T00:00:00';
var m = moment.utc(input);
var output = m.format();

Для этого вам не нужен момент-часовой пояс.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...