Python: деректен өз есебіңізге дейін 14-сабақ (барлығы 56)
Күндер мен уақыт: 45 күн, уақыт белдеуі және екі түрлі оқылатын пішім
Python курсының он төртінші сабағы. 15 қаңтар мен 1 наурыздың арасы — 45 күн, оны сіз емес, `timedelta` санайды. Плюс екі тұзақ: `01.02.2026` бірде-бір қатесіз екі пішіммен де талданады — қаңтар мен ақпан болып, — ал белдеусіз уақытты белдеуі бардан алуға болмайды, әрі Python мұны тіке айтады.
Не үшін керек
Өткен сабақта жыл "2025" деген жолмен келді де, біз одан сан жасадық: әрі қарай оны салыстыру керек еді. Күндерде де солай, тек қымбатырақ.
Деректер экспортындағы күн — мәтін: 2026-01-15, 15.01.2026, 15 қаңтар. Ол мәтін болып тұрғанда онымен ештеңе істей алмайсыз: алуға да, апта қосуға да, «неше күн өтті» деп сұрауға да келмейді.
Ал оны талдағанда бір жолдың екі түрлі оқылатыны, әрі екеуі де сенімді көрінетіні белгілі болады. Оның үстіне сандарда болмаған сұрақ шығады: тоғыз жарым — бұл қай жерде?
Бірден тұтас
kunder.py файлы. Іске қосу: ортадан python kunder.py.
Міндеттісі — алғашқы екі блок: жолдан күнге және күндердің айырмасы. Үшінші мен төртіншісі сабақ жазылған пішім мен уақыт белдеуін көрсетеді.
"""14-сабақ: күн — жол емес, уақыт өсіндегі нүкте.
Өткен сабақта жыл "2025" деген жолмен келді де, біз одан сан жасадық. Күндерде
де солай, тек қымбатырақ: "01.02.2026" екі түрлі оқылады, әрі екеуі де сенімді
көрінеді.
"""
from datetime import date, datetime, timedelta, timezone
# Деректер экспортынан күндер мәтін болып келеді. ISO пішімі түсіндірмесіз оқылады.
raw = ["2026-01-15", "2026-02-01", "2026-03-01"]
print("== жолдан күнге")
days = []
for text in raw:
day = date.fromisoformat(text)
days.append(day)
print(f"{text} → {day} | жыл {day.year}, ай {day.month}, күн {day.day}")
print()
print("== күндердің айырмасы — бұл timedelta")
span = days[-1] - days[0]
print("біріншісі мен соңғысының арасы:", span)
print("күн:", span.days)
print("соңғысынан бір апта кейін:", days[-1] + timedelta(days=7))
print()
print("== өз пішімімен талдап, өз пішіміңмен басу")
moment = datetime.strptime("01.02.2026 09:30", "%d.%m.%Y %H:%M")
print("талдадық:", moment)
print("бастық:", moment.strftime("%d.%m.%Y, %H:%M"))
print("файлға былай жазады:", moment.isoformat())
try:
datetime.strptime("2026-02-01", "%d.%m.%Y")
except ValueError as error:
print("бөтен пішім:", error)
print()
print("== уақыт белдеуі: белдеусіз және белдеуі бар уақыт")
naive = datetime(2026, 2, 1, 9, 30)
aware = datetime(2026, 2, 1, 9, 30, tzinfo=timezone.utc)
almaty = timezone(timedelta(hours=5))
print("белдеусіз: ", naive, "| белдеу:", naive.tzinfo)
print("белдеуі бар:", aware, "| белдеу:", aware.tzinfo)
print("сол сәт Алматыда:", aware.astimezone(almaty))
try:
print(aware - naive)
except TypeError as error:
print("біреуінен екіншісін алуға болмайды:", error)
Шығатыны:
== жолдан күнге
2026-01-15 → 2026-01-15 | жыл 2026, ай 1, күн 15
2026-02-01 → 2026-02-01 | жыл 2026, ай 2, күн 1
2026-03-01 → 2026-03-01 | жыл 2026, ай 3, күн 1
== күндердің айырмасы — бұл timedelta
біріншісі мен соңғысының арасы: 45 days, 0:00:00
күн: 45
соңғысынан бір апта кейін: 2026-03-08
== өз пішімімен талдап, өз пішіміңмен басу
талдадық: 2026-02-01 09:30:00
бастық: 01.02.2026, 09:30
файлға былай жазады: 2026-02-01T09:30:00
бөтен пішім: time data '2026-02-01' does not match format '%d.%m.%Y'
== уақыт белдеуі: белдеусіз және белдеуі бар уақыт
белдеусіз: 2026-02-01 09:30:00 | белдеу: None
белдеуі бар: 2026-02-01 09:30:00+00:00 | белдеу: UTC
сол сәт Алматыда: 2026-02-01 14:30:00+05:00
біреуінен екіншісін алуға болмайды: can't subtract offset-naive and offset-aware datetimes
Талдау
Жол күнге бір рет — талдау кезінде — айналады
day = date.fromisoformat(text)
fromisoformat күнді ISO 8601 пішімімен оқиды: жыл-ай-күн, төрт цифр, екеу, екеу. Бұл — өткен сабақтағы int(row["date"]) дегеннің дәл өзі: мәтін «керек болғанда» емес, бірден мәнге айналады.
Ал керек бірден болады. Күннен қажет нәрсенің бәрі — арифметика: айырма, жылжыту, салыстыру. Жолдармен мұның бірі де жоқ: "2026-03-01" - "2026-01-15" — қате.
Жолдарды салыстыру, шынында, жүреді: "2026-03-01" > "2026-01-15" — дұрыс. Бірақ ол кездейсоқ дұрыс: ISO солай құрылған, жолдардың реті күндердің ретімен сәйкес келеді. 01.02.2026-да сол салыстыру үнсіз өтірік айтады.
Елестетіп көріңіз. Пошта мөрі. Күн қағаздағы таңба болып тұрғанда, ол — сурет; хаттың неше күн жүргенін санау үшін оны оқу керек.
Күндердің айырмасы — сан емес, аралық
біріншісі мен соңғысының арасы: 45 days, 0:00:00
күн: 45
Екі күнді азайту сан емес, timedelta — аралық береді. Ол өзінше басылады, ал күн санын одан сұрайды: .days. Қасында сағат пен минут маңызды болғанда керек .seconds пен .total_seconds() тұр.
Кері жағы да жүреді: days[-1] + timedelta(days=7) — бір аптадан кейінгі күн. Санды емес, аралықты қосады: күндердің санмен қосылуы жоқ, әрі бұл дұрыс, өйткені «жеті» — бұл нешеу дегеннің жетеуі.
strptime оқиды, strftime басып шығарады
moment = datetime.strptime("01.02.2026 09:30", "%d.%m.%Y %H:%M")
print(moment.strftime("%d.%m.%Y, %H:%M"))
Есте сақтауы оңай: p — parse, мәтінді күнге талдау; f — format, күнді мәтінмен басу. Пішім — пайызы бар жол: %d — күн, %m — ай, %Y — төрт цифрлы жыл, %H:%M — сағат пен минут. Толық тізімі — құжаттамада.
Екеуі де керек, өйткені күннің екі мекенжайы бар. Файлға және API-ге күнді ISO-мен жазады — moment.isoformat() — әрі оны кез келген адам оқиды. Адамға таныс 01.02.2026 көрсетіледі.
Сыпайылықтың да тұзағы бар: %B айдың атын береді — бірақ жүйе локалі бапталмаған күні «қаңтар» емес, January болып шығады. Сондықтан файлда ISO ұсталады, ал айдың аты керек болса, оны өздері жинайды: бағдарламаның үш тілі бар, ал локаль біреу.
Екі түрлі оқылатын пішім
бөтен пішім: time data '2026-02-01' does not match format '%d.%m.%Y'
Мұнда Python дауыстап айтты: пішім келмеді. Бірақ бұл — сәтті жағдай.
Сәтсізі — 01.02.2026. Қазақстан мен Ресейде бұл — бірінші ақпан, АҚШ-та — екінші қаңтар. Екі күн де бар, екеуі де қатесіз талданады, әрі қайсысы шығатынын жол емес, сіз атаған пішім шешеді. Дұрысын атамасаңыз, қате де, ескерту де болмайды: басқа күн болады. Мұндай қатені бір айдан кейін, есеп сәйкес келмегенде табады.
Осыдан ереже шығады: файлдар мен API-де — ISO 8601, 2026-02-01. Ол бір мағыналы, жол ретінде сұрыпталады, әрі оны fromisoformat түсінеді. «Күн.ай.жыл» — экранға арналған.
Белдеусіз уақыт (naive) және белдеуі бар уақыт (aware)
белдеусіз: 2026-02-01 09:30:00 | белдеу: None
белдеуі бар: 2026-02-01 09:30:00+00:00 | белдеу: UTC
datetime-да tzinfo өрісі бар, әрі ол бос болуы мүмкін. Бос болса — бұл белдеусіз уақыт (ағылшынша naive): тоғыз жарым, ал қай жерде — белгісіз. Жетінші сабақтағы сол None, тек енді уақыт белдеуі жоқ.
Белдеусіз уақыт «бұл қай сәт» деген сұраққа жауап бермейді. Алматыдағы 9:30 бен Варшавадағы 9:30 — әртүрлі сәт, олардың арасы төрт сағат. Уақыт белдеусіз болып тұрғанда, төрт сағаттық айырма көрінбейді — ол жай ғана саналмаған.
Белдеуі бар уақыт (ағылшынша aware) өз белдеуін біледі, әрі оны аударуға болады: aware.astimezone(almaty) сол сәтті алматылық жазумен береді — 14:30. Сәт біреу, жазуы бөлек.
Осыдан біреуінен екіншісін алу әрекеті шығады:
біреуінен екіншісін алуға болмайды: can't subtract offset-naive and offset-aware datetimes
Python бас тартады — әрі бұл — оның істей алатын ең жақсы ісі. Үнсіз бес сағаттық айырма дауыстап айтылған қатеден қымбат.
Тұтас есте қалатын ереже: UTC-де сақтайды, жергіліктімен көрсетеді. datetime.now() белдеусіз жергілікті уақыт береді, datetime.now(timezone.utc) — белдеуі барын; файлға да, дерекқорға да екіншісін жазады.
Белдеу ығысу түрінде — timezone(timedelta(hours=5)) — тек «плюс бесті» біледі. Белдеу аты бойынша — zoneinfo модуліндегі ZoneInfo("Asia/Almaty") — сағат ауыстыру тарихын да біледі, ал ол әлемде ойлағаннан жиі өзгереді.
timedelta-да не жоқ
Ай мен жыл. Аралық күнмен, сағатпен, секундпен өлшенеді — әрқашан бірдей ұзындықтағы нәрсемен. «Ай» бірдей ұзындықта болмайды: ол бірде 28 күн, бірде 31.
Ай қосу дегені — алдымен 31 қаңтармен не істейтінін келісу деген сөз. Стандартты кітапхана мұндай келісімді таңбайды; бөтен кітапханалар (dateutil) оны өз ережелерімен бірге ұсынады.
Сабақ картасы
Өз сөзіңізбен айтыңыз
Қарамай, дауыстап немесе қағазға жауап беріңіз. Жауаптары — сабақтың соңында.
- Күнді неге жол күйінде қалдырмай, талдау кезінде
date-ке айналдырады? strptimestrftime-дан немен өзгеше, әрі мұны қалай есте сақтауға болады?- Белдеусіз уақыт деген не, әрі Python оны белдеуі бардан алуға неге жол бермейді?
Жаттығу
Тапсырмаға дейінгі үш қысқа қадам: болжау, толықтыру, жөндеу. Жауаптары — сабақтың соңында, бірақ алдымен өзіңіз жауап беріңіз.
1. Болжаңыз. Бұл бағдарлама не басып шығарады?
from datetime import date
a = date(2026, 3, 1)
b = date(2026, 1, 15)
print((a - b).days, a > b)
2. Бос орынды толтырыңыз. ... орнына осы жол талданатын пішімді қойыңыз.
from datetime import datetime
moment = datetime.strptime("01.02.2026 09:30", ...)
print(moment.date())
3. Жөндеңіз. Қазақстаннан келген деректер экспортында 01.02.2026 — бірінші ақпан. Бағдарлама құламайды, бірақ басқа күнді басып шығарады. Себебін табыңыз.
from datetime import datetime
day = datetime.strptime("01.02.2026", "%m.%d.%Y")
print(day.date())
Тапсырма
Міндетті. Берілгені:
rows = [
("2026-01-15", 520.0),
("2026-02-01", 546.5),
("2026-03-01", 498.0),
]
report = "02.03.2026 08:00"
Өлшеу күндерін талдап, әрқайсысын 15.01.2026: 520.0 түрінде басып шығарыңыз. Содан кейін бірінші мен соңғы өлшеудің арасында неше күн бар екенін; өлшеулер арасындағы орташа аралықты екі таңбамен; соңғысынан отыз күннен кейін болатын келесі өлшеудің күнін басыңыз. Соңында есеп сәтін күн.ай.жыл сағат:минут пішімімен талдап, оны Алматы уақыты (UTC+5) деп жариялаңыз да, екі рет басып шығарыңыз: Алматы бойынша ISO-мен және UTC-де.
Күтілетін шығу:
15.01.2026: 520.0
01.02.2026: 546.5
01.03.2026: 498.0
бірінші мен соңғының арасындағы күн: 45
орташа аралық: 22.50 күн
келесі өлшеу: 31.03.2026
Алматы бойынша есеп: 2026-03-02T08:00:00+05:00
сол UTC-де: 2026-03-02T03:00:00+00:00
Дайын болғаны: шығу жол-жолмен сәйкес келеді; күндер талдау кезінде date не datetime болады, жол болып қалмайды; орташа аралық өлшеу санына емес, аралық санына бөлінеді; есеп сәті талданған жерде белдеуін алады — әйтпесе UTC-де сол сандармен келеді.
Өз деректеріңізде. Өзіңіздің үш күніңізді алыңыз — чектер, төлемдер, үстінде саны бар кез келген нәрсе. Біріншісі мен соңғысының арасында неше күн бар екенін санап, әр күнді таныс түрде басып шығарыңыз. Біреуін бөтен пішіммен жазыңыз (15/01/2026 немесе 15 Jan 2026) да, оны өз strptime-ыңызбен талдаңыз.
Қалауыңызша.
01.02.2026-ны екі пішіммен —%d.%m.%Yжәне%m.%d.%Y— талдап, екі күнді қатар басып шығарыңыз.- Тұрақты ығысудың орнына
ZoneInfo("Asia/Almaty")алып, нәтижені салыстырыңыз. - Күнге
timedelta(months=1)қосып көріңіз де, Python не айтатынын оқыңыз.
Жобада бұл қайда тұрады
Шолуда уақыт өсі пайда болады. Өлшеулер жай сан болуын қояды: олардың арасында күн саналады, ал «қашан жиналғаны» UTC-мен жазылады — әдемі болғаны үшін емес, шолу бір күні серверге көшеді, ал оның сағаты Алматы бойынша тұрмайды.
Қарыздар. Ай қосатын нәрсе бізде әлі жоқ, ал тұрақты ығысу сағат ауыстыруды білмейді. Біріншісі келісіммен, екіншісі zoneinfo-мен шешіледі; екеуіне де шолу кесте бойынша жұмыс істей бастағанда ораламыз.
Жауаптар
Жауаптарды көрсету
Сұрақтарға
- Өйткені әрі қарай арифметика керек: айырма, аптаға жылжыту, салыстыру. Жол мұның бірін де істей алмайды, ал жолдарды салыстыру күндерді салыстырумен тек ISO-да және тек кездейсоқ сәйкес келеді.
p— parse:strptimeмәтінді оқып,datetimeжасайды.f— format:strftimedatetime-ды алып, мәтін жасайды. Біріншісі кіріске, екіншісі шығысқа керек.- Белдеусіз — бұл
tzinfo-сы босdatetime: орынсыз уақыт. Оны белдеуі бардан алуға болмайды, өйткені арасында неше сағат бары белгісіз; Python айырманы бүтін белдеуге қателесіп санаудың орнына дауыстап бас тартады.
Жаттығуға
45 True. Күндердің айырмасы —timedelta, одан.daysсұрайды; күндерді тікелей салыстыруға болады, ал 1 наурыз 15 қаңтардан кейін.
45 True
"%d.%m.%Y %H:%M". Пішім алғың келгенді емес, кіріс жолды сипаттайды: күн, нүкте, ай, нүкте, жыл, бос орын, сағат, қос нүкте, минут.
from datetime import datetime
moment = datetime.strptime("01.02.2026 09:30", "%d.%m.%Y %H:%M")
print(moment.date())
2026-02-01
- Пішім америкалық болып аталған:
%m.%d.%Y— алдымен ай. Жол оған сәйкес келді, қате болмады, әрі бірінші ақпанның орнына екінші қаңтар шықты. Күндердегі ең қымбат қате осылай көрінеді: құлау емес, басқа күн.
from datetime import datetime
day = datetime.strptime("01.02.2026", "%d.%m.%Y")
print(day.date())
2026-02-01
Пікірлер (0)
Пікір қалдыру үшін кіріңіз →
Әзірге пікір жоқ. Бірінші болыңыз.