一,旧API的问题
旧的API主要存在两个问题:
1,线程不安全
2,使用较麻烦
使用SimpleDateFormat演示线程不安全的示例:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TestSimpleDateFormat {
public static void main(String[] args) {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
ExecutorService executorService = Executors.newFixedThreadPool(10);
for(int i=0;i<100;i++){
executorService.execute(()->{
try {
Date date = format.parse("2023-03-19");
System.out.println(date);
} catch (ParseException e) {
e.printStackTrace();
}
});
}
executorService.shutdown();
}
}
运行后偶尔会报错如下:
使用LocalDate、DateTimeFormatter对上述代码进行改写之后,不再有线程安全问题:
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TestSimpleDateFormat {
public static void main(String[] args) {
DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd");
ExecutorService executorService = Executors.newFixedThreadPool(10);
for(int i=0;i<100;i++){
executorService.execute(()->{
LocalDate date = LocalDate.parse("2023-03-19",format);
System.out.println(date);
});
}
executorService.shutdown();
}
}
二,常用API介绍
日期类LocalDate 、时间类LocalTime、日期时间类LocalDateTime
时间戳类型Instant、时间差Duration和Period 使用实例
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
public class LocalTest {
public static void main(String[] args) throws InterruptedException {
LocalDate localDate = LocalDate.now();
//默认的格式是iso-8601,即yyyy-MM-dd
System.out.println("localdate=" + localDate);
LocalTime localTime = LocalTime.now();
//默认的格式是iso-8601,即HH:mm:ss.SSS
System.out.println("localTime=" + localTime);
//格式化成自定义格式
String myTime = localTime.format(DateTimeFormatter.ofPattern("HH:mm:ss"));
System.out.println("myTime=" + myTime);
LocalDateTime localDateTime = LocalDateTime.now();
//默认的格式是iso-8601,即yyyy-MM-ddTHH:mm:ss.SSS
System.out.println("localDateTime=" + localDateTime);
//格式化成自定义格式
String myDateTime = localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
System.out.println("myDateTime=" + myDateTime);
//从字符串解析出LocalDateTime
localDateTime = LocalDateTime.parse("2023-02-10 08:10:30", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
//根据指定的年月日时分秒创建LocalDateTime
localDateTime = LocalDateTime.of(2023, 3, 19, 10, 30, 15);
//对LocalDateTime做加减,可对年、月、周、日、时、分、秒、毫秒等做加减操作,
//加的方法以plus开头,减的方法以minus开头
localDateTime = localDateTime.plusDays(5);
System.out.println("执行plusDays后:"+localDateTime);
localDateTime = localDateTime.minusHours(2);
System.out.println("执行minusHours后:"+localDateTime);
//获取年、月、周、日、时、分、秒、毫秒等
System.out.println(localDateTime.getYear());
System.out.println(localDateTime.getMonthValue());
System.out.println(localDateTime.getDayOfWeek().getValue());
System.out.println(localDateTime.getDayOfMonth());
System.out.println(localDateTime.getHour());
System.out.println(localDateTime.getYear());
System.out.println(localDateTime.getSecond());
System.out.println(localDateTime.getNano());
//修改年、月、周、日、时、分、秒、毫秒等,以with开头的方法,修改后返回新的localDateTime对象
System.out.println("执行with前:"+localDateTime);
localDateTime = localDateTime.withYear(2024);//将年改为2024年
localDateTime = localDateTime.withMonth(5);//将月份改为5月
System.out.println("执行with后:"+localDateTime);
//获取当前月份第一天
localDateTime = localDateTime.with(TemporalAdjusters.firstDayOfMonth());
System.out.println("执行with后,当前月份第一天:"+localDateTime);
//获取下一个周日
localDateTime = localDateTime.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
System.out.println("执行with后,下个周日:"+localDateTime);
//自定义TemporalAdjuster实现类,将时间调整到下一个工作日
localDateTime = localDateTime.with(temporal -> {
//入参类型为Temporal,强转为子类型
LocalDateTime input = (LocalDateTime)temporal;
//获取DayOfWeek
DayOfWeek dayOfWeek = input.getDayOfWeek();
if(dayOfWeek.equals(DayOfWeek.FRIDAY)){
//入参是周五,则加3天
return input.plusDays(3);
}else if(dayOfWeek.equals(DayOfWeek.SATURDAY)){
//入参是周六,则加2天
return input.plusDays(2);
}else{
//其余加1天
return input.plusDays(1);
}
}
);
System.out.println("下一个工作日是:"+localDateTime);
Instant ins = Instant.now();
System.out.println("当前UTC时区的时间戳:"+ins);//默认获取UTC时区(0时区),即格林威治时间,比Asia/Shanghai慢8小时
System.out.println("在UTC时区基础上加8个小时:"+ins.atOffset(ZoneOffset.ofHours(8)));//加8个小时
System.out.println("toEpochMilli转为毫秒值:"+ins.toEpochMilli());//转为毫秒值
ins = Instant.ofEpochMilli(1679224886288L);//从时间戳创建Instant
System.out.println("ofEpochMilli毫秒值转Instant:"+ins);
//Duration计算两个Instant之间时差
Instant instant1 = Instant.now();
Thread.sleep(1000);
Instant instant2 = Instant.now();
Duration duration1 = Duration.between(instant1, instant2);
System.out.println("Duration有几个to开头的方法:"+duration1.toMillis());
System.out.println("Duration有几个get开头的方法:"+duration1.getSeconds());
System.out.println("Duration也有plus/minus等方法:"+duration1.plusSeconds(10).toMillis());
//Duration计算两个LocalTime之间时差
LocalTime localTime1 = LocalTime.now();
Thread.sleep(1000);
LocalTime localTime2 = LocalTime.now();
Duration duration2 = Duration.between(localTime1, localTime2);
//Duration计算两个LocalTime之间时差
LocalDateTime localDateTime1 = LocalDateTime.now();
Thread.sleep(1000);
LocalDateTime localDateTime2 = LocalDateTime.now();
Duration duration3 = Duration.between(localDateTime1, localDateTime2);
//Duration计算两个LocalDate之间时差
LocalDate localDate1 = LocalDate.of(2023,1,1);
LocalDate localDate2 = LocalDate.now();
//Duration不能计算LocalDate之间的时差,虽然语法不报错,但执行时会报错
//Duration duration4 = Duration.between(localDate1, localDate2);
Period period = Period.between(localDate1, localDate2);
System.out.println(period);//输出P2M18D, 2M表示2个月,18D表示18天,即两者之间相差2个月18天
System.out.println("LocalDate之间相差天数:"+period.getDays());
}
}
运行结果如下:
localdate=2023-03-20
localTime=00:26:33.145
myTime=00:26:33
localDateTime=2023-03-20T00:26:33.169
myDateTime=2023-03-20 00:26:33
执行plusDays后:2023-03-24T10:30:15
执行minusHours后:2023-03-24T08:30:15
2023
3
5
24
8
2023
15
0
执行with前:2023-03-24T08:30:15
执行with后:2024-05-24T08:30:15
执行with后,当前月份第一天:2024-05-01T08:30:15
执行with后,下个周日:2024-05-05T08:30:15
下一个工作日是:2024-05-06T08:30:15
当前UTC时区的时间戳:2023-03-19T16:26:33.182Z
在UTC时区基础上加8个小时:2023-03-20T00:26:33.182+08:00
toEpochMilli转为毫秒值:1679243193182
ofEpochMilli毫秒值转Instant:2023-03-19T11:21:26.288Z
Duration有几个to开头的方法:1020
Duration有几个get开头的方法:1
Duration也有plus/minus等方法:11020
P2M19D
LocalDate之间相差天数:19
Process finished with exit code 0
三,时区
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Set;
public class ZoneTest {
public static void main(String[] args) {
//获取所有时区
Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();
//availableZoneIds.forEach(System.out::println);
//创建时不指定时区,默认取系统的时区
LocalDateTime now = LocalDateTime.now();
System.out.println("本地(系统默认时区)时间:"+now);
//创建时指定时区
LocalDateTime tokyo = LocalDateTime.now(ZoneId.of("Asia/Tokyo"));
System.out.println("Asia/Tokyo时区的时间:"+tokyo);
//ZonedDateTime,默认格式会带上时区偏移量和时区名称
ZonedDateTime zonedDateTime = ZonedDateTime.now();
System.out.println("zonedDateTime="+zonedDateTime);
}
}
运行结果如下: