Elixir має вбудовані типи та модулі для роботи з датами, часом і часовими інтервалами. Основними модулями є Date, Time, NaiveDateTime, DateTime та Calendar.
Важливо розуміти різницю між ними. Date описує календарну дату, Time — час доби, NaiveDateTime — дату й час без інформації про часовий пояс, а DateTime — дату й час разом із часовим поясом.
У порівнянні з Java це приблизно відповідає класам LocalDate, LocalTime, LocalDateTime та ZonedDateTime з пакета java.time.
Дата за допомогою Date
Для представлення календарної дати використовується структура Date:
date = ~D[2026-08-21] date.year # 2026 date.month # 8 date.day # 21
Літерал ~D є sigil, спеціальним синтаксисом Elixir для створення дати.
Дата також може бути створена за допомогою функції Date.new/3:
{:ok, date} = Date.new(2026, 8, 21) date # ~D[2026-08-21]
Якщо передати некоректну дату, функція поверне помилку:
Date.new(2026, 2, 30) # {:error, :invalid_date}
Поточна дата
Поточну дату можна отримати за допомогою Date.utc_today/0:
date = Date.utc_today() IO.inspect(date) # ~D[2026-08-21]
Це аналогічно використанню LocalDate.now() у Java, хоча в Elixir явно вказано, що використовується UTC.
Час за допомогою Time
Тип Time використовується для представлення часу доби без дати та часового поясу:
time = ~T[14:30:00] time.hour # 14
time.minute # 30 time.second # 0
Час можна створити через Time.new/3 або Time.new/4, якщо потрібно вказати мікросекунди:
{:ok, time} = Time.new(14, 30, 15)
time # ~T[14:30:15]
Поточний час у UTC можна отримати за допомогою Time.utc_now/0:
time = Time.utc_now()
IO.inspect(time) # ~T[08:42:17.123456]
NaiveDateTime
NaiveDateTime поєднує дату та час, але не містить інформації про часовий пояс. Назва Naive якраз підкреслює, що це "наївна" дата-часова величина.
datetime = ~N[2026-08-21 14:30:00] datetime.year # 2026
datetime.month # 8
datetime.day # 21
datetime.hour # 14
Наприклад, значення ~N[2026-08-21 14:30:00] саме по собі не говорить, чи це 14:30 у Києві, Лондоні, Нью-Йорку чи іншому часовому поясі.
Приблизним аналогом у Java є LocalDateTime.
Коли використовувати NaiveDateTime
NaiveDateTime підходить тоді, коли часовий пояс не має значення. Наприклад, якщо потрібно зберегти локальний час, введений користувачем, але часовий пояс буде визначатися окремо.
meeting = ~N[2026-09-01 10:00:00]
Однак для подій, які відбуваються в конкретний момент часу у світі, наприклад для платежів, логів або моменту створення запису, зазвичай краще використовувати DateTime та UTC.
DateTime
DateTime використовується для представлення конкретної дати та часу з урахуванням часового поясу.
datetime = DateTime.utc_now() IO.inspect(datetime)
Результат може виглядати приблизно так:
~U[2026-08-21 08:45:12.123456Z]
Символ Z означає UTC.
Для створення UTC-дати можна використовувати sigil ~U:
datetime = ~U[2026-08-21 12:30:00Z]
У Java найближчим аналогом буде Instant або ZonedDateTime, залежно від того, чи потрібно зберігати лише момент часу, чи також часову зону.
Часові пояси
Одна з важливих відмінностей між NaiveDateTime і DateTime полягає саме в часовому поясі.
Наприклад, один і той самий момент часу можна представити в UTC та в часовому поясі Europe/Kyiv:
utc = ~U[2026-08-21 09:00:00Z]
DateTime.shift_zone(utc, "Europe/Kyiv") # {:ok, ~U[2026-08-21 12:00:00+03:00]}
Для роботи з часовими поясами Elixir використовує календарну інфраструктуру та часові зони. У стандартному середовищі доступні UTC та деякі базові можливості, а для повноцінної роботи з базою часових зон часто використовується бібліотека tzdata.
Додавання та віднімання часу
Для роботи з датами можна використовувати функції модуля Date:
date = ~D[2026-08-21]
Date.add(date, 10) # ~D[2026-08-31]
Date.add(date, -10) # ~D[2026-08-11]
Таким способом можна додавати або віднімати кількість днів.
Різниця між датами
Функція Date.diff/2 дозволяє отримати кількість днів між двома датами:
date1 = ~D[2026-08-21]
date2 = ~D[2026-09-01]
Date.diff(date2, date1) # 11
Результат може бути і від'ємним:
Date.diff(date1, date2) # -11
Порівняння дат
Дати є звичайними значеннями Elixir, тому їх можна порівнювати за допомогою операторів:
date1 = ~D[2026-08-21]
date2 = ~D[2026-09-01]
date1 < date2 # true
Також можна використовувати функції Date.compare/2:
Date.compare(~D[2026-08-21], ~D[2026-09-01]) # :lt
Date.compare(~D[2026-09-01], ~D[2026-08-21]) # :gt
Date.compare(~D[2026-08-21], ~D[2026-08-21]) # :eq
Робота з компонентами дати та часу
Окремі компоненти можна отримати безпосередньо з відповідних структур:
date = ~D[2026-08-21] date.year # 2026 date.month # 8 date.day # 21
Для DateTime аналогічно:
datetime = ~U[2026-08-21 12:30:45Z]
datetime.year # 2026
datetime.hour # 12
datetime.minute # 30
datetime.second # 45
Форматування дат
Elixir має функції для перетворення дат у рядки та навпаки. Для складнішого форматування часто використовують бібліотеку Timex або власне форматування.
Простий варіант — використати Calendar.strftime/2:
date = ~D[2026-08-21]
Calendar.strftime(date, "%Y-%m-%d") # "2026-08-21"
Calendar.strftime(date, "%d.%m.%Y") # "21.08.2026"
Для DateTime це працює аналогічно:
datetime = ~U[2026-08-21 12:30:45Z]
Calendar.strftime(datetime, "%Y-%m-%d %H:%M:%S") # "2026-08-21 12:30:45"
Основні символи форматування
| Формат | Значення | Приклад |
|---|---|---|
%Y | Рік | 2026 |
%m | Місяць | 08 |
%d | День | 21 |
%H | Година | 14 |
%M | Хвилина | 30 |
%S | Секунда | 45 |
%A | Повна назва дня тижня | Friday |
%B | Повна назва місяця | August |
Перетворення рядка в дату
Для перетворення рядка у структуру Date можна використовувати Date.from_iso8601/1:
Date.from_iso8601("2026-08-21") # {:ok, ~D[2026-08-21]}
Для ISO 8601 datetime можна використовувати DateTime.from_iso8601/1:
DateTime.from_iso8601("2026-08-21T12:30:00Z") # {:ok, ~U[2026-08-21 12:30:00Z], 0}
Це особливо важливо при роботі з REST API, JSON та базами даних, оскільки ISO 8601 є поширеним форматом передачі дат і часу.
Робота з часовими інтервалами
У Elixir існує структура Date.Range, яка дозволяє описувати діапазон дат:
range = Date.range(~D[2026-08-21], ~D[2026-08-25])
Enum.to_list(range) # [ # ~D[2026-08-21], # ~D[2026-08-22], # ~D[2026-08-23], # ~D[2026-08-24], # ~D[2026-08-25] # ]
Це добре поєднується з модулем Enum:
Date.range(~D[2026-08-21], ~D[2026-08-25]) |>
Enum.each(fn date -> IO.inspect(date) end)
Мікросекунди
Типи часу та datetime підтримують мікросекундну точність:
time = ~T[14:30:15.123456] time.microsecond # {123456, 6}
Другий елемент кортежу показує точність значення.
Unix timestamp
Для представлення моменту часу у вигляді Unix timestamp можна використовувати DateTime.to_unix/1:
datetime = ~U[2026-08-21 12:00:00Z]
DateTime.to_unix(datetime) # 1787313600
Зворотне перетворення виконується через DateTime.from_unix/1:
DateTime.from_unix(1787313600) # {:ok, ~U[2026-08-21 12:00:00Z]}
Який тип використовувати?
| Тип | Для чого використовувати | Приблизний аналог Java |
|---|---|---|
Date | Календарна дата без часу | LocalDate |
Time | Час доби без дати | LocalTime |
NaiveDateTime | Дата + час без часового поясу | LocalDateTime |
DateTime | Дата + час із часовою зоною | ZonedDateTime |
DateTime у UTC | Конкретний момент часу | Instant |
Date.Range | Діапазон дат | Окремого прямого аналога немає |
На що варто звернути увагу Java-розробнику
Для Java-розробника концепція роботи з датами в Elixir багато в чому знайома завдяки сучасному API java.time. Наприклад, Date приблизно відповідає LocalDate, а NaiveDateTime — LocalDateTime.
Однак важлива відмінність полягає у функціональній природі Elixir. Значення дат і часу є іммутабельними. Функція, яка змінює дату або час, не модифікує існуюче значення, а повертає нове:
date = ~D[2026-08-21] new_date = Date.add(date, 10)
IO.inspect(date) # ~D[2026-08-21]
IO.inspect(new_date) # ~D[2026-08-31]
Це відповідає загальній моделі Elixir, де дані не змінюються після створення.
Коментарі
Дописати коментар