Введение в работу с датами и временем в Java
Работа с датами и временем — одна из ключевых задач в разработке любого приложения. Будь то логирование событий, расчёт сроков доставки, работа с расписанием или анализ данных — без понимания того, как Java управляет временными объектами, не обойтись. В этой статье мы разберём все основные аспекты: от старого API (Date и Calendar) до современного пакета java.time (Java 8+). Вы узнаете, как создавать, форматировать, сравнивать и вычислять разницу между датами.
1. Старый API: Date и Calendar
До Java 8 основными классами для работы с датами были java.util.Date и java.util.Calendar. Они до сих пор встречаются в легаси-коде, поэтому важно понимать их базовые возможности и ограничения.
1.1 Класс Date
Date представляет конкретный момент времени с точностью до миллисекунды. Однако у него много недостатков: он мутабельный (небезопасен в многопоточных приложениях) и плохо поддерживает интернационализацию.
import java.util.Date;
public class DateExample {
public static void main(String[] args) {
// Текущая дата и время
Date now = new Date();
System.out.println("Текущая дата: " + now);
// Устаревший способ получения года (1900 + ...)
int year = now.getYear() + 1900;
System.out.println("Год: " + year);
}
}
1.2 Класс Calendar
Calendar — более гибкий, но громоздкий класс. Позволяет манипулировать отдельными компонентами даты (год, месяц, день).
import java.util.Calendar;
public class CalendarExample {
public static void main(String[] args) {
Calendar cal = Calendar.getInstance();
System.out.println("Текущее время: " + cal.getTime());
// Установка конкретной даты
cal.set(2025, Calendar.MARCH, 15);
System.out.println("Установленная дата: " + cal.getTime());
// Добавление 7 дней
cal.add(Calendar.DAY_OF_MONTH, 7);
System.out.println("Через неделю: " + cal.getTime());
}
}
Недостатки: нумерация месяцев с 0 (январь = 0), мутабельность, отсутствие простого форматирования.
2. Новый API: java.time (Java 8+)
Начиная с Java 8, в стандартную библиотеку был добавлен пакет java.time, основанный на идеях библиотеки Joda-Time. Он состоит из неизменяемых (immutable) классов, что делает код безопасным и предсказуемым.
2.1 LocalDate — только дата
LocalDate представляет дату без времени (год, месяц, день). Идеально подходит для дней рождения, календарей.
import java.time.LocalDate;
import java.time.Month;
public class LocalDateExample {
public static void main(String[] args) {
// Текущая дата
LocalDate today = LocalDate.now();
System.out.println("Сегодня: " + today);
// Конкретная дата
LocalDate specificDate = LocalDate.of(2025, Month.DECEMBER, 31);
System.out.println("Новый год: " + specificDate);
// Прибавление/вычитание дней
LocalDate nextWeek = today.plusDays(7);
System.out.println("Через неделю: " + nextWeek);
}
}
2.2 LocalTime — только время
LocalTime хранит время (часы, минуты, секунды, наносекунды) без привязки к дате.
import java.time.LocalTime;
public class LocalTimeExample {
public static void main(String[] args) {
LocalTime now = LocalTime.now();
System.out.println("Текущее время: " + now);
LocalTime meeting = LocalTime.of(14, 30);
System.out.println("Встреча в: " + meeting);
// Сравнение времени
if (now.isAfter(meeting)) {
System.out.println("Встреча уже прошла");
}
}
}
2.3 LocalDateTime — дата и время вместе
LocalDateTime объединяет дату и время. Самый популярный класс для хранения момента времени.
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class LocalDateTimeExample {
public static void main(String[] args) {
LocalDateTime now = LocalDateTime.now();
System.out.println("Сейчас: " + now);
// Создание конкретного момента
LocalDateTime newYear = LocalDateTime.of(2026, 1, 1, 0, 0);
System.out.println("Новый год 2026: " + newYear);
// Форматирование вывода
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss");
String formatted = now.format(formatter);
System.out.println("Форматированная дата: " + formatted);
}
}
3. Форматирование и парсинг дат
Работа с пользовательским вводом и выводом требует умения преобразовывать строки в даты и обратно.
3.1 DateTimeFormatter
Основной класс для форматирования в новом API. Поддерживает стандартные и пользовательские шаблоны.
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
public class FormattingExample {
public static void main(String[] args) {
LocalDate date = LocalDate.now();
// Стандартные форматы
DateTimeFormatter iso = DateTimeFormatter.ISO_LOCAL_DATE;
System.out.println("ISO: " + date.format(iso));
// Пользовательский формат
DateTimeFormatter custom = DateTimeFormatter.ofPattern("dd/MM/yyyy");
System.out.println("Пользовательский: " + date.format(custom));
// Парсинг строки в дату
String dateStr = "15-03-2025";
DateTimeFormatter parser = DateTimeFormatter.ofPattern("dd-MM-yyyy");
LocalDate parsed = LocalDate.parse(dateStr, parser);
System.out.println("Распарсено: " + parsed);
}
}
3.2 SimpleDateFormat (старый способ)
Для легаси-кода может пригодиться java.text.SimpleDateFormat. Однако он не потокобезопасен.
import java.text.SimpleDateFormat;
import java.util.Date;
public class SimpleDateFormatExample {
public static void main(String[] args) {
Date now = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("Форматирование: " + sdf.format(now));
}
}
4. Разница между датами: Duration и Period
Часто требуется вычислить интервал между двумя датами или временами. Для этого существуют два класса:
- Duration — для разницы во времени (секу