Moment: endOf ('day') falla en los días que no comienzan a la medianoche

Creado en 20 abr. 2016  ·  15Comentarios  ·  Fuente: moment/moment

Considerar:

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

En la mayoría de las zonas horarias, esto devolverá "2016-10-16 23:59:59" . Sin embargo, en Brasil, esto devolverá "2016-10-17 00:59:59" . Esto es incorrecto, porque solo falta la hora de 00:00 a 00:59 del 2016-10-16. El final del 2016-10-16 sigue siendo a las 23:59:59 del mismo día.

Esto también es reproducible con moment-timezone:

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

El problema está en el método endOf . Para calcular el final del día, tomamos el _comienzo_ del día, sumamos un día y luego restamos un milisegundo. Esa lógica es defectuosa cuando el día no comienza a la medianoche. En lugar de agregar un día, debemos agregar la duración exacta del día en particular.

Bug DST

Todos 15 comentarios

Esto se informó originalmente como momento / momento-zona horaria # 327.

2749 está relacionado, pero es ligeramente diferente.

A diferencia de calcular la duración exacta del día, ¿no puede simplemente hacer:

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

Funciona bien el día 15 cuando se empuja al 16 también:

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

¿Existe un caso límite en el que no estoy pensando?

Supongo que podría haber un beneficio de rendimiento al hacerlo de manera diferente, pero diablos, ¡puedes leerlo!

Hmmmm, algo más loco aquí:

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 tratando con todo el comportamiento ambiguo del navegador aquí? ¿O hay algo más?

En cromo con la zona horaria de 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"

En Chrome con mi zona horaria 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 pasa con la zona horaria del momento? Realmente no conozco ese código, por lo que es difícil de decir. Sin embargo, no parece el navegador si el primero funciona.

Creo que esto es el resultado del hecho de que la zona horaria del momento siempre retrasará una fecha no válida, si se ha 'agregado' a esa fecha. Ya sea por diseño o por accidente, no estoy seguro.

//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"

Creo que esto tiene algo que ver con intentar usar la configuración de keepTime cuando no puedes mantener el tiempo. No conozco este código lo suficientemente bien como para decirle por qué el código es como es, pero estoy seguro de que si la llamada a keepTime en este código fuera 0 en lugar de 1, todo saldría adelante como se esperaba. Es porque se mantiene el tiempo que se retrasa. Y mantener el tiempo debería estar encendido, simplemente es funky con este estuche de borde.

    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);
            }
        }
    };

No sé lo suficiente sobre la zona horaria del momento para ser útil aquí, pero quizás el boleto sobre por qué se usa keepTime sea ​​útil para cualquiera que investigue: https://github.com/moment/moment-timezone/ cuestiones / 28

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

Este es el último gran cambio en las zonas de manipulación en este momento. No estoy seguro si está relacionado con este problema, pero debería ayudar.

@maggiepint, ¿puedes explicar un poco el

siempre retrasará una fecha no válida

parte. Quiero decir, ¿tenemos un ejemplo que expone un problema con la zona horaria del momento, o simplemente necesitamos un código inteligente en el momento para detectar el horario de verano al inicio / final del día y manejarlo adecuadamente? El segundo es de medio a fácil. Si tenemos que refactorizar nuevamente la zona que pasa entre el momento-tz y el momento, entonces es un infierno; prefiero esperar a 3.0 y esperar que la nueva interfaz no tenga este problema.

@ichernev tal como está el código hoy, tenemos dos problemas en este número. Uno es el problema que planteó originalmente

La otra es que la zona horaria de momento, cuando se presenta con una fecha inválida, avanza si esa fecha inválida se usa en el constructor, pero retrocede si se 'agrega' a esa fecha. Este es, tal como está, un problema con la zona horaria del momento y no con el momento. No estoy seguro de cómo cambia eso la interfaz de la zona horaria; tendría que pensarlo un poco.

@maggiepint gracias por la clara explicación.

Entonces, para solucionar el problema del momento: endOf('day') es inexacto - simplemente "apunte" al final del día, vaya allí, si son las 00:00, termine, de lo contrario apunte de nuevo, si el segundo objetivo llega a 00: 00 hemos terminado, de lo contrario, use el primer disparo. El segundo objetivo ayudará si saltamos el horario de verano y nos "distorsionamos" una hora. Si el final del día es un tiempo inválido debido al horario de verano, el segundo objetivo no hará daño.

Deberíamos usar este algoritmo para todos los endOf , tal vez incluso startOf , pero eso es más difícil de razonar con la puesta a cero que hacemos actualmente.

Hola chicos, también me afecta este problema en la versión actual de moment (2.14.1).

He enviado el número 3716 para solucionar este problema, pero actualmente tengo problemas con Travis CI por motivos de transpilación. Lo estaré investigando más pronto.

Este también está relacionado (configuración regional brasileña predeterminada).

Resultados de la operación en la misma fecha:

momento ("2017-10-16T00: 59: 59.999"). restar (1, 'día'). endOf ('día')
=> "2017-10-16T00: 59: 59.999"

Oye, acabo de enviar el número 4164, que corrige esto tanto para startOf como para endOf. Me encantaría recibir comentarios allí, así que, con suerte, finalmente podemos avanzar.

@ mj1856 , cerré mi PR porque el problema con endOf en el borde DST parece estar solucionado. ¿Esto también se podría arreglar?

He probado el # 4164 y parece que se ha solucionado. Esperando fusionarse.

¿Fue útil esta página
0 / 5 - 0 calificaciones

Temas relacionados

vbullinger picture vbullinger  ·  3Comentarios

dogukankotan picture dogukankotan  ·  3Comentarios

Shoroh picture Shoroh  ·  3Comentarios

ninigix picture ninigix  ·  3Comentarios

RobinvanderVliet picture RobinvanderVliet  ·  3Comentarios