Треки
/
Julia
Julia
/
Вправи
/
Запис на красу
Запис на красу

Запис на красу

Навчальна вправа

Вступ

«Дати й час ми вчимо малих дітей. Що в цьому складного?»

Багато програмістів припускалися цієї помилки, і подальший досвід зазвичай погано позначається на їхньому здоровʼї та щасті.

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

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

Модуль Dates

Більшість базової функціональності міститься в Dates, модулі, який входить до типової інсталяції, але не є частиною стандартної бібліотеки.

Щоб скористатися модулем, є два варіанти:

  1. Додамо import Dates, а потім додаватимемо Dates. перед усіма викликами функцій.
  2. Додамо using Dates, що вносить увесь модуль у поточний простір імен (крім кількох проблемних назв).
# option 1
julia> import Dates

julia> Dates.now()
2025-06-21T16:02:39.080

julia> now()  # wrong: need to include `Dates.` after an import
ERROR: UndefVarError: `now` not defined in `Main`


# option 2
julia> using Dates

julia> now()  # functions are now in the namespace
2025-06-21T16:03:04.161

Модуль Dates великий і складний, але він надає чотири основні типи функціональності:

  • Dates.Date, який містить день, місяць і рік, але без часу доби.
  • Dates.Time, який містить час доби, але без дати.
  • Dates.DateTime, який поєднує дату й час.
  • Dates.Period, який опрацьовує інтервали часу й дат.

Зауважмо, що DateTime зазвичай не містить інформації про часовий пояс (Python назвав би це «наївним» datetime). Один виняток - now(), який бере місцевий час із системного годинника й за потреби може перетворити його на UTC.

Мабуть, найчастіші потреби такі:

  • Розібрати вхідні дані у відповідному форматі, щоб побудувати тип із Dates.
  • Отримати з типу Dates потрібний числовий формат або рядок тексту (англ. string).
  • Застосувати зсув до значення Date, Time або DateTime.
  • Обчислити інтервал між двома такими значеннями.
  • Отримати поточну дату (за допомогою today()) та/або час (за допомогою now()).
Note

Щоб зменшити візуальне відволікання, більшість прикладів коду в решті цього документа припускає using Dates і не включає назву модуля Dates. у виклики функцій.

Формати дати й часу

Існує багато способів записувати дати й час, і вони зазвичай залежать від культури. Дати, записані самими числами, як-от «7/6/23», неоднозначні, заплутані й призводили до багатьох дорогих помилок у міжнародних організаціях (автор каже це з гіркого особистого досвіду).

Міжнародний стандарт визначено в ISO 8601, і він має дві головні переваги:

  • Розбір швидкий і однозначний.
  • Сортування легке, бо дату й час можна розглядати як звичайний текст і сортувати за алфавітом.

У попередньому прикладі ми бачили, що Date.now() повернув 2025-06-21T16:03:04.161.

Він складається з різних частин:

  • YYYY-MM-DD для частини з датою.
  • hh:mm:ss для частини з часом.
  • За бажанням, мілісекунди (або ще менша одиниця) після десяткової коми.

Інші формати рядків тексту ми обговоримо в пізнішому розділі.

Дати

Dates.Date - відносно простий тип лише для дати, який нічого не знає про час чи часові пояси.

# constructor with year, month, day arguments
julia> date1 = Date(2025, 06, 23)
2025-06-23

# constructor with ISO 8601 string
julia> date2 = Date("2025-06-23")
2025-06-23

julia> date1 == date2
true

julia> typeof(date1)
Date

Для окремих частин дати є функції доступу, і вони йдуть парами, які розрізняються регістром.

# lowercase returns an integer
julia> month(date1)
6

julia> typeof(month(date1))
Int64

# Propercase returns a Period type
julia> Month(date1)
6 months

julia> typeof(Month(date1))
Month

Функції запитів

Є чимало функцій, які дещо знають про календар. Наступний приклад показує лише кілька з них.

julia> date1
2025-06-23

julia> dayofweek(date1) # 1 = Monday, 7 = Sunday
1

julia> dayname(date1)
"Monday"

julia> daysinmonth(date1)
30

julia> isleapyear(date1)
false

julia> lastdayofmonth(date1)
2025-06-30

Час

Dates.Time - базовий тип лише для часу. Він нічого не знає про дати: час автоматично переходить до Time(0, 0, 0) опівночі.

Повний формат конструктора - Time(hour, min, sec, millisec, microsec) або його еквівалент за ISO 8601.

Усі параметри необовʼязкові й типово дорівнюють 0.

julia> Time(14, 57, 25, 142)
14:57:25.142

julia> Time("14:57:25.142")
14:57:25.142

julia> Time(14, 57, 25, 142, 32)
14:57:25.142032

Як і з Date, окремі частини доступні через функції доступу:

julia> minute(t) # => integer
57

julia> Minute(t) # => Period
57 minutes

Дати й час

Dates.DateTime поєднує більшість можливостей типів Date і Time.

julia> dt1 = DateTime(2025, 6, 23, 14, 57, 25, 142)
2025-06-23T14:57:25.142

# date1 and t were defined in previous examples
julia> dt2 = DateTime(date1, t)
2025-06-23T14:57:25.142

Параметри року, місяця й дня типово дорівнюють 1, а параметри часу - 0.

Не заплутатися в усіх цих параметрах - непросте завдання, тож для вхідних даних формат ISO може виявитися кращим.

Або ж DateTime можна побудувати з Date і Time, як у наведеному вище прикладі.

Періоди

Кожен із компонентів дати й часу має власний тип Period, від Year аж до Nanosecond, що представляє інтервал часу. Вони особливо корисні для арифметики.

julia> dt1
2025-06-23T14:57:25.142

julia> Year(21)
21 years

julia> Second(61)
61 seconds

julia> dt1 + Year(21) - Second(61)
2046-06-23T14:56:24.142

julia> Date(2025, 07, 03) - Date(2025, 04, 25)
69 days

Працюючи з типами Period, Julia намагається розумно поводитися з календарними нерівностями, як-от довжина місяця, округлюючи за потреби.

# February has fewer days than January
julia> Date(2025, 1, 31) + Month(1) 
2025-02-28

Подання рядків тексту

Раніше ми згадували стандарт ISO 8601 - типове подання дати й часу в Julia під час форматування чи розбору рядків тексту.

Очевидно, часто використовують багато інших форматів, нерідко з огляду на культурні особливості. Щоб їх опрацьовувати, у Julia є тип DateFormat, який можна побудувати з рядка формату довільної складності.

# dateformat"" string syntax
julia> dtfmt = dateformat"d/m/y"
dateformat"d/m/y"

julia> typeof(dtfmt)
DateFormat{Symbol("d/m/y"), Tuple{Dates.DatePart{'d'}, Dates.Delim{Char, 1}, Dates.DatePart{'m'}, Dates.Delim{Char, 1}, Dates.DatePart{'y'}}}

# DateFormat constructor
julia> DateFormat("d/m/y")
dateformat"d/m/y"

Наведений вище приклад дуже простий: лише дата у форматі день/місяць/рік, поширеному в Європі. Показано два варіанти синтаксису, але результат однаковий.

Тоді DateFormat можна використати для розбору будь-якого відповідного рядка тексту:

julia> DateTime("14/7/2023", dtfmt)
2023-07-14T00:00:00

Створення DateFormat повʼязане зі значними накладними витратами, тож виконати цей крок лише раз (як тут із dtfmt) корисно для швидкодії, коли ми перебираємо багато рядків тексту з датами й часом.

Формати можуть бути значно складнішими за це, тож для подробиць звернімося до посібника.

Той самий DateFormat можна також використати, щоб вивести дату й час у будь-якому бажаному форматі рядка тексту, за допомогою функції Dates.format().

На жаль, схоже, є конфлікт просторів імен із format (принаймні станом на Julia 1.11.5), тож краще додавати префікс Dates. навіть після using Dates.

julia> dt1
2025-06-23T14:57:25.142

julia> Dates.format(dt1, dateformat"e, u d")
"Mon, Jun 23"

Як задокументовано, "e, u d" дає скорочене текстове подання для дня тижня й місяця.

Текстове подання типово англійською. Можна додати інші мови, хоча нині підтримка цього не найкраща.

Вказівки

У цій вправі ми працюватимемо над планувальником зустрічей для салону краси в Нью-Йорку, який відкрився 15 вересня 2012 року.

На нас чекає пʼять завдань, і всі вони стосуються дат зустрічей. Час подано у 24-годинному форматі (без позначок AM/PM).

1. Розібрати дату зустрічі, що містить лише числа

Реалізуйте функцію schedule_appointment(), яка перетворює текстове подання дати зустрічі у відповідний формат DateTime.

Зауважте, що вхідні дані подано в американському порядку місяць/день/рік.

julia> schedule_appointment("07/25/2023 13:45:00")
2023-07-25T13:45:00

2. Перевірити, чи зустріч уже минула

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

julia> has_passed(DateTime(1999, 12, 31, 9, 0, 0))
true

3. Перевірити, чи зустріч відбудеться після обіду

Реалізуйте функцію is_afternoon_appointment(), яка приймає дату зустрічі й перевіряє, чи призначено зустріч на післяобідній час (>= 12:00 та < 18:00):

julia> is_afternoon_appointment(DateTime(2023, 3, 29, 15, 0, 0))
true

4. Описати час і дату зустрічі

Реалізуйте функцію description(), яка приймає дату зустрічі й повертає опис цієї дати й часу:

julia> describe(DateTime(2023, 3, 29, 15, 0, 0))
"You have an appointment on Wednesday, March 29, 2023 at 15:00"

5. Повернути дату річниці

Реалізуйте функцію anniversary_date(), яка повертає дату річниці цього року, а саме 15 вересня:

julia> anniversary_date()  # run during 2025
2025-09-15
Редагувати через GitHub Посилання відкривається в новому вікні або вкладці
Julia Exercism

Час розпочати Запис на красу?

Зареєструйтеся на Exercism, щоб вивчати й опановувати Julia, а також 35 концепцій128 вправ та справжнє наставництво від людей, і все це безкоштовно.