Moment: isSameOrAfter fornece uma saída aleatória ao comparar o momento () ao momento ()

Criado em 21 fev. 2017  ·  4Comentários  ·  Fonte: moment/moment

Descrição
Então, eu e um colega encontramos um bug em nosso código que acabou sendo causado por nós usando uma variável indefinida (basicamente moment(undefined) e, em seguida, tentando comparar isso com uma nova instância de momento ( moment() ) com o método isSameOrAfter .

Então, o que basicamente usamos foi:

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

Executar esse código uma ou duas vezes retornará true , mas nem sempre. De vez em quando retorna false , acho que é porque criar duas instâncias de momento, uma após a outra, sem tempo definido pode criá-las com alguns microssegundos de diferença.

Aqui está um teste que executei no Node v7.1.0 no Windows 10 e no Chrome / 56.0.2924.87 com 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();

As duas primeiras funções registrarão false algumas vezes em 1000, e a terceira não. Ele só registra quando encontra uma exceção.

Ambiente:
Ter, 21 de fevereiro de 2017 14:36:06 GMT + 0100 (Horário padrão da Europa Ocidental)
21/02/2017 14:36:06
-60
Mozilla / 5.0 (Windows NT 10.0; Win64; x64) AppleWebKit / 537.36 (KHTML, como Gecko) Chrome / 56.0.2924.87 Safari / 537.36
2.17.1

Comentários muito úteis

@imrvshah Primeiro, observe que

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

cria um novo momento com a hora atual, formata-o como uma string e passa essa string para isSameOrAfter() , que a analisa novamente. Você deveria apenas ter dito:

...isSameOrAfter(moment())

E salvou o momento -> string -> trabalho de momento. Esse é um código muito melhor, mas também aposto que corrige o bug. Você notou avisos de depreciação dizendo "ei, você não deve passar strings para o momento assim"? Moment sabe como analisar strings ISO 8601 como moment("1982-05-25") . Ele também sabe como analisar strings onde o formato é especificado, como moment("05-25-1982", "MM-DD-YYYY") . Mas não faz ideia de que uma string como "05-25-1982" deve ser "MM-DD-AAAA" sem que você diga. Assim, permite que o navegador adivinhe apenas entregando aquela string ao construtor Date . Em outras palavras, seu código se desenrola assim:

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

Há um motivo pelo qual deixamos de usar isso: ele fornece resultados inconsistentes com base no navegador que o está executando. Então, o que você está descobrindo é que o iOS não suporta esse formato nativamente. No meu console de desenvolvimento Safari:

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

Isso gerou comparações ruins que deixaram você com um array vazio.

Todos 4 comentários

Provavelmente eu tenho o mesmo tipo de problema. Ele está funcionando conforme o esperado no Chrome e no dispositivo Android, mas não no iOS.

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

no iOS, estou obtendo array null enquanto trabalha no Chrome e no Android.

Ambiente:

Cordova CLI: 6.4.0
Versão do Ionic Framework: 2.0.0
Versão Ionic CLI: 2.1.18
Versão Ionic App Lib: 2.1.9
Versão dos scripts do aplicativo Ionic: 1.0.0
versão ios-deploy: 1.9.0
versão ios-sim: 5.0.13
SO: macOS Sierra
Versão do nó: v6.9.2
Versão do Xcode: Xcode 8.2.1 Versão da compilação 8C1002

@ErikMartensson

Acho que é porque criar duas instâncias de momento, uma após a outra, sem tempo definido, pode criá-las com alguns microssegundos de diferença.

Sim, moment() ou moment(undefined) --que são idênticos - significa agora . As datas JS têm resolução em milissegundos, portanto, se agora for um milissegundo diferente, o que às vezes acontece, uma vez é após a outra. AFAIK, JS não define que ordem moment().isSameOrAfter(moment()) avalia essas duas chamadas moment() . Mas, como ele obviamente tem que fazer a segunda chamada antes de executar isSameOrAfter() qualquer maneira, não me surpreenderia se a segunda chamada na prática sempre viesse primeiro. Isso significa que, se houver uma diferença de tempo, ele também será reprovado na parte "orAfter" do teste. Você pode confirmar isso com um depurador.

Eu não sei o que te dizer. É assim que os datetimes de resolução finita precisam funcionar; "agora" significa uma hora diferente com base em quando você diz isso.

@imrvshah Primeiro, observe que

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

cria um novo momento com a hora atual, formata-o como uma string e passa essa string para isSameOrAfter() , que a analisa novamente. Você deveria apenas ter dito:

...isSameOrAfter(moment())

E salvou o momento -> string -> trabalho de momento. Esse é um código muito melhor, mas também aposto que corrige o bug. Você notou avisos de depreciação dizendo "ei, você não deve passar strings para o momento assim"? Moment sabe como analisar strings ISO 8601 como moment("1982-05-25") . Ele também sabe como analisar strings onde o formato é especificado, como moment("05-25-1982", "MM-DD-YYYY") . Mas não faz ideia de que uma string como "05-25-1982" deve ser "MM-DD-AAAA" sem que você diga. Assim, permite que o navegador adivinhe apenas entregando aquela string ao construtor Date . Em outras palavras, seu código se desenrola assim:

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

Há um motivo pelo qual deixamos de usar isso: ele fornece resultados inconsistentes com base no navegador que o está executando. Então, o que você está descobrindo é que o iOS não suporta esse formato nativamente. No meu console de desenvolvimento Safari:

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

Isso gerou comparações ruins que deixaram você com um array vazio.

@icambron

Eu concordo com você e descubro o caso em um console que era um aviso de suspensão de uso por causa do formato de data.

Obrigado pelo seu comentário sobre não embrulhar várias vezes e apenas usar. ...isSameOrAfter(moment())

Esta página foi útil?
0 / 5 - 0 avaliações