Работа с датой\времени осуществлялась в Java ещё со времён первой версии. Понятно, что в практике каждого разработчика встречаются случаи, когда надо производить операции с датами: формирование, разбор, учёт часовых поясов и тому подобное. Специально для этого начиная с версии 1.0 в JDK присутствует пакет java.util.Date.
Правда, в самом начале он служил не для задания дат, а момент времени с точностью до миллисекунд. Удобству вредили странные решения, например, отсчёт лет начинался с 1900 года, а месяцев с 0.
Такой подход был не самым интуитивным, в следствии чего инструментарий работы с датами постоянно совершенствовался. На смену Date пришёл класс java.util.Calendar, который, к сожалению, обладал теми же недостатками и вносил ещё больше неразберихи в том, какой из двух классов вообще надо использовать.
В конце концов, в Java 8 разработчики языка полностью пересмотрели работу с датой\временем (не в последнюю очередь потому что взяли удачные практики из сторонних библиотек, типа Joda-time) и выкатили пакет java.time. Основные классы которого мы разберём в этом разделе.
LocalDate - основной класс, который является представлением простой даты без времени и часового пояса. Создать объект можно с помощью одного из фабричных методов of. Например, создадим экземпляр LocalDate хранящий дату написания этих строк:
LocalDate date = LocalDate.of(2022, 8, 16);
У экземпляра LocalDate есть методы для чтения значений года, месяца, дня недели и т.д.
int year = date.getYear(); //2022
Month month = date.getMonth(); //August
int day = date.getDayOfMonth(); //164
DayOfWeek dow = date.getDayOfWeek(); //Tuesday (вторник)
int len = date.lenghtOfMonth(); //31 (дней в августе)
Boolean leap date.isLeapYear(); //false (год не високосный)
Данную информацию можно получить так же при помощи объектов, реализующих интерфейс TemporalField. Он описывает способ получения значения конкретного поля временного объекта. ChronoField является реализацией этого интерфейса в виде перечисляемого типа, элементы которого можно использовать в методе get у объектов LocalDate.
int year = date.get(ChronoField.YEAR);
int month = date.get(ChronoField.MONTH_OF_YEAR);
int day = date.get(ChronoField.DAY_OF_MONTH);
Текущую дату от системных часов можно получить с помощью фабричного метода now:
LocalDate today = LocalDate.now();
Аналогичные фабричные методы есть и у других классов даты\времени.
Для представлении времени дня предусмотрен класс LocalTime, у которого есть два перегруженных фабричных метода: первый принимает часы и минуты, а второй ещё и секунды. Так же у LocalTime есть геттеры, которые предоставляют доступ к значениям.
LocalTime time = LocalTime.of(16, 45, 0) //16:45:00 int hour = time.getHour(); //16
int minute = time.getMinute(); //45
int second = time.getSecond(); //0
Помимо этого для создания экземпляров даты\времени можно использовать парсинг (синтаксический разбор) соответствующих строковых значений. Для этого существует статический метод parse:
LocalDate date = LocalDate.parse("2022-08-16");
LocalTime time = LocalTime.parse("16:45:00");
В этот метод также можно передать объект типа DateTimeFormatter. Экземпляр этого класса отвечает за способ форматирования объекта даты\времени. В случае, если передаваемые строковые аргументы не являются корректным видом даты или времени метод генерирует исключение DateTimeParseException.