Рубрики
Без рубрики

Введение в API даты и времени Java 8

В этой статье мы рассмотрим новые API Java 8 для определения даты и времени, а также насколько проще создавать и манипулировать датами и временем.

Автор оригинала: baeldung.

1. Обзор

Java 8 представила новые API для Даты и времени для устранения недостатков более старых java.util.Дата и java.util.Календарь .

В рамках этой статьи давайте начнем с проблем в существующих Date и Calendar API и обсудим, как новые API Java 8 Date и Time решают их.

Мы также рассмотрим некоторые основные классы нового проекта Java 8, которые являются частью пакета java.time , например LocalDate , LocalDateTime, LocalDateTime, ZonedDateTime, Period, Duration и их поддерживаемые API.

Дальнейшее чтение:

Работа с параметрами даты весной

Проверьте, является ли строка Допустимой датой в Java

2. Проблемы с существующими API-интерфейсами даты и времени

  • Потокобезопасность – Классы Дата и Календарь не являются потокобезопасными, оставляя разработчикам решать головную боль, связанную с трудными проблемами отладки параллелизма и написанием дополнительного кода для обработки потокобезопасности. Напротив, новые API Date и Time , представленные в Java 8, являются неизменяемыми и потокобезопасными, что избавляет разработчиков от головной боли параллелизма.
  • Дизайн API и простота понимания – API Дата и Календарь плохо разработаны с неадекватными методами для выполнения повседневных операций. Новый API Date/Time является изоцентрическим и следует согласованным моделям домена для даты, времени, продолжительности и периодов. Существует большое разнообразие полезных методов, которые поддерживают самые распространенные операции.
  • ZonedDate и Time – Разработчикам пришлось написать дополнительную логику для обработки логики часового пояса со старыми API, в то время как с новыми API обработка часового пояса может выполняться с помощью Local и ZonedDate /| Time API.

3. Использование LocalDate, LocalTime и LocalDateTime

Наиболее часто используемыми классами являются LocalDate , LocalTime и LocalDateTime . Как следует из их названий, они представляют локальную дату/время из контекста наблюдателя.

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

3.1. Работа С LocalDate

Локальная дата представляет дату в формате ISO (гггг-ММ-дд) без времени .

Его можно использовать для хранения дат, таких как дни рождения и дни выплаты жалованья.

Экземпляр текущей даты может быть создан из системных часов, как показано ниже:

LocalDate localDate = LocalDate.now();

Локальные данные , представляющие конкретный день, месяц и год, могут быть получены с помощью метода ” of “или с помощью метода” parse “. Например, приведенные ниже фрагменты кода представляют Локальные данные за 20 февраля 2015 года:

LocalDate.of(2015, 02, 20);

LocalDate.parse("2015-02-20");

Local Date предоставляет различные служебные методы для получения разнообразной информации. Давайте быстро взглянем на некоторые из этих методов API.

Следующий фрагмент кода получает текущую локальную дату и добавляет один день:

LocalDate tomorrow = LocalDate.now().plusDays(1);

В этом примере получается текущая дата и вычитается один месяц. Обратите внимание, как он принимает перечисление в качестве единицы времени:

LocalDate previousMonthSameDay = LocalDate.now().minus(1, ChronoUnit.MONTHS);

В следующих двух примерах кода мы анализируем дату “2016-06-12” и получаем день недели и день месяца соответственно. Обратите внимание на возвращаемые значения, первое-это объект, представляющий DayOfWeek , а второе-в int , представляющее порядковое значение месяца:

DayOfWeek sunday = LocalDate.parse("2016-06-12").getDayOfWeek();

int twelve = LocalDate.parse("2016-06-12").getDayOfMonth();

Мы можем проверить, происходит ли дата в високосный год. В этом примере мы проверяем, является ли текущая дата високосным годом:

boolean leapYear = LocalDate.now().isLeapYear();

Связь одной даты с другой может быть определена до или после другой даты:

boolean notBefore = LocalDate.parse("2016-06-12")
  .isBefore(LocalDate.parse("2016-06-11"));

boolean isAfter = LocalDate.parse("2016-06-12")
  .isAfter(LocalDate.parse("2016-06-11"));

Границы дат могут быть получены с заданной даты. В следующих двух примерах мы получаем LocalDateTime , представляющий начало дня (2016-06-12T00:00) данной даты, и LocalDate , представляющий начало месяца (2016-06-01) соответственно:

LocalDateTime beginningOfDay = LocalDate.parse("2016-06-12").atStartOfDay();
LocalDate firstDayOfMonth = LocalDate.parse("2016-06-12")
  .with(TemporalAdjusters.firstDayOfMonth());

Теперь давайте посмотрим, как мы работаем с местным временем.

3.2. Работа С Местным Временем

Местное время представляет время без даты .

Аналогично Local Data экземпляр LocalTime может быть создан из системных часов или с помощью методов “parse” и “of”. Быстрый взгляд на некоторые из часто используемых API ниже.

Экземпляр текущего Местного времени может быть создан из системных часов, как показано ниже:

LocalTime now = LocalTime.now();

В приведенном ниже примере кода , мы создаем Местное время , представляющее 06:30 утра, путем анализа строкового представления:

LocalTime sixThirty = LocalTime.parse("06:30");

Фабричный метод “of” можно использовать для создания Местного времени . Например, приведенный ниже код создает Местное время , представляющее 06:30 утра, используя заводской метод:

LocalTime sixThirty = LocalTime.of(6, 30);

В приведенном ниже примере создается Местное время путем анализа строки и добавляется к ней час с помощью API “плюс”. Результатом будет Местное время , представляющее 07:30 утра:

LocalTime sevenThirty = LocalTime.parse("06:30").plus(1, ChronoUnit.HOURS);

Доступны различные методы получения, которые можно использовать для получения определенных единиц времени, таких как час, минута и сек, как показано ниже:

int six = LocalTime.parse("06:30").getHour();

Мы также можем проверить, является ли определенное время до или после другого определенного времени. Приведенный ниже пример кода сравнивает два Местное время , для которых результат будет истинным:

boolean isbefore = LocalTime.parse("06:30").isBefore(LocalTime.parse("07:30"));

Максимальное, минимальное и полуденное время суток можно получить с помощью констант в классе LocalTime . Это очень полезно при выполнении запросов к базе данных для поиска записей в течение заданного промежутка времени. Например, приведенный ниже код представляет 23:59:59.99:

LocalTime maxTime = LocalTime.MAX

Теперь давайте погрузимся в LocalDateTime .

3.3. Работа С LocalDateTime

LocalDateTime используется для представления комбинации даты и времени .

Это наиболее часто используемый класс, когда нам нужна комбинация даты и времени. Класс предлагает множество API, и мы рассмотрим некоторые из наиболее часто используемых.

Экземпляр LocalDateTime может быть получен из системных часов, аналогичных LocalDate и LocalTime:

LocalDateTime.now();

В приведенных ниже примерах кода объясняется, как создать экземпляр с помощью методов factory “of” и “parse”. Результатом будет экземпляр LocalDateTime , представляющий 20 февраля 2015 года, 06:30 утра:

LocalDateTime.of(2015, Month.FEBRUARY, 20, 06, 30);
LocalDateTime.parse("2015-02-20T06:30:00");

Существуют служебные API для поддержки сложения и вычитания определенных единиц времени, таких как дни, месяцы, год и минуты. Приведенные ниже примеры кода демонстрируют использование методов “плюс” и “минус”. Эти API ведут себя точно так же, как их аналоги в LocalDate и LocalTime:

localDateTime.plusDays(1);
localDateTime.minusHours(2);

Методы геттера доступны для извлечения определенных единиц измерения, аналогичных классам даты и времени. Учитывая приведенный выше экземпляр LocalDateTime , приведенный ниже пример кода вернет месяц февраль:

localDateTime.getMonth();

4. Использование API ZonedDateTime

Java 8 предоставляет ZonedDateTime , когда нам нужно иметь дело с конкретной датой и временем часового пояса. ZoneId – это идентификатор, используемый для представления различных зон. Существует около 40 различных часовых поясов, и ZoneId используется для их представления следующим образом.

В этом фрагменте кода мы создаем Зону для Парижа:

ZoneId zoneId = ZoneId.of("Europe/Paris");

Набор всех идентификаторов зон можно получить следующим образом:

Set allZoneIds = ZoneId.getAvailableZoneIds();

LocalDateTime может быть преобразован в определенную зону:

ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, zoneId);

Метод ZonedDateTime предоставляет метод parse для получения конкретной даты часового пояса:

ZonedDateTime.parse("2015-05-03T10:15:30+01:00[Europe/Paris]");

Другой способ работы с часовым поясом-использовать OffsetDateTime . OffsetDateTime – это неизменяемое представление даты-времени со смещением. Этот класс хранит все поля даты и времени с точностью до наносекунд, а также смещение от UTC/Гринвича.

Экземпляр OffsetDateTime можно создать, как показано ниже, с помощью Zone Offset . Здесь мы создаем LocalDateTime , представляющий 6:30 утра 20 февраля 2015 года:

LocalDateTime localDateTime = LocalDateTime.of(2015, Month.FEBRUARY, 20, 06, 30);

Затем мы добавим два часа к этому времени, создав смещение зоны и установив для экземпляра LocalDateTime :

ZoneOffset offset = ZoneOffset.of("+02:00");

OffsetDateTime offSetByTwo = OffsetDateTime
  .of(localDateTime, offset);

Теперь у нас есть LocalDateTime 2015-02-20 06:30 +02:00. Теперь давайте перейдем к тому, как изменить значения даты и времени с помощью классов Period и Duration .

5. Использование периода и продолжительности

Класс Period представляет количество времени в годах, месяцах и днях, а класс Duration представляет количество времени в секундах и наносекундах.

5.1. Работа С Периодом

Класс Period широко используется для изменения значений заданной даты или для получения разницы между двумя датами:

LocalDate initialDate = LocalDate.parse("2007-05-10");

Датой можно управлять с помощью Периода , как показано в следующем фрагменте кода:

LocalDate finalDate = initialDate.plus(Period.ofDays(5));

Класс Period имеет различные методы получения, такие как getyear, getmonth и getday для получения значений из объекта Period . Приведенный ниже пример кода возвращает int значение 5, поскольку мы пытаемся получить разницу в днях :

int five = Period.between(initialDate, finalDate).getDays();

Период между двумя датами может быть получен в определенной единице, такой как дни, месяц или годы, с помощью ChronoUnit.between:

long five = ChronoUnit.DAYS.between(initialDate, finalDate);

Этот пример кода возвращает пять дней. Давайте продолжим, взглянув на класс Duration .

5.2. Работа С Длительностью

Подобно Period, класс Duration используется для работы с Time. В следующем коде мы создаем Местное время 6:30 утра, а затем добавляем продолжительность 30 секунд, чтобы сделать Местное время 06:30:30 утра:

LocalTime initialTime = LocalTime.of(6, 30, 0);

LocalTime finalTime = initialTime.plus(Duration.ofSeconds(30));

Длительность между двумя моментами может быть получена либо как Длительность , либо как определенная единица измерения. В первом фрагменте кода мы используем метод between() класса Duration , чтобы найти разницу во времени между final Time и initialTime и вернуть разницу в секундах:

long thirty = Duration.between(initialTime, finalTime).getSeconds();

Во втором примере мы используем метод between() класса ChronoUnit для выполнения той же операции:

long thirty = ChronoUnit.SECONDS.between(initialTime, finalTime);

Теперь мы рассмотрим, как преобразовать существующую Дату и Календарь в новую Дату Время.

6. Совместимость с датой и календарем

Java 8 добавила их в метод Instant () , который помогает преобразовать существующие Данные и Календарь экземпляр в новый API даты и времени, как показано в следующем фрагменте кода:

LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
LocalDateTime.ofInstant(calendar.toInstant(), ZoneId.systemDefault());

LocalDateTime может быть построен из секунд эпохи, как показано ниже. Результатом приведенного ниже кода будет LocalDateTime , представляющий 2016-06-13T11:34:50:

LocalDateTime.ofEpochSecond(1465817690, 0, ZoneOffset.UTC);

Теперь перейдем к Дате и времени форматированию.

7. Форматирование даты и времени

Java 8 предоставляет API для удобного форматирования Даты и времени :

LocalDateTime localDateTime = LocalDateTime.of(2015, Month.JANUARY, 25, 6, 30);

Приведенный ниже код передает формат даты ISO для форматирования локальной даты. Результат будет 2015-01-25:

String localDateString = localDateTime.format(DateTimeFormatter.ISO_DATE);

DateTimeFormatter предоставляет различные стандартные параметры форматирования. Пользовательские шаблоны также могут быть предоставлены для метода форматирования, как показано ниже, который вернет Локальную дату как 2015/01/25:

localDateTime.format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));

Мы можем передать стиль форматирования как SHORT , LONG или MEDIUM как часть опции форматирования. Приведенный ниже пример кода даст вывод, представляющий LocalDateTime в 25-Jan-2015, 06:30:00:

localDateTime
  .format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM))
  .withLocale(Locale.UK);

Давайте рассмотрим альтернативы, доступные для Java 8 Core Date |/Time |/API.

8. Backport и альтернативные варианты

8.1. Использование проектной информации

Для организаций, которые находятся на пути перехода на Java 8 с Java 7 или Java 6 и хотят использовать API даты и времени, project threeten предоставляет возможность обратного порта. Разработчики могут использовать классы, доступные в этом проекте, для достижения той же функциональности, что и в новом Java 8 Date и Time API, и как только они перейдут на Java 8, пакеты могут быть переключены. Артефакт для проекта можно найти в центральном репозитории maven :


    org.threeten
    threetenbp
    1.3.1

8.2. Библиотека Joda-Time

Другой альтернативой для Java 8 Date и Time library является Joda-Time library. На самом деле Java 8 Date Time API был совместно разработан автором библиотеки Joda-Time (Стивен Коулборн) и Oracle. Эта библиотека предоставляет практически все возможности, которые поддерживаются в Java 8 Date Time project. Артефакт можно найти в maven central , включив в свой проект приведенную ниже зависимость pom:


    joda-time
    joda-time
    2.9.4

9. Заключение

Java 8 предоставляет богатый набор API с согласованным дизайном API для облегчения разработки.

Примеры кода для приведенной выше статьи можно найти в репозитории Java 8 Date/Time git.