Objek Date JavaScript tradisional didasarkan pada kalender Gregorian proleptik, sehingga sulit untuk membangun aplikasi bagi pengguna yang mengandalkan sistem kalender lain, seperti kalender Islam (lunar), Ibrani (lunisolar), atau China (lunisolar). Sebelumnya, developer harus mengandalkan library pihak ketiga yang kompleks atau penghitungan manual untuk mendukung sistem ini.
Temporal API memberikan dukungan terbaik untuk beberapa sistem kalender. Dengan mengaitkan ID kalender dengan objek tanggal, Temporal menangani aritmetika dan pemformatan kompleks yang diperlukan untuk berbagai konteks budaya secara native.
Cara Menerapkan
Untuk mendukung sistem kalender global menggunakan Temporal:
- Kaitkan Kalender (Wajib): Saat membuat atau mengonversi objek Temporal (seperti
Temporal.PlainDate), Anda harus menentukan sistem kalender yang diinginkan menggunakanwithCalendar()untuk melakukan operasi yang sensitif terhadap kalender. - Gunakan ID Stabil (Wajib untuk Kalender Lunisolar): Anda harus menggunakan
monthCode, bukan indeksmonthnumerik untuk mengidentifikasi bulan tertentu di berbagai tahun dalam kalender lunisolar. Hanya gunakan ini untuk kalender yang menggunakan bulan kabisat, seperti kalender Ibrani dan China. - Patuhi Invarian Kalender (Wajib): Saat melakukan iterasi melalui bulan atau hari, Anda tidak boleh mengasumsikan nilai tetap (seperti 12 bulan dalam setahun atau 31 hari dalam sebulan). Gunakan properti seperti
monthsInYeardandaysInMonthuntuk memastikan kode Anda berfungsi di semua kalender. - Gunakan Perbandingan yang Memperhitungkan Kalender (Wajib): Saat membandingkan tanggal dalam sistem kalender tertentu, Anda harus menggunakan
Temporal.PlainDate.compare(), bukan membandingkan properti tahun/bulan/hari secara manual. Hal ini menangani urutan kronologis dengan benar dalam aturan kalender.
Contoh Kode: Mengonversi dan Melakukan Iterasi Kalender
// 1. Helper to check calendar support
function isCalendarSupported(calendarId) {
try {
return Intl.supportedValuesOf('calendar').includes(calendarId);
} catch {
// Fallback for environments where supportedValuesOf is not available
return false;
}
}
// 2. Get current date in default ISO 8601 calendar
const isoDate = Temporal.Now.plainDateISO();
// 3. Convert to Hebrew calendar if supported
const calendarId = 'hebrew';
const targetDate = isCalendarSupported(calendarId)
? isoDate.withCalendar(calendarId)
: isoDate; // Fallback to ISO if not supported
if (targetDate.calendar.id !== calendarId) {
console.warn(`Calendar ${calendarId} not supported; falling back to ISO 8601`);
}
// 4. Log properties specific to the calendar
console.log(`Calendar: ${targetDate.calendar.id}`);
console.log(`Year: ${targetDate.year}`);
console.log(`Month Code: ${targetDate.monthCode}`); // Stable across leap years
// 5. Safely iterate through months in the current year
for (let m = 1; m <= targetDate.monthsInYear; m++) {
console.log(`Month ${m} has ${targetDate.with({ month: m }).daysInMonth} days.`);
}
// 6. Compare dates within the same calendar
const today = Temporal.Now.plainDateISO().withCalendar(calendarId);
const comparison = Temporal.PlainDate.compare(targetDate, today);
const relative = comparison < 0 ? 'Past' : comparison > 0 ? 'Future' : 'Today';
console.log(`Timeline: ${relative}`);
// 7. Format for display using toLocaleString (including era for era-based calendars like 'japanese')
const localizedDisplay = targetDate.toLocaleString('en-u-ca-hebrew', {
day: 'numeric',
month: 'long',
year: 'numeric',
era: 'long'
});
Penerapan Strategis & Praktik Terbaik
- LAKUKAN penggunaan
monthsInYearsebagai batas atas saat melakukan loop selama berbulan-bulan, bukan mengasumsikan 12. - LAKUKAN penggunaan
monthCodeuntuk mengidentifikasi bulan tertentu dalam kalender yang menggunakan bulan kabisat (misalnya, Ibrani atau China), terlepas dari tahunnya. - JANGAN berasumsi bahwa
date.month === 12adalah bulan terakhir dalam setahun. Gunakandate.month === date.monthsInYear. - JANGAN berasumsi bahwa
inLeapYear === trueberarti tahun tersebut hanya lebih panjang satu hari. Dalam kalender lunisolar, satu bulan kabisat penuh dapat ditambahkan. - LAKUKAN penggunaan
Temporal.PlainDate.compare()saat membandingkan dua tanggal dalam sistem kalender tertentu, bukan membandingkan properti Tahun/Bulan/Hari secara manual. - LAKUKAN penggunaan
toLocaleString()untuk memformat tanggal bagi pengguna, bukan penyambungan string manual. - LAKUKAN verifikasi bahwa sistem kalender target didukung oleh lingkungan menggunakan
Intl.supportedValuesOf('calendar')sebelum membuat objek Temporal khusus kalender. - LAKUKAN: Ketahuilah bahwa beberapa kalender (seperti varian kalender Islam) mungkin mengandalkan pengamatan visual, bukan penghitungan tetap.
TemporalAPI mengikuti implementasiIntllingkungan, yang biasanya menggunakan perkiraan yang dihitung. Untuk penghitungan tanggal budaya atau agama yang penting, verifikasi dengan pakar domain atau gunakan library khusus. - LAKUKAN penghitungan nama era saat menggunakan kalender yang menggunakan era (misalnya, Jepang, Buddha), menggunakan
toLocaleString().
Strategi Penggantian
Penggantian & dukungan browser untuk Temporal
Untuk browser yang belum mendukung Temporal API native, gunakan deteksi fitur dan muat temporal-polyfill secara dinamis (~15 KB min+gz).
Perhatikan bahwa mengimpor temporal-polyfill tidak otomatis menetapkan objek Temporal ke cakupan global. Tetapkan secara eksplisit jika kode Anda mengandalkan globalThis.Temporal.
// Check if Temporal is supported natively
(async () => {
if (typeof Temporal === 'undefined') {
// Load the polyfill conditionally
const module = await import('https://esm.sh/temporal-polyfill');
globalThis.Temporal = module.Temporal;
// Extend Date.prototype if needed
Date.prototype.toTemporalInstant = module.toTemporalInstant;
}
initializeApp();
})();