Moment: isSameOrAfter donne une sortie aléatoire lors de la comparaison de moment () à moment ()

Créé le 21 févr. 2017  ·  4Commentaires  ·  Source: moment/moment

La description
Donc, moi et un collègue avons trouvé un bogue dans notre code qui s'est avéré être causé par nous en utilisant une variable non définie (essentiellement moment(undefined) puis en essayant de comparer cela à une nouvelle instance de moment ( moment() ) avec la méthode isSameOrAfter .

Donc, ce que nous avons essentiellement utilisé, était ceci:

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

Exécuter ce code une ou deux fois va retourner true , mais pas toujours. De temps en temps, il renvoie false , je suppose que c'est parce que la création de deux instances de moment, l'une après l'autre, sans temps défini pourrait les créer avec une différence de quelques microsecondes.

Voici un test que j'ai exécuté à la fois dans Node v7.1.0 sur Windows 10 et dans Chrome/56.0.2924.87 avec 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();

Les deux premières fonctions enregistreront false quelques fois sur 1000, et pas la troisième. Il ne se connecte qu'en cas d'exception.

Environnement:
Mar 21 février 2017 14:36:06 GMT+0100 (W. Europe Standard Time)
2017-02-21 14:36:06
-60
Mozilla/5.0 (Windows NT 10.0 ; Win64 ; x64) AppleWebKit/537.36 (KHTML, comme Gecko) Chrome/56.0.2924.87 Safari/537.36
2.17.1

Commentaire le plus utile

@imrvshah Notez d'abord que

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

crée un nouveau moment avec l'heure actuelle, le formate sous forme de chaîne et passe cette chaîne à isSameOrAfter() , qui l'analyse à nouveau. Tu aurais juste dû dire :

...isSameOrAfter(moment())

Et enregistré le moment -> chaîne -> travail moment. C'est un bien meilleur code, mais je parierais aussi que cela corrige le bogue. Avez-vous remarqué des avertissements de dépréciation disant « hé, vous n'êtes pas censé passer des chaînes à un moment comme ça » ? Moment sait comment analyser les chaînes ISO 8601 comme moment("1982-05-25") . Il sait également comment analyser les chaînes où le format est spécifié, comme moment("05-25-1982", "MM-DD-YYYY") . Mais il n'a aucune idée qu'une chaîne comme "25-05-1982" est censée être "MM-JJ-AAAA" sans que vous le disiez. Il laisse donc le navigateur deviner en remettant simplement cette chaîne au constructeur Date . En d'autres termes, votre code se déroule comme ceci :

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

Il y a une raison pour laquelle nous avons déconseillé cela : il donne des résultats incohérents en fonction du navigateur qui l'exécute. Donc, ce que vous rencontrez, c'est qu'iOS ne prend pas en charge ce format de manière native. Dans ma console de développement Safari :

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

Cela vous a donné de mauvaises comparaisons qui vous ont laissé un tableau vide.

Tous les 4 commentaires

J'ai probablement le même genre de problème. Il fonctionne comme prévu sur les appareils Chrome et Android, mais pas sur iOS.

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

dans iOS, je reçois un tableau null pendant qu'il fonctionne sur Chrome et Android.

Environnement:

CLI de Cordoue : 6.4.0
Version du cadre ionique : 2.0.0
Version Ionic CLI : 2.1.18
Version de l'application Ionic Lib : 2.1.9
Version des scripts d'applications ioniques : 1.0.0
version de déploiement d'ios : 1.9.0
version ios-sim : 5.0.13
Système d'exploitation : macOS Sierra
Version du nœud : v6.9.2
Version Xcode : Xcode 8.2.1 Version de construction 8C1002

@ErikMartensson

Je suppose que c'est parce que la création de deux instances de moment, l'une après l'autre, sans temps défini, pourrait les créer avec une différence de quelques microsecondes.

Oui, moment() ou moment(undefined) --qui sont identiques--signifie maintenant . Les dates JS ont une résolution en millisecondes, donc si maintenant est une milliseconde différente, ce qui arrivera parfois, une heure est après l'autre. AFAIK, JS ne définit pas dans quel ordre moment().isSameOrAfter(moment()) évalue ces deux appels moment() . Mais comme il doit évidemment faire le deuxième appel avant d'exécuter isSameOrAfter() toute façon, cela ne me surprendrait pas si le second en pratique venait toujours en premier. Cela signifierait que s'il y a une différence de temps, la partie "orAfter" du test échouera également. Vous pouvez le confirmer avec un débogueur.

Je ne sais pas quoi te dire. C'est ainsi que les datetimes à résolution finie doivent fonctionner ; « maintenant » signifie un moment différent en fonction du moment où vous le dites.

@imrvshah Notez d'abord que

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

crée un nouveau moment avec l'heure actuelle, le formate sous forme de chaîne et passe cette chaîne à isSameOrAfter() , qui l'analyse à nouveau. Tu aurais juste dû dire :

...isSameOrAfter(moment())

Et enregistré le moment -> chaîne -> travail moment. C'est un bien meilleur code, mais je parierais aussi que cela corrige le bogue. Avez-vous remarqué des avertissements de dépréciation disant « hé, vous n'êtes pas censé passer des chaînes à un moment comme ça » ? Moment sait comment analyser les chaînes ISO 8601 comme moment("1982-05-25") . Il sait également comment analyser les chaînes où le format est spécifié, comme moment("05-25-1982", "MM-DD-YYYY") . Mais il n'a aucune idée qu'une chaîne comme "25-05-1982" est censée être "MM-JJ-AAAA" sans que vous le disiez. Il laisse donc le navigateur deviner en remettant simplement cette chaîne au constructeur Date . En d'autres termes, votre code se déroule comme ceci :

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

Il y a une raison pour laquelle nous avons déconseillé cela : il donne des résultats incohérents en fonction du navigateur qui l'exécute. Donc, ce que vous rencontrez, c'est qu'iOS ne prend pas en charge ce format de manière native. Dans ma console de développement Safari :

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

Cela vous a donné de mauvaises comparaisons qui vous ont laissé un tableau vide.

@icambron

Je suis d'accord avec vous et je comprends que dans une console, il s'agissait d'un avertissement de dépréciation à cause du format de la date.

Merci pour votre commentaire sur le fait de ne pas l'envelopper plusieurs fois et de simplement l'utiliser. ...isSameOrAfter(moment())

Cette page vous a été utile?
0 / 5 - 0 notes