Наскрізний приклад той самий, що в лекції й практиці, — журнал замовлень крамниці.
Формат рядка: номер;дд.мм.рррр;гг:хх:сс, час у журналі київський.
Правило, спільне для всіх трьох рівнів: жодного datetime.now() у логіці. Момент
«зараз» передається аргументом, усі дати в тестах зашиті числами. Інакше твій код
не можна буде перевірити двічі поспіль з тим самим результатом.
рівень 1Рівень 1 — База
Напиши функцію звіт_по_журналу(рядки), яка бере список рядків журналу й повертає
словник із трьома ключами:
"найраніше"і"найпізніше"— обізнаніdatetimeу поясіEurope/Kyiv;"розмах_днів"— ціле число повних діб між ними.
Виведи обидві крайні дати українськими словами («28 березня 2026, субота»),
не покладаючись на %B і %A: назви бери зі свого списку.
Візьми журнал із практики й додай до нього щонайменше три власні записи, серед яких має бути хоча б один із літнього місяця й хоча б один із зимового.
Зроблено, якщо:
- звіт["розмах_днів"] дорівнює (звіт["найпізніше"] - звіт["найраніше"]).days;
- обидві крайні дати надруковані словами, і в них правильний день тижня
(звір із будь-яким календарем);
- у записах із літніх місяців utcoffset() дорівнює +03:00, із зимових — +02:00,
і це видно у виводі.
рівень 2Рівень 2 — Плюс
Крамниця обіцяє доставку за 3 робочі дні. Напиши функцію
строк_доставки(момент_замовлення, робочих_днів=3), яка повертає обізнаний datetime
— момент, коли строк спливає.
Правила, які треба закласти:
- вихідні (субота й неділя) не рахуються;
- відлік починається з наступного робочого дня після замовлення;
- час доби зберігається таким самим, як у момент замовлення.
Далі перевір функцію на трьох випадках і поясни результат двома реченнями кожен: замовлення в понеділок, замовлення в пʼятницю ввечері, замовлення в суботу.
Зроблено, якщо:
- три assert з ручним підрахунком проходять — зокрема пʼятничне замовлення
потрапляє на середу, а не на понеділок;
- функція правильно поводиться при робочих_днів=0 (повертає той самий момент)
і не зациклюється при від'ємному значенні — тут або виняток, або документована
поведінка, але не мовчазне зависання;
- у всьому коді немає жодного now().
рівень 3Рівень 3 — Виклик
Знайди всі переходи на літній час у поясі Europe/Kyiv за 2015–2035 роки,
не заглядаючи в жодні довідники й не зашиваючи дат руками. Єдине джерело правди —
utcoffset(): перебирай моменти в UTC і лови зміну зміщення.
Для кожного переходу надрукуй рядком: дату, місцевий час до й після стрибка, напрямок (уперед чи назад) і довжину тієї місцевої доби в годинах.
Потім поясни в коментарі, чому довжину доби не можна порахувати як
(північ_наступного_дня - північ), якщо обидві опівночі лишити в київському поясі,
і як це виправляє переведення в UTC.
Зроблено, якщо:
- знайдено рівно 42 переходи — по два на кожен із 21 року;
- усі весняні доби мають 23 години, усі осінні — 25, і це підтверджено assert-ом
на всьому наборі, а не на одному прикладі;
- перебір іде по годинах у UTC (не по місцевому часу) — інакше неіснуючу годину
ти просто не зможеш побачити;
- у розвʼязку немає жодної зашитої дати переходу.
Підказки
- Перебирати рік по годинах зручно так: почни з
datetime(рік, 1, 1, tzinfo=timezone.utc)і додавайtimedelta(hours=1), щоразу дивлячись на.astimezone(київ).utcoffset(). Зміна цього значення між сусідніми годинами і є переходом. - Довжина місцевої доби — це різниця двох опівночей, переведених у UTC:
(північ_завтра.astimezone(utc) - північ_сьогодні.astimezone(utc)). Без переведення отримаєш настінну відповідь «рівно 24 години» завжди. date.weekday()дає 0 для понеділка й 6 для неділі; будні — це< 5.- Для «наступного робочого дня» природно напрошується цикл
while, який додає по одному дню й пропускає вихідні. Це не найшвидший спосіб, зате його прочитає й перевірить руками будь-хто — а на трьох днях швидкість не має значення. - Якщо
ZoneInfo("Europe/Kyiv")кидаєZoneInfoNotFoundError(типово для Windows), постав базу поясів:pip install tzdata.