До Java 8 обработку даты и времени можно было делать через Date и Calendar, потому что я давно не связывался с Java, и моя обработка даты все еще на них.Новый набор API обработки даты Давайте обсудим, чем они отличаются от предыдущих классов обработки данных, каковы преимущества нового API и как их использовать.
Эта статья будет расширяться в следующем порядке:
- Почему появился новый API для обработки дат и какие проблемы с обработкой дат были в прошлом?
- Какие оптимизации были сделаны в API даты в Java 8 и каковы новые функции?
- Использование API даты Java 8.
Проблемы с датой
Давайте сначала рассмотрим некоторые проблемы с Date.Я проверил некоторую информацию в Интернете, и все они говорят, что у Date есть проблемы с потокобезопасностью и простотой использования. Давайте сначала посмотрим, в чем проблема.
проблема безопасности потоков
Напишите программу для запуска форматирования даты в многопоточном режиме.
public static void main(String[] args) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
for(int i=0; i < 5; i++) {
new Thread(() -> {
for(;;) {
try{
System.out.println(Thread.currentThread() + ":" + simpleDateFormat.format(new Date(Math.abs(new Random().nextLong()))));
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
}).start();
}
}
Как видите, в середине работы программы сообщается об ошибке.
мы нажимаем вSimpleDateFormat
посмотреть исходный код,SimpleDateFormat
унаследовано отDateFormat
,а такжеDateFormat
внутренне содержит глобальнуюcalendar
объекта, а форматирование или синтаксический анализ даты должен работать с этим объектом. Тогда давайте посмотримformat
Исходный код этого метода.
Вы можете видеть это в строке 943, даcalendar
Назначается необходимость форматированияdate
объект, если в многопоточной среде установлен поток 1calendar
раз, но логика форматирования не доработана, тут 2-й тред снова правcalendar
При установке времени настройка потока 1 перезаписывается, затем поток 1 считывает его позжеcalendar
Время объекта вызовет ошибку. Чтобы решить эту проблему, для каждого потока можно создать только один поток.SimpleDateFormat
, изолированный от других потоков.
Точно так же дляparse
Метод, каждый раз, когда строка даты анализируется в объекты,calendar
Он очистит всю последнюю сохраненную информацию о дате и времени, а затем сохранит последнюю информацию о дате и времени, которая выйдет при многопоточности.После того, как поток 1 установит дату и время, поток 2 снова очистит их, и, наконец, программа сообщит об ошибке.
parse
Метод, наконец, вызовет следующий метод в первом114
Строка очищает информацию о дате.
Простота использования
Я считаю, что все знают сложность даты и календаря. Всего несколько примеров.
Date
месяц начинается с0
начать с11
В конце каждой операции месяц должен быть увеличен на 1, чтобы соответствовать текущему месяцу.
Если вы хотите выполнить операции с датами, добавить один день, вычесть один день, добавить один месяц, вычесть один месяц и т. д., вы можете только передатьCalendar
продолжать,Date
а такжеCalendar
Преобразование туда и обратно довольно хлопотно.
Date
Объединение даты и времени при столкновении со сценой, в которой нужно иметь дело только с датой или временем,Date
Это немного раздутый, аDate
Вывод также не очень читабелен, и не форматировать его выглядит мучительно.
API новой даты Java 8
Основываясь на вышеуказанных проблемах, дата оптимизирована в Java 8. Во-первых, дата и время спроектированы как неизменяемые типы, как и тип String, что позволяет избежать проблемы безопасности потоков, вызванной изменением даты при многопоточности. Операция над датой создаст новый объект даты, кроме того, функция доработана, работа с датой стала более удобной, а вывод более удобным для пользователя.
Давайте взглянем на некоторые часто используемые API-интерфейсы для работы с датами, которые в основном предоставляет Java 8.
Как видно из рисунка выше, Java 8 разделяет дату и время,LocalDateTime
содержит дату и время,LocalDate
Только часть даты,LocalTime
содержит только временную часть,Instant
представляет мгновенный момент времени на временной шкале, но часовой пояс по умолчаниюUTC+0
из.
public static void main(String[] args) {
System.out.println("LocalDateTime: " + LocalDateTime.now());
System.out.println("LocalDate: " + LocalDate.now());
System.out.println("LocalTime: " + LocalTime.now());
System.out.println("Instant: (UTC+0)" + Instant.now());
System.out.println("Instant: (UTC+8)" + Instant.now().atZone(ZoneId.systemDefault()));
}
LocalDateTime
,LocalDate
,LocalTime
,Instant
все сбудетсяTemporal
а такжеTemporalAdjuster
интерфейс,Temporal
Предоставляет некоторые интерфейсы для операций с датами, таких как сложение и вычитание дат,TemporalAdjuster
Предоставляет только интерфейс для настройки объектов даты/времени.
Кроме тогоLocalDateTime
Внутри просто инкапсулированLocalDate
а такжеLocalTime
, когда верноLocalDateTime
Когда операция выполняется, операция выполняется для указанной даты или времени.
Кроме тогоLocalDateTime
,LocalDate
,LocalTime
,Instant
Каждая операция имеет свой ограниченный диапазон,LocalDateTime
Может поддерживать операции даты и времени;LocalDate
Поддерживает только операции с минимальной детализацией 1 день, а неLocalDate
действовать вовремя;LocalTime
Он поддерживает операции от наносекунд до часов и не может работать с датами;Instant
Поддерживаются только операции от наносекунд до секунд. Неподдерживаемое исключение выдается, если выполняется операция за пределами указанного диапазона.
ноLocalTime
а такжеInstant
изplus
Есть специальные, которые поддерживают операции до неба, т.к.plus
Внутренне конвертируйте дни в единицы в пределах диапазона и выполняйте вычисления.
Использование нового API даты Java 8
Выше упоминалась оптимизация API даты Java 8 с точки зрения безопасности и простоты использования. Теперь давайте подытожим, как использовать часто используемый API в повседневной жизни.
здесь сLocalDate
Например,LocalDateTime
а такжеLocalTime
использование аналогично.
public static void main(String[] args) {
// 获取当天日期时间
LocalDate today = LocalDate.now();
print("获取当天日期时间: ", today);
// 加一天
LocalDate tomorrow = today.plusDays(1);
print("加一天: ", tomorrow);
// 加一个月
LocalDate nextMonth = today.plusMonths(1);
print("加一个月: ", nextMonth);
// 减一天
LocalDate yesterday = today.minusDays(1);
print("减一天: ", yesterday);
// 减一个月
LocalDate lastMonth = today.minusMonths(1);
print("减一个月: ", lastMonth);
// 获取今天是本月第几天
int dayOfMonth = today.getDayOfMonth();
print("获取今天是本月第几天: ", dayOfMonth);
// 获取今天是本周第几天
int dayOfWeek = today.getDayOfWeek().getValue();
print("获取今天是本周第几天: ", dayOfWeek);
// 获取今天是本年第几天
int dayOfYear = today.getDayOfYear();
print("获取今天是本年第几天: ", dayOfYear);
// 获取本月天数。
int daysOfMonth = today.lengthOfMonth();
print("获取本月天数: ", daysOfMonth);
// 获取本年天数
int daysOfYear = today.lengthOfYear();
print("获取本年天数: ", daysOfYear);
// 获取本月指定的第n天
LocalDate date1 = today.withDayOfMonth(15);
print("获取本月指定的第n天: ", date1);
// 获取本月的最后一天
LocalDate lastDaysOfMonth = today.with(TemporalAdjusters.lastDayOfMonth());
print("获取本月的最后一天: ", lastDaysOfMonth);
// 日期字符串解析。 严格按照ISO yyyy-MM-dd 验证
LocalDate date = LocalDate.parse("2021-01-17");
print("日期字符串解析: ", date);
// 日期字符串解析。 自定义格式
DateTimeFormatter dft = DateTimeFormatter.ofPattern("yyyy-M-dd");
LocalDate date2 = LocalDate.parse("2021-1-17", dft);
print("日期字符串解析(日期字符串解析): ", date2);
// 格式化日期
String dateStr = today.format(dft);
print("格式化日期: ", dateStr);
// 自定义日期
LocalDate cusDate = LocalDate.of(2020, 8, 14);
print("自定义日期: ", cusDate);
// 日期比较
boolean before = today.isBefore(tomorrow);
print("今天是否比明天早: ", before);
boolean before1 = today.isBefore(yesterday);
print("今天是否比昨天早: ", before1);
boolean after = today.isAfter(tomorrow);
print("今天是否比明天晚: ", after);
boolean after1 = today.isAfter(yesterday);
print("今天是否比昨天晚: ", after1);
// 获取两个时间相差多少天/周/月... 根据单位不同返回不同
long until = today.until(nextMonth, ChronoUnit.WEEKS);
print("今天到下个月相差几周: ", until);
Month month = today.getMonth();
print("月份:", month);
print("月份: ", month.getValue());
}
Как видно из вывода за последний месяц, Java 8 оптимизирует месяц в класс перечисления, а также настраивает диапазон месяцев от 1 до 12.
Продолжительность и период
Java 8 также предоставляет 2 API для вычисления разницы между двумя временами/датами.
Duration
упакованный внутриseconds
а такжеnanos
, первое - секунды, а второе - наносекунды, представляющие разницу между двумя временами;
а такжеPeriod
упакованный внутриday
,month
,years
3 атрибута, представляющих разницу между двумя периодами дат.
так,Duration
Только объекты, которые содержат время, могут быть вычислены, такие какLocalDateTime
,LocalTime
,Instant
, если вычислитьLocalDate
Если это так, будет неподдерживаемое исключение.
По аналогии,Period
который поддерживает толькоLocalDate
расчет.
Давайте посмотрим, как они используются.
Duration
public static void main(String[] args) {
LocalDateTime today = LocalDateTime.now();
LocalDateTime tomorrow = today.plusDays(1);
// 根据两个时间获取 Duration
Duration duration = Duration.between(today, tomorrow);
print("获取纳秒数差值:", duration.toNanos());
print("获取毫秒数差值:", duration.toMillis());
print("获取秒数差值: ", duration.getSeconds());
print("获取分钟数差值:", duration.toMinutes());
print("获取小时数差值:", duration.toHours());
print("获取天数差值:", duration.toDays());
// 当第1个时间比第2个时间小时为false, 反之true。可以用来判断2个时间的大小。
boolean negative = duration.isNegative();
print("isNegative: ", negative);
// 以1天的差值创建Duration
Duration duration1 = Duration.ofDays(1);
print("以1天的差值创建Duration: ", duration1.getSeconds());
}
Duration
также поддерживаетplus
а такжеminus
Операция, здесь не продемонстрированная.
Кроме тогоDuration
Существует также функция, которая может генерировать объекты путем разбора строк. Правила для строк таковы:PnDTnHnMn.nS
.P
для фиксированного запуска,n
это число,D
это количество дней,T
За представителем следует временная часть,H
,M
,S
Часы, минуты и секунды соответственно. Буквы не чувствительны к регистру, прописные или строчные. Также поддерживает+
а также-
.+
Чтобы добавить время,-
уменьшить время.
public static void main(String[] args) {
Duration duration = Duration.parse("P1DT1H1M1S");
print("当前时间加上1天1小时1分钟1秒的差值: ", duration.getSeconds());
Duration duration1 = Duration.parse("P2D");
print("当前时间加上2天的差值: ", duration1.getSeconds());
Duration duration2 = Duration.parse("PT2H");
print("当前时间加上2小时的差值: ", duration2.getSeconds());
Duration duration3 = Duration.parse("PT-2H");
print("当前时间减去2小时的差值: ", duration3.getSeconds());
Duration duration4 = Duration.parse("PT-2H30M");
print("当前时间减去1小30分的差值: ", duration4.getSeconds());
Duration duration5 = Duration.parse("PT-2H-30M");
print("当前时间减去2小30分的差值: ", duration5.getSeconds());
// 上面的也可以写成这样
Duration duration6 = Duration.parse("-PT2H30M");
print("当前时间减去2小30分的差值: ", duration6.getSeconds());
}
каждыйn
Фронт неявно добавляется+
,картина-2H30M
это значитминус 2 часа плюс 30 минут, то есть 1 час 30 минут, но еслиP
добавить один впереди-
Если это так, это повлияет на все числа в нем. На самом деле, как и в начальной школе по математике, используйте круглые скобки, чтобы поместитьPnDTnHnMn.nS
скобка, (PnDTnHnMn.nS
), добавить-
, все символы в нем перевернуты, но если вы добавите его перед одним числом, он повлияет только на себя.
Period
Period
а такжеDuration
На самом деле употребление почти одинаковое, и все они выражают разницу во времени. Просто один отображает дату, а другой — время с разной степенью детализации. Не для демонстрации.
Суммировать
Почти подведены итоги наиболее часто используемых функций и методов API обработки данных в Java 8. По сути, их очень много для повседневного использования. Этот набор API-интерфейсов для работы с датами очень удобен в использовании после выяснения их различий и логики, стоящей за ними. не говорить об этом.Использование, при разработке и использовании, проверьте документацию, и вы можете использовать ее сразу.Нижний слой эти базовые знания.