Moment: isSameOrAfter дает случайный результат при сравнении moment () с moment ()

Созданный на 21 февр. 2017  ·  4Комментарии  ·  Источник: moment/moment

Описание
Итак, я и мой коллега обнаружили ошибку в нашем коде, которая, как оказалось, была вызвана тем, что мы использовали неопределенную переменную (в основном moment(undefined) а затем пытались сравнить ее с новым экземпляром момента ( moment() ) методом isSameOrAfter .

В основном мы использовали следующее:

let isSame = moment(undefined).isSameOrAfter(moment());

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

Вот тест, который я провел как в Node v7.1.0 в Windows 10, так и в Chrome / 56.0.2924.87 с Moment.js 2.17.1.

const moment = require('moment');

function isSameOrAfter() {
    console.log('isSameOrAfter')
    for (let i = 0; i < 1000; i++) {
        let output = moment().isSameOrAfter(moment());
        if (!output) {
            console.log(output, i);
        }
    }
}

function isSame() {
    console.log('isSame')
    for (let i = 0; i < 1000; i++) {
        let output = moment().isSame(moment());
        if (!output) {
            console.log(output, i);
        }
    }
}

function sameExactVariable() {
    console.log('Another test comparing the same exact variable')
    for (let i = 0; i < 1000; i++) {
        const now = moment();
        let output = now.isSame(now);
        if (!output) {
            console.log(output, i);
        }
    }
}

isSameOrAfter();
isSame();
sameExactVariable();

Первые две функции будут регистрировать false несколько раз из 1000, а третья функция - нет. Он регистрирует только исключение.

Среда:
Вт, 21 февраля 2017 г., 14:36:06 GMT + 0100 (стандартное время западной Европы)
2017-02-21 14:36:06
-60
Mozilla / 5.0 (Windows NT 10.0; Win64; x64) AppleWebKit / 537.36 (KHTML, как Gecko) Chrome / 56.0.2924.87 Safari / 537.36
2.17.1

Самый полезный комментарий

@imrvshah Сначала обратите внимание, что

...isSameOrAfter(moment().format('MM-DD-YYYY'))

создает новый момент с текущим временем, форматирует его как строку и передает эту строку в isSameOrAfter() , который снова анализирует ее. Вы должны были просто сказать:

...isSameOrAfter(moment())

И сохранил момент -> строка -> момент работы. Это намного лучший код, но я уверен, что он исправляет ошибку. Вы заметили предупреждения об устаревании, в которых говорится: «Эй, вы не должны передавать строки в такой момент»? Moment знает, как разбирать строки ISO 8601, например moment("1982-05-25") . Он также знает, как анализировать строки, в которых указан формат, например moment("05-25-1982", "MM-DD-YYYY") . Но он понятия не имеет, что строка типа «05-25-1982» должна быть «ММ-ДД-ГГГГ» без вашего ведома. Таким образом, он позволяет браузеру угадывать, просто передав эту строку конструктору Date . Другими словами, ваш код разворачивается следующим образом:

m.isSameOrAfter("05-25-1982");
m.isSameOrAfter(moment("05-25-1982"))
m.isSameOrAfter(moment(new Date("05-25-1982")))

Есть причина, по которой мы отказались от этого: он дает противоречивые результаты в зависимости от того, в каком браузере он запущен. Итак, вы столкнулись с тем, что iOS изначально не поддерживает этот формат. В моей консоли разработчика Safari:

> new Date("05-25-1982")
Invalid Date

Это дало вам плохие сравнения, оставившие вас с пустым массивом.

Все 4 Комментарий

Наверное, у меня такая же проблема. Он работает должным образом на устройствах Chrome и Android, но не на iOS.

let arrDates: Array<String> = []; _.each(Dates, (date) => { if (moment(date).isSameOrAfter(moment().format('MM-DD-YYYY'))) { arrDates.push(date); } });

в iOS я получаю нулевой массив, пока он работает на Chrome и Android.

Среда:

Кордова CLI: 6.4.0
Версия Ionic Framework: 2.0.0
Версия Ionic CLI: 2.1.18
Версия Ionic App Lib: 2.1.9
Версия Ionic App Scripts: 1.0.0
версия ios-deploy: 1.9.0
версия ios-sim: 5.0.13
ОС: macOS Sierra
Версия узла: v6.9.2
Версия Xcode: Xcode 8.2.1 Версия сборки 8C1002

@ErikMartensson

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

Да, moment() или moment(undefined) - которые идентичны - означает " сейчас" . Даты JS имеют разрешение в миллисекундах, поэтому, если сейчас другая миллисекунда, что иногда случается, один раз за другим. AFAIK, JS не определяет, какой порядок moment().isSameOrAfter(moment()) оценивает эти два вызова moment() . Но поскольку он, очевидно, в любом случае должен выполнить второй вызов перед выполнением isSameOrAfter() , меня не удивит, если на практике второй всегда будет первым. Это будет означать, что если есть разница во времени, то часть теста «orAfter» также не удастся. Вы можете подтвердить это с помощью отладчика.

Я не знаю, что тебе сказать. Именно так должны работать даты с конечным разрешением; «сейчас» означает другое время в зависимости от того, когда вы это говорите.

@imrvshah Сначала обратите внимание, что

...isSameOrAfter(moment().format('MM-DD-YYYY'))

создает новый момент с текущим временем, форматирует его как строку и передает эту строку в isSameOrAfter() , который снова анализирует ее. Вы должны были просто сказать:

...isSameOrAfter(moment())

И сохранил момент -> строка -> момент работы. Это намного лучший код, но я уверен, что он исправляет ошибку. Вы заметили предупреждения об устаревании, в которых говорится: «Эй, вы не должны передавать строки в такой момент»? Moment знает, как разбирать строки ISO 8601, например moment("1982-05-25") . Он также знает, как анализировать строки, в которых указан формат, например moment("05-25-1982", "MM-DD-YYYY") . Но он понятия не имеет, что строка типа «05-25-1982» должна быть «ММ-ДД-ГГГГ» без вашего ведома. Таким образом, он позволяет браузеру угадывать, просто передав эту строку конструктору Date . Другими словами, ваш код разворачивается следующим образом:

m.isSameOrAfter("05-25-1982");
m.isSameOrAfter(moment("05-25-1982"))
m.isSameOrAfter(moment(new Date("05-25-1982")))

Есть причина, по которой мы отказались от этого: он дает противоречивые результаты в зависимости от того, в каком браузере он запущен. Итак, вы столкнулись с тем, что iOS изначально не поддерживает этот формат. В моей консоли разработчика Safari:

> new Date("05-25-1982")
Invalid Date

Это дало вам плохие сравнения, оставившие вас с пустым массивом.

@icambron

Я согласен с вами и выяснил, что в консоли это предупреждение об устаревании из-за формата даты.

Спасибо за комментарий о том, что не нужно оборачивать его несколько раз, а просто использовать. ...isSameOrAfter(moment())

Была ли эта страница полезной?
0 / 5 - 0 рейтинги