Jiff, pustaka tanggal dan waktu untuk Rust
(github.com/BurntSushi)- Jiff adalah pustaka tanggal dan waktu untuk Rust yang menargetkan tipe dasar tanggal dan waktu tingkat tinggi yang sulit disalahgunakan serta performa yang masuk akal
- Fitur intinya mencakup integrasi otomatis dengan Time Zone Database, aritmetika dan pembulatan yang sadar DST, pemformatan dan parsing lossless untuk tanggal dan waktu dengan zona waktu, serta dukungan Serde opsional
- Desain API-nya sangat dipengaruhi oleh Temporal, proposal TC39 untuk memperbaiki penanganan tanggal dan waktu di JavaScript
- Jiff 1.0 semula ditargetkan rilis pada musim panas 2025, tetapi per April 2026 jadwalnya mundur, dan saat ini tidak ada linimasa rilis 1.0
- Performa adalah tujuan penting, tetapi keterpahaman API dan akurasi diprioritaskan; di Unix, Jiff mengikuti kebijakan dependensi konservatif yang sengaja mempertahankan 0 dependensi
Model tanggal dan waktu yang disediakan Jiff
- Jiff adalah pustaka untuk menangani tanggal dan waktu di Rust, dengan fokus menyediakan tipe dasar tingkat tinggi yang sulit digunakan secara keliru
- Fitur utama yang didukung
- Integrasi otomatis dan mulus dengan Time Zone Database
- Aritmetika dan pembulatan yang sadar DST
- Pemformatan dan parsing lossless untuk tanggal dan waktu dengan zona waktu
- Dukungan
serdeopsional
- Desain API-nya sangat dipengaruhi oleh Temporal, proposal TC39 untuk memperbaiki penanganan tanggal dan waktu di JavaScript
- Lisensinya adalah lisensi ganda MIT atau UNLICENSE
Dokumentasi dan contoh penggunaan
- Dokumentasi dan materi terkait
- Dokumentasi API di docs.rs
- Dokumen perbandingan dengan
chrono,time,hifitime,icu - Dokumen alasan desain API Jiff
- Dokumen dukungan platform
- Changelog
- Contoh dasar mem-parse string waktu RFC 3339, lalu mengubahnya menjadi tanggal dan waktu dengan zona waktu, menambahkan durasi, kemudian mencetaknya sebagai string lossless
- Mem-parse
"2024-07-11T01:14:00Z"sebagaiTimestamp - Mengonversi ke zona waktu
America/New_York - Menambahkan
1.month().hours(2) - String hasilnya adalah
"2024-08-10T23:14:00-04:00[America/New_York]" - Waktu UTC dalam format RFC 3339 adalah
"2024-08-11T03:14:00Z"
- Mem-parse
Instalasi dan alur eksekusi dasar
- Jiff tersedia di crates.io, dan dapat digunakan dengan menambahkan
jiffke dependensiCargo.tomldi proyek Rust - Perintah sederhana untuk menambahkannya adalah
cargo add jiff - Alur contoh lengkap di README
- Membuat proyek baru dengan
cargo new jiff-example - Menambahkan dependensi dengan
cargo add jiff - Di
src/main.rs, membulatkan waktu saat ini ke satuan detik denganZoned::now().round(Unit::Second)? - Menjalankannya dengan
cargo run
- Membuat proyek baru dengan
- Contoh output menampilkan bentuk yang menyertakan zona waktu, yaitu
2024-07-10T19:54:20-04:00[America/New_York] - Pada eksekusi pertama, output kompilasi akan lebih banyak, tetapi pada eksekusi berikutnya dependensi tidak perlu dikompilasi ulang
Feature flag dan rencana 1.0
- Jiff menyediakan beberapa crate feature untuk mengatur dukungan pustaka standar Rust, dukungan
serde, dan apakah Time Zone Database disematkan ke dalam binary - Daftar lengkap feature flag yang didukung ada di bagian “crate features” dalam dokumentasi
- Rencana rilis awal Jiff 1.0 adalah musim panas 2025, tetapi per April 2026 jadwalnya sudah mundur dan saat ini tidak ada linimasa rilis
- Setelah rilis 1.0, API direncanakan dipertahankan tanpa batas waktu, dengan tujuan agar pengguna dapat memakai Jiff sebagai fondasi stabil untuk API publik
- Setelah Jiff 1.0 dirilis, Jiff 0.2 tetap direncanakan menerima pembaruan perbaikan bug penting selama 1 tahun
- Tidak ada pengembangan fitur aktif
- Karena sudah banyak pengguna yang memakai Jiff 0.2, rencananya adalah menyediakan masa tenggang untuk migrasi
Performa dan jalur pemformatan tingkat lanjut
- Tujuan desain paling penting adalah menjadi pustaka tanggal dan waktu tingkat tinggi yang sulit disalahgunakan
- Performa adalah tujuan kedua; Jiff mengejar performa yang masuk akal, tetapi mungkin masih ada area yang dapat ditingkatkan
- Benchmark berada di direktori
bench - Sebagian area sudah dioptimalkan, tetapi masih banyak area yang belum dioptimalkan
- Peningkatan performa adalah tujuan, tetapi secara umum keterpahaman API dan akurasi diprioritaskan di atas performa
- Submodul Jiff, terutama
jiff::fmt, berfungsi sebagai escape hatch untuk API yang lebih kompleks ketika diperlukan kontrol lebih besar- Implementasi
std::fmt::DisplaypadaZoneddapat menyulitkan penulisan ke buffer yang dapat digunakan ulang jiff::fmt::temporal::DateTimePrinter::print_zonedmemungkinkanZonedditulis keStringatauVec<u8>yang sudah ada
- Implementasi
Penanganan zona waktu per platform
- Masalah dukungan platform pada pustaka tanggal dan waktu terutama berkaitan dengan dukungan zona waktu
- Interaksi platform yang ditangani Jiff
- Cara menemukan data transisi untuk identifier zona waktu IANA seperti
Antarctica/Troll - Cara menemukan zona waktu default sistem saat ini
- Cara menemukan data transisi untuk identifier zona waktu IANA seperti
- Data transisi zona waktu bergantung pada IANA Time Zone Database
- Di Unix, biasanya
/usr/share/zoneinfodigunakan, dan pengaturan variabel lingkunganTZDIRjuga diikuti - Di Windows, salinan Time Zone Database secara otomatis disematkan ke pustaka yang dikompilasi
- Cara deteksi zona waktu sistem
- Di Unix, membaca
/etc/localtime - Di Windows, membaca identifier zona waktu khusus Windows dengan
GetDynamicTimeZoneInformation, lalu memetakannya ke identifier zona waktu IANA melalui CLDR XML data dari Unicode
- Di Unix, membaca
- Dukungan untuk platform lain diperkirakan akan bertambah seiring waktu, tetapi platform langka yang sulit diuji kemungkinan besar akan bergantung pada pull request dari kontributor
Kebijakan dependensi dan MSRV
- Jiff yang memiliki 0 dependensi di Unix adalah desain yang disengaja
- Kriteria untuk menambahkan dependensi baru ke Jiff sebagai crate ekosistem bersifat konservatif
- Jika benar-benar diperlukan untuk berinteraksi dengan platform
- Jika diperlukan untuk interoperabilitas, misalnya
serde
- Dependensi untuk tujuan interoperabilitas juga diperlakukan secara konservatif; umumnya Jiff berusaha hanya bergantung pada proyek yang memiliki lebih sedikit rilis breaking change dibanding Jiff
- Memecah Jiff menjadi beberapa crate dapat menimbulkan dependensi baru, tetapi saat ini tidak ada rencana untuk itu
- Arahnya adalah menjaga jumlah crate tetap kecil, dengan pengalaman bahwa mengelola banyak batas API semver menimbulkan overhead pemeliharaan yang besar
- Versi minimum Rust compiler yang didukung Jiff adalah MSRV 1.70.0
- Jiff sendiri dan dependensi Jiff di dalam repositori tidak menggunakan versi Rust yang menuntut compiler Rust yang dirilis dalam 1 tahun terakhir
- Crate di dalam repositori yang bergantung pada Jiff, seperti
jiff-icu, dapat menggunakan MSRV yang lebih baru, tetapi tidak akan menuntut MSRV yang lebih baru daripada crate target integrasinya - MSRV dependensi eksternal seperti
windows-sysdanportable-atomictidak dapat dikendalikan oleh Jiff - Sesuai konvensi ekosistem Rust, Jiff tidak menganggap kenaikan MSRV sebagai perubahan yang tidak kompatibel secara semver, tetapi kenaikan MSRV dibatasi pada pembaruan minor version
1 komentar
Opini Hacker News
Secara keseluruhan terlihat bagus, tetapi saya agak tersandung pada sintaks ToSpan
let span = 5.days().hours(8).minutes(1);Rasanya agak canggung karena hanya angka pertama yang muncul di depan, sementara sisanya masuk sebagai argumen fungsi
Kalau tidak suka, bisa menulisnya seperti
let span = Span::new().days(5).hours(8).minutes(1);, dan karena hanya menambah beberapa karakter, tidak terlalu burukuse jiff::{Timestamp, ToSpan};, saya tersandung pada bagian ketika"2024-07-11T01:14:00Z".parse()?di-parse menjadi TimestampSeingat saya Rust memakai sesuatu seperti interface alih-alih class, jadi saya penasaran mengapa ketika library diimpor, string tiba-tiba mendapat method
parse(), dan mengapa method bernama umum itu membuat objekTimestampSaya juga penasaran apakah tipe di sisi kiri yang menentukan makna
str.parse(), dan apa yang terjadi jika library tanggal dan library ekspresi Lisp sama-sama menambahkanparse()ke stringPertanyaannya jadi makin banyak, termasuk mengapa tidak memakai sintaks seperti
Timestamp.parse(str)let span = 5.days() + 8.hours() + 1.minutes();Sintaks aslinya terlihat seperti bentuk yang mungkin dipakai Ruby
Saat membaca kode, akan lebih baik jika terlebih dahulu terlihat bahwa kita sedang menangani span
let span = Span::days(5).hours(8).minutes(1);terlihat lebih baikSaya sering melihat orang meremehkan kompleksitas library tanggal/waktu
Pernyataan seperti “representasi internal cukup UTC/Unix time”, “durasi cukup direpresentasikan dalam nanodetik”, “pakai offset saja alih-alih zona waktu” terus berulang
Kalau Anda berpikir begitu, sebaiknya baca dokumen desain Jiff: https://github.com/BurntSushi/jiff/blob/master/DESIGN.md
Seperti karya BurntSushi lainnya, dokumen itu luar biasa dan terperinci
Perbandingannya dengan chrono, library tanggal/waktu de facto standar di Rust, juga layak dibaca: https://docs.rs/jiff/latest/jiff/_documentation/comparison/i...
Hal-hal seperti aritmetika DST yang tetap benar setelah serialisasi/deserialisasi, durasi yang bisa dibulatkan, aritmetika kalender yang sadar zona waktu, dan deteksi konflik zona waktu historis membuat library ini akurat, berguna, dan nyaman dipakai
chrono adalah library yang komprehensif dan “akurat”, tetapi kaku dan tidak terlalu mudah digunakan
Saya sudah memakai ripgrep bahkan sebelum Debian menyediakan
rgsecara default, dan juga pernah memakai JodaTime pada masa ketika masih ada orang yang berpikir Eclipse lebih baik daripada IntelliJ IDEANamun di dokumen itu tidak ada bagian yang membantah “durasi cukup direpresentasikan dalam nanodetik”
Pengguna memang perlu melihat waktu yang benar sesuai zona waktu dan DST, tetapi program biasanya tidak
Jika pekerjaan Anda bukan menangani banyak zona waktu secara langsung, merepresentasikan durasi dalam milidetik/nanodetik umumnya sangat aman
Fakta bahwa manusia menciptakan zona waktu dan DST tidak mengubah fenomena fisik bahwa jam internal CPU berdetak miliaran kali per detik
Lihat saja kernel sistem operasi yang beberapa hari lalu tidak meledak di separuh bumi; banyak bagian timeout dalam kode diekspresikan dalam milidetik
Orang bisa salah paham seolah-olah untuk mengimplementasikan “cooldown 30 detik” kita harus menambahkan 30 detik ke zona waktu saat ini, menyimpannya sebagai string yang mencakup zona waktu, DST, format 12/24 jam, lalu memeriksa sampai ke leap second
Cukup gunakan timeout/cooldown 30 detik yang direpresentasikan dalam milidetik, dan meskipun dari sudut pandang pengguna terjadi setelah 29 detik, kita tidak perlu peduli soal leap second
Terlihat seperti library yang keren
Saya penasaran kenapa BurntSushi membuat library baru
Saya belum banyak menangani waktu di Rust, jadi ingin tahu apakah library yang ada punya masalah performa, API yang ada tidak nyaman dipakai, atau hanya dibuat untuk bersenang-senang, atau ada alasan lain
Implementasi standard library Java kurang bagus, lalu JodaTime muncul untuk mengatasi masalah itu
Kemudian di Java 8 masuk DateTime API baru yang sangat dipengaruhi JodaTime, dan karena ada di standard library, para pembuat library bisa mengadopsinya lebih luas
https://www.joda.org/joda-time/
https://www.baeldung.com/java-8-date-time-intro
https://github.com/BurntSushi/jiff/blob/master/DESIGN.md
https://github.com/BurntSushi/jiff/blob/master/COMPARE.md
Ringkasnya, terutama karena API dan dukungan zona waktu IANA
Kondisi library kalender di Rust tidak terlalu ideal
Di Pandas ada
.tz_convert()dan.tz_localize(), dan konversi zona waktu praktis selesai dengan ituOperasi yang saya jadikan patokan adalah “mendapatkan jam pertama dari satu hari CET/CEST untuk tanggal tertentu dalam UTC”, dan di Pandas itu sangat sederhana
Di Chrono, harus membuat
NaiveDate, mengubahnya menjadiDateTime, lalu mengubahnya lagi menjadiDateTime, dan saya tidak menemukan pola yang konsisten untuk konversi seperti iniKadang berupa member function, kadang static method dari objek zona waktu
Saya berharap suatu hari ada yang membenahinya. Jiff terlihat seperti satu langkah ke arah yang benar, tetapi sintaksnya kadang terasa aneh, jadi saya menginginkan bentuk yang lebih dapat diprediksi
date(y, m, d).intz("Europe/Rome")?Jika ingin mendapatkan UTC dari situ, tinggal tambahkan
with_time_zone(TimeZone::UTC)Akan menarik kalau bisa dijelaskan lebih lanjut bagaimana Jiff bisa dibuat lebih baik, dan bagian mana dari sintaksnya yang terasa aneh
“Sayang, bangun, BurntSushi baru sudah keluar”[0]
Lebih seriusnya, saya penasaran apakah ada pengguna Rust di sini yang tahu kenapa crate ini tidak memakai sesuatu seperti
tracingMungkin karena terlalu berat. Dari sisi crate, ukurannya hampir setengahnya
logtentu saja oke, dan saya juga tidak tahu apakah melacak sampai pemanggilan operasi zona waktu adalah use case umum, tetapi saya penasaran apakah ada alasan khusus[0] https://knowyourmeme.com/memes/wake-up-babe
logkurang lebih sebagai penyebut umum terkecilIa juga terintegrasi baik dengan
tracing, jadi mungkin itulah alasan Jiff memakainyaItu juga sesuatu yang sudah terus dipakai sejak masa-masa awal crates.io
Jiff tidak punya kebutuhan selain mengeluarkan pesan pada level log tertentu
Tentu saja, menurut saya
tracingjuga pasti akan bekerja dengan baikBurntSushi juga orang yang membuat seluruh ekosistem regex Rust
Hal yang paling saya sayangkan dari library waktu yang ada, baik di Rust maupun ekosistem lain, adalah kurangnya dukungan leap second
Biasanya karena secara internal mereka memakai timestamp UNIX, bukan TAI, dan sayangnya library ini juga tidak berbeda
Sepertinya ada cara untuk mendukungnya sampai tingkat tertentu dengan file tzif, tetapi bukan dukungan kelas satu
Ada detailnya di issue Jiff terkait: https://github.com/BurntSushi/jiff/issues/7
Karena timestamp UNIX tidak memakai definisi detik SI, melainkan 1/86000 dari hari saat ini, panjang semua detik UNIX tidak sama sehingga perhitungan durasi yang benar menjadi rusak
Saya paham ini adalah kompromi untuk mewarisi kompatibilitas dengan cara lama melacak waktu dan membuat pemformatan kalender cepat, tetapi saya tidak menganggapnya kompromi yang tepat
Timestamp UNIX mencampurkan urusan representasi dengan data
Menurut saya leap second harus diperlakukan persis seperti 29 Februari atau zona waktu
hifitimetidak cocokSetiap kali pembahasan leap second muncul, biasanya terasa mengarah ke hal yang abstrak
Sangat jarang terhubung dengan use case dunia nyata
Saya memahami use case ilmiah, dan menurut saya kebutuhan seperti itu ditangani dengan baik oleh library khusus
Di luar itu, saya tidak terlalu yakin apakah masih ada kebutuhan lain
Jiffdilafalkan dengan G keras, jadi “Giff”go, atau G seperti digin?“Jiff dilafalkan sebagai
gifdengan g lembut seperti padagem.”Sama sekali tidak boleh!
Saya akan tetap memakai chrono †
† Tentu saja dilafalkan “trono”, seperti
chpadachaseJadi, ini diucapkan jiff, atau gif?
“Jiff diucapkan
gifdengan g lembut seperti padagem.”Ah, paham ini leluconnya apa…
GIF menurut pembuatnya selalu diucapkan “jif”, jadi agar tidak membingungkan, semoga pembuat alat baru ini mengucapkan Jiff sebagai “gif”