Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
154 changes: 154 additions & 0 deletions lessons/java-core/034/Date and time in Java.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
# Работа с датами и временем

Работая с различными типами данных, ранее мы не касались вопросов работы с датой и временем. Тем не менее, классы для
работы с ними – одни из наиболее используемых. В рамках этого урока мы рассмотрим как устаревшие, так и современные типы
данных, предназначенных для работы с датой и временем.

## Date. Calendar

До Java 8 единственными, не касаясь внешних библиотек, способами работы с датами и временем были классы **Date** (по
сути, оберткой над временем, прошедшем с начала **UNIX-эпохи** – _с 1 января 1970 года_) и **Calendar**. Оба класса
являются изменяемыми.

Более подробно с этими классами, а также с **форматированием** строк для их представления в виде объектов указанных
классов предлагаю познакомиться в рамках
[статьи](https://javarush.com/groups/posts/1941-kak-ne-poterjatjhsja-vo-vremeni--datetime-i-calendar)

Данные классы все еще можно встретить в старых проектах, поэтому считаю необходимым иметь хотя бы общее представление о
них и методах, которые они предоставляют.

Сами классы не считаются официально устаревшими – не помечены как `@Deprecated`, однако все конструкторы `Date`, кроме
конструктора по умолчанию (формирует объект для текущих даты и времени) и принимающего время в миллисекундах – уже
устарели.

## Пакет java.time

В рамках Java 8 – очень крупного релиза, по сути, заложившего основу Java в том виде, в котором она известна сегодня,
добавились и новые механизмы для работы с датой и временем – пакет `java.time`.

Он предоставляет достаточно разнообразные инструменты. Сразу отмечу характерную особенностью рассматриваемых классов –
они неизменяемые.

Более близкое знакомство начнем с идеологического наследника класса `Date` – `Instant`. Он также хранит время, прошедшее
с начала UNIX-эпохи. Данный класс тяжело назвать популярным, но иногда с ним приходится сталкиваться. Он является
достаточно специфичным в плане работы – в отличии от классов, рассматриваемых ниже, `Instant` лишен части узких методов
по манипуляции со значением. Те же, что есть – являются более многословными, нежели у классов, рассматриваемых ниже.

Другой относительно большой блок классов представлен ниже. Их отличительной особенностью является то, что они НЕ
работают с датой и временем относительно начала UNIX-эпохи. И именно с этими классами придется сталкиваться чаще всего:

- `LocalDate`. Класс для работы с датами. В отличии от `Date` или `Instant`, хранит год, месяц и дату в отдельных
полях. Более подробно с методами можно ознакомиться в [статье](https://metanit.com/java/tutorial/12.3.php);
- `LocalTime`. Все тоже самое, только для времени. Отдельной статьи под методы этого класса у меня нет, но большинство
из них однотипны с методами `LocalDate`. Предлагаю ознакомиться с ними самостоятельно;
- `LocalDateTime`. Класс, объединяющий `LocalDate` и `LocalTime` (они представлены полями в этом классе). Имеет методы,
возвращающие объект даты или времени (`toLocalDate()` и `toLocalTime()` соответственно). Обратите внимание,
классы `LocalDate` и `LocalTime` (в меньшей степени) также имеют методы, возвращающие объект типа `LocalDateTime`. В
целом, данный класс наиболее популярен из всего пакета;
- `ZonedDateTime`. Содержит внутри себя поле типа `LocalDateTime`, а также несколько объектов, отвечающих за **timezone
** – часовой пояс. Как правило, в рамках внутренней логики используются объекты `LocalDateTime`, но общение с внешними
интерфейсами (получение и отправка дат при взаимодействии с клиентской (браузерной) частью клиент-серверного
приложения, например) происходит с помощью `ZonedDateTime`.

Также описанные классы имеют функционал (методы) для создания объектов из `Instant`. Как и `Instant` имеет методы
создания объектов на основании параметров, являющихся наследниками `Temporal` (сюда относятся и сам `Instant`, и все
описанные в данном подразделе классы). Таким образом реализуется совместимость использования двух подходов по работе с
датой и временем в рамках `java.time`.

В данной статье нет описания методов классов из `java.time`, поскольку они являются достаточно предсказуемыми на
основании названия (в отличии от некоторых методов `String`, например). Однако я настоятельно рекомендую ознакомиться с
ними самостоятельно. Обратите внимание, что объекты описанных выше классов создаются через статические методы, а не
конструкторы.

## Пакет java.time. DateTimeFormatter

Класс `DateTimeFormatter` выполняет примерно те же функции в `java.time`, что и `SimpleDateFormat` для работы с `Date`
и `Calendar`. Способ описания шаблонов также является схожим с `SimpleDateFormat`.

Для желающих ознакомиться подробнее, рекомендую обратиться к
[документации](https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html)
(там содержится и таблица обозначений для описания паттернов в `DateTimeFormatter`):

В рамках данного класса рекомендую ознакомиться с константами типа `DateTimeFormatter`, которые там представлены (в
документации выше есть примеры для них, обратите внимание), а также тремя методами:

1. `static ofPattern()`. Является перегруженным для указания локали. Возвращает объект `DateTimeFormatter` на основании
строки-паттерна, переданной параметром. Таким параметром может быть, например, _"yyyy-MM-dd HH:mm:ss"_;
2. `format()`. Возвращает строку на основании переданной параметром реализации `TemporalAccessor` (предок
интерфейса `Temporal`, который реализуют все рассмотренные в предыдущем подразделе классы `java.time`). Таким
образом, из метода мы получим строковое отражение даты и/или времени в необходимом формате.
3. `parse()`. Является противоположностью `format()` и возвращает объекты даты и/или времени (или `Temporal`, или его
наследника, если использовать перегруженный парметризованный метод) на основании переданной строки. Пример такой
строки – _"2022-12-20 19:51:00"_. Чаще всего этот метод не вызывается явно, вместо него используются статические
методы `parse()` в классах, объекты которых нужно получить. Внутри этих _static_-методов и вызывается рассматриваемый
метод.

## Вместо итога

Рассмотренная сегодня тема является, безусловно, важной и нужной. При этом она крайне проста, за исключением, возможно,
работы с форматерами. Однако я рекомендую плотно ознакомиться с методами создания, изменения, сравнения объектов даты
и/или времени, по крайней мере в рамках класса `LocalDateTime` и его составляющих. Нужные методы или однотипны, или
одноименны в различных классах, достаточно просты в запоминании, но их незнание может привести к усложнению логики без
всякой необходимости. Также рекомендую запомнить, у каких классов объекты будут изменяемы, а у каких – нет. Это тоже
несложно, но сэкономит время на исправлении простых ошибок в логике.

Безусловно, пакет `java.time` шире, чем классы, которые мы рассмотрели. Как минимум, мы не познакомились с
интерфейсом `TemporalAmount` и его наследниками (наиболее известные - `Duration` и `Period`).

Это не связано со сложностью использования остальной функциональности, скорее с тем, что необходимость в использовании
нерассмотренной части пакета возникает крайне редко. Но прежде чем изобретать собственный велосипед - всегда стоит
сначала поискать готовое решение. Поэтому при возникновении нестандартных задач в рамках данной темы рекомендую
обратиться, в первую очередь, к документации по пакету.

#### С теорией на сегодня все!

![img.png](../../../commonmedia/defaultFooter.jpg)

Переходим к практике. Не вижу особого смысла давать задачи на классы из `java.util`, поэтому задания направлены на
закрепление знаний о `java.time`. Но вы можете самостоятельно адаптировать задачи под использование `Date` и `Calendar`,
если считаете необходимым. Я не откажу в их проверке.

## Задача 1:

Реализуйте метод, возвращающий объект `LocalDateTime` на основании переданной строки. Пример входящей строки:
_20.12.2022 20:16:00_.

## Задача 2:

Реализуйте программу, выводящую в консоль сообщение, являются ли введенные с клавиатуры дата и время больше или меньше
текущего. Формат вводимых даты и времени рекомендую взять из _Задачи 1_.

## Задача 3:

Реализуйте программу, выводящую в консоль количество времени между двумя введенными с клавиатуры датами и временем в
секундах, минутах, часах, днях, месяцах и годах.

Пример ввода:

```
20.12.2022 20:16:00
28.06.1932 02:51:56
```

Пример вывода:

```
Seconds: 2855323444
Minutes: 47588724
Hours: 793145
Days: 33047
Months: 1085
Years: 90
Summary: 90 years, 5 months, 22 days, 17 hours 24 minutes 4 seconds
```

Примечание: данная задача не предполагает реализацию через наследников интерфейса `TemporalAmount`. Однако вы можете
использовать их для альтернативного решения.

> Если что-то непонятно или не получается – welcome в комменты к посту или в лс:)
>
> Канал: https://t.me/ViamSupervadetVadens
>
> Мой тг: https://t.me/ironicMotherfucker
>
> **Дорогу осилит идущий!**