Moment: endOf('day') gagal pada hari-hari yang tidak dimulai pada tengah malam

Dibuat pada 20 Apr 2016  ·  15Komentar  ·  Sumber: moment/moment

Mempertimbangkan:

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

Di sebagian besar zona waktu, ini akan mengembalikan "2016-10-16 23:59:59" . Namun, di Brasil, ini akan mengembalikan "2016-10-17 00:59:59" . Ini tidak benar, karena hanya jam 00:00-00:59 pada 2016-10-16 yang hilang. Akhir 2016-10-16 masih 23:59:59 di tanggal yang sama.

Ini juga dapat direproduksi dengan zona waktu-saat:

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

Masalahnya ada di metode endOf . Untuk menghitung akhir hari, kita ambil _mulai_ hari, tambahkan satu hari, lalu kurangi satu milidetik. Logika itu cacat ketika hari tidak dimulai pada tengah malam. Alih-alih menambahkan satu hari, kita perlu menambahkan durasi yang tepat dari hari tertentu.

Bug DST

Semua 15 komentar

Ini awalnya dilaporkan sebagai momen/momen-zona waktu#327.

2749 terkait, tetapi sedikit berbeda.

Berbeda dengan menghitung lama waktu yang tepat dalam sehari, tidak bisakah Anda melakukan:

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

Bekerja dengan baik pada tanggal 15 ketika didorong ke tanggal 16 juga:

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

Apakah ada kasus tepi yang tidak saya pikirkan?

Saya kira mungkin ada manfaat kinerja untuk melakukannya secara berbeda, tetapi sial, Anda dapat membacanya!

Hmmm, ada hal lain yang aneh di sini:

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"

Apakah kita hanya berurusan dengan seluruh perilaku browser yang ambigu di sini? Atau ada yang lebih dari itu?

Di chrome dengan zona waktu windows 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"

Di chrome dengan zona waktu saya menggunakan Zona Waktu Momen:

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"

KEREN!

Ada yang salah dengan zona waktu momen? Saya tidak begitu tahu kode itu jadi sulit untuk mengatakannya. Sepertinya bukan browser jika yang pertama berfungsi.

Saya pikir ini adalah hasil dari fakta bahwa zona waktu momen akan selalu mendorong kembali tanggal yang tidak valid, jika telah 'ditambahkan' ke tanggal tersebut. Entah karena desain atau kebetulan, saya tidak yakin.

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

Saya pikir ini ada hubungannya dengan mencoba menggunakan pengaturan keepTime ketika Anda tidak dapat mengatur waktu. Saya tidak tahu kode ini dengan cukup baik untuk memberi tahu Anda mengapa kodenya seperti itu, tetapi saya tahu pasti bahwa jika panggilan keepTime dalam kode ini adalah 0 bukannya 1, semuanya akan berjalan seperti yang diharapkan. Itu karena menjaga waktu pada itu didorong kembali. Dan waktu tetap harus menyala, hanya saja funky dengan kasing tepi ini.

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

Saya tidak cukup tahu tentang zona waktu-saat untuk membantu di sini, tetapi mungkin tiket tentang mengapa keepTime digunakan akan membantu siapa pun yang menyelidiki: https://github.com/moment/moment-timezone/ masalah/28

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

Ini adalah perubahan besar terakhir dalam menangani zona saat ini. Tidak yakin apakah ini terkait dengan masalah ini, tetapi itu akan membantu.

@maggiepint dapatkah Anda menjelaskan sedikit?

akan selalu mendorong tanggal yang tidak valid kembali

bagian. Maksud saya -- apakah kita memiliki contoh yang memperlihatkan masalah dengan zona waktu-saat, atau kita hanya memerlukan beberapa kode cerdas pada saat itu untuk mendeteksi DST pada awal/akhir hari dan menanganinya dengan tepat. Yang kedua adalah medium-to-easy. Jika kita harus refactor lagi zona yang lewat antara momen-tz dan momen, maka itu neraka -- Saya lebih suka menunggu 3.0 dan berharap antarmuka baru tidak akan memiliki masalah ini.

@ichernev cara kode berdiri hari ini, kami memiliki dua masalah dalam satu masalah ini. Salah satunya adalah masalah yang awalnya diangkat oleh @mj1856 , yaitu bahwa hari-hari yang tidak dimulai pada tengah malam berakhir dengan nilai akhir hari yang funky. Ini adalah masalah momen.

Yang lainnya adalah zona waktu saat itu, ketika disajikan dengan tanggal yang tidak valid, maju jika tanggal yang tidak valid itu digunakan dalam konstruktor, tetapi mundur jika 'ditambahkan' ke tanggal itu. Ini, sebagaimana adanya, masalah dengan zona waktu momen dan bukan momen. Saya tidak yakin bagaimana antarmuka zona waktu mengubah itu - saya harus memikirkannya sedikit.

@maggiepint terima kasih atas penjelasan yang jelas.

Jadi untuk memperbaiki masalah momen : endOf('day') tidak akurat -- cukup "bidik" untuk akhir hari, pergi ke sana, jika 00:00, selesai, jika tidak bidik lagi, jika bidikan kedua mencapai 00: 00 kita selesai jika tidak gunakan tembakan pertama. Tujuan kedua akan membantu jika kita melompati DST dan "terdistorsi" selama satu jam. Jika akhir hari adalah waktu yang tidak valid karena DST, bidikan kedua tidak ada salahnya.

Kita harus menggunakan algo ini untuk semua endOf , bahkan mungkin startOf , tetapi itu lebih sulit untuk dijelaskan dengan set-to-zero yang saat ini kita lakukan.

Hai teman-teman, saya juga terpengaruh oleh masalah ini pada versi momen saat ini (2.14.1).

Saya telah mengirimkan #3716 untuk memperbaikinya, tetapi saat ini saya melihat masalah dengan Travis CI karena alasan transpile. Akan segera menyelidikinya.

Yang ini juga terkait (lokal Brasil default).

Hasil operasi pada tanggal yang sama:

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

Hai - Saya baru saja mengirimkan #4164 yang memperbaiki ini untuk startOf dan juga endOf. Akan sangat senang mendapatkan umpan balik di sana sehingga kami berharap akhirnya bisa memajukan ini.

@mj1856 , saya menutup PR saya karena masalah dengan endOf di DST edge tampaknya telah diperbaiki. Ini bisa diperbaiki juga?

Saya telah menguji #4164 dan sepertinya ini sudah diperbaiki. Menunggu penggabungan.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat