# Домашнє завдання · Дати й час

> Лекція: [lecture.html](lecture.html) · Практика: [practice.ipynb](practice.ipynb) · Тест: [quiz.html](quiz.html)

Наскрізний приклад той самий, що в лекції й практиці, — **журнал замовлень крамниці**.
Формат рядка: `номер;дд.мм.рррр;гг:хх:сс`, час у журналі київський.

Правило, спільне для всіх трьох рівнів: **жодного `datetime.now()` у логіці**. Момент
«зараз» передається аргументом, усі дати в тестах зашиті числами. Інакше твій код
не можна буде перевірити двічі поспіль з тим самим результатом.

---

## 🟢 Рівень 1 — База

Напиши функцію `звіт_по_журналу(рядки)`, яка бере список рядків журналу й повертає
словник із трьома ключами:

- `"найраніше"` і `"найпізніше"` — обізнані `datetime` у поясі `Europe/Kyiv`;
- `"розмах_днів"` — ціле число повних діб між ними.

Виведи обидві крайні дати **українськими словами** («28 березня 2026, субота»),
не покладаючись на `%B` і `%A`: назви бери зі свого списку.

Візьми журнал із практики й додай до нього щонайменше три власні записи, серед яких
має бути хоча б один із **літнього** місяця й хоча б один із зимового.

**Зроблено, якщо:**
- `звіт["розмах_днів"]` дорівнює `(звіт["найпізніше"] - звіт["найраніше"]).days`;
- обидві крайні дати надруковані словами, і в них правильний день тижня
  (звір із будь-яким календарем);
- у записах із літніх місяців `utcoffset()` дорівнює `+03:00`, із зимових — `+02:00`,
  і це видно у виводі.

---

## 🟡 Рівень 2 — Плюс

Крамниця обіцяє доставку **за 3 робочі дні**. Напиши функцію
`строк_доставки(момент_замовлення, робочих_днів=3)`, яка повертає обізнаний `datetime`
— момент, коли строк спливає.

Правила, які треба закласти:

- вихідні (субота й неділя) не рахуються;
- відлік починається з **наступного** робочого дня після замовлення;
- час доби зберігається таким самим, як у момент замовлення.

Далі перевір функцію на трьох випадках і поясни результат двома реченнями кожен:
замовлення в понеділок, замовлення в пʼятницю ввечері, замовлення в суботу.

**Зроблено, якщо:**
- три `assert` з ручним підрахунком проходять — зокрема пʼятничне замовлення
  потрапляє на середу, а не на понеділок;
- функція правильно поводиться при `робочих_днів=0` (повертає той самий момент)
  і не зациклюється при від'ємному значенні — тут або виняток, або документована
  поведінка, але не мовчазне зависання;
- у всьому коді немає жодного `now()`.

---

## 🔴 Рівень 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`.
