Введение
Работа с датами и временем — одна из самых частых задач в современной разработке. Будь то логирование событий, расчет сроков, отображение календаря или интернационализация приложения, разработчику на Kotlin необходимо уметь правильно обрабатывать временные данные. В этой статье мы подробно разберем, как работать с датами и временем в Kotlin, используя современный API java.time, который доступен начиная с Java 8 и полностью совместим с Kotlin. Вы узнаете о ключевых классах, форматировании, парсинге, работе с часовыми поясами и практических примерах, которые помогут вам писать чистый и надежный код.
Основные классы для работы с датами и временем
В Kotlin, как и в Java, основная работа с датами и временем строится на пакете java.time. Этот пакет был создан для замены устаревших java.util.Date и java.util.Calendar. Он предлагает неизменяемые (immutable) и потокобезопасные классы. Рассмотрим самые важные из них.
LocalDate — дата без времени
Класс LocalDate представляет собой дату (год, месяц, день) без учета времени и часового пояса. Идеально подходит для дней рождения, праздников или дат событий.
import java.time.LocalDate
fun main() {
// Текущая дата
val today: LocalDate = LocalDate.now()
println("Сегодня: $today") // Вывод: 2025-04-11
// Конкретная дата
val specificDate: LocalDate = LocalDate.of(2025, 12, 25)
println("Рождество: $specificDate")
// Добавление дней
val nextWeek: LocalDate = today.plusDays(7)
println("Через неделю: $nextWeek")
}
LocalTime — время без даты
Если вам нужно только время (часы, минуты, секунды, наносекунды), используйте LocalTime.
import java.time.LocalTime
fun main() {
val now: LocalTime = LocalTime.now()
println("Текущее время: $now")
val meetingTime: LocalTime = LocalTime.of(14, 30)
println("Встреча в: $meetingTime")
val oneHourLater: LocalTime = now.plusHours(1)
println("Через час: $oneHourLater")
}
LocalDateTime — дата и время вместе
Это комбинация LocalDate и LocalTime. Самый популярный класс для хранения момента времени без привязки к часовому поясу.
import java.time.LocalDateTime
fun main() {
val currentDateTime: LocalDateTime = LocalDateTime.now()
println("Сейчас: $currentDateTime")
val newYear: LocalDateTime = LocalDateTime.of(2026, 1, 1, 0, 0)
println("Новый год: $newYear")
}
ZonedDateTime и Instant — работа с часовыми поясами
ZonedDateTime добавляет к LocalDateTime информацию о часовом поясе (ZoneId). Instant представляет собой момент времени в UTC (машинное время).
import java.time.ZonedDateTime
import java.time.ZoneId
import java.time.Instant
fun main() {
// Время в конкретном часовом поясе
val moscowTime: ZonedDateTime = ZonedDateTime.now(ZoneId.of("Europe/Moscow"))
println("Время в Москве: $moscowTime")
// Текущий момент в UTC
val instant: Instant = Instant.now()
println("Метка времени UTC: $instant")
}
Форматирование и парсинг дат
Для преобразования даты в строку (форматирование) и строки в дату (парсинг) используется класс DateTimeFormatter. Он позволяет задавать любые шаблоны.
Форматирование даты в строку
import java.time.LocalDate
import java.time.format.DateTimeFormatter
fun main() {
val date = LocalDate.now()
val formatter: DateTimeFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy")
val formattedDate: String = date.format(formatter)
println("Отформатированная дата: $formattedDate") // Вывод: 11.04.2025
// Другие примеры шаблонов
val formatter2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
val dateTime = LocalDateTime.now()
println(dateTime.format(formatter2))
}
Парсинг строки в дату
import java.time.LocalDate
import java.time.format.DateTimeFormatter
fun main() {
val dateString = "25.12.2025"
val formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy")
val parsedDate: LocalDate = LocalDate.parse(dateString, formatter)
println("Распарсеная дата: $parsedDate") // Вывод: 2025-12-25
}
Сравнение и вычисление разницы между датами
Kotlin поддерживает операторы сравнения для дат. Для вычисления разницы используйте классы Duration (для времени) и Period (для дат).
Сравнение дат
import java.time.LocalDate
fun main() {
val date1 = LocalDate.of(2025, 4, 11)
val date2 = LocalDate.of(2025, 12, 25)
println("date1 раньше date2? ${date1.isBefore(date2)}") // true
println("date1 позже date2? ${date1.isAfter(date2)}") // false
println("Даты равны? ${date1.isEqual(date2)}") // false
}
Разница между датами (Period)
import java.time.LocalDate
import java.time.Period
fun main() {
val start = LocalDate.of(2025, 1, 1)
val end = LocalDate.of(2025, 4, 11)
val period: Period = Period.between(start, end)
println("Прошло: ${period.years} лет, ${period.months} месяцев, ${period.days} дней")
// Вывод: Прошло: 0 лет, 3 месяцев, 10 дней
}
Разница во времени (Duration)
import java.time.Duration
import java.time.LocalTime
fun main() {
val start = LocalTime.of(9, 0)
val end = LocalTime.of(17, 30)
val duration: Duration = Duration.between(start, end)
println("Длительность рабочего дня: ${duration.toHours()} часов ${duration.toMinutes() % 60} минут")
// Вывод: Длительность рабочего дня: 8 часов 30 минут
}