Moment: Поддержка недопустимой продолжительности

Созданный на 28 июл. 2014  ·  44Комментарии  ·  Источник: moment/moment

В настоящее время нет способа определить, был ли анализ продолжительности успешным, даже путем проверки полей.

New Feature

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

Есть ли обновления по этому поводу?

С moment 2.23.0 функция isValid() также возвращает true при попытке создать продолжительность из недопустимой строки ISO8601.

Пример:

const mom = moment.duration('asdf')
console.log(mom.isValid()) // This returns true, expected would be false 

Это меня раздражает. и полностью побеждает цель функции isValid() на объектах Duration (есть ли вообще случай, когда isValid() возвращает false поскольку момент интерпретирует даже недопустимый Вход?)

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

Я согласен. Для начала нам нужен метод isValid.

Я думаю, что недопустимые длительности должны вызывать исключения, а текущая обработка недопустимых длительностей - это ошибка, а не улучшение. Рассмотрим эти случаи:

`var wrong = moment.duration(3,'mintues');`

Что будет в результате? Документы не определяют, что происходит при неправильном вводе.

Это имеет каскадный эффект, так как duration используется вместо add() и subtract() , поэтому они также имеют неопределенное поведение:

var hmm = moment().subtract(3,'mintues').toDate();
var uhoh = moment().add(3,'mintues').toDate();

Из ручного тестирования я могу сказать вам, что происходит: moment "успешно" с нулевой продолжительностью.

Если бы moment() просто выдал исключение при неверном вводе, эта проблема была бы обнаружена немедленно. Поскольку это молчаливо «удалось», ошибка класса «Входящий мусор, выходящий мусор» сохранялась.

Поскольку поведение длительности с опечаткой в ​​настоящее время не определено, запуск исключения для неверных строк будет обратно совместимым.

Если используется ненадежная строка, которая может содержать опечатку, try/catch можно использовать явно при проверке возможности использования строки для описания допустимой продолжительности.

+1 @markstos.

Как насчет поддержки опции strict (например, самого момента для дат), которая выбрасывает? Возвращать нулевую длительность при сбое синтаксического анализа довольно опасно.

Вариант strict был бы лучше, чем отсутствие изменений, но я не думаю, что анализ недопустимых дат, поскольку нулевая длительность в первую очередь является хорошим поведением по умолчанию.

Согласовано. Будет ли возможное изменение приземлиться только с моментом @ 2.10?

Почему бы не использовать тот же шаблон, что и в остальное время? Имейте поле _isValid и метод isValid () и установите продолжительность как недопустимую, если синтаксический анализ завершится неудачно.

Для справки, вот другие задокументированные места, где используется isValid ():

https://github.com/moment/momentjs.com/search?utf8=%E2%9C%93&q=isValid

Ссылка на документацию, а не на код, была преднамеренной, хотя упоминания кода также актуальны.

+1
Очень нужна возможность узнать, был ли разбор успешным или нет.
Если обратная совместимость вызывает беспокойство, то можно было бы ввести метод Duration.parse(input: string, strict?: boolean = true): Duration который будет выдавать, если ввод неверен и указан аргумент strict .
Текущее поведение, когда мы получаем Duration со всеми нулями для произвольных данных, очень странно.

+1
Было бы удобно иметь метод isValid () на продолжительности (чтобы увидеть, был ли синтаксический анализ успешным).

Привет всем, Moment 2.18.0 теперь имеет метод .isValid для длительностей. Однако это довольно снисходительно. @markstos @theazureshadow и другие, попробуйте и дайте нам знать, если у вас есть предложения.

@marwahaha ,

В качестве первоначального теста я скопировал / вставил один из приведенных выше примеров. Вместо того, чтобы вернуть истину или ложь, как ожидалось, он выдает исключение (с моментом 2.18.0):

 moment.duration(3,'mintues').isValid();

(Созданная недопустимая продолжительность по-прежнему "успешно" без выдачи исключения, но теперь проверка, действительна ли она, вызывает исключение!)

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

@markstos Я только что запустил этот код в консоли Momentjs.com - у которой есть версия 2.18.0 - без проблем. Можем ли мы получить более подробную информацию об этом?

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

21 марта 2017 г. в 14:35 "Мэгги Пинт" [email protected] написала:

@markstos https://github.com/markstos Я только что запустил этот код в
консоль Momentjs.com, на которой установлена ​​версия 2.18.0, без проблем. Мы можем получить
подробнее об этом?

-
Вы получаете это, потому что вас упомянули.
Ответьте на это письмо напрямую, просмотрите его на GitHub
https://github.com/moment/moment/issues/1805#issuecomment-288176838 или отключить звук
нить
https://github.com/notifications/unsubscribe-auth/ACbGmWIf24KlRs8oiS2wTn206iJNMod7ks5roBhfgaJpZM4CRuVM
.

@maggiepint @marwahaha Да, неправильное написание "минут" - ЭТО причина , по которой продолжительность должна быть недействительной.

@markstos Я также не могу воспроизвести это исключение в консоли Momentjs.com. (Сейчас это 2.18.1.) Если вы все еще можете воспроизвести исключение при вызове isValid, можем ли мы получить более подробную информацию?

screen shot 2017-03-22 at 10 38 06

(Очевидно, Марк хотел, чтобы isValid возвращал false в этой ситуации, но это отдельная проблема от исключения. Для меня не на 100% очевидно, как мы должны обрабатывать валидность синтаксического анализа с входными данными объекта.)

Я не могу воспроизвести исключение и с 2.18.1. Возможно, это была ложная тревога. Я могу воспроизвести результат @butterflyhug, когда такая недопустимая продолжительность возвращает "true" для "isValid ()".

Разве в этом случае разбор не должен завершиться ошибкой вместо того, чтобы в результате вернуть «0 минут» в качестве ошибочно правильного вывода?

Должен - это другой вопрос, но IIRC то, что он делает, интерпретирует это
значение в миллисекундах, потому что единица измерения не найдена в хеш-таблице единиц измерения.

Должен ли он быть недействительным? ИМО наверное.

22 марта 2017 г. в 8:42 «Марк Стосберг» [email protected] написал:

Я не могу воспроизвести исключение и с 2.18.1. Возможно, это было ложью
тревога. Я могу воспроизвести @butterflyhug https://github.com/butterflyhug 's
результат того, что такая недействительная продолжительность возвращает "истина" для
"является действительным()".

В этом случае синтаксический анализ не должен завершиться неудачно вместо того, чтобы возвращать «0 минут» в качестве
неправильный вывод в результате?

-
Вы получаете это, потому что вас упомянули.
Ответьте на это письмо напрямую, просмотрите его на GitHub
https://github.com/moment/moment/issues/1805#issuecomment-288440827 или отключить звук
нить
https://github.com/notifications/unsubscribe-auth/AFxi0nZAz8gwAJM8fVx5rYPyIWjeEfHMks5roUF4gaJpZM4CRuVM
.

Похоже, здесь есть ошибка:

https://github.com/moment/moment/blob/497f918515ae6ab900f008f19523b1e4ae5e2450/src/lib/duration/create.js#L34

Предполагается, что строка действительна и отображается на карте «длительности». Похоже, что исправление состоит в том, чтобы добавить здесь проверку, чтобы подтвердить, что строка является допустимым значением для установки. Если нет, установите _isValid:false

Такое поведение согласуется со стандартным методом isValid :

moment({'mintues': 3}).isValid()
> true

Источником этого является normalizeObjectUnits https://github.com/moment/moment/blob/497f918515ae6ab900f008f19523b1e4ae5e2450/src/lib/units/aliases.js#L14 -L29, который добавляет только допустимые атрибуты (и отбрасывает оскорбительные атрибуты). единицы).

@maggiepint @ichernev должно ли это поведение измениться? Скоро мы сделаем пробный релиз ...

Преобразование «3 мин.» В «0 минут» и объявление результата «действительным» является ошибкой. Это может быть критическое изменение, чтобы исправить это, но это все еще исправление ошибки.

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

Рассмотрим случай, когда вы разбираете что-то вроде moment({'minutes': 3, '$cacheKey': 92619502}).isValid() . Я очень надеюсь, что у нас есть пользователи, которые ценят этот синтаксический анализ как действительный момент, и я не вижу принципиального различия между этим примером и ошибкой, которую вы написали.

Обсуждаемый нами API - это «анализатор объектов» для конструктора moment , который задокументирован здесь:

http://momentjs.com/docs/#/parsing/object/

В документации пока ничего не говорится о передаче неизвестных или дополнительных аргументов.

Прямо сейчас поведение Moment здесь можно описать как «Мусор на входе, мусор на выходе». Ввод мусора автоматически принимается, и в результате получается "мусор на выходе" - даты с ошибками преобразуются в другие даты и считаются действительными!

Эти обновления позволят разработчику как можно скорее узнать, что он допустил ошибку:

  • Документ о том, что исключение будет вызвано неизвестными аргументами, передается конструктору объекта.

    • Выбрасывать исключение, если в конструктор объекта передаются неизвестные аргументы.

До тех пор, пока Moment продолжает принимать «Garbage In» как действительный, это будет по-прежнему оказывать медвежью услугу разработчикам, и пользователи останутся с Moment, ошибочно сообщающим, что разбитые даты «действительны».

Это улучшение, кажется, стоит «критического» изменения.

Меня только что укусило: moment().subtract('1 day') ... это неверный способ выразить продолжительность. Я бы не ожидал, что это будет эквивалентно .subtract(0) . ИМО, наименее неожиданная вещь в этом случае - это бросить.

@johnvh Полностью согласен.

Вы знаете, что это неверный способ выразить продолжительность, но вы все равно пишете этот код? Что вы ожидаете? Я полагаю, вы пришли к выводу, что это неправильный способ выразить продолжительность из отличной документации, предоставленной авторами?

25.04.2017, в 08:29, Марк Стосберг [email protected] написал:

@johnvh Полностью согласен.

-
Вы получаете это, потому что подписаны на эту ветку.
Ответьте на это письмо напрямую, просмотрите его на GitHub или отключите обсуждение.

Разработчики @simonfox - люди. Мы совершаем ошибки. Вот почему половина нашей кодовой базы - это тесты. Документация Moment / прекрасна /, но она не поможет, если вы считаете, что правильно запомнили API и не нуждаетесь в ссылках на документацию. Вот почему полезно иметь не только отличную документацию, но и код, который дает сбой при недопустимом вводе, вместо того, чтобы молча преобразовывать недопустимый ввод в неработающий «действительный» ввод. Если бы @johnvh сразу получил ошибку проверки при

@markstos точно. Согласен на 100%.

Это была ошибка, которую нужно было отследить. Мы не писали это так, конечно, зная, что это недействительно. Это выглядит правильно, поскольку методы манипуляции моментом очень либеральны в своих поддерживаемых сигнатурах. Мы также используем повестку дня в том же проекте, который использует человеческий интервал для преобразования естественного языка в длительности. Таким образом, у нас будет что-то вроде этого, только строки друг от друга:

moment().subtract('1 day');
agenda.processEvery('1 day');

Последний работает так, как задумано, а первый - нет. Если бы первое вызвало исключение, это бы предупредило нас о нашей ошибке.

Кроме того, тот факт, что Moment / имеет / метод isValid (), означает, что он проверяет значения как действительные или недопустимые. В случаях, когда недопустимые значения классифицируются как допустимые, метод isValid() видимому, работает не так, как описано в документации.

Привет всем, мы хотели бы рассмотреть любые PR в этой области!

Я столкнулся с этой ошибкой или чем-то похожим на нее. Если я запускаю moment.duration('3', 'minutes').asMinutes() с помощью Moment 2.18.1, я получаю результат 0. Я думаю, что это должно либо вернуть 3, либо вызвать исключение. По крайней мере, moment.duration('3', 'minutes').isValid() должен вернуть false .

То, как Moment ведет себя сейчас, может вызвать множество проблем, вызывая ошибки, которые может быть трудно обнаружить и диагностировать, как уже упоминали здесь несколько человек.

Это было решено?

@TomJSmith Быстрый тест показывает, что ошибка все еще существует. Этот код:

 moment().subtract('1 day');

"успешно", вычитая ноль дней вместо одного дня, как ожидалось. Вы можете вызвать .isValid() в результирующую дату и получить ответ true указывающий, что результат действителен, когда это не так.

Текущее поведение может привести к плохим последствиям в некоторых случаях использования и должно быть четко задокументировано с предупреждением:

Пример использования
Я хочу удалить ресурсы в зависимости от срока хранения:

const duration = moment.duration('invalid');
const currentDate = moment();
const removeBeforeDate  = moment().subtract(duration);

console.log(`currentDate      : ${currentDate}`);
console.log(`removeBeforeDate : ${removeBeforeDate}`);

Результат:

currentDate      : Fri Apr 13 2018 13:15:04 GMT+0200
removeBeforeDate : Fri Apr 13 2018 13:15:04 GMT+0200

Последствие:
Все ресурсы до текущей даты удаляются ...

До сих пор я нашел единственный способ обойти это, если проверить значение после синтаксического анализа:

const duration = moment.duration('invalid');
if (duration.toISOString() === 'P0D') {
    // throw an Error
}

Да, это плохая ошибка, она открыта с 2014 года. Это то, что у проектов date-fns правильно. Они фактически сообщают вам, является ли недопустимый ввод недопустимым. https://date-fns.org/ К сожалению, date-fns не обрабатывает преобразования часовых поясов, но, возможно, есть способ справиться с ними с помощью внешней библиотеки.

Чтобы проект Moment исправил это, они должны прекратить принимать ввод мусора и рассматривать его как действительную дату. Хотя это кажется лучшим поведением, технически это изменение «обратного разрушения», поэтому кажется, что есть сопротивление, чтобы внести изменения. Но, учитывая, что проект не принимал никаких мер в последние почти четыре года, я бы не ожидал исправления в ближайшее время.

Есть ли обновления по этому поводу?

С moment 2.23.0 функция isValid() также возвращает true при попытке создать продолжительность из недопустимой строки ISO8601.

Пример:

const mom = moment.duration('asdf')
console.log(mom.isValid()) // This returns true, expected would be false 

Это меня раздражает. и полностью побеждает цель функции isValid() на объектах Duration (есть ли вообще случай, когда isValid() возвращает false поскольку момент интерпретирует даже недопустимый Вход?)

@robbiecloset После моего последнего сообщения в апреле проект "date-fns" улучшился в поддержке часовых поясов. Теперь есть проекты "date-fns-timezone" и "date-fns-tz", чтобы помочь в этом.

Я бы подумал об использовании его, если возможно переключение.

Я использую moment.duration(value).toISOString() === value , это значение считывается из конфигурации.

Я использую значение moment.duration (value) .toISOString () ===, это значение считывается из конфигурации.

@ bors-ltd Я думаю, что часть проблемы заключается в том, что в этот момент можно было бы декодировать два значения, которые производят одно и то же закодированное значение.

Например: moment.duration('PT0M0S').toISOString() === moment.duration('PT0S').toISOString() .

Если вы посмотрите на тесты, кажется, что недопустимые значения на самом деле не входят в спецификацию:

https://github.com/moment/moment/blob/2.24.0/src/test/moment/duration.js#L419 -L420

Шаблоны, не соответствующие стандарту продолжительности ISO, тестируются как «0» секунд.

Здравствуйте, у нас также была такая же проблема с методом isValid() и мы сделали это вручную.
const isValidDuration = duration => { return !!duration.match( /^(-?)P(?=\d|T\d)(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)([DW]))?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+(?:\.\d+)?)S)?)?$/ ); };
Надеюсь, это поможет кому-нибудь.

См. Https://momentjs.com/docs/#/ -project-status /

Спасибо за обсуждение здесь.

Хакерское исправление - заменить метод isValid методом, который гарантирует, что сумма частей данных> 0 (или, по крайней мере, вероятно, недействительна).

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