Menggunakan New Date Di Javascript - CRUDPRO

Menggunakan New Date Di Javascript

Menggunakan New Date Di Javascript

Pernahkah Anda merasa bahwa Javascript tanggal 0.1.2023, mewakili Tahun Baru, tidak masuk akal? Jika demikian, mari kita lihat bagaimana Javascript di masa mendatang akan memperbaikinya ditambah beberapa masalah DateJS lainnya.

Tapi hal pertama yang pertama: mengapa Januari sama dengan nol? Jawabannya terletak pada masa lalu yang jauh. Penulis Javascript, Brendan Eich, tidak memiliki waktu untuk menciptakan format Tanggal Javascript sendiri. Jadi dia menyalin Tanggal Java, yang bulannya dimulai dengan nol. Jadi mengapa Java mewakili Januari sebagai bulan nol? Karena perilaku yang sama ada dalam bahasa bernama POSIX C. Mengapa POSIX C memiliki perilaku ini? Mari kita berhenti di sini — melanjutkan hanya akan turun ke lubang kelinci.

Sayangnya, penomoran unik sebulan hanyalah puncak gunung es. Masalah dengan JS Date sangat banyak. Untuk menyebutkan beberapa:

  • Anda tidak dapat bekerja dengan kencan tanpa paruh waktu
  • JS Date hanya mendukung zona waktu pengguna dan UTC
  • Konstruktor Tanggal JS tidak memeriksa batas
new Date(2021,1,31).toDateString() equals Wed Mar 03 2021

Ditambah, mutabilitas JS Date adalah masalah besar lainnya. Lihatlah kode berikut dan perhatikan bahwa besok sama dengan hari ini:

const today = new Date()
const tomorrow = today.setDate(today.getDate() + 1)
tomorrow.valueOf() === today.valueOf() // => true

Ini jelas bukan perilaku yang ramah programmer.

Bekerja dengan tanggal dan waktu itu sulit

Selain semua masalah Tanggal JS yang disebutkan di atas (alias kompleksitas yang tidak disengaja), mengukur waktu dan tanggal saja mengandung kompleksitas intrinsik yang sangat besar.

Saya selalu bertanya-tanya mengapa bekerja dengan tanggal terasa lebih menantang daripada bekerja dengan string, angka, atau boolean. Dalam banyak bahasa, tipe tanggal hanyalah tipe primitif, seperti tipe string atau angka. Namun, tidak seperti angka, saya selalu mengalami kesulitan (permainan kata-kata) dengan aritmatika tanggal dan waktu, tidak peduli bahasa apa yang saya gunakan.

Kecurigaan saya bahwa ada sesuatu yang salah dengan tanggal telah dikonfirmasi oleh video Computerphile yang terkenal tentang zona waktu. Jadi, jika ada yang percaya bahwa kencan adalah topik yang lebih sederhana, harap perhatikan penjelasannya. Anda akan melihat apa yang saya bicarakan.

MomentJS, Luxon, tanggal-fns

Untuk mengurangi masalah yang disebutkan di atas, komunitas JS telah mulai membuat perpustakaan baru. Mungkin yang paling dikenal adalah MomentJS, alat praktis yang menangani banyak gangguan dalam tipe Tanggal JS. Pustaka lain, Luxon, yang menggantikan MomentJS, menawarkan kekekalan dan operator asli. Kekekalan Luxon sangat berguna seperti yang Anda lihat dalam contoh berikut:

// MomentJS
var m1 = moment()
var m2 = m1.add(1, 'minutes')
m1.valueOf() === m2.valueOf() // ==> true

// Luxon
var now = DateTime.now()
var yesterday = now.plus({ days: -1 })
now === yesterday // ==> false

Pustaka populer lainnya, Date-fns, menyediakan serangkaian fungsi utilitas yang mencoba memperbaiki titik nyeri utama dari objek JS Date standar. Namun, Anda masih bekerja dengan JS Dates yang berarti bahwa bahkan contoh resmi memiliki getaran aneh JS Date yang sama:

import {  format } from 'date-fns'
format(new Date(2014, 1, 11), 'yyyy-MM-dd') //=> '2014-02-11'

Akankah Temporal menjadi penyelamat baru kita?

MomentJs, Luxon, dan date-fns memang bagus, tetapi bukankah kita pantas mendapatkan sesuatu yang lebih asli? Ya, kami pasti melakukannya, dan dengan demikian API Temporal lahir.

Temporal JS bertujuan untuk menggantikan objek JS Date lama dengan menghadirkan fungsionalitas tanggal dan waktu modern. Ini sudah dalam tahap 3 yang berarti cukup stabil dan pada akhirnya akan mendarat di browser kami.

Saya melihat API Temporal sebagai peningkatan besar, membawa banyak fungsi. Namun demikian, saya tidak ingin menyebutkan apa yang dapat Anda baca dalam dokumentasinya. Alih-alih itu, mari kita fokus pada beberapa poin penting.

Satu jenis untuk setiap masalah

Peningkatan utama tampaknya adalah bahwa Temporal merangkul konsep satu tipe khusus untuk satu kasus penggunaan. Untuk lebih memahami nilainya, kita harus melihat bagaimana kita bekerja dengan waktu dalam kehidupan kita sehari-hari.

Orang menggunakan representasi waktu yang berbeda untuk berbagai kesempatan.

Anda tidak mengatakan: Saya berulang tahun pada 5.5.2023 dan kemudian 5.5.2024 dan kemudian 5.5.2025. Sebagai gantinya, Anda mengatakan: Saya akan mengadakan pesta pada hari Jumat 5.5, bawa kue Anda sendiri.

Sejalan dengan itu, sangat jarang Anda menyatakan: Saya akan berada di sana pada 10:30 hari ini waktu UTC ditambah 5 jam. Anda bilang: beri saya satu jam untuk sampai ke sana.

API Temporal menghormati skenario kehidupan nyata ini dan menawarkan serangkaian jenis untuk berbagai situasi model. Sedangkan kelas JS Date menawarkan satu objek tunggal untuk setiap situasi, Temporal memiliki beberapa tipe konkret untuk kasus penggunaan kami. Berikut ini adalah yang paling berguna:

PlainDateTime mewakili tanggal dan waktu jam dinding tanpa informasi zona waktu. Jika Anda tidak ingin berurusan dengan zona waktu, PlainDateTime adalah cara yang tepat.

ZonedDateTime mewakili tanggal dan waktu yang tepat dengan informasi zona waktu. Ini adalah pengganti langsung untuk objek JS Date yang lama.

PlainDate mewakili tanggal kalender tanpa zona waktu atau waktu.

PlainTime hanya mewakili waktu. Independen dari setiap zona waktu atau tanggal.

Instan mewakili titik waktu dengan presisi dalam nanodetik — tanpa zona waktu atau kalender. Ini mewakili hitungan nanodetik bilangan bulat sejak zaman Unix.

Durasi menyatakan lamanya waktu. Anda akan menggunakannya untuk aritmatika tanggal dan waktu.

Saya belum menyertakan jenis Temporal yang kurang penting, jadi jika Anda ingin mempelajari lebih lanjut, silakan lihat ringkasan API yang luar biasa ini.

Kegamblangan

Poin berikut berkaitan dengan poin sebelumnya di mana kami mengetahui bahwa Temporal menawarkan Anda lebih dari satu jenis. Ini berarti Anda harus tepat (alias eksplisit) dengan memilih jenis yang tepat untuk kasus penggunaan Anda. Jadi ketika Anda perlu bekerja dengan waktu, Anda harus menggunakan PlainTime. Sedangkan, ketika kasus penggunaan Anda memerlukan zona waktu, gunakan kelas ZonedDateTime.

Selain itu, penulis Temporal membuat beberapa keputusan cerdas untuk lebih meregangkan keeksplisitannya. Misalnya, ketik Instan (yang mewakili waktu saat ini) tidak memiliki properti hari, bulan, atau tahun. Pada pandangan pertama, itu tidak masuk akal. Seperti yang mungkin Anda ketahui, Anda dapat menulis kode berikut dengan Tanggal JS lama:

const month = new Date().getMonth()

Di sisi lain, saat menggunakan Temporal.Instant Anda harus terlebih dahulu memberikan zona waktu untuk mendapatkan tanggal ini:

const instant = Temporal.Instant.from('2022-01-01T00:00+00:00')
console.log(instant.hour) // returns undefined!

const zdtTokyo = instant.toZonedDateTimeISO('Asia/Tokyo')
console.log(zdtTokyo.hour) //returns 9

const zdtPrague = instant.toZonedDateTimeISO('Europe/Prague')
console.log(zdtPrague.hour) //returns 1

const zdtNewYork = instant.toZonedDateTimeISO('America/New_York')
console.log(zdtNewYork.hour) //returns 19

Setelah sedikit berpikir, Anda akan menyadari bahwa pendekatan ini masuk akal. Meskipun Anda dapat memiliki titik waktu yang tepat, Anda tidak dapat mengetahui jam atau hari apa tanpa zona waktu tertentu. Jenis ketegasan itu berarti tidak ada kejutan seperti zona waktu tersembunyi dalam serialisasi JSON:

//equals `2023-01-31T23:00:00.000Z` in my time zone
new Date(2021,1,1).toISOString()

Kekekalan secara default

Kekekalan membuktikan nilainya bertahun-tahun yang lalu dan Temporal menganut konsep seperti yang Anda lihat di sini:

const today = Temporal.Now.plainDateISO()
const tomorrow = today.add({ days: 4, months: 2 }).toString()
//The value of today remains today.

Temporal menawarkan metode dengan, yang merupakan cara yang berguna untuk mengubah instans Temporal:

const date = Temporal.PlainDate.from('2023-05-10')
const newDate1 = date.with({ day: 9 })
console.log(newDate1.toString()) // => 2023-05-09

const dateTime = Temporal.PlainDateTime.from('2023-05-10T11:58:32')
const newDateTime = dateTime.with({ year: 2024, minute: 10, hour: 5 })
console.log(newDateTime.toString()) // => 2024-05-10T05:10:32

Tanggal variabel tidak berubah dan newDate memiliki properti yang sama dengan tanggal kecuali hari. Ini mengingatkan pada bahasa F#, yang memiliki fungsi yang sama. Namun, fungsi ini bekerja dengan semua instance, tidak hanya instance DateTime.

Serangkaian fungsi yang besar

Temporal mendukung seluruh rentang fungsi untuk bekerja dengan tanggal dan waktu. Misalnya, metode sejak, hingga, dan sama dengan menutupi perbandingan sederhana, dan mengurangi dan menambahkan manipulasi sampul dengan tanggal. Selain itu, API Temporal juga mendukung transformasi PlainDate ke ZonedDateTime dan sebaliknya. Terakhir, konversi antara tipe Temporal dan tanggal JS lawas juga didukung.

const legacyDate = new Date('1970-01-01T00:00:01Z')
const instant = legacyDate.toTemporalInstant()
const zoned= legacyDate.toZonedDateTime({timeZone, calendar})
const zonedISO = legacyDate.toZonedDateTimeISO()
// and more ...

Untuk mendapatkan ikhtisar fungsi Temporal, lihat Buku Masak TC39 untuk mempelajari lebih banyak contoh kanonik.

Perbandingan

Saya agak kecewa dengan operator perbandingan yang hilang untuk Temporals. Akibatnya, Anda tidak dapat membandingkan instans Temporal semudah mungkin dengan Tanggal JS lama. Anda perlu menggunakan metode statis untuk membandingkan. Namun, ada tangkapan! Sangat mudah untuk membuat kesalahan dengan menggunakan jenis yang berbeda untuk perbandingan. Dalam contoh berikut saya melakukan perbandingan dengan menggunakan dua jenis: PlainDate dan PlainDateTime. Menggunakan jenis yang berbeda memberi Anda hasil yang berbeda:

const dt1 = Temporal.PlainDateTime.from({
    year: 2022,
    month: 12,
    day: 7,
    hour: 15
});

const dt2 = dt1.with({
    hour: 16
})

Temporal.PlainDate.compare(dt1, dt2) == 0 // => true
Temporal.PlainDateTime.compare(dt1, dt2) == 0 // => false

Metode sayangnya kurang eksplisit. Anda dapat membandingkan PlainDateTime dengan PlainDate tanpa kesalahan, yang dapat menyebabkan bug. Operator <, > akan memecahkan masalah ini.

Dukungan untuk aritmatika zona waktu

Pernahkah Anda melihat video tentang zona waktu di atas? Kemudian Anda melihat mengapa aritmatika zona adalah topik yang kompleks. API Temporal menyediakan solusi yang cukup kuat untuk menangani semua keanehan, seperti waktu musim panas, zona waktu ganjil, dan ambiguitas waktu. Dengan ambiguitas waktu, maksud saya perbedaan antara Waktu Jam dan Waktu Tepat. Sebagai contoh, di Amerika Serikat pukul 01:30 pada 13 Maret 2022 terjadi dua kali karena waktu musim panas. Itu mungkin baik untuk orang tetapi buruk bagi pengembang perangkat lunak. Anda dapat membaca lebih lanjut di buku masak Temporal.

Memformat

Di sini saya punya kabar buruk untuk Anda: pemformatan tampaknya masih terbatas. Ada sedikit diskusi panas tentang itu, namun API Temporal hanya mendukung Intl.DateTimeFormat sejauh ini. Lihat contoh berikut:

// Old way
format(Date.now(), 'yyyy-MM-dd HH:mm:ss')
// returns 2022-10-25 07:43:16

// New way
Temporal.Now.zonedDateTimeISO()
    .toPlainDate()
    .toLocaleString('en-US', { year: '2-digit', month: 'long', day: 'numeric' })
// returns October 22, 25

Tampaknya bahasa pemformatan mini yang potensial seperti yyyy-MM-dd HH:mm:ss harus disediakan oleh perpustakaan pihak 3D di masa mendatang.

Dukungan kalender

API Temporal mendukung kalender selain hanya ISO. Ini mungkin tampak sedikit tidak perlu dari perspektif dunia Barat kita. Namun, di zaman pasar berkembang seperti Cina dan India ini, ini menjadi fitur penting dari setiap perpustakaan dewasa. Untuk informasi lebih lanjut, baca artikel tentang penulisan kode lintas kalender.

Menyeimbangkan

Sekarang mari kita bicara tentang durasi waktu. Seperti yang mungkin dapat Anda bayangkan, kita dapat merepresentasikan durasi waktu dalam berbagai bentuk. Misalnya, dua jam sama dengan 180 menit atau 7 200 detik — dalam berbagai kasus penggunaan, Anda memerlukan berbagai format. Kabar baiknya adalah bahwa API Temporal mendukung konversi ke format yang berbeda melalui penyeimbangan:

duration = Temporal.Duration.from({ minutes: 80, seconds: 90 }) 
// => 80 minutes, 90 seconds

duration.round({ largestUnit: 'hour' }) 
// => 1 hour, 21 minutes, 30 seconds 

duration.round({ largestUnit: 'minute' })
// => 81 minutes, 30 seconds 

duration.round({ largestUnit: 'second' })
// => 4890 seconds

Anda dapat menggunakan putaran metode praktis untuk mengubah durasi menjadi representasi yang berbeda. Lihatlah dokumentasi resmi untuk mempelajari lebih lanjut.

Pendukung

Sekarang tiba bagian paling menyedihkan dari teks saya. Dukungan API Temporal masih buruk. Belum ada browser yang menerapkannya dan bahkan tidak ada browser yang memberi isyarat bahwa akan ada tonggak sejarah segera.

Menggunakan New Date Di Javascript

Namun, sisi baiknya, ada polyfill, yang mendapatkan daya tarik, seperti yang ditunjukkan grafik unduhan:

Menggunakan New Date Di Javascript

Jadi, saya merasa Anda bisa mulai berpikir untuk mengadopsi Temporal. Saya telah menguji polyfill dan kualitasnya terlihat bagus. Meskipun demikian, beberapa optimasi masih perlu dilakukan menurut penulis.

Kesimpulan

Meskipun saya dapat membayangkan beberapa peningkatan, seperti menggunakan operator tipe Luxon (< > ==), saya berharap dapat melihat API Temporal dimasukkan ke dalam browser kami. Ini adalah API yang lebih baik daripada Tanggal JS di banyak tingkatan. Selain itu, dokumentasinya ditulis dengan baik, dengan materi pendukung seperti buku masak praktis atau referensi cepat.

Untuk saat ini, saya sarankan mencoba polyfill di bagian tidak penting dari aplikasi Anda dan menunggu implementasi asli.