IlmHamroh
JavaScript Full-stack/12-qism. JavaScript: ilg'or mavzular va kod sifati15/44-dars20 daqiqa
Mundarija (33)

JavaScript Intl.RelativeTimeFormat: "3 kun oldin" va "ertaga" ni har tilda chiqarish

Qisqacha: Intl.RelativeTimeFormat sonni va vaqt birligini nisbiy vaqt matniga aylantiradi: new Intl.RelativeTimeFormat("uz").format(-3, "day") → "3 kun oldin". Manfiy son — o'tgan vaqt, musbat — kelajak. numeric: "auto" bilan -1 kun "kecha", 1 kun "ertaga" bo'ladi. Qaysi birlikni tanlash (daqiqa, soat yoki kun) — sizning ishingiz: ikki sana farqidan birlikni o'zingiz hisoblaysiz.

Bu darsda

  • format(son, birlik) bilan o'zbek, rus va ingliz tilida nisbiy vaqt yozasiz.
  • numeric: "auto" va style sozlamalari nimani o'zgartirishini bilasiz.
  • formatToParts bilan natijaning bo'laklarini alohida olasiz.
  • Ikki sana farqidan to'g'ri birlikni tanlaydigan nisbiyVaqt funksiyasini yozasiz.
  • Node 24 va Chrome 154 da natija nega farq qilishini va brauzerda bunga qanday tayyorlanishni tushuntira olasiz.

Oldin bilishingiz kerak: Intl.DateTimeFormat, Date va vaqt zonalari, Parametrda destructuring va options obyekti.

1. Nega bu kerak?

O'tgan darsda sanani 5-oktabr, 2026 kabi chiroyli ko'rsatishni o'rgandik. Lekin ko'p joyda odamga aniq sana emas, qancha vaqt o'tgani qiziq. Telegram'da "5 daqiqa oldin onlayn edi" deb yozadi. «Bahor» saytida esa sharh ostida "2 kun oldin", buyurtma holatida "12 daqiqa oldin qabul qilindi" turishi kerak.

Sardor buni bir qatorda yozib qo'ydi:

js
function oldin(kun) {
  return `${kun} kun oldin`;
}

console.log(oldin(3)); // 3 kun oldin
console.log(oldin(1)); // 1 kun oldin

O'zbekcha ishlayapti. Lekin 1 kun oldin g'alati — odam "kecha" deydi. Keyin Jasur aka saytning ruscha versiyasini so'radi. Rus tilida son o'zgarganda so'z ham o'zgaradi: 1 день назад, 2 дня назад, 5 дней назад, 21 день назад. Ingliz tilida 1 day ago, lekin 3 days ago, kelajak uchun esa so'z tartibi boshqa: in 3 days.

Har tilning qoidalarini qo'lda yozish — o'nlab if. Bu qoidalar esa allaqachon yozilgan va brauzer hamda Node ichida turibdi. Ularga eshik — Intl.RelativeTimeFormat.

2. Birinchi formatlovchi

2.1 format(son, birlik)

Intl.DateTimeFormat darsidagi tartib bu yerda ham: avval tilni berib formatlovchi yasaymiz, keyin uni ishlatamiz.

js
const rtf = new Intl.RelativeTimeFormat("uz");

console.log(rtf.format(-3, "day")); // 3 kun oldin
console.log(rtf.format(3, "day")); // 3 kundan keyin
console.log(rtf.format(-5, "minute")); // 5 daqiqa oldin
console.log(rtf.format(2, "hour")); // 2 soatdan keyin

rtf — "relative time format" (nisbiy vaqt formati) so'zlarining bosh harflari, dasturchilar shunday atashadi. format ikki narsa oladi:

  • son — necha birlik. Manfiy bo'lsa — o'tgan vaqt ("oldin"), musbat bo'lsa — kelajak ("keyin").
  • birlik — inglizcha nomi: "second", "minute", "hour", "day", "week", "month", "quarter" (chorak), "year".

Birlik ko'plikda ham qabul qilinadi: "days" ham "day" bilan bir xil ishlaydi. Natija — satr, xuddi DateTimeFormat dagidek.

Diqqat: Bu darsdagi "Konsolda" natijalari Node 24 da olingan. Sahifadagi «Ishga tushir» tugmasi esa kodni brauzeringizda bajaradi. Chrome'da o'zbekcha natijalar boshqacha chiqadi — buni ataylab qoldirdik, farqni o'zingiz ko'rasiz. Sababini «Node va Chrome: bir kod, ikki natija» bo'limida ochamiz.

2.2 Uch tilda

Endi «Nega bu kerak?» bo'limidagi rus va ingliz muammosi:

js
const uz = new Intl.RelativeTimeFormat("uz");
const ru = new Intl.RelativeTimeFormat("ru");
const en = new Intl.RelativeTimeFormat("en");

for (const kun of [-1, -2, -5, -21]) {
  console.log(uz.format(kun, "day"), "|", ru.format(kun, "day"));
}
console.log(en.format(-1, "day"), "|", en.format(3, "day"));

Konsolda:

text
1 kun oldin | 1 день назад
2 kun oldin | 2 дня назад
5 kun oldin | 5 дней назад
21 kun oldin | 21 день назад
1 day ago | in 3 days

Ruscha день, дня, дней — uch shakl, va 21 yana день bilan. Inglizchada in 3 days — so'z sondan oldin. Biz bitta qator ham if yozmadik. Bu qoidalar qayerdan kelishini Intl.PluralRules darsida ochamiz.

O'zbekchada esa son bilan so'z o'zgarmaydi: 1 kun, 5 kun. Lekin qo'shimcha o'zgaradi: kun oldin, lekin kundan keyin. Buni ham formatlovchi o'zi biladi.

Tekshirib ko'ring: new Intl.RelativeTimeFormat("uz").format(-90, "minute") nima qaytaradi? "1,5 soat oldin"mi?

Javob

"90 daqiqa oldin". Formatlovchi birlikni o'zgartirmaydi — qaysi birlikni bersangiz, shuni yozadi. 90 daqiqani soatga aylantirish — sizning ishingiz. Buni «Birlikni tanlash» bo'limida qilamiz.

3. numeric: "auto" — "kecha" va "ertaga"

3.1 So'z bilan aytiladigan qiymatlar

Formatlovchiga ikkinchi argument — sozlamalar obyektini berish mumkin. Eng foydalisi — numeric:

js
const rtf = new Intl.RelativeTimeFormat("uz", { numeric: "auto" });

console.log(rtf.format(-1, "day")); // kecha
console.log(rtf.format(0, "day")); // bugun
console.log(rtf.format(1, "day")); // ertaga
console.log(rtf.format(-2, "day")); // 2 kun oldin
console.log(rtf.format(-1, "week")); // o‘tgan hafta
console.log(rtf.format(1, "month")); // keyingi oy
console.log(rtf.format(0, "second")); // hozir

numeric ning ikki qiymati bor:

Qiymat Ma'nosi format(-1, "day")
"always" (standart) doim son bilan 1 kun oldin
"auto" so'z bo'lsa — so'z bilan kecha

"auto" "so'z bor bo'lsa ishlat" degani. O'zbek tilida kun uchun faqat uchta so'z bor: kecha, bugun, ertaga. Shuning uchun -2 kun baribir 2 kun oldin. Rus tilida esa ko'proq:

js
const ru = new Intl.RelativeTimeFormat("ru", { numeric: "auto" });
const en = new Intl.RelativeTimeFormat("en", { numeric: "auto" });

console.log(ru.format(-2, "day"), "|", en.format(-2, "day"));
console.log(ru.format(2, "day"), "|", en.format(2, "day"));

Konsolda:

text
позавчера | 2 days ago
послезавтра | in 2 days

Rus tilida "o'tgan kuni" (позавчера) va "indinga" (послезавтра) uchun alohida so'z bor, ingliz tilida yo'q. Biz kodni o'zgartirmadik — farq tilning o'zidan.

3.2 Nol qiymat

numeric siz nol g'alati chiqadi:

js
const odatiy = new Intl.RelativeTimeFormat("uz");
const avto = new Intl.RelativeTimeFormat("uz", { numeric: "auto" });

console.log(odatiy.format(0, "day")); // 0 kundan keyin
console.log(avto.format(0, "day")); // bugun
console.log(avto.format(0, "minute")); // shu daqiqada

"0 kundan keyin" — hech kim shunday gapirmaydi. Shuning uchun foydalanuvchiga ko'rinadigan matnda deyarli doim numeric: "auto" ishlatiladi.

Maslahat: numeric: "auto" dagi so'zlarga e'tibor bering: o‘tgan hafta dagi ‘ — oddiy apostrof emas, boshqa belgi. Til ma'lumotlari bazasi o'zbek harflarini shunday yozadi. Bu tuzoqni «Ko'p uchraydigan xatolar» bo'limida ko'ramiz.

Tekshirib ko'ring: Rus tilida numeric: "auto" bilan format(-3, "day") nima beradi?

Javob

"3 дня назад". Rus tilida "3 kun oldin" uchun alohida so'z yo'q — faqat позавчера (−2), вчера (−1), сегодня, завтра, послезавтра (+2). So'z bo'lmasa, "auto" ham son bilan yozadi.

4. style — uzun, qisqa, tor

Ikkinchi sozlama — style. U matn qanchalik qisqa bo'lishini belgilaydi: "long" (standart), "short", "narrow".

js
for (const style of ["long", "short", "narrow"]) {
  const en = new Intl.RelativeTimeFormat("en", { style });
  const ru = new Intl.RelativeTimeFormat("ru", { style });
  console.log(en.format(-5, "minute"), "|", ru.format(3, "month"));
}

Konsolda:

text
5 minutes ago | через 3 месяца
5 min. ago | через 3 мес.
5m ago | +3 мес.

{ style } — bu { style: style } ning qisqa yozuvi, Shorthand, computed kalitlar va metodlar darsidan eslaysiz. Telefondagi tor ro'yxatda "short" yoki "narrow" joy tejaydi.

O'zbek tili uchun esa uchala uslub bir xil chiqadi: 5 daqiqa oldin. Til ma'lumotlarida o'zbekcha qisqa shakllar alohida yozilmagan. Shuning uchun o'zbekcha interfeysda style ni o'zgartirishdan foyda yo'q — qisqa joy kerak bo'lsa, matnni o'zingiz qisqartirasiz.

5. formatToParts — bo'laklarga bo'lish

Dizayner so'radi: "Sharh ostida sonni qalin qilib ko'rsating: 3 kun oldin". Tayyor satrdan sonni qirqib olish xavfli: 1 250 kun oldin da son ichida bo'sh joy bor. Buning uchun formatToParts bor:

js
const rtf = new Intl.RelativeTimeFormat("uz");

console.log(rtf.formatToParts(-3, "day"));

Konsolda:

text
[
  { type: 'integer', value: '3', unit: 'day' },
  { type: 'literal', value: ' kun oldin' }
]

Natija — obyektlar massivi. Har bo'lakning type i bor: "integer" — sonning butun qismi, "literal" — qolgan matn. Son bo'laklarida unit ham bor — qaysi birlik. Katta sonda son bir necha bo'lakka bo'linadi: "group" — minglarni ajratuvchi bo'sh joy. Bu bo'laklar keyingi darsdagi Intl.NumberFormat bilan bir xil.

Endi qalin son yasash oson — map bilan har bo'lakni o'raymiz:

js
const rtf = new Intl.RelativeTimeFormat("uz");

function qalinSon(son, birlik) {
  return rtf
    .formatToParts(son, birlik)
    .map((b) =>
      b.type === "literal" ? b.value : `<b>${b.value}</b>`,
    )
    .join("");
}

console.log(qalinSon(-3, "day")); // <b>3</b> kun oldin

Brauzerda bunday satrni innerHTML ga berishdan oldin o'ylang: ichida foydalanuvchi matni bo'lsa, XSS xavfi bor (Kontentni o'zgartirish va XSS xavfi). Bu yerda bo'laklar faqat formatlovchidan keladi, shuning uchun xavf yo'q.

O'zingiz to'ldiring: formatToParts natijasida sonning butun qismi type qiymati bo'lgan bo'lakda turadi.

6. Birlikni tanlash

6.1 Muammo

Real ilovada sizda format(-3, "day") emas, ikki sana bor: sharh yozilgan vaqt va hozir. Ularning farqi — millisekund. Qaysi birlikda ko'rsatish kerak?

  • 40 soniya farq → "40 soniya oldin";
  • 12 daqiqa → "12 daqiqa oldin", "720 soniya oldin" emas;
  • 3 soat → "3 soat oldin";
  • 2 hafta → "2 hafta oldin", "14 kun oldin" emas.

Intl.RelativeTimeFormat bu tanlovni qilmaydi. Algoritm sodda: birliklarni kattasidan kichigiga tekshiramiz. Farq shu birlikdan katta yoki teng bo'lsa — shu birlikni olamiz.

6.2 Qadamma-qadam

Avval qisqa variantni ko'ramiz: uchta birlik va bitta farq. 720 soniya — 12 daqiqa oldin:

Asosiy g'oya: Math.abs — farqning ishorasiz qiymati, chunki o'tgan va kelajak uchun qoida bir xil. Ishorani esa format ga o'zi uzatamiz — "oldin" yoki "keyin" ni u tanlaydi.

6.3 To'liq funksiya

Endi barcha birliklar bilan. Oy — 30 kun, yil — 365 kun deb olamiz. Bu taxminiy, lekin "3 oy oldin" uchun yetarli:

js
const BIRLIKLAR = [
  ["year", 365 * 24 * 60 * 60],
  ["month", 30 * 24 * 60 * 60],
  ["week", 7 * 24 * 60 * 60],
  ["day", 24 * 60 * 60],
  ["hour", 60 * 60],
  ["minute", 60],
  ["second", 1],
];
const rtf = new Intl.RelativeTimeFormat("uz", { numeric: "auto" });

function nisbiyVaqt(sana, hozir = new Date()) {
  const soniya = (sana - hozir) / 1000;
  for (const [birlik, hajm] of BIRLIKLAR) {
    if (Math.abs(soniya) >= hajm || birlik === "second") {
      return rtf.format(Math.round(soniya / hajm), birlik);
    }
  }
}

const hozir = new Date("2026-10-05T12:00:00Z");
const sanalar = [
  "2026-10-05T11:59:30Z",
  "2026-10-05T11:48:00Z",
  "2026-10-04T12:00:00Z",
  "2026-10-08T12:00:00Z",
  "2026-09-20T12:00:00Z",
  "2026-07-01T12:00:00Z",
];
for (const s of sanalar) {
  console.log(nisbiyVaqt(new Date(s), hozir));
}

Konsolda:

text
30 soniya oldin
12 daqiqa oldin
kecha
3 kundan keyin
2 hafta oldin
3 oy oldin

Kod qatorlarini ko'rib chiqamiz:

  • sana - hozir — ikki Date ni ayirsak, millisekunddagi farq chiqadi (Date asoslari). / 1000 — soniyaga.
  • hozir = new Date() — standart qiymatli parametr. Odatda "hozir" — haqiqiy hozirgi vaqt. Sinovda esa aniq sana beramiz, aks holda natija har kuni o'zgaradi.
  • birlik === "second" — oxirgi birlik shartsiz olinadi. Aks holda 0.3 soniya farqda funksiya undefined qaytarardi.
  • Math.round — yaxlitlash: 89 daqiqa 1 soat, 1,8 kun 2 kun bo'ladi.

Formatlovchi funksiyadan tashqarida bir marta yaratildi. Uni har chaqiruvda qayta yaratish sekin — Intl.DateTimeFormat darsida o'lchagan edik, Intl.NumberFormat darsida sonlar uchun ham o'lchaymiz.

Tekshirib ko'ring: nisbiyVaqt ga 10 kun oldingi sanani bersak, nima chiqadi?

Javob

"o‘tgan hafta". 10 kun ≥ 7 kun, shuning uchun week tanlanadi. 10 / 7 ≈ 1,43, Math.round uni 1 qiladi va format(-1, "week") chaqiriladi. Formatlovchi numeric: "auto" bilan yaratilgan, shuning uchun son o'rniga so'z chiqadi. numeric siz bo'lsa — "1 hafta oldin".

6.4 Kalendar kuni va soat farqi

Bir nozik joy bor. Sharh kecha soat 20:00 da yozilgan, hozir bugun 09:00. Farq — 13 soat. Funksiyamiz 13 soat oldin deydi. Odam esa "kecha" deb o'ylaydi.

Ikkalasi ham to'g'ri — savol boshqacha. "Qancha vaqt o'tdi?" — 13 soat. "Qaysi kunda?" — kecha. Telegram ikkinchisini tanlaydi: bir kundan uzoq bo'lsa, "kecha 20:00" deb yozadi. Bunday holatda kunlar farqini soatdan emas, kalendar sanasidan hisoblash kerak. Buni Temporal bilan qilish ancha oson: PlainDate larning until metodi aniq kunlar farqini beradi. Kalendar kuni esa vaqt zonasiga bog'liq — Toshkentda hali "bugun", Londonda esa allaqachon boshqa kun bo'lishi mumkin.

7. Node va Chrome: bir kod, ikki natija

7.1 Farq

Yuqoridagi kodlarni Chrome 154 da (masalan sahifadagi «Ishga tushir» bilan) bajarsangiz, mana nima chiqadi:

Kod Node 24 Chrome 154
format(-3, "day") 3 kun oldin -3 d
format(2, "hour") 2 soatdan keyin +2 h
auto: format(-1, "day") kecha yesterday
auto: format(0, "second") hozir now

Chrome'da o'zbekcha nisbiy vaqt matnlari yo'q. U umumiy zaxira shablonga qaytadi: son va birlik belgisi (d — day, h — hour) yoki inglizcha so'z. Rus va ingliz tillarida esa ikkalasi bir xil natija beradi — biz yuqoridagi barcha ru va en misollarini Chrome 154 da ham sinadik.

7.2 Nega?

Tilga oid qoidalar — oylar nomi, "kecha", ruscha uch shakl — JavaScript dvigatelining o'zida emas. Ular ICU (International Components for Unicode — xalqaro dasturlar uchun ochiq kutubxona) ichidagi katta ma'lumotlar bazasidan olinadi. Bu bazani CLDR loyihasi to'ldiradi. Intl.DateTimeFormat darsida bu nomlarni eshitgansiz.

  • Node 24 ICU'ni to'liq ma'lumot bilan olib keladi. Biz sinagan versiya: ICU 78.3, CLDR 48. O'zbek tili qoidalari ham ichida.
  • Chrome esa yuklab olish hajmini kamaytirish uchun ma'lumotlarni qisqartirib olib yuradi. Biz sinagan 154-versiyada (kompyuter) o'zbek lotin (uz) tilining nisbiy vaqt matnlari shu qisqartirishga tushgan — Intl.DateTimeFormat darsidagi oy nomlari kabi.

Eng xavflisi — Chrome buni yashiradi:

js
const rtf = new Intl.RelativeTimeFormat("uz");
console.log(rtf.resolvedOptions().locale);
// Chrome 154: "uz"   Node 24: "uz"

resolvedOptions().locale — formatlovchi aslida qaysi tilni ishlatayotgani. Chrome "uz" deydi, lekin -3 d chiqaradi. Ya'ni "tilni qo'llaysanmi?" deb so'rash yetmaydi — natijani tekshirish kerak.

Firefox va Safari o'z ICU ma'lumotlarini boshqacha tanlaydi — ularda natija boshqa bo'lishi mumkin. Biz ularni sinamadik. Mobil Chrome ham alohida tekshirishni talab qiladi.

7.3 Brauzerda nima qilish kerak

Uch yo'l bor.

1. Matnni serverda yasash. «Bahor» sahifasi serverda (Node'da) tayyorlansa, "3 kun oldin" matni ham o'sha yerda yoziladi. Brauzer tayyor matnni ko'rsatadi, xolos. Server qismini kursda keyinroq quramiz.

2. Natijani tekshirib, zaxiraga o'tish. Brauzer o'zbekchani bilishini bitta sinov bilan aniqlaymiz:

js
const rtf = new Intl.RelativeTimeFormat("uz");
const UZBEKCHA_BOR = rtf.format(-1, "day") === "1 kun oldin";

const NOMLAR = { minute: "daqiqa", hour: "soat", day: "kun" };

function oldinYoz(son, birlik) {
  if (UZBEKCHA_BOR) {
    return rtf.format(-son, birlik);
  }
  return `${son} ${NOMLAR[birlik]} oldin`;
}

console.log(oldinYoz(5, "minute")); // 5 daqiqa oldin

Node'da birinchi yo'l ishlaydi, Chrome'da — ikkinchisi. Ikkalasida ham natija bir xil. Zaxira lug'at kichik bo'lgani bilan o'zbekcha uchun yetarli: o'zbek tilida son bilan so'z shakli o'zgarmaydi.

3. Tayyor kutubxona. date-fns (4-versiya) va Day.js (1-versiya) kabi kutubxonalar o'z tarjimalarini o'zi olib yuradi va o'zbek tilini ham qo'llaydi. Ularni npm orqali qo'shasiz — Temporal API va sana kutubxonalari darsida temporal-polyfill ni shunday o'rnatgan edik.

Tekshirib ko'ring: Nega Chrome'da supportedLocalesOf(["uz"]) yoki resolvedOptions() bilan tekshirish yetarli emas?

Javob

Chrome 154 ikkalasida ham "uz bor" deydi. Lekin o'zbekcha matnlar o'rniga zaxira shablonni (-3 d) ishlatadi. Ishonchli tekshiruv — ma'lum natijani solishtirish: format(-1, "day") === "1 kun oldin".

8. Ko'p uchraydigan xatolar

8.1 Ishorani teskari berish

js
const rtf = new Intl.RelativeTimeFormat("uz");

console.log(rtf.format(3, "day")); // 3 kundan keyin

Sardor "3 kun oldin" kutgan edi. Qoidani eslang: manfiy — o'tgan. Odatda farqni sana - hozir deb hisoblang: sana o'tgan bo'lsa, natija o'z-o'zidan manfiy chiqadi.

8.2 O'zbekcha birlik nomi

js
const rtf = new Intl.RelativeTimeFormat("uz");

console.log(rtf.format(-3, "kun"));
text
RangeError: Invalid unit argument for Intl.RelativeTimeFormat.prototype.format() 'kun'

Tarjimasi: "Diapazon xatosi: format() uchun birlik argumenti noto'g'ri — 'kun'". Til "uz" bo'lsa ham, birlik nomlari doim inglizcha. "millisecond" ham yo'q — eng kichik birlik "second".

8.3 NaN ni formatlash

Sana noto'g'ri bo'lsa (new Date("bugun")), farq NaN chiqadi va format xato tashlaydi:

text
RangeError: Value need to be finite number for Intl.RelativeTimeFormat.prototype.format()

Tarjimasi: "Qiymat chekli son bo'lishi kerak". Inglizcha xabarda grammatik xato bor ("need" o'rniga "needs" bo'lishi kerak edi) — bu V8 dvigatelidagi asl matn, biz uni o'zgartirmadik. Tuzatish: sanani formatlashdan oldin tekshiring — Number.isNaN(sana.getTime()).

8.4 Natijani apostrofli matn bilan solishtirish

js
const rtf = new Intl.RelativeTimeFormat("uz", { numeric: "auto" });
const matn = rtf.format(-1, "week");

console.log(matn); // o‘tgan hafta
console.log(matn.includes("o'tgan")); // false

Ko'zga bir xil, lekin false. Til bazasi o‘ ni oddiy ' bilan emas, ‘ (U+2018) belgisi bilan yozadi. Boshqa joylarda esa ʻ (U+02BB) uchraydi — buni keyingi darsda soʻm da ko'rasiz. Formatlangan matnni faqat ko'rsatish uchun ishlating, unga if yoki testda tayanmang. Bu qoidani Pul va aniq hisob-kitob darsida ham aytgan edik.

8.5 Yaxlitlash "katta" natija beradi

1 yil 9 oy oldingi sanani nisbiyVaqt "2 yil oldin" deb yozadi: 1,76 → Math.round → 2. Ba'zi ilovalar uchun bu xato. "To'liq yillar" kerak bo'lsa, Math.round o'rniga Math.trunc ishlating — u kasr qismini tashlab yuboradi va "1 yil oldin" beradi.

9. Mashqlar

1-mashq (oson): Bron eslatmasi

«Bahor» mehmonga eslatma yuboradi: "Broningiz ertaga", "Broningiz 3 kundan keyin". bronEslatmasi(kunlar) funksiyasini yozing. kunlar — bronga necha kun qolgani (0, 1, 3). Ishora: numeric: "auto" sozlamasi 0 ni "bugun", 1 ni "ertaga" qiladi.

js
console.log(bronEslatmasi(0)); // Broningiz bugun
console.log(bronEslatmasi(1)); // Broningiz ertaga
console.log(bronEslatmasi(3)); // Broningiz 3 kundan keyin
Yechim
js
const rtf = new Intl.RelativeTimeFormat("uz", { numeric: "auto" });

function bronEslatmasi(kunlar) {
  return `Broningiz ${rtf.format(kunlar, "day")}`;
}

console.log(bronEslatmasi(0)); // Broningiz bugun
console.log(bronEslatmasi(1)); // Broningiz ertaga
console.log(bronEslatmasi(3)); // Broningiz 3 kundan keyin

Formatlovchi funksiyadan tashqarida, bir marta yaratildi. Kun soni musbat — bron kelajakda.

2-mashq (o'rta): Uch tilda "oxirgi faollik"

faollikMatni(daqiqa, til) funksiyasi daqiqalar sonini (o'tgan vaqt) berilgan tilda qaytarsin. 60 dan kam bo'lsa — daqiqada, aks holda — soatda (Math.round bilan). Uni uz, ru, en tillari va 5, 150 daqiqa bilan sinang. Ishora: tilni parametrdan oling — new Intl.RelativeTimeFormat(til).

js
console.log(faollikMatni(5, "ru")); // 5 минут назад
console.log(faollikMatni(150, "en")); // 3 hours ago
Yechim
js
function faollikMatni(daqiqa, til) {
  const rtf = new Intl.RelativeTimeFormat(til);
  if (daqiqa < 60) {
    return rtf.format(-daqiqa, "minute");
  }
  return rtf.format(-Math.round(daqiqa / 60), "hour");
}

for (const til of ["uz", "ru", "en"]) {
  console.log(faollikMatni(5, til), "|", faollikMatni(150, til));
}

Konsolda:

text
5 daqiqa oldin | 3 soat oldin
5 минут назад | 3 часа назад
5 minutes ago | 3 hours ago

150 daqiqa — 2,5 soat, Math.round uni 3 ga yaxlitladi. Bu yerda formatlovchi har chaqiruvda yaratilyapti, chunki til har safar boshqa bo'lishi mumkin. Real ilovada har til uchun bittadan yaratib, Map da saqlash mumkin.

3-mashq (qiyin): Sharhlar ro'yxati

Sharhlar massivi bor: { muallif, vaqt }, vaqt — ISO satr. sharhlarniYoz(sharhlar, hozir) har sharh uchun "Dilshod aka — 2 soat oldin" ko'rinishidagi qatorni chiqarsin. Darsdagi nisbiyVaqt funksiyasidan foydalaning va sharhlarni yangisi birinchi bo'ladigan qilib tartiblang. Ishora: tartiblash uchun toSorted va sanalar farqi (Nusxa bilan o'zgartirish).

Yechim
js
const BIRLIKLAR = [
  ["year", 31536000], ["month", 2592000], ["week", 604800],
  ["day", 86400], ["hour", 3600], ["minute", 60], ["second", 1],
];
const rtf = new Intl.RelativeTimeFormat("uz", { numeric: "auto" });

function nisbiyVaqt(sana, hozir = new Date()) {
  const soniya = (sana - hozir) / 1000;
  for (const [birlik, hajm] of BIRLIKLAR) {
    if (Math.abs(soniya) >= hajm || birlik === "second") {
      return rtf.format(Math.round(soniya / hajm), birlik);
    }
  }
}

function sharhlarniYoz(sharhlar, hozir) {
  const tartiblangan = sharhlar.toSorted(
    (a, b) => new Date(b.vaqt) - new Date(a.vaqt),
  );
  for (const { muallif, vaqt } of tartiblangan) {
    console.log(`${muallif} — ${nisbiyVaqt(new Date(vaqt), hozir)}`);
  }
}

sharhlarniYoz(
  [
    { muallif: "Malika", vaqt: "2026-10-02T09:00:00Z" },
    { muallif: "Dilshod aka", vaqt: "2026-10-05T10:00:00Z" },
    { muallif: "Bobur", vaqt: "2026-10-05T11:55:00Z" },
  ],
  new Date("2026-10-05T12:00:00Z"),
);

Konsolda:

text
Bobur — 5 daqiqa oldin
Dilshod aka — 2 soat oldin
Malika — 3 kun oldin

Soniyalar soni bu safar tayyor raqam bilan yozildi (86400 = bir kun) — qator qisqa bo'lsin deb. toSorted asl massivni o'zgartirmaydi. Sanalarni ayirib tartiblash — b - a — yangisini birinchi qo'yadi.

4-mashq: Vazifalar qadami — "qachon qo'shildi"

vazifalar ilovasidagi vazifalarda hozircha yaratilgan vaqt yo'q. Kelajakda qo'shilsa, ro'yxatda "3 kun oldin" ko'rinishi kerak bo'ladi. Shu yordamchini hozirdan kurs/mashqlar/12/15-nisbiy-vaqt/nisbiy-vaqt.mjs da yozing: nisbiyVaqt(sana, hozir) va UZBEKCHA_BOR tekshiruvi. Chrome'da o'zbekcha bo'lmasa, zaxira lug'at second, minute, hour, day birliklarini qamrasin. Node'da UZBEKCHA_BOR qiymatini chiqarib ko'ring.

Yechim
js
const rtf = new Intl.RelativeTimeFormat("uz", { numeric: "auto" });
const UZBEKCHA_BOR = rtf.format(-1, "day") === "kecha";
const NOMLAR = {
  second: "soniya", minute: "daqiqa", hour: "soat", day: "kun",
};
const BIRLIKLAR = [["day", 86400], ["hour", 3600], ["minute", 60]];

function zaxiraYoz(son, birlik) {
  const qism = son < 0 ? " oldin" : "dan keyin";
  return `${Math.abs(son)} ${NOMLAR[birlik]}${qism}`;
}

export function nisbiyVaqt(sana, hozir = new Date()) {
  const soniya = (sana - hozir) / 1000;
  let birlik = "second";
  let son = Math.round(soniya);
  for (const [nom, hajm] of BIRLIKLAR) {
    if (Math.abs(soniya) >= hajm) {
      birlik = nom;
      son = Math.round(soniya / hajm);
      break;
    }
  }
  if (!UZBEKCHA_BOR) {
    return zaxiraYoz(son, birlik);
  }
  return rtf.format(son, birlik);
}

const hozir = new Date("2026-10-05T12:00:00Z");
console.log(UZBEKCHA_BOR); // true
const otgan = new Date("2026-10-02T12:00:00Z");
console.log(nisbiyVaqt(otgan, hozir)); // 3 kun oldin

numeric: "auto" bilan sinov so'zi "kecha" bo'ldi — formatlovchi qanday sozlangan bo'lsa, shu bilan tekshiramiz. export — funksiyani boshqa modulda ishlatish uchun (ES modullar). Zaxirada "keyin" uchun "dan keyin" qo'shimchasini so'zga yopishtirdik: 3 kundan keyin, 5 daqiqadan keyin. Bizning to'rt so'zimiz (soniya, daqiqa, soat, kun) bilan -dan doim to'g'ri tushadi. Zaxirada "kecha"/"ertaga" yo'q — u faqat son bilan yozadi.

bash
git add 12/15-nisbiy-vaqt/nisbiy-vaqt.mjs
git commit -m "12/15: nisbiy vaqt yordamchisi va brauzer zaxirasi"

10. Real ishda

  • Ijtimoiy tarmoq va chat. Telegram'dagi "yaqinda onlayn edi", GitHub'dagi "updated 3 days ago", YouTube'dagi "2 hafta oldin" — hammasi shu g'oya: farqdan birlik, birlikdan matn.
  • Kutubxonalar. date-fns'dagi formatDistance, Day.js'ning relativeTime plagini — ichida xuddi biz yozgan birlik tanlash algoritmi, lekin chegaralari puxtaroq (masalan, 45 daqiqadan keyin "1 soat"). React'da ham shu funksiyalar ishlatiladi — React'ni kursda alohida o'rganamiz.
  • Davomiylik. "1 soat 30 daqiqa" — bu nisbiy vaqt emas, davomiylik. Uning uchun yangi Intl.DurationFormat bor (Baseline 2025-mart): Node 24 da 1 soat 30 daqiqa deb yozadi. Hozircha bilib qo'ying, xolos.
  • Intervyu. "Foydalanuvchiga '5 minutes ago' ni qanday chiqarasiz?" — Intl.RelativeTimeFormat va birlik tanlashni aytsangiz, kutubxonasiz yechimni bilishingizni ko'rsatasiz.

Xulosa

  • new Intl.RelativeTimeFormat(til).format(son, birlik) — nisbiy vaqt matni; manfiy — o'tgan, musbat — kelajak.
  • Birlik nomlari doim inglizcha: second … year; "kun" yoki "millisecond" — RangeError.
  • numeric: "auto" — "kecha", "bugun", "ertaga", o‘tgan hafta; foydalanuvchiga ko'rinadigan matnda deyarli doim shu.
  • formatToParts — natijani integer, group, literal bo'laklariga bo'ladi.
  • Birlikni formatlovchi tanlamaydi: farqni soniyada hisoblab, kattasidan kichigiga tekshirasiz.
  • Chrome 154 da o'zbekcha matnlar yo'q (-3 d), lekin u "uz bor" deydi — natijani solishtirib tekshiring yoki matnni serverda yasang.

Keyingi dars: Intl.NumberFormat — son, so'm, foiz va birliklarni (kg, km) til qoidalari bo'yicha formatlaymiz va formatlovchini nega bir marta yaratish kerakligini o'lchab ko'ramiz.

Manbalar

  • MDN: "Intl.RelativeTimeFormat", "Intl.RelativeTimeFormat.prototype.format", "formatToParts" — developer.mozilla.org
  • ECMA-402 (ECMAScript Internationalization API Specification), "RelativeTimeFormat Objects" — tc39.es/ecma402
  • Unicode CLDR — cldr.unicode.org; ICU — icu.unicode.org
  • web-features 3.40: intl-relative-time-format — Baseline 2020-sentabr
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
JavaScript Intl.RelativeTimeFormat: "3 kun oldin" va "ertaga" ni har tilda chiqarish — IlmHamroh