момент-timezone.js делает неправильное преобразование

Я пытаюсь преобразовать из одного часового пояса в другой (вручную), получая объект Date и возвращая другой с помощью этой функции:

 getDateInMomentFormatToSave: function (date) {
                function padNums(num) {
                    return num.toString().length == 1 ? "0" + num : num;
                }
                var month = padNums(date.getMonth() + 1);
                var day = padNums(date.getDate());
                var hour = padNums(date.getHours());
                var minutes = padNums(date.getMinutes());
                var result = moment(date.getFullYear() + "-" + month + "-" + day + " " + hour + ":" + minutes, "YYYY-MM-DD HH:mm");
                var sourceMoment = moment.tz(result, "America/Mexico_City"); //UTC neutro de la BD moment.tz.guess()
                var localMoment = sourceMoment.clone().tz("Europe/Lisbon").format('YYYY-MM-DD[T]HH:mm:ss');
                return new Date(localMoment.substring(0, 19));
            }

Один пример:

  • Дата date = пт, 17 августа 2018 г., 14:36:25 GMT + 0200 (центральная гора верано)
  • Источник моментаMoment = "2018-08-17 14:36" Момент
  • localMoment = "2018-08-17T13: 36: 00"

Почему Мексика -> Лиссабон всего на час впереди? Насколько я знаю, местный момент должен быть «2018-08-17T20: 36: 00».

Что я делаю неправильно? Кажется, это работает для Европы / Лиссабона в Европу / Мадрид, но я не знаю почему.

Спасибо.

Решение:

var result = moment.tz(date.getFullYear() + "-" + month + "-" + day + " " + hour + ":" + minutes, "America/Mexico_City");
var localMoment = result.clone().tz("Europe/Lisbon").format('YYYY-MM-DD[T]HH:mm:ss');

person Javier Pallarés    schedule 17.08.2018    source источник
comment
Я не знаю почему, но вызов .tz при инициализации момента решает проблему: var result = moment.tz (date.getFullYear () + - + month + - + day + + hour +: + minutes, America / Mexico_City); var localMoment = result.clone (). tz (Европа / Лиссабон) .format ('ГГГГ-ММ-ДД [Т] ЧЧ: мм: сс');   -  person Javier Pallarés    schedule 17.08.2018


Ответы (1)


Объект Date не может никогда представлять время в произвольном часовом поясе. Он внутренне отслеживает миллисекунды с 1970-01-01 00:00:00 UTC. Функции, которые показывают время, отличное от времени в формате UTC, всегда преобразуют время в формате UTC и местный часовой пояс компьютера, на котором выполняется код. Любая попытка вернуть объект Date, который находится в другом часовом поясе, в конечном итоге потерпит неудачу, независимо от того, используете ли вы момент для управления вещами или какой-либо другой метод, потому что вы не можете обойти поведение местного часового пояса.

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

Вы можете использовать объект Date в качестве входных данных при создании объекта moment, но это будет для преобразования из момента времени UTC, сохраняемого объектом Date. Вы можете создать объект Date по местному времени или по времени UTC, но не по произвольному часовому поясу. Таким образом, вы не можете утверждать America/Mexico_City в качестве часового пояса ввода, если ваш источник - объект Date. Вместо этого вы можете передать строку, массив, целые числа с отдельными частями или любой другой метод создания объекта moment, описанный в документации.

Точно так же вы никогда не сможете вывести объект Date, если хотите, чтобы он отражал произвольный часовой пояс. Хотя у moment есть функция .toDate(), она будет построена на основе времени UTC (из-за ограничений объекта Date). Другими словами, такой код, как moment(someDateObject).tz(someTimeZone).toDate(), просто приведет к тому же someDateObject, с которым вы начали, независимо от пройденного часового пояса.

Код для преобразования из одного часового пояса в другой с помощью строк выглядит следующим образом:

moment.tz("2018-08-17 14:36:25", "YYYY-MM-DD HH:mm:ss", "America/Mexico_City")
      .tz("Europe/Lisbon").format("YYYY-MM-DD HH:mm:ss")

//=> "2018-08-17 20:36:25"

Тот же код с использованием массивов выглядит так:

moment.tz([2018, 7, 17, 14, 36, 25, 0], "America/Mexico_City")
      .tz("Europe/Lisbon").toArray()

//=> [2018, 7, 17, 20, 36, 25, 0]   (note months are 0-11)

Но теперь посмотрим, используем ли мы Date объектов, как это не работает:

moment.tz(new Date(2018, 7, 17, 14, 36, 25, 0), "America/Mexico_City")
      .tz("Europe/Lisbon").toDate()

//=> Fri Aug 17 2018 14:36:25 GMT-0700 (Pacific Daylight Time)

Поскольку мой компьютер находится в тихоокеанском времени, дата ввода обрабатывается как тихоокеанское время (а не в Мехико), а дата вывода отображается как тихоокеанское время (не лиссабонское). Даже если бы я попытался настроить время, чтобы оно соответствовало другому часовому поясу, оно все равно показало бы GMT-0700 и Pacific Daylight Time. Что еще более важно, он по-прежнему будет использовать переходы на летнее время между тихоокеанским стандартным временем и тихоокеанским летним временем, независимо от того, применимы ли они в другом часовом поясе.

Это иллюстрирует ограничения часового пояса объекта Date. У объекта moment таких ограничений нет.

Наконец, если вы пишете новое приложение, ориентированное только на современные браузеры или Node.js, команда Moment рекомендует использовать Luxon вместо этого. Его поддержка часового пояса обеспечивается средой, а не файлами данных, поэтому он намного меньше.

person Matt Johnson-Pint    schedule 17.08.2018
comment
Спасибо, что очистили момент создания объекта. Это сильно упростило мой код. По поводу использования Luxon я попробую. Спасибо, - person Javier Pallarés; 20.08.2018