Joda-Time — це бібліотека для роботи з датами та часом в Java, створена Стівеном Коулборном як альтернатива незручним java.util.Date та java.util.Calendar. До виходу Java 8 ця бібліотека була де-факто стандартом для роботи з датами в промисловій розробці, включаючи Android-додатки. За даними Oracle Java Magazine (2023), понад 60% проектів мігрували з Joda-Time на java.time протягом двох років після виходу Android API 26.
Головне
Joda-Time — це бібліотека з відкритим кодом (Apache 2.0), яка надає якісну заміну для класів java.util.Date та java.util.Calendar у мові Java. Проект був заснований Стівеном Коулборном у 2004 році як відповідь на нумерозні проблеми стандартних API роботи з датами, включаючи мутабельність, складність форматування та обмежену підтримку часових поясів. Бібліотека отримала широке поширення в Java-спільноті та використовувалася тисячами проектів, включаючи великі enterprise-системи та Android-додатки. З моменту виходу Java 8 у 2014 році та появи пакету java.time (JSR-310) бібліотека переведена в режим підтримки — нові функції не додаються, а існуючий функціонал повністю покривається новим API.
Joda-Time побудована на принципі іммутабельності: кожен об’єкт дати або часу після створення не може бути змінений. Будь-яка операція — додавання дня, зміна місяця, встановлення часового поясу — повертає новий об’єкт, залишаючи вихідний без змін. Такий підхід повністю усунає клас помилок, пов’язаних з ненавмисною модифікацією об’єктів, які були характерні для мутабельних java.util.Date та java.util.Calendar. Immutable-дизайн також робить бібліотеку потокобезпечною без додаткової синхронізації.
Бібліотека надає кілька основних класів для різних сценаріїв: DateTime — повна дата та час з часовим поясом, LocalDate — тільки дата без часу, LocalTime — тільки час без дати, LocalDateTime — дата та час без прив’язки до поясу. Крім того, включено класи для роботи з інтервалами (Interval), періодами (Period) та тривалістю (Duration), які дозволяють обчислювати різницю між двома моментами часу в різних одиницях виміру. Кожен клас реалізує інтерфейс ReadableInstant або ReadablePartial для єдинообразного опрацювання.
Проблема стандартних API дат в Java була відома з самого появи платформи. Класи java.util.Date та java.util.Calendar мали фундаментальні недоліки: місяці нумерувалися з 0, Date одночасно представляв і дату, і час, Calendar був мутабельним та вимагав складного налаштування. Форматування через SimpleDateFormat не було потокобезпечним — в багатопотокових додатках це призводило до некоректного парсингу дат. Стівен Коулборн, працюючи над проектами з інтенсивним використанням дат, вирішив створити альтернативу, яка виправила б усі ці проблеми.
За даними інтерв’ю на InfoQ (2014), Коулборн тестував Joda-Time в промислових проектах більше року до першого публічного релізу. Перша версія вийшла у 2004 році і одразу привернула увагу спільноти. До 2010 року бібліотека стала стандартною залежністю в більшості Java-проектів, включаючи такі фреймворки, як Spring та Hibernate. Успіх Joda-Time прямо повплинав на специфікацію JSR-310 (Date and Time API), яка була включена в Java 8 — причому автором специфікації став той самий Стівен Коулборн.
Joda-Time не просто вирішила проблему дат — вона змінила підхід до проектування API в Java. Концепція іммутабельних value-об’єктів, продемонстрована бібліотекою, була прийнята як стандарт в Java 8 для всіх нових API. Більше того, популярність Joda-Time показала Oracle, що спільнота не готова миритися з неякісними стандартними бібліотеками — після Joda-Time в Java були перероблені API для роботи з файлами (NIO.2), часом (java.time) та опціональними значеннями (Optional).
Joda-Time надає набір можливостей, який до Java 8 був недоступний в стандартній бібліотеці. Основні переваги включають підтримку 200+ часових поясів з автоматичною обробкою літнього часу, багатий API форматування з патернами та локалями, а також обчислення періодів між датами в різних одиницях — роках, місяцях, днях, годинах. Окремої уваги заслужує система інтервалів: Interval (проміжок між двома моментами), Period (різниця в календарних одиницях) та Duration (точна тривалість в мілісекундах).
Клас DateTimeFormatter в Joda-Time надає потокобезпечне форматування дат — на відміну від java.text.SimpleDateFormat. Форматери можна створювати через патерни (наприклад, «yyyy-MM-dd HH:mm:ss») або через стилі (SHORT, MEDIUM, LONG, FULL) для локалізованого виведення. Бібліотека також підтримує кешування форматерів, що прискорює роботу в високонавантажених додатках. Парсинг дат з рядків виконується з контролем суворості — можна дозволити або заборонити неповні або некоректні дати.
Одна з сильних сторін Joda-Time — робота з часовими проміжками. Клас Interval представляє точний часовий відрізок між двома моментами (моментами) та підтримує операції перетину, об’єднання та перевірки входження. Period, на відміну від Interval, оперує календарними одиницями — наприклад, різниця між 1 березня та 1 квітня становить рівно 1 місяць, хоча за тривалістю це може бути 28–31 день. Duration ж представляє точну тривалість в мілісекундах без прив’язки до календаря та підходить для вимірювання часу виконання операцій.
import org.joda.time.*;
import org.joda.time.format.*;
DateTime now = new DateTime();
DateTimeFormatter fmt = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
String formatted = fmt.print(now);
DateTime nextWeek = now.plusWeeks(1);
Period period = new Period(now, nextWeek);
int days = period.getDays(); // дні = 7
Interval interval = new Interval(now, nextWeek);
boolean contains = interval.contains(now); // true
Пакет java.time (JSR-310) був розроблений тим же автором — Стівеном Коулборном — та вбрав в себе найкращі ідеї Joda-Time з урахуванням десяти років експлуатаційного досвіду. Обидва API використовують immutable-класи, підтримують часові пояси та надають багатий набір операцій. Однак java.time повністю інтегрований в стандартну бібліотеку Java, не вимагає зовнішніх залежностей та використовує більш послідовну систему назв: Instant замість ReadableInstant, LocalDate замість LocalDate (назва збережена), ZonedDateTime замість DateTime.
| Характеристика | Joda-Time | java.time |
|---|---|---|
| Рік виходу | 2004 | 2014 (Java 8) |
| Статус | Підтримка (maintenance) | Активна розробка |
| Базова дата/час | DateTime | ZonedDateTime |
| Тільки дата | LocalDate | LocalDate |
| Незмінність | Так | Так |
| Форматування | DateTimeFormatter | DateTimeFormatter |
| Різниця дат | Period / Duration | Period / Duration |
java.time виправляє кілька архітектурних рішень Joda-Time. По-перше, в java.time усунена плутанина між методами, що повертають null та відсутніми значеннями — замість цього використовуються Optional. По-друге, додана підтримка альтернативних календарних систем (японська, тайська, ісламська) через інтерфейс Chronology. По-третє, java.time включає клас Instant для роботи з моментами часу в UTC без прив’язки до календаря — це спрощує інтеграцію з мережевими протоколами та базами даних. Для Android рекомендується використовувати java.time починаючи з API 26 (Android 8.0) або через desugaring для старіших версій.
Міграція з Joda-Time на java.time — процес, який автори бібліотеки старалися зробити максимально безпечним та предбачуваним. Більшість класів мають прямі аналоги: DateTime → ZonedDateTime, LocalDate → LocalDate (назва збігається), LocalTime → LocalTime, DateTimeZone → ZoneId, Period → Period, Duration → Duration. Основні зміни стосуються способу створення об’єктів та назв методів — наприклад, замість `now.toDate()` використовується `Date.from(instant)`, а `DateTime.now()` замінюється на `ZonedDateTime.now()`.
Начати міграцію рекомендується з ізоляції Joda-Time в тонкому шарі абстракції — це дозволить замінювати бібліотеку поэтапно, не затрогуючи всю кодову базу. Першим кроком зазвичай замінюють роботу з LocalDate та LocalTime — ці класи мають найменшу кількість відмінностей між бібліотеками. Другим етапом мігрують DateTime (на ZonedDateTime) та часові пояси. На третьому етапі замінюють Interval, Period та Duration — тут потрібно уважно перевірити поведінку з урахуванням літнього часу. Після завершення міграції Joda-Time повністю видаляється з залежностей проекту.
// Joda-Time (до міграції)
val dateTime = DateTime.now(DateTimeZone.forID("Europe/Moscow"))
val formatted = dateTime.toString("dd.MM.yyyy")
val plusDay = dateTime.plusDays(1)
// java.time (після міграції)
val zonedDateTime = ZonedDateTime.now(ZoneId.of("Europe/Moscow"))
val formatted2 = zonedDateTime.format(
DateTimeFormatter.ofPattern("dd.MM.yyyy")
)
val plusDay2 = zonedDateTime.plusDays(1)
Існує кілька утиліт, що полегшують перехід з Joda-Time на java.time. OpenRewrite (by Moderne) підтримує автоматичну міграцію через рецепт org.openrewrite.java.migrate.JodaTimeToJavaTime — він замінює класи, методи та імпорти, зберігаючи логіку програми. Для Gradle-проектів плагін de.fayard.refreshVersions також містить правила міграції. Вручну міграцію найпростіше проводити з IDEA: плагін Java Time Migration Assistant підсвічує виклики Joda-Time та пропонує відповідні заміни на java.time, що прискорює процес в 2–3 рази порівняно з ручною заміною.
Розглянемо практичні приклади роботи з Joda-Time в Android-додатках. Бібліотека особливо корисна для задач форматування дат під локальні стандарти, обчислення віку користувача, визначення тривалості подій та розрахунку інтервалів між двома датами. Усі приклади використовують immutable-об’єкти — кожен виклик повертає новий екземпляр, а вихідний об’єкт залишається незмінним.
// Обчислити вік користувача
val birthDate = LocalDate.parse("1990-05-15")
val today = LocalDate.now()
val age = Years.yearsBetween(birthDate, today).getYears()
// вік == 36
// Форматувати з локаллю користувача
val dateTime = DateTime.now()
val formatter = DateTimeFormat.forStyle("MM").withLocale(Locale.getDefault())
val localized = formatter.print(dateTime)
Інтервали в Joda-Time дозволяють ефективно вирішувати завдання перевірки перетину часових відрізків, розрахунку накладень та пошуку найближчої події. Наприклад, при розробці календарного додатка можна перевірити, чи перетинається нова подія з існуючими. Клас Interval підтримує операції contains, overlaps, gap та abuts — остання показує, чи стосуються інтервали межами. Для вимірювання тривалості між двома моментами використовується Duration з точністю до мілісекунд.
// Перевірити перекриття інтервалів
Interval meeting1 = new Interval(
new DateTime(2026, 7, 21, 10, 0),
new DateTime(2026, 7, 21, 11, 0)
);
Interval meeting2 = new Interval(
new DateTime(2026, 7, 21, 10, 30),
new DateTime(2026, 7, 21, 11, 30)
);
boolean overlaps = meeting1.overlaps(meeting2); // true
Duration gap = meeting1.gap(meeting2); // null (немає прогалину)
Часто задавані питання
Joda-Time — бібліотека для роботи з датами та часом в Java, створена до виходу Java 8. Вона виправляла недоліки java.util.Date та java.util.Calendar: мутабельність, нумерацію місяців з 0, відсутність повноцінної підтримки часових поясів та потоконебезпечне форматування.
Java.time (JSR-310) — наступник Joda-Time, розроблений тим же автором. Основні відмінності: java.time вбудований в стандартну бібліотеку Java 8+, використовує більш послідовну систему назв, підтримує альтернативні календарні системи та включає клас Instant для роботи з UTC-часом.
Ні, для нових проектів рекомендується використовувати java.time. Joda-Time знаходиться в режимі підтримки з 2014 року та більше не отримує нових можливостей. Для Android з API 26+ java.time доступний нативно, а для старіших версій використовується desugaring — механізм, що дозволяє використовувати java.time на пристроях з API 19+.
Міграція виконується поэтапно: ізолюйте Joda-Time в абстракції, замініть LocalDate та LocalTime першими, потім DateTime → ZonedDateTime, і на останньому етапі — Period, Duration та Interval. Інструмент OpenRewrite підтримує автоматичну міграцію через рецепт JodaTimeToJavaTime, що прискорює процес в 2–3 рази.
DateTime → ZonedDateTime, LocalDate → LocalDate (збігається), LocalTime → LocalTime, LocalDateTime → LocalDateTime, DateTimeZone → ZoneId, Interval → відсутній прямий аналог (використовується комбінація Instant + Duration), Period → Period, Duration → Duration. Назви методів також близькі: plusDays, minusMonths, withZone доступні в обох бібліотеках.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.