Java поддерживает создание и изменение даты и времени, используя в основном два пакета java.time и java.util. Пакет java.time был частью релиза Java 8(JSR-310), который представил новые неизменяемые классы, решающие недостатки устаревших классов java.util.Date и java.util.Calendar.
1. Устаревший API даты и времени(до Java 8)
1.1 Основные классы
Основными унаследованными классами для управления датой и временем были:
- java.util.Date : представляет определенный момент времени с точностью до миллисекунд.
- java.util.Calendar : абстрактный класс, предоставляющий методы для преобразования между экземплярами и манипулирования полями календаря различными способами.
- java.text.SimpleDateFormat : конкретный класс для форматирования и анализа дат с учетом локали и любых предопределенных, а также определенных пользователем шаблонов.
- java.util.TimeZone : представляет смещение часового пояса, а также вычисляет летнее время.
- System.currentTimeMillis() : представляет текущую дату и время в миллисекундах с 1 января 1970 года.
1.2.Вызовы
Хотя эти API очень хорошо обслуживали простые варианты использования, сообщество Java все еще постоянно жаловалось на проблемы с эффективным использованием этих классов. По этой причине многие другие сторонние библиотеки(например, Joda-Time или классы в Apache Commons ) были более популярны.
Вот некоторые из проблем:
- Класс Date должен представлять дату, но он также представляет экземпляр, который имеет часы, минуты и секунды.
- Но Date не имеет никакого связанного часового пояса. Он автоматически выбирает часовой пояс по умолчанию. Вы не можете представить дату в каком-то другом часовом поясе.
- Классы изменяемы. Так что это создает дополнительную нагрузку на разработчиков, чтобы клонировать дату перед передачей функции, что может ее изменить.
- Классы форматирования даты также не являются потокобезопасными. Экземпляр форматера не может быть использован без дополнительной синхронизации, иначе код может сломаться.
- По какой-то причине существует еще один класс java.sql.Date, который содержит информацию о часовом поясе.
- Создание даты с другим часовым поясом — очень сложная задача, которая часто приводит к некорректному результату.
- Его классы месяцами используют нулевой индекс, что на протяжении многих лет является причиной множества ошибок в приложениях.
2. Новый API даты и времени(Java 8 и более поздние версии)
Новый API даты пытается исправить вышеуказанные проблемы с устаревшими классами. Он содержит в основном следующие классы:
- java.time.LocalDate : представляет год-месяц-день в календаре ISO и полезен для представления даты без времени. Его можно использовать для представления только информации о дате, например, даты рождения или даты свадьбы.
- java.time.LocalTime : имеет дело только со временем. Полезно для представления человеческого времени суток, например, времени показа фильмов или времени открытия и закрытия местной библиотеки.
- java.time.LocalDateTime : обрабатывает как дату, так и время, без часового пояса. Это комбинация LocalDate с LocalTime.
- java.time.ZonedDateTime : объединяет класс LocalDateTime с информацией о зоне, указанной в классе ZoneId. Он представляет собой полную метку даты и времени вместе с информацией о часовом поясе.
- java.time.OffsetTime : обрабатывает время с соответствующим смещением часового пояса от Гринвича/UTC, без идентификатора часового пояса.
- java.time.OffsetDateTime : обрабатывает дату и время с соответствующим смещением часового пояса от Гринвича/UTC, без идентификатора часового пояса.
- java.time.Clock : обеспечивает доступ к текущему моменту, дате и времени в любом часовом поясе. Хотя использование класса Clock необязательно, эта функция позволяет нам тестировать ваш код для других часовых поясов или с использованием фиксированных часов, где время не меняется.
- java.time.Instant : представляет начало наносекунды на временной шкале(с EPOCH) и полезен для генерации временной метки для представления машинного времени. Момент, который происходит до эпохи, имеет отрицательное значение, а момент, который происходит после эпохи, имеет положительное значение.
- java.time.Duration : разница между двумя моментами времени, измеряемая в секундах или наносекундах, не использует конструкции на основе даты, такие как годы, месяцы и дни, хотя класс предоставляет методы, которые преобразуют в дни, часы и минуты.
- java.time.Period : для определения разницы между датами в значениях на основе дат(годы, месяцы, дни).
- java.time.ZoneId : указывает идентификатор часового пояса и предоставляет правила преобразования между Instant и LocalDateTime.
- java.time.ZoneOffset : указывает смещение часового пояса относительно времени Гринвича/UTC.
- java.time.format.DateTimeFormatter : предоставляет множество предопределенных форматировщиков, или мы можем определить свои собственные. Он предоставляет метод parse() или format() для разбора и форматирования значений даты и времени.
- TemporalAdjusters : предоставляет множество полезных встроенных корректоров для обработки повторяющихся событий.
- TemporalQuery : может использоваться в качестве цели назначения для лямбда-выражения или ссылки на метод.
- DayOfWeek : перечисление, представляющее семь дней недели — понедельник, вторник, среда, четверг, пятница, суббота и воскресенье.
3. Выполнение общих задач
В этих примерах используются новые классы, представленные в API даты и времени Java 8.
3.1. Получить текущую дату и время
Все классы даты и времени имеют фабричный метод now(), который является предпочтительным способом получения текущей даты и времени в Java 8.
LocalTime currentTime = LocalTime.now(); //13:33:43.557LocalDate currentDate = LocalDate.now(); //2020-05-03LocalDateTime currentDateTime = LocalDateTime.now(); //2020-05-03T13:33:43.557
3.2 Анализ даты и времени
Анализ даты выполняется с помощью класса DateTimeFormatter и методов parse() в классах даты и времени.
String dateString = "2020-04-08 12:30";DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");LocalDateTime parsedDateTime = LocalDateTime.parse(dateString, formatter);System.out.println(parsedDateTime); //2020-04-08T12:30
3.3 Формат даты и времени
Форматирование даты выполняется с помощью класса DateTimeFormatter и методов format() в классах даты и времени.
//Format a dateLocalDateTime myDateObj = LocalDateTime.now();DateTimeFormatter myFormatObj = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm");String formattedDate = myDateObj.format(myFormatObj);System.out.println(formattedDate); // 03-05-2020 13:46
3.4. Измерение прошедшего времени
Чтобы получить прошедшее время выполнения в разных единицах времени, используйте такие методы, как toDays(), toHours(), toMillis(), toMinutes(), toNanos() и getSeconds() из классов java.time.Instant и java.time.Duration.
Instant start = Instant.now();//Measure execution time for this methodmethodToMeasureExecutionTime();Instant finish = Instant.now();long timeElapsed = Duration.between(start, finish).toMillis(); //in millis
3.5. Рассчитайте количество дней между двумя датами
Для расчета количества дней между двумя датами в Java 8 используются методы ChronoUnit.DAYS.between() и LocalDate.until().
LocalDate date1 = LocalDate.now();LocalDate date2 = date1.plusDays(99);long diffInDays = ChronoUnit.DAYS.between(date1, date2);
4. Заключение
Целью этого руководства было познакомить вас с устаревшими классами Date/Time и проблемами, с которыми сталкиваются программисты при работе с этими API. Мы также увидели, как новые API решают существующие проблемы, используя специальные классы для представления информации о дате и времени.
Кроме того, мы кратко рассмотрели, как работать с новыми API.