Memformat tanggal dalam zona waktu tertentu

177

Saya menggunakan Moment.js untuk mem-parsing dan memformat tanggal di aplikasi web saya. Sebagai bagian dari objek JSON, server backend saya mengirimkan tanggal sebagai beberapa milidetik dari zaman UTC (Unix offset).

Mem-parsing tanggal dalam zona waktu tertentu itu mudah - cukup tambahkan pengidentifikasi zona waktu RFC 822 ke akhir string sebelum menguraikan:

// response varies according to your timezone
const m1 = moment('3/11/2012 13:00').utc().format("MM/DD HH:mm")

// problem solved, always "03/11 17:00"
const m2 = moment('3/11/2012 13:00 -0400').utc().format("MM/DD HH:mm")

console.log({ m1, m2 })
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>

Tetapi bagaimana cara memformat tanggal dalam zona waktu tertentu ?

Saya ingin hasil yang konsisten terlepas dari waktu browser saat ini, tetapi saya tidak ingin menampilkan tanggal dalam UTC.

tenang
sumber
2
Moment belum mendukung ini, tetapi mereka sedang mengusahakannya. github.com/timrwood/moment/pull/671
Ben
5
Ini seharusnya bekerja. Jika Anda melewatkan string waktu yang termasuk offset yang diinginkan, maka itu harus mempertahankan offset itu dan menampilkan waktu lokal seperti yang diberikan, daripada secara otomatis menyesuaikan ke waktu browser-lokal. Jika saya ingin menyesuaikannya dengan waktu browser-lokal, maka saya akan memberikan waktu UTC alih-alih secara eksplisit memberikannya offset untuk digunakan. Maksud saya ... saya memberikan offset eksplisit, mengapa pada dasarnya memakannya dan melakukan konversi sendiri ke offset browser. Desain yang mengerikan.
Triynko
Offset @Triynko dikenakan penghematan siang hari jadi, itu tidak selalu bekerja seperti yang diharapkan.
pinkpanther
1
Sesuatu yang berkaitan dengan ini, saya ingin mencetak waktu dalam format tertentu, misalnya 15 Maret 2018 tetapi tidak dapat menemukan string format untuk melakukan ini. Obat generik DD MMM, YYYYtidak berfungsi, ketika saya menggunakannya suka moment.tz("2018-02-15T14:20:00.000+0530", "Asia/Bangkok").format("DD MMM, YYYY"). Dapatkah seseorang menunjukkan saya pada dokumentasi di mana saya dapat menemukan semua kunci untuk memformat waktu ketika menggunakan api ini.
pRmdk
@Ramodumumar Ada apa? Itu memberi "15 Feb, 2018". Apakah Anda bermaksud menggunakan string format DD MMMM, YYYYuntuk mendapatkan "15 February, 2018"?
quietmint

Jawaban:

248

Seperti yang ditunjukkan dalam jawaban Manto , .utcOffset()adalah metode yang disukai pada Momen 2.9.0. Fungsi ini menggunakan offset nyata dari UTC, bukan offset terbalik (mis., -240 untuk New York selama DST). String offset seperti "+0400" bekerja sama seperti sebelumnya:

// always "2013-05-23 00:55"
moment(1369266934311).utcOffset(60).format('YYYY-MM-DD HH:mm')
moment(1369266934311).utcOffset('+0100').format('YYYY-MM-DD HH:mm')

Yang lebih tua .zone()sebagai setter sudah tidak digunakan lagi di Moment.js 2.9.0. Ia menerima string yang berisi pengidentifikasi zona waktu (misalnya, "-0400" atau "-04: 00" selama -4 jam) atau angka yang mewakili menit di belakang UTC (misalnya, 240 untuk New York selama DST).

// always "2013-05-23 00:55"
moment(1369266934311).zone(-60).format('YYYY-MM-DD HH:mm')
moment(1369266934311).zone('+0100').format('YYYY-MM-DD HH:mm')

Untuk bekerja dengan zona waktu bernama bukannya offset numerik, sertakan Moment Timezone dan gunakan .tz()sebagai gantinya:

// determines the correct offset for America/Phoenix at the given moment
// always "2013-05-22 16:55"
moment(1369266934311).tz('America/Phoenix').format('YYYY-MM-DD HH:mm')
tenang
sumber
Saya mengalami masalah dengan ini melalui kesalahan "TypeError: Object 240 tidak memiliki metode 'format'". Saya menyadari bahwa zona hanya tersedia sebagai setter pada versi 2.1.0 dan lebih tinggi dari Moment.js (dan saya menggunakan versi yang lebih lama). Terima kasih!
Melinda Weathers
5
@ebi Ini sudah menggunakan zona waktu browser secara default. Untuk mengakses offset zona waktu browser, gunakan .zone()sebagai pengambil, yang mengembalikan menit dari UTC (mis. Mengembalikan 300 untuk New York selama waktu standar).
quietmint
1
@EricCope Tidak, tidak cukup. Anda dapat menggunakan .tz("America/Phoenix")jika Anda memasukkan momentjs.com/timezone juga. Saya telah memperbarui jawabannya dengan sebuah contoh.
quietmint
1
Perhatikan bahwa menggunakan offset tidak akan berfungsi seperti yang diharapkan jika zona waktu memiliki offset yang berbeda karena penghematan siang hari.
pinkpanther
1
Apakah .utcOffset () secara otomatis mengelola waktu musim panas? seperti ketika saya mengatur UTC +1 CET di Musim Dingin akankah ia bertaruh UTC +2 CEST selama waktu musim panas? Karena ini membuatnya dapat digunakan atau tidak!
haemse
61

Gunakan zona waktu-saat

moment(date).tz('Europe/Berlin').format(format)

Sebelum dapat mengakses zona waktu tertentu, Anda harus memuatnya seperti itu (atau menggunakan metode alternatif yang dijelaskan di sini )

moment.tz.add('Europe/Berlin|CET CEST CEMT|-10 -20 -30')
Philip Nuzhnyy
sumber
Saya tidak berpikir saat ini tersedia ketika pertanyaan diajukan, tetapi saya pikir ini mungkin cara untuk pergi. Saat ini saya sedang mengerjakan masalah serupa dengan semua cap waktu disimpan sebagai UTC di MySQL, tetapi untuk dilihat di zona tertentu tergantung pada konfigurasi pengguna dan bukan zona waktu klien.
nickdnk
47

Beberapa jawaban sudah menyebutkan bahwa moment-timezone adalah cara untuk menggunakan timezone bernama. Saya hanya ingin menjelaskan sesuatu tentang perpustakaan ini yang cukup membingungkan bagi saya. Ada perbedaan antara dua pernyataan ini:

moment.tz(date, format, timezone)

moment(date, format).tz(timezone)

Dengan asumsi bahwa zona waktu tidak ditentukan dalam tanggal yang dilewati:

Kode pertama mengambil tanggal dan mengasumsikan zona waktu adalah yang dilewati. Kode kedua akan mengambil tanggal, menganggap zona waktu dari browser dan kemudian mengubah waktu dan zona waktu sesuai dengan zona waktu yang dilewati.

Contoh:

moment.tz('2018-07-17 19:00:00', 'YYYY-MM-DD HH:mm:ss', 'UTC').format() // "2018-07-17T19:00:00Z"

moment('2018-07-17 19:00:00', 'YYYY-MM-DD HH:mm:ss').tz('UTC').format() // "2018-07-18T00:00:00Z"

Zona waktu saya adalah +5 dari utc. Jadi dalam kasus pertama tidak berubah dan menetapkan tanggal dan waktu untuk memiliki zona waktu utc.

Dalam kasus kedua, diasumsikan tanggal yang dilewati berada di -5, lalu mengubahnya menjadi UTC, dan itulah sebabnya ia mengeluarkan tanggal "2018-07-18T00: 00: 00Z"

CATATAN: Parameter format sangat penting. Jika momen yang dihilangkan dapat kembali ke kelas Tanggal yang dapat perilaku yang tidak dapat diprediksi


Dengan asumsi zona waktu ditentukan pada tanggal yang dilewati:

Dalam hal ini mereka berdua berperilaku sama


Meskipun sekarang saya mengerti mengapa itu bekerja seperti itu, saya pikir ini adalah fitur yang cukup membingungkan dan layak untuk dijelaskan.

Nicola Pedretti
sumber
1
moment (...). tz bukan fungsi
K - Toksisitas dalam SO bertambah.
5
Apakah Anda menginstal zona waktu?
Nicola Pedretti
apakah ada cara untuk mengembalikan momen yang diuraikan dan dikonversi tanpa memformat? Misalnya, jika saya ingin memformat berbagai cara tanpa harus mengulang semuanya.
jEremyB
Terima kasih telah mengklarifikasi ini - Saya mengalami masalah saat menetapkan zona waktu yang berbeda dari zona waktu browser pengguna, dan ini adalah masalah yang sebenarnya.
Robin Schaaf
20

.zone () telah usang, dan Anda harus menggunakan utcOffset sebagai gantinya:

// for a timezone that is +7 UTC hours
moment(1369266934311).utcOffset(420).format('YYYY-MM-DD HH:mm')
Manto
sumber
8

Saya mengalami masalah yang sama dengan Moment.js. Saya telah menginstal zona waktu, tetapi masalahnya tidak teratasi. Lalu, saya melakukan apa yang ada di sini, mengatur zona waktu dan berfungsi seperti pesona:

moment(new Date({your_date})).zone("+08:00")

Terima kasih banyak!

facundofaria
sumber
16
Anda seharusnya tidak menggunakan new Date()konstruktor. Momen menyediakan semua yang Anda butuhkan untuk menguraikan tanggal. Lihat Memilah dokumen.
quietmint
Ya, tetapi jika saya tidak melakukan itu, saya menerima peringatan dari Moment, bahwa itu sudah usang seperti itu
facundofarias
7
Peringatan itu berarti Moment secara internal kembali ke apa yang Anda lakukan (menggunakan new Date()internal), tetapi ini tidak konsisten di seluruh browser . Sebagai gantinya, Anda harus menggunakan menyediakan format yang diharapkan sebagai argumen kedua. Contoh: moment("12-25-1995", "MM-DD-YYYY").
quietmint
4

Baru saja datang acreoss ini, dan karena saya memiliki masalah yang sama, saya hanya memposting hasil yang saya dapatkan

saat parsing, Anda dapat memperbarui offset (yaitu saya mengurai data (1.1.2014) dan saya hanya menginginkan tanggal, 1 Januari 2014. Pada GMT + 1, saya mendapatkan 31.12.2013. Jadi, saya mengimbangi nilainya terlebih dahulu.

moment(moment.utc('1.1.2014').format());

Ya, berguna bagi saya untuk mendukung lintas zona waktu

B

Bard Rotzer
sumber
-7

Anda bisa Coba ini,

Di sini Anda bisa mendapatkan tanggal berdasarkan Zona Waktu Klien (Browser).

moment(new Date().getTime()).zone(new Date().toString().match(/([-\+][0-9]+)\s/)[1]).format('YYYY-MM-DD HH:mm:ss')

Regex pada dasarnya memberi Anda nilai offset.

Bersulang!!

K.Karthik
sumber
Biasanya, momen memberi Anda semua yang Anda butuhkan. Anda tidak perlu mencocokkan kebiasaan apa pun.
Mahesh Samudra