IlmHamroh
Python kursi/Standart kutubxona5/16-dars24 daqiqa
Mundarija (21)

15.5-dars: Vaqt mintaqalari va zoneinfo

15-QISM — STANDART KUTUBXONA · 5-dars


1. Kirish va motivatsiya

15.4-darsda sanalar bilan ishlashni o'rgandik, lekin bitta savolni chetga surdik: "14:00" — qaysi joydagi 14:00?

Toshkentdagi 14:00, Berlindagi 14:00 va Nyu-Yorkdagi 14:00 — uchta turli vaqt nuqtasi. Bundan tashqari, ko'p mamlakatlarda yiliga ikki marta soatlar suriladi (yozgi vaqt, DST): bahorda bir soat yo'qoladi, kuzda bir soat ikki marta takrorlanadi.

Real vaziyat. O'zbekistondagi kompaniya Germaniyadagi hamkorlar bilan har kuni 09:00 (Berlin vaqti) da uchrashuv o'tkazadi. Taqvim tizimi uchrashuvni bir marta yaratib, keyingi kunlarni + timedelta(hours=24) bilan hisoblardi — UTC da. 29-martdan keyin Berlinda soatlar oldinga surildi va uchrashuv nemis hamkorlar uchun 10:00 ga ko'chdi. Toshkent tomonda esa hech kim buni sezmadi: O'zbekistonda 1992-yildan beri yozgi vaqt yo'q.

Boshqa jamoa foydalanuvchi vaqtini "2026-03-01T09:00+01:00" shaklida saqlagan. Olti oydan keyingi eslatma ham +01:00 bilan hisoblandi — lekin sentabrda Berlin +02:00 da. Eslatma bir soat kechikdi: +01:00 — bu mintaqa emas, faqat o'sha lahzadagi siljish.

Bu darsda zoneinfo bilan to'g'ri ishlashni, yozgi vaqt tuzoqlarini va "UTC da saqlash, mahalliy vaqtda ko'rsatish" qoidasini amalda o'rganamiz.

Bu darsda:

  • Mintaqa (Asia/Tashkent) va siljish (+05:00) — farqi
  • zoneinfo.ZoneInfo va Windows'da tzdata
  • UTC da saqlash, astimezone bilan ko'rsatish
  • Mavjud bo'lmagan va ikki marta takrorlanadigan vaqtlar, fold
  • Bir mintaqa ichidagi arifmetika — devor soati bo'yicha
  • Tarixiy o'zgarishlar: Toshkent siljishlari
  • Amaliy: turli mamlakatlar uchun kundalik eslatmalar jadvali

2. Nazariya — chuqur tushuntirish

2.1. Siljish va mintaqa

Tushuncha Misol Nimani biladi
UTC UTC Hamma narsaning asosi, yozgi vaqt yo'q
Siljish (offset) +05:00, timezone(timedelta(hours=5)) Faqat bitta raqam
Mintaqa (IANA) Asia/Tashkent, Europe/Berlin Siljish qoidalari tarixi: yozgi vaqt, qonun o'zgarishlari

+01:00 dan mintaqani tiklab bo'lmaydi: Berlin, Parij, Lagos — hammasi qishda +01:00, lekin yozda Berlin va Parij +02:00, Lagos esa +01:00 da qoladi.

Tur Qachon
datetime.UTC / timezone.utc Saqlash va hisoblash
timezone(timedelta(...)) Qat'iy siljish — ISO satrdan o'qilganda shunday bo'ladi
ZoneInfo("Europe/Berlin") Foydalanuvchiga ko'rsatish, kalendar voqealari

2.2. zoneinfo va tzdata

python
from zoneinfo import ZoneInfo, available_timezones

TOSHKENT = ZoneInfo("Asia/Tashkent")
datetime(2026, 9, 17, 14, 0, tzinfo=TOSHKENT)     # 2026-09-17 14:00:00+05:00
Platforma IANA ma'lumotlar bazasi
Linux, macOS Tizimda bor (/usr/share/zoneinfo)
Windows Yo'q — pip install tzdata
Docker slim obrazlar Ko'pincha yo'q — tzdata paketi

tzdata siz: ZoneInfoNotFoundError: 'No time zone found with key Asia/Tashkent'. Ilovangiz bog'liqliklariga tzdata ni qo'shing — shunda hamma platformada bir xil ishlaydi.

ZoneInfo obyektlari keshlanadi: ZoneInfo("Asia/Tashkent") is ZoneInfo("Asia/Tashkent") → True.

2.3. astimezone va replace(tzinfo=...)

Metod Nima qiladi Vaqt nuqtasi
aware.astimezone(zona) Boshqa mintaqaga o'giradi O'zgarmaydi
naive.replace(tzinfo=zona) Mintaqani yopishtiradi "Bu devor soati shu zonada"
aware.replace(tzinfo=boshqa) Yopishtiradi Boshqa nuqtaga aylanadi
naive.astimezone(zona) Naive ni server mahalliy vaqti deb oladi Serverga bog'liq
python
utc_vaqt = datetime(2026, 9, 17, 9, 0, tzinfo=UTC)
utc_vaqt.astimezone(ZoneInfo("Asia/Tashkent"))       # 14:00+05:00 — o'sha lahza
utc_vaqt.astimezone(ZoneInfo("America/New_York"))    # 05:00-04:00 — o'sha lahza

Solishtirish:

Holat Qanday solishtiriladi
Aware, turli tzinfo UTC ga o'girib — to'g'ri
Aware, bir xil tzinfo Devor soati bo'yicha — fold e'tiborsiz
Naive va aware == → False, < → TypeError

2.4. Yozgi vaqt: bo'shliq va takror

Bahor — bo'shliq (gap). Berlin, 2026-yil 29-mart: 02:00 dan to'g'ridan-to'g'ri 03:00 ga. 02:30 mavjud emas.

Kuz — takror (fold). 25-oktabr: 03:00 dan yana 02:00 ga. 02:30 ikki marta bo'ladi.

datetime bu holatlarni fold atributi (0 yoki 1) bilan ifodalaydi (PEP 495):

Holat fold=0 fold=1
Takror (kuz) Birinchi 02:30 (+02:00) Ikkinchi 02:30 (+01:00)
Bo'shliq (bahor) Siljish o'tishdan oldingi O'tishdan keyingi

Mavjud bo'lmagan vaqt xato bermaydi — u yaratiladi, UTC ga o'girib qaytarilganda esa boshqa devor soatiga aylanadi (02:30 → 03:30).

Aniqlash usuli — UTC orqali aylanib kelish:

python
def mavjudmi(d: datetime) -> bool:
    qaytgan = d.astimezone(UTC).astimezone(d.tzinfo)
    return qaytgan.replace(tzinfo=None) == d.replace(tzinfo=None)

def ikki_manolimi(d: datetime) -> bool:
    return d.replace(fold=0).utcoffset() != d.replace(fold=1).utcoffset()

2.5. Arifmetika: devor soati yoki haqiqiy vaqt

Bir xil tzinfo li aware datetime larda arifmetika devor soati bo'yicha bajariladi:

python
b = ZoneInfo("Europe/Berlin")
s = datetime(2026, 3, 28, 12, 0, tzinfo=b)
s + timedelta(days=1)                         # 29-mart 12:00+02:00 — devor soati bir xil
# haqiqatan o'tgan vaqt: 23 soat

(s.astimezone(UTC) + timedelta(hours=24)).astimezone(b)   # 29-mart 13:00+02:00
Vazifa To'g'ri usul
"Ertaga shu vaqtda" (uchrashuv, eslatma) Mahalliy devor soatida qo'shish
"24 soatdan keyin" (muddat, token, SLA) UTC da qo'shish
Ikki lahza orasidagi haqiqiy vaqt Ikkalasini UTC ga o'girib ayirish

Bir mintaqadagi ikki datetime ni ayirish ham devor soati farqini beradi: 29-mart 12:00 − 28-mart 12:00 → 1 day, haqiqatda esa 23 soat.

2.6. Tarix va siyosat

Mintaqa qoidalari qonun bilan o'zgaradi — shuning uchun tzdata muntazam yangilanadi.

Yil Asia/Tashkent yozda
1990 +07:00
1991 +06:00
1992 dan beri +05:00, yozgi vaqt yo'q

Kelajakdagi voqealar uchun (bir yildan keyingi uchrashuv) mahalliy vaqt + mintaqa nomi saqlanadi: agar qoidalar o'zgarsa, UTC qayta hisoblanadi. O'tgan voqealar uchun — UTC.

2.7. Qoidalar

Qatlam Nima
Baza / jurnal / API Aware UTC (timestamptz, ISO 8601 Z yoki +00:00)
Foydalanuvchi profili IANA mintaqa nomi (Asia/Tashkent), siljish emas
Ko'rsatish astimezone(ZoneInfo(foydalanuvchi.mintaqa))
Kelajakdagi kalendar voqeasi Mahalliy vaqt + mintaqa nomi
Muddatlar, taymerlar UTC + timedelta

3. Tez ma'lumotnoma

python
from datetime import UTC, datetime, timedelta
from zoneinfo import ZoneInfo

TOSHKENT = ZoneInfo("Asia/Tashkent")
hozir = datetime.now(UTC)                          # saqlash
hozir.astimezone(TOSHKENT)                         # ko'rsatish
mahalliy = datetime(2026, 9, 17, 9, 0, tzinfo=ZoneInfo("Europe/Berlin"))
mahalliy.astimezone(UTC)                           # saqlashga
muddat = hozir + timedelta(hours=24)               # haqiqiy 24 soat — UTC da
haqiqiy_farq = a.astimezone(UTC) - b.astimezone(UTC)
d.replace(fold=1)                                  # takrorlanuvchi soatning ikkinchisi

Qoidalar

saqlash — UTC, ko'rsatish — ZoneInfo
profilda mintaqa nomi, siljish emas
Windows va slim konteynerlar — tzdata paketi
bir zona ichidagi arifmetika — devor soati
haqiqiy davomiylik — UTC ga o'girib
naive.astimezone() — server mintaqasiga bog'liq

4. Batafsil misollar

Misol 1 — Mintaqalar asoslari

python
"""ZoneInfo yaratish; astimezone va replace farqi; turli zonalarni solishtirish; siljish va mintaqa; tarixiy siljishlar; noma'lum kalit."""

from datetime import UTC, datetime, timedelta, timezone
from zoneinfo import ZoneInfo, ZoneInfoNotFoundError, available_timezones

TOSHKENT = ZoneInfo("Asia/Tashkent")
BERLIN = ZoneInfo("Europe/Berlin")
NYU_YORK = ZoneInfo("America/New_York")


def main() -> None:
    print("=== 1. Bitta lahza — turli mintaqalarda ===")
    lahza = datetime(2026, 9, 17, 9, 0, tzinfo=UTC)
    for zona in (UTC, TOSHKENT, BERLIN, NYU_YORK):
        mahalliy = lahza.astimezone(zona)
        print(f"  {str(zona):17} {mahalliy:%Y-%m-%d %H:%M}  siljish={mahalliy:%z}  nomi={mahalliy.tzname()}")
    print(f"  hammasi teng: {len({lahza.astimezone(z) for z in (TOSHKENT, BERLIN, NYU_YORK)}) == 1}")

    print("\n=== 2. ⚠️ astimezone va replace ===")
    toshkent_14 = datetime(2026, 9, 17, 14, 0, tzinfo=TOSHKENT)
    print(f"  asl:                     {toshkent_14}")
    print(f"  astimezone(BERLIN):      {toshkent_14.astimezone(BERLIN)}  ← o'sha lahza")
    print(f"  replace(tzinfo=BERLIN):  {toshkent_14.replace(tzinfo=BERLIN)}  ← boshqa lahza")
    farq = toshkent_14.replace(tzinfo=BERLIN) - toshkent_14
    print(f"  replace dan keyingi farq: {farq}")

    print("\n=== 3. Siljish va mintaqa ===")
    iso = datetime.fromisoformat("2026-03-01T09:00:00+01:00")
    print(f"  ISO satrdan tzinfo: {iso.tzinfo!r} (turi: {type(iso.tzinfo).__name__})")
    olti_oy_siljish = iso + timedelta(days=184)
    olti_oy_zona = iso.replace(tzinfo=BERLIN) + timedelta(days=184)
    print(f"  +184 kun, qat'iy siljish bilan: {olti_oy_siljish}")
    print(f"  +184 kun, Europe/Berlin bilan:  {olti_oy_zona}")
    print(f"  UTC da farq: {olti_oy_siljish.astimezone(UTC) - olti_oy_zona.astimezone(UTC)}  ← eslatma bir soat kechikadi")
    for zona_nomi in ("Europe/Berlin", "Europe/Paris", "Africa/Lagos"):
        z = ZoneInfo(zona_nomi)
        qish, yoz = datetime(2026, 1, 15, 12, tzinfo=z), datetime(2026, 7, 15, 12, tzinfo=z)
        print(f"  {zona_nomi:14} qishda {qish:%z}, yozda {yoz:%z}")

    print("\n=== 4. Tarix: Asia/Tashkent yozgi siljishi ===")
    for yil in (1985, 1990, 1991, 1992, 2026):
        print(f"  {yil}-yil iyul: {datetime(yil, 7, 1, 12, tzinfo=TOSHKENT):%z}")

    print("\n=== 5. Mavjud mintaqalar va xatolar ===")
    zonalar = available_timezones()
    print(f"  jami 400 dan ko'p: {len(zonalar) > 400}")
    print(f"  O'zbekiston: {sorted(z for z in zonalar if z in ('Asia/Tashkent', 'Asia/Samarkand'))}")
    try:
        ZoneInfo("Toshkent")
    except ZoneInfoNotFoundError as xato:
        print(f"  ZoneInfo('Toshkent') → {type(xato).__name__}: {xato}")
    print(f"  kesh: ZoneInfo(...) is ZoneInfo(...) → {ZoneInfo('Asia/Tashkent') is TOSHKENT}")
    print(f"  qat'iy siljish +05:00 mintaqa nomini bilmaydi: {timezone(timedelta(hours=5))}")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Bitta lahza — turli mintaqalarda ===
  UTC               2026-09-17 09:00  siljish=+0000  nomi=UTC
  Asia/Tashkent     2026-09-17 14:00  siljish=+0500  nomi=+05
  Europe/Berlin     2026-09-17 11:00  siljish=+0200  nomi=CEST
  America/New_York  2026-09-17 05:00  siljish=-0400  nomi=EDT
  hammasi teng: True

=== 2. ⚠️ astimezone va replace ===
  asl:                     2026-09-17 14:00:00+05:00
  astimezone(BERLIN):      2026-09-17 11:00:00+02:00  ← o'sha lahza
  replace(tzinfo=BERLIN):  2026-09-17 14:00:00+02:00  ← boshqa lahza
  replace dan keyingi farq: 3:00:00

=== 3. Siljish va mintaqa ===
  ISO satrdan tzinfo: datetime.timezone(datetime.timedelta(seconds=3600)) (turi: timezone)
  +184 kun, qat'iy siljish bilan: 2026-09-01 09:00:00+01:00
  +184 kun, Europe/Berlin bilan:  2026-09-01 09:00:00+02:00
  UTC da farq: 1:00:00  ← eslatma bir soat kechikadi
  Europe/Berlin  qishda +0100, yozda +0200
  Europe/Paris   qishda +0100, yozda +0200
  Africa/Lagos   qishda +0100, yozda +0100

=== 4. Tarix: Asia/Tashkent yozgi siljishi ===
  1985-yil iyul: +0700
  1990-yil iyul: +0700
  1991-yil iyul: +0600
  1992-yil iyul: +0500
  2026-yil iyul: +0500

=== 5. Mavjud mintaqalar va xatolar ===
  jami 400 dan ko'p: True
  O'zbekiston: ['Asia/Samarkand', 'Asia/Tashkent']
  ZoneInfo('Toshkent') → ZoneInfoNotFoundError: 'No time zone found with key Toshkent'
  kesh: ZoneInfo(...) is ZoneInfo(...) → True
  qat'iy siljish +05:00 mintaqa nomini bilmaydi: UTC+05:00

Nima ko'rsatdi: 2.1, 2.2, 2.3, 2.6-bo'limlar.

Misol 2 — Yozgi vaqt: bo'shliq va takror

python
"""Bahorgi bo'shliq: mavjud bo'lmagan vaqt; kuzgi takror va fold; aniqlash funksiyalari; butun kunni soatma-soat ko'rish."""

from datetime import UTC, datetime, timedelta
from zoneinfo import ZoneInfo

BERLIN = ZoneInfo("Europe/Berlin")
TOSHKENT = ZoneInfo("Asia/Tashkent")


def mavjudmi(d: datetime) -> bool:
    qaytgan = d.astimezone(UTC).astimezone(d.tzinfo)
    return qaytgan.replace(tzinfo=None) == d.replace(tzinfo=None)


def ikki_manolimi(d: datetime) -> bool:
    return d.replace(fold=0).utcoffset() != d.replace(fold=1).utcoffset()


def main() -> None:
    print("=== 1. ⚠️ Bahor: 29-mart, Berlin ===")
    for soat, daqiqa in ((1, 30), (2, 0), (2, 30), (3, 0), (3, 30)):
        d = datetime(2026, 3, 29, soat, daqiqa, tzinfo=BERLIN)
        print(f"  {d:%H:%M}  siljish={d:%z}  mavjud={mavjudmi(d)!s:5}  UTC={d.astimezone(UTC):%H:%M}")
    yoq = datetime(2026, 3, 29, 2, 30, tzinfo=BERLIN)
    print(f"  02:30 xato bermadi, UTC orqali qaytganda: {yoq.astimezone(UTC).astimezone(BERLIN):%H:%M %z}")

    print("\n=== 2. ⚠️ Kuz: 25-oktabr, Berlin ===")
    for fold in (0, 1):
        d = datetime(2026, 10, 25, 2, 30, fold=fold, tzinfo=BERLIN)
        print(f"  02:30 fold={fold}: siljish={d:%z}, UTC={d.astimezone(UTC):%H:%M}, ikki ma'noli={ikki_manolimi(d)}")
    birinchi = datetime(2026, 10, 25, 2, 30, fold=0, tzinfo=BERLIN)
    ikkinchi = birinchi.replace(fold=1)
    print(f"  birinchi == ikkinchi: {birinchi == ikkinchi}  ← bir xil tzinfo: devor soati solishtirildi")
    print(f"  ikkinchi - birinchi: {ikkinchi - birinchi}")
    print(f"  UTC da farq: {ikkinchi.astimezone(UTC) - birinchi.astimezone(UTC)}")

    print("\n=== 3. UTC dan soatma-soat: kuzgi kecha ===")
    boshlanish = datetime(2026, 10, 24, 23, 30, tzinfo=UTC)
    for i in range(4):
        u = boshlanish + timedelta(hours=i)
        m = u.astimezone(BERLIN)
        print(f"  UTC {u:%H:%M} → Berlin {m:%H:%M} {m:%z} fold={m.fold}")
    print("  ⭐ UTC da hech narsa takrorlanmaydi — shuning uchun saqlash UTC da")

    print("\n=== 4. Toshkentda bunday muammo yo'q ===")
    for oy, kun in ((3, 29), (10, 25)):
        d = datetime(2026, oy, kun, 2, 30, tzinfo=TOSHKENT)
        print(f"  {d:%d.%m %H:%M}: mavjud={mavjudmi(d)}, ikki ma'noli={ikki_manolimi(d)}")

    print("\n=== 5. Siyosat: foydalanuvchi mavjud bo'lmagan vaqt tanlasa ===")

    def tuzat(d: datetime) -> tuple[datetime, str]:
        if not mavjudmi(d):
            return d.astimezone(UTC).astimezone(d.tzinfo), "surildi (bo'shliq)"
        if ikki_manolimi(d):
            return d.replace(fold=0), "birinchisi tanlandi (takror)"
        return d, "o'zgarishsiz"

    for d in (datetime(2026, 3, 29, 2, 15, tzinfo=BERLIN),
              datetime(2026, 10, 25, 2, 15, tzinfo=BERLIN),
              datetime(2026, 9, 17, 2, 15, tzinfo=BERLIN)):
        natija, izoh = tuzat(d)
        print(f"  {d:%d.%m %H:%M} → {natija:%d.%m %H:%M %z}  {izoh}")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. ⚠️ Bahor: 29-mart, Berlin ===
  01:30  siljish=+0100  mavjud=True   UTC=00:30
  02:00  siljish=+0100  mavjud=False  UTC=01:00
  02:30  siljish=+0100  mavjud=False  UTC=01:30
  03:00  siljish=+0200  mavjud=True   UTC=01:00
  03:30  siljish=+0200  mavjud=True   UTC=01:30
  02:30 xato bermadi, UTC orqali qaytganda: 03:30 +0200

=== 2. ⚠️ Kuz: 25-oktabr, Berlin ===
  02:30 fold=0: siljish=+0200, UTC=00:30, ikki ma'noli=True
  02:30 fold=1: siljish=+0100, UTC=01:30, ikki ma'noli=True
  birinchi == ikkinchi: True  ← bir xil tzinfo: devor soati solishtirildi
  ikkinchi - birinchi: 0:00:00
  UTC da farq: 1:00:00

=== 3. UTC dan soatma-soat: kuzgi kecha ===
  UTC 23:30 → Berlin 01:30 +0200 fold=0
  UTC 00:30 → Berlin 02:30 +0200 fold=0
  UTC 01:30 → Berlin 02:30 +0100 fold=1
  UTC 02:30 → Berlin 03:30 +0100 fold=0
  ⭐ UTC da hech narsa takrorlanmaydi — shuning uchun saqlash UTC da

=== 4. Toshkentda bunday muammo yo'q ===
  29.03 02:30: mavjud=True, ikki ma'noli=False
  25.10 02:30: mavjud=True, ikki ma'noli=False

=== 5. Siyosat: foydalanuvchi mavjud bo'lmagan vaqt tanlasa ===
  29.03 02:15 → 29.03 03:15 +0200  surildi (bo'shliq)
  25.10 02:15 → 25.10 02:15 +0200  birinchisi tanlandi (takror)
  17.09 02:15 → 17.09 02:15 +0200  o'zgarishsiz

Nima ko'rsatdi: 2.4-bo'lim.

Misol 3 — Arifmetika: devor soati va haqiqiy vaqt

python
"""Bir zona ichida +1 kun va +24 soat farqi; ayirma devor soati bo'yicha; haqiqiy davomiylik UTC da; muddat va eslatma uchun to'g'ri tanlov."""

from datetime import UTC, datetime, timedelta
from zoneinfo import ZoneInfo

BERLIN = ZoneInfo("Europe/Berlin")
NYU_YORK = ZoneInfo("America/New_York")


def haqiqiy_farq(a: datetime, b: datetime) -> timedelta:
    return a.astimezone(UTC) - b.astimezone(UTC)


def main() -> None:
    print("=== 1. ⚠️ Bahorgi o'tish atrofida ===")
    s = datetime(2026, 3, 28, 12, 0, tzinfo=BERLIN)
    bir_kun = s + timedelta(days=1)
    yigirma_tort = (s.astimezone(UTC) + timedelta(hours=24)).astimezone(BERLIN)
    print(f"  boshlanish:              {s}")
    print(f"  + timedelta(days=1):     {bir_kun}  (haqiqatda {haqiqiy_farq(bir_kun, s)})")
    print(f"  UTC da + 24 soat:        {yigirma_tort}  (haqiqatda {haqiqiy_farq(yigirma_tort, s)})")
    print(f"  bir_kun - s (bir zona): {bir_kun - s}  ⚠️")

    print("\n=== 2. Kuzgi o'tish atrofida ===")
    s = datetime(2026, 10, 24, 12, 0, tzinfo=BERLIN)
    bir_kun = s + timedelta(days=1)
    print(f"  + 1 kun: {bir_kun}, devor soati farqi {bir_kun - s}, haqiqiy {haqiqiy_farq(bir_kun, s)}")

    print("\n=== 3. Turli zonalar orasida ayirma — to'g'ri ===")
    ketish = datetime(2026, 3, 28, 22, 0, tzinfo=BERLIN)
    kelish = datetime(2026, 3, 29, 1, 30, tzinfo=NYU_YORK)
    print(f"  Berlin 28.03 22:00 → Nyu-York 29.03 01:30: parvoz {kelish - ketish}")
    print(f"  UTC orqali: {haqiqiy_farq(kelish, ketish)}")

    print("\n=== 4. Qaysi holatda qaysi usul ===")
    tuzilgan = datetime(2026, 3, 28, 9, 0, tzinfo=BERLIN)
    token_muddati = tuzilgan.astimezone(UTC) + timedelta(hours=24)
    ertangi_uchrashuv = tuzilgan + timedelta(days=1)
    print(f"  kirish tokeni (24 soat):      {token_muddati.astimezone(BERLIN):%d.%m %H:%M %z}")
    print(f"  ertangi uchrashuv (shu vaqt): {ertangi_uchrashuv:%d.%m %H:%M %z}")
    print(f"  token aynan 24 soat: {haqiqiy_farq(token_muddati, tuzilgan) == timedelta(hours=24)}")
    print(f"  uchrashuv mahalliy 09:00 da: {ertangi_uchrashuv.hour == 9}")

    print("\n=== 5. Bir yillik ish soati hisobi ===")
    yil_boshi = datetime(2026, 1, 1, tzinfo=BERLIN)
    yil_oxiri = datetime(2027, 1, 1, tzinfo=BERLIN)
    print(f"  devor soati bo'yicha: {(yil_oxiri - yil_boshi).total_seconds() / 3600:.0f} soat")
    print(f"  haqiqiy:              {haqiqiy_farq(yil_oxiri, yil_boshi).total_seconds() / 3600:.0f} soat")
    print("  ⭐ yil davomida bir soat yo'qolib, bir soat qaytgani uchun jami teng")
    bahor = datetime(2026, 3, 1, tzinfo=BERLIN)
    kuz = datetime(2026, 10, 1, tzinfo=BERLIN)
    print(f"  1-mart → 1-oktabr: devor soati {(kuz - bahor).total_seconds() / 3600:.0f}, "
          f"haqiqiy {haqiqiy_farq(kuz, bahor).total_seconds() / 3600:.0f} soat")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. ⚠️ Bahorgi o'tish atrofida ===
  boshlanish:              2026-03-28 12:00:00+01:00
  + timedelta(days=1):     2026-03-29 12:00:00+02:00  (haqiqatda 23:00:00)
  UTC da + 24 soat:        2026-03-29 13:00:00+02:00  (haqiqatda 1 day, 0:00:00)
  bir_kun - s (bir zona): 1 day, 0:00:00  ⚠️

=== 2. Kuzgi o'tish atrofida ===
  + 1 kun: 2026-10-25 12:00:00+01:00, devor soati farqi 1 day, 0:00:00, haqiqiy 1 day, 1:00:00

=== 3. Turli zonalar orasida ayirma — to'g'ri ===
  Berlin 28.03 22:00 → Nyu-York 29.03 01:30: parvoz 8:30:00
  UTC orqali: 8:30:00

=== 4. Qaysi holatda qaysi usul ===
  kirish tokeni (24 soat):      29.03 10:00 +0200
  ertangi uchrashuv (shu vaqt): 29.03 09:00 +0200
  token aynan 24 soat: True
  uchrashuv mahalliy 09:00 da: True

=== 5. Bir yillik ish soati hisobi ===
  devor soati bo'yicha: 8760 soat
  haqiqiy:              8760 soat
  ⭐ yil davomida bir soat yo'qolib, bir soat qaytgani uchun jami teng
  1-mart → 1-oktabr: devor soati 5136, haqiqiy 5135 soat

Nima ko'rsatdi: 2.5-bo'lim.

Misol 4 — Amaliy: xalqaro jamoa uchun kundalik uchrashuvlar

Kirishdagi vaziyatni to'g'ri hal qilamiz. Uchrashuv Berlin vaqti bilan har kuni 09:00 da. Qoida: uchrashuv mahalliy vaqt + mintaqa nomi sifatida saqlanadi, har kun uchun UTC qayta hisoblanadi va har ishtirokchiga o'z mintaqasida ko'rsatiladi. Oxirida xato usul (UTC da +24 soat) bilan solishtiramiz.

python
"""Kalendar voqeasi: mahalliy vaqt + mintaqa; har kun UTC ni qayta hisoblash; ishtirokchilar mintaqasida ko'rsatish; xato usul bilan solishtirish."""

from dataclasses import dataclass
from datetime import UTC, date, datetime, time, timedelta
from zoneinfo import ZoneInfo


@dataclass(frozen=True, slots=True)
class Uchrashuv:
    nom: str
    mahalliy_vaqt: time
    mintaqa: str

    def lahza(self, kun: date) -> datetime:
        zona = ZoneInfo(self.mintaqa)
        d = datetime.combine(kun, self.mahalliy_vaqt, tzinfo=zona)
        return d.astimezone(UTC)                     # saqlash va eslatma uchun


ISHTIROKCHILAR = {
    "Aziz (Toshkent)": "Asia/Tashkent",
    "Anna (Berlin)": "Europe/Berlin",
    "John (Nyu-York)": "America/New_York",
}


def main() -> None:
    uchrashuv = Uchrashuv("Kundalik stendap", time(9, 0), "Europe/Berlin")
    kunlar = [date(2026, 3, 27) + timedelta(days=i) for i in range(4)]

    print(f"=== 1. {uchrashuv.nom}: {uchrashuv.mahalliy_vaqt:%H:%M} {uchrashuv.mintaqa} ===")
    sarlavha = "  sana        UTC    " + "  ".join(f"{n:16}" for n in ISHTIROKCHILAR)
    print(sarlavha)
    for kun in kunlar:
        utc = uchrashuv.lahza(kun)
        qator = "  ".join(f"{utc.astimezone(ZoneInfo(z)):%H:%M %z}".ljust(16) for z in ISHTIROKCHILAR.values())
        print(f"  {kun:%d.%m.%Y}  {utc:%H:%M}  {qator}")

    print("\n=== 2. Tekshiruvlar ===")
    berlinda = [uchrashuv.lahza(k).astimezone(ZoneInfo("Europe/Berlin")).time() for k in kunlar]
    print(f"  Berlinda har kuni 09:00: {all(t == time(9, 0) for t in berlinda)}")
    toshkentda = sorted({f"{uchrashuv.lahza(k).astimezone(ZoneInfo('Asia/Tashkent')):%H:%M}" for k in kunlar})
    print(f"  Toshkentda vaqt o'zgardi: {toshkentda}")
    utclar = [uchrashuv.lahza(k) for k in kunlar]
    oraliqlar = [str(b - a) for a, b in zip(utclar, utclar[1:])]
    print(f"  UTC dagi oraliqlar: {oraliqlar}")

    print("\n=== 3. ⚠️ Xato usul: birinchi lahzaga +24 soat ===")
    birinchi = uchrashuv.lahza(kunlar[0])
    for i, kun in enumerate(kunlar):
        xato = (birinchi + timedelta(hours=24 * i)).astimezone(ZoneInfo("Europe/Berlin"))
        togri = uchrashuv.lahza(kun).astimezone(ZoneInfo("Europe/Berlin"))
        belgi = "✅" if xato == togri else "❌"
        print(f"  {belgi} {kun:%d.%m}: xato usul {xato:%H:%M}, to'g'ri {togri:%H:%M}")

    print("\n=== 4. Nyu-Yorkdagi o'tish (8-mart va 1-noyabr) atrofida ===")
    nyu_york_uchrashuvi = Uchrashuv("Hisobot", time(8, 30), "America/New_York")
    for kun in (date(2026, 3, 7), date(2026, 3, 9), date(2026, 10, 31), date(2026, 11, 2)):
        utc = nyu_york_uchrashuvi.lahza(kun)
        print(f"  {kun:%d.%m}: Nyu-York 08:30 = Toshkent {utc.astimezone(ZoneInfo('Asia/Tashkent')):%H:%M}")

    print("\n=== 5. Qoidalar ===")
    print("  ✅ kelajakdagi kalendar voqeasi: mahalliy vaqt + IANA mintaqa nomi")
    print("  ✅ aniq lahza (eslatma yuborish): har kun UTC ga qayta hisoblash")
    print("  ✅ ko'rsatish: har ishtirokchining o'z mintaqasida")
    print("  ❌ bitta UTC lahzaga +24 soat qo'shib borish")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Kundalik stendap: 09:00 Europe/Berlin ===
  sana        UTC    Aziz (Toshkent)   Anna (Berlin)     John (Nyu-York)
  27.03.2026  08:00  13:00 +0500       09:00 +0100       04:00 -0400
  28.03.2026  08:00  13:00 +0500       09:00 +0100       04:00 -0400
  29.03.2026  07:00  12:00 +0500       09:00 +0200       03:00 -0400
  30.03.2026  07:00  12:00 +0500       09:00 +0200       03:00 -0400

=== 2. Tekshiruvlar ===
  Berlinda har kuni 09:00: True
  Toshkentda vaqt o'zgardi: ['12:00', '13:00']
  UTC dagi oraliqlar: ['1 day, 0:00:00', '23:00:00', '1 day, 0:00:00']

=== 3. ⚠️ Xato usul: birinchi lahzaga +24 soat ===
  ✅ 27.03: xato usul 09:00, to'g'ri 09:00
  ✅ 28.03: xato usul 09:00, to'g'ri 09:00
  ❌ 29.03: xato usul 10:00, to'g'ri 09:00
  ❌ 30.03: xato usul 10:00, to'g'ri 09:00

=== 4. Nyu-Yorkdagi o'tish (8-mart va 1-noyabr) atrofida ===
  07.03: Nyu-York 08:30 = Toshkent 18:30
  09.03: Nyu-York 08:30 = Toshkent 17:30
  31.10: Nyu-York 08:30 = Toshkent 17:30
  02.11: Nyu-York 08:30 = Toshkent 18:30

=== 5. Qoidalar ===
  ✅ kelajakdagi kalendar voqeasi: mahalliy vaqt + IANA mintaqa nomi
  ✅ aniq lahza (eslatma yuborish): har kun UTC ga qayta hisoblash
  ✅ ko'rsatish: har ishtirokchining o'z mintaqasida
  ❌ bitta UTC lahzaga +24 soat qo'shib borish

Nima ko'rsatdi: 2.5, 2.7-bo'limlar.


5. To'g'ri va noto'g'ri tushunishlar

Noto'g'ri fikr To'g'risi
"+05:00 — Toshkent mintaqasi" Faqat siljish; mintaqa — Asia/Tashkent
"ZoneInfo hamma joyda ishlaydi" Windows va slim konteynerlarda tzdata kerak
"replace(tzinfo=...) mintaqaga o'giradi" Yopishtiradi — boshqa lahza bo'lib qoladi
"Mavjud bo'lmagan vaqt xato beradi" Jim yaratiladi
"Bir zonadagi ikki vaqt ayirmasi — haqiqiy davomiylik" Devor soati farqi
"timedelta(days=1) = 24 soat" Yozgi vaqt o'tishida 23 yoki 25 soat
"Kelajakdagi voqeani UTC da saqlash yetarli" Qoidalar o'zgarishi mumkin — mahalliy vaqt + mintaqa
"O'zbekistonda bu muammolar yo'q" Hamkorlar, serverlar va foydalanuvchilar boshqa mintaqada

6. Keng tarqalgan xatolar va yechimlari

1. Siljishni mintaqa sifatida saqlash

python
foydalanuvchi.mintaqa = "+01:00"                   # ❌
foydalanuvchi.mintaqa = "Europe/Berlin"            # ✅

2. replace bilan o'girish

python
utc_vaqt.replace(tzinfo=TOSHKENT)                  # ❌ 5 soat siljidi
utc_vaqt.astimezone(TOSHKENT)                      # ✅

3. Naive vaqtni astimezone qilish

python
datetime(2026, 9, 17, 14).astimezone(UTC)          # ⚠️ server mintaqasiga bog'liq
datetime(2026, 9, 17, 14, tzinfo=TOSHKENT).astimezone(UTC)   # ✅

4. Takroriy voqeani UTC da qo'shish

python
keyingi = oldingi_utc + timedelta(days=1)          # ❌ yozgi vaqtda siljiydi
keyingi = datetime.combine(kun, vaqt, tzinfo=zona).astimezone(UTC)   # ✅

5. Davomiylikni bir zona ichida ayirish

python
davom = tugash_berlin - boshlanish_berlin          # ⚠️ devor soati
davom = tugash_berlin.astimezone(UTC) - boshlanish_berlin.astimezone(UTC)   # ✅

6. tzdata ni bog'liqliklarga qo'shmaslik

toml
# ❌ Linux'da ishlaydi, Windows/Docker slim'da ZoneInfoNotFoundError
# ✅ pyproject.toml
dependencies = ["tzdata"]

7. Foydalanuvchi tanlagan vaqtni tekshirmaslik

python
# ⚠️ 29-mart 02:30 Berlin — mavjud emas
if not mavjudmi(tanlangan): ...                    # ✅ surish yoki ogohlantirish

8. Server vaqtiga tayanish

python
datetime.now()                                     # ❌ server qayerda?
datetime.now(UTC)                                  # ✅

7. Integratsiya — bu bilim qayerda kerak bo'ladi

  • 15.4-dars (o'tilgan): datetime turlari va arifmetika
  • 15.16-dars: logging — jurnallarda UTC vaqt belgilari
  • 16.2-dars: JSON da ISO 8601 bilan saqlash
  • 17-qism: yozgi vaqt o'tish kunlari uchun testlar
  • 20.6-dars: so'rov va javob — API da vaqtni qabul qilish va qaytarish
  • 23-qism: PostgreSQL timestamptz va AT TIME ZONE
  • 26-qism: cron va rejalashtirilgan vazifalar mintaqalari

8. Eng yaxshi amaliyotlar

  1. Saqlash — aware UTC.

  2. Foydalanuvchi profilida — IANA mintaqa nomi.

  3. Ko'rsatishda — astimezone(ZoneInfo(...)).

  4. Kelajakdagi kalendar voqealari — mahalliy vaqt + mintaqa, UTC har safar hisoblanadi.

  5. Muddat va taymerlar — UTC + timedelta.

  6. tzdata ni bog'liqliklarga qo'shing va muntazam yangilang.

  7. Yozgi vaqt o'tish kunlarini testlarga kiriting — bo'shliq va takror uchun.

  8. Naive datetime ni tizim chegarasidan ichkariga o'tkazmang.


9. Amaliy topshiriq

Vazifa 1: Natijani bashorat qiling

python
from datetime import UTC, datetime, timedelta, timezone
from zoneinfo import ZoneInfo
T, B = ZoneInfo("Asia/Tashkent"), ZoneInfo("Europe/Berlin")
1.  print(datetime(2026, 9, 17, 9, tzinfo=UTC).astimezone(T).hour)
2.  print(datetime(2026, 9, 17, 14, tzinfo=T) == datetime(2026, 9, 17, 9, tzinfo=UTC))
3.  print(datetime(2026, 1, 15, 12, tzinfo=B).utcoffset())
4.  print(datetime(2026, 7, 15, 12, tzinfo=B).utcoffset())
5.  print(datetime(2026, 9, 17, 14, tzinfo=T).replace(tzinfo=UTC).hour)
6.  print(str(T))
7.  print(datetime(2026, 7, 1, tzinfo=T).dst())
8.  print(datetime(2026, 10, 25, 2, 30, fold=1, tzinfo=B).utcoffset())
9.  print(datetime(2026, 3, 29, 12, tzinfo=B) - datetime(2026, 3, 28, 12, tzinfo=B))
10. print(datetime.fromisoformat("2026-09-17T14:00+05:00").tzinfo == timezone(timedelta(hours=5)))
11. print(ZoneInfo("Asia/Tashkent") is T)
12. print(datetime(1990, 7, 1, 12, tzinfo=T).utcoffset())
Javoblar
  1. 14
  2. True — turli tzinfo, UTC bo'yicha solishtiriladi
  3. 1:00:00
  4. 2:00:00
  5. 14 — replace faqat yopishtiradi
  6. Asia/Tashkent
  7. 0:00:00
  8. 1:00:00
  9. 1 day, 0:00:00 — devor soati bo'yicha
  10. True
  11. True — kesh
  12. 7:00:00

Vazifa 2: Xatolarni tuzating

python
1.  def korsat(utc_vaqt, mintaqa):
        return utc_vaqt.replace(tzinfo=ZoneInfo(mintaqa))

2.  def keyingi_eslatma(oxirgi_utc):
        return oxirgi_utc + timedelta(days=7)        # har dushanba 09:00 Toshkent vaqti

3.  def davomiylik(boshlanish, tugash):             # ikkalasi Europe/Berlin
        return tugash - boshlanish

4.  class Foydalanuvchi:
        mintaqa: str = "+05:00"

5.  def saqlash_vaqti():
        return datetime.now().isoformat()
Javoblar
python
1.  def korsat(utc_vaqt, mintaqa):
        return utc_vaqt.astimezone(ZoneInfo(mintaqa))

2.  def keyingi_eslatma(oxirgi_kun: date) -> datetime:
        kun = oxirgi_kun + timedelta(days=7)
        mahalliy = datetime.combine(kun, time(9, 0), tzinfo=ZoneInfo("Asia/Tashkent"))
        return mahalliy.astimezone(UTC)
    # Toshkentda yozgi vaqt yo'q, lekin qoida mintaqa almashsa ham to'g'ri qoladi

3.  def davomiylik(boshlanish, tugash):
        return tugash.astimezone(UTC) - boshlanish.astimezone(UTC)

4.  class Foydalanuvchi:
        mintaqa: str = "Asia/Tashkent"

5.  def saqlash_vaqti():
        return datetime.now(UTC).isoformat()

Vazifa 3: Yozgi vaqt o'tishlarini topish

otishlar(mintaqa, yil) funksiyasini yozing:

  1. Yil davomida siljish o'zgargan barcha lahzalarni toping (soatma-soat UTC bo'ylab, keyin daqiqagacha aniqlashtiring)
  2. Har o'tish uchun: sana, eski va yangi siljish, bo'shliq yoki takror
  3. Europe/Berlin, America/New_York, Australia/Sydney, Asia/Tashkent uchun ishga tushiring
  4. Australia/Sydney da o'tishlar nega "teskari" ekanini tushuntiring
  5. Asia/Tashkent uchun 1981–1992 yillar tarixini jadval qiling

Vazifa 4: Dunyo soati

  1. Foydalanuvchi kiritgan mintaqalar ro'yxati uchun hozirgi vaqtni ko'rsating (hozir parametr orqali)
  2. Toshkentga nisbatan farq: "+3 soat", "-10 soat", "+5:30"
  3. Har shahar uchun "ish vaqti" (09:00–18:00) ichidami — belgi bilan
  4. Hamma uchun qulay uchrashuv soatini toping (Toshkent vaqtida)

Vazifa 5: Takroriy voqealar

takrorlash(boshlanish_mahalliy, mintaqa, qoida, soni):

  1. Qoidalar: "kunlik", "haftalik", "har oy 31-kuni" (15.4-darsdagi qisish bilan)
  2. Har voqea uchun UTC lahza va mahalliy vaqt
  3. Mavjud bo'lmagan vaqt — keyingi mavjud vaqtga surilsin, takrorlanuvchi — birinchisi
  4. Europe/Berlin da mart va oktabrni o'z ichiga olgan sinovlar

Vazifa 6: Jurnallarni birlashtirish

Uch serverdan jurnallar: biri UTC, biri +05:00 siljishli, biri naive (lekin America/New_York vaqtida yozilgan ekani ma'lum):

  1. Hammasini aware UTC ga keltiring
  2. Kuzgi takror soatidagi naive yozuvlar uchun fold ni ketma-ketlik tartibidan aniqlang
  3. Birlashtirilgan jurnalni vaqt bo'yicha saralang
  4. Tartib buzilgan joylarni (soat noto'g'ri) aniqlang

Vazifa 7: O'ylash

Ko'p davlatlar yozgi vaqtdan voz kechmoqda (O'zbekiston — 1992, Rossiya — 2014, Yevropa Ittifoqi muhokama qilmoqda). Agar mamlakat qoidani e'lon qilingandan bir necha hafta o'tib o'zgartirsa, dasturiy tizimlarda nima sodir bo'ladi? UTC da saqlangan kelajakdagi uchrashuvlar bilan nima bo'ladi va tzdata yangilanishi nega muhim?

Javob

Qisqa javob: Mintaqa qoidalari — dasturiy ta'minot uchun tashqi, o'zgaruvchan ma'lumot. Qoida o'zgarsa, tzdata yangilanmagan tizimlar noto'g'ri vaqt ko'rsatadi, kelajakdagi voqealarni UTC da saqlagan tizimlar esa foydalanuvchi kutgan mahalliy vaqtni yo'qotadi. Shuning uchun kelajakdagi kalendar voqealari "mahalliy vaqt + mintaqa" sifatida saqlanadi va tzdata muntazam yangilanadi.

1. IANA tz ma'lumotlar bazasi

  • Ko'ngillilar tomonidan yuritiladi, yiliga bir necha marta yangilanadi (masalan, 2026d — 2026-yilning 4-versiyasi)
  • Operatsion tizimlar, brauzerlar, Java, Python tzdata, PostgreSQL — hammasi undan nusxa oladi
  • Har nusxa alohida yangilanadi — bitta tizimda bir necha xil versiya bo'lishi mumkin

2. Qisqa ogohlantirish bilan o'zgarish

Qatlam Nima bo'ladi
Eski tzdata li server Eski qoida bo'yicha hisoblaydi — 1 soat xato
Mobil qurilmalar OS yangilanishini kutadi
Brauzerdagi JavaScript Brauzer versiyasiga bog'liq
Baza (timestamptz) O'z tz nusxasiga bog'liq

Natija: bir xil voqea turli tizimlarda turli vaqtda ko'rinadi.

3. UTC da saqlangan kelajakdagi voqea

Uchrashuv: "2027-yil 1-aprel, 09:00, Europe/Berlin" — yaratilgan paytdagi qoida bo'yicha 07:00 UTC saqlandi.

Agar Yevropa Ittifoqi yozgi vaqtni bekor qilsa va Berlin doimiy +01:00 da qolsa:

  • UTC da saqlangan: 07:00 UTC → yangi qoidada Berlinda 08:00 — foydalanuvchi 09:00 ni kutgan edi
  • Mahalliy vaqt + mintaqa saqlangan: 09:00 Europe/Berlin → yangi tzdata bilan 08:00 UTC qayta hisoblanadi
Voqea turi Saqlash
O'tgan voqea (to'lov, kirish) UTC — bu fakt, o'zgarmaydi
Kelajakdagi kalendar voqeasi Mahalliy vaqt + mintaqa (+ keshlangan UTC)
Muddat, taymer ("24 soatdan keyin") UTC — fizik vaqt

4. Muhandislik amaliyoti

  1. tzdata ni bog'liqlik sifatida qo'shing va CI da yangilanishini kuzating
  2. Kelajakdagi voqealar uchun UTC ni kesh deb hisoblang: tzdata yangilanganda qayta hisoblang
  3. Mijoz va server bir xil mintaqa qoidalaridan foydalanayotganini tekshiring (masalan, API javobida UTC va mintaqa nomini birga bering)
  4. Muhim tizimlarda (aviatsiya, moliya) — mintaqa ma'lumotlari versiyasini jurnalga yozing

5. Xulosa

  1. Vaqt mintaqasi — fizika emas, siyosat
  2. Qoidalar o'zgaradi, ba'zan bir necha haftalik ogohlantirish bilan
  3. O'tgan voqealar — UTC; kelajakdagi kalendar voqealari — mahalliy vaqt + mintaqa
  4. tzdata — ilovaning boshqa bog'liqliklari kabi yangilanishi shart bo'lgan qism

Nimani mustahkamlaydi: 2.1–2.7-bo'limlar.


Xulosa

Bu darsda vaqt mintaqalari bilan ishlashni va yozgi vaqt tuzoqlarini o'rgandik.

Eng muhim uch fikr:

  1. Siljish — mintaqa emas. +01:00 faqat bitta lahzadagi farq; Europe/Berlin esa qoidalar tarixini biladi. ISO satrdan o'qilgan qat'iy siljish bilan olti oy keyingi vaqtni hisoblash bir soat xato beradi. Profilda mintaqa nomi saqlanadi, zoneinfo bilan ishlatiladi; Windows va slim konteynerlarda buning uchun tzdata paketi kerak. astimezone o'giradi, replace(tzinfo=...) esa faqat yopishtiradi.

  2. Yozgi vaqt: bo'shliq, takror va fold. Bahorda ba'zi devor soatlari mavjud emas — lekin datetime xato bermaydi, UTC orqali qaytganda boshqa vaqtga aylanadi. Kuzda bir soat ikki marta keladi va fold=0/1 bilan farqlanadi; bir xil tzinfo li ikki shunday vaqt == bo'yicha teng, ayirmasi 0, UTC da esa bir soat farq qiladi.

  3. Arifmetika: devor soati yoki haqiqiy vaqt — ongli tanlov. Bir mintaqa ichida + timedelta(days=1) devor soatini saqlaydi (o'tish kuni 23 yoki 25 soat), ayirma ham devor soati farqini beradi. Haqiqiy davomiylik va muddatlar — UTC da; takroriy uchrashuvlar — mahalliy vaqt + mintaqa bo'yicha har kun qayta hisoblanadi. UTC da +24 soat qo'shib borish esa hamkorlar uchun uchrashuvni bir soatga siljitadi.

Keyingi darsda collections moduliga o'tamiz: Counter va defaultdict — sanash va guruhlashning eng qulay vositalari.

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!