Moment: endOf ('day') falha em dias que não começam à meia-noite

Criado em 20 abr. 2016  ·  15Comentários  ·  Fonte: moment/moment

Considerar:

moment("2016-10-16").endOf('day').format("YYYY-MM-DD HH:mm:ss")

Na maioria dos fusos horários, isso retornará "2016-10-16 23:59:59" . No entanto, no Brasil, isso retornará "2016-10-17 00:59:59" . Isso está incorreto, porque apenas a hora de 00:00 a 00:59 em 2016-10-16 está faltando. O final de 2016/10/16 ainda é 23:59:59 na mesma data.

Isso também é reproduzível com fuso horário de momento:

moment.tz("2016-10-16","America/Sao_Paulo").endOf('day').format("YYYY-MM-DD HH:mm:ss")

O problema está no método endOf . Para calcular o final do dia, pegamos o _início_ do dia, adicionamos um dia e subtraímos um milissegundo. Essa lógica é falha quando o dia não começa à meia-noite. Em vez de adicionar um dia, precisamos adicionar a duração exata de um determinado dia.

Bug DST

Todos 15 comentários

Isso foi originalmente relatado como fuso horário de momento / momento # 327.

2749 está relacionado, mas ligeiramente diferente.

Ao contrário de calcular a duração exata do dia, você não pode simplesmente fazer:

moment('2016-10-16').startOf('day').add(1, 'day').startOf('day').subtract(1, 'millisecond').format()
"2016-10-16T23:59:59-02:00"

Funciona bem no dia 15 quando empurrado para o dia 16 também:

moment('2016-10-15').startOf('day').add(1, 'day').startOf('day').subtract(1, 'millisecond').format()
"2016-10-15T23:59:59-03:00"

Existe um caso extremo em que não estou pensando?

Acho que pode haver um benefício de desempenho em fazer isso de maneira diferente, mas diabos, você pode ler!

Hmmmm, outra coisa complicada aqui:

moment.tz("2016-10-16","America/Sao_Paulo").startOf('day').add(1,'day').startOf('day').subtract(1,'ms').format()
// "2016-10-16T23:59:59-02:00"  (ok)

moment.tz("2016-10-15","America/Sao_Paulo").startOf('day').add(1,'day').startOf('day').subtract(1,'ms').format()
// "2016-10-14T23:59:59-03:00"  (wrong date)

moment.tz("2016-10-15","America/Sao_Paulo").startOf('day').add(1,'day').format()
// "2016-10-15T23:00:00-03:00"  should have skipped forward to "2016-10-16T01:00:00-02:00"

Estamos apenas lidando com todo o comportamento ambíguo do navegador aqui? Ou há algo mais nisso?

Em cromo com o fuso horário windows de Brasillia:

moment("2016-10-15").startOf('day').format()
"2016-10-15T00:00:00-03:00"
moment("2016-10-15").startOf('day').add(1, 'day').format()
"2016-10-16T01:00:00-02:00"

No cromo com meu fuso horário usando Moment Timezone:

moment.tz("2016-10-15","America/Sao_Paulo").startOf('day').format()
"2016-10-15T00:00:00-03:00"
moment.tz("2016-10-15","America/Sao_Paulo").startOf('day').add(1, 'day').format()
"2016-10-15T23:00:00-03:00"

FRIO!

Algo relacionado ao fuso horário do momento? Eu realmente não conheço esse código, então é difícil dizer. Não parece o navegador se o primeiro funcionar.

Acho que isso é resultado do fato de que o fuso horário do momento sempre adiará uma data inválida, se ela tiver sido "adicionada" a essa data. Não tenho certeza se por projeto ou acidente.

//setting moves forward
moment.tz("2016-10-16T00:00:00","America/Sao_Paulo").format()
"2016-10-16T01:00:00-02:00"
//adding moves backward
moment.tz("2016-10-15T00:00:00","America/Sao_Paulo").add(1, 'day').format()
"2016-10-15T23:00:00-03:00"

//setting moves forward
moment.tz("2016-03-13T02:00:00","America/Chicago").format()
"2016-03-13T03:00:00-05:00"
//adding moves backward
moment.tz("2016-03-12T02:00:00","America/Chicago").add(1, 'day').format()
"2016-03-13T01:00:00-06:00"

//one more time for funzies
moment.tz("2016-03-27T01:00:00","Europe/London").format()
"2016-03-27T02:00:00+01:00"

moment.tz("2016-03-26T01:00:00","Europe/London").add(1, 'day').format()
"2016-03-27T00:00:00Z"

Acho que isso tem a ver com a tentativa de usar a configuração keepTime quando você não consegue manter o tempo. Não conheço esse código bem o suficiente para dizer por que ele é assim, mas tenho certeza de que, se a chamada de keepTime nesse código fosse 0 em vez de 1, tudo ocorreria conforme o esperado. É porque o tempo está ativado que ele é adiado. E o tempo de manutenção deve estar ligado, é só funky com este caso extremo.

    moment.updateOffset = function (mom, keepTime) {
        var zone = moment.defaultZone,
            offset;

        if (mom._z === undefined) {
            if (zone && needsOffset(mom) && !mom._isUTC) {
                mom._d = moment.utc(mom._a)._d;
                mom.utc().add(zone.parse(mom), 'minutes');
            }
            mom._z = zone;
        }
        if (mom._z) {
            offset = mom._z.offset(mom);
            if (Math.abs(offset) < 16) {
                offset = offset / 60;
            }
            if (mom.utcOffset !== undefined) {
                mom.utcOffset(-offset, keepTime);
            } else {
                mom.zone(offset, keepTime);
            }
        }
    };

Não sei o suficiente sobre o fuso horário para ser útil aqui, mas talvez o tíquete sobre por que keepTime é usado seja útil para qualquer pessoa que esteja investigando: https://github.com/moment/moment-timezone/ questões / 28

https://github.com/moment/moment/pull/1564

Esta é a última grande mudança nas zonas de manuseio no momento. Não tenho certeza se está relacionado a esse problema, mas deve ajudar.

@maggiepint você pode explicar um pouco o

sempre atrasará uma data inválida

papel. Quero dizer - temos um exemplo que expõe um problema com fuso horário, ou apenas precisamos de algum código inteligente no momento para detectar o horário de verão no início / fim do dia e lidar com isso de forma adequada. A segunda é de médio a fácil. Se tivermos que refatorar novamente a zona que passa entre o momento-tz e o momento, então é um inferno - prefiro esperar pelo 3.0 e torcer para que a nova interface não tenha esse problema.

@ichernev da maneira que o código está hoje, temos dois problemas neste único problema. Um é o problema que @ mj1856 originalmente levantou, que é que os dias que não começam à meia-noite terminam com um valor de fim de dia desagradável. Este é um problema momentâneo.

A outra é que o fuso horário do momento, quando apresentado com uma data inválida, avança se essa data inválida for usada no construtor, mas retrocede se for 'adicionado' àquela data. Este é, como está, um problema com o fuso horário do momento e não com o momento. Não tenho certeza de como a interface do fuso horário muda isso - eu teria que pensar um pouco sobre isso.

@maggiepint obrigado pela explicação clara.

Então, para resolver o problema do momento: endOf('day') sendo impreciso - apenas "mire" para o final do dia, vá lá, se for 00:00, termine, caso contrário, mire novamente, se o segundo objetivo chegar a 00: 00 terminamos, caso contrário, use o primeiro tiro. O segundo objetivo ajudará se pularmos o DST e formos "distorcidos" por uma hora. Se o final do dia for um horário inválido por causa do DST, a segunda mira não fará mal.

Devemos usar este algoritmo para todos os endOf , talvez até startOf , mas isso é mais difícil de raciocinar com o set-to-zero que fazemos atualmente.

Olá pessoal, também estou sendo afetado por esse problema na versão atual do moment (2.14.1).

Enviei o nº 3716 para corrigir isso, mas atualmente estou vendo problemas com o Travis CI por motivos de transpilação. Estarei investigando mais em breve.

Este também está relacionado (localidade brasileira padrão).

Resultados da operação na mesma data:

moment ("2017-10-16T00: 59: 59.999"). subtrair (1, 'dia'). endOf ('dia')
=> "2017-10-16T00: 59: 59.999"

Ei - acabei de enviar # 4164 que corrige isso para startOf e também para endOf. Gostaríamos muito de receber feedback lá para que possamos finalmente seguir em frente.

@ mj1856 , fechei meu PR porque o problema com endOf na borda do DST parece estar resolvido. Isso também poderia ser consertado?

Eu testei o # 4164 e parece que ele foi corrigido. Aguardando mesclagem.

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

Questões relacionadas

benhathaway picture benhathaway  ·  3Comentários

danieljsinclair picture danieljsinclair  ·  3Comentários

BCup picture BCup  ·  3Comentários

RobinvanderVliet picture RobinvanderVliet  ·  3Comentários

vbullinger picture vbullinger  ·  3Comentários