1. JDK8时间日期API
在Java8以前,Java处理时间基本都是使用Date和Calendar这两个类。但是Date大部分方法已被废弃,Calendar又有很多不太友好的设计(月份从0开始)。Java8中提供了一套全新的时间处理库,源码中的目录为java.time,该包中的类都是不可变且线程安全。
主要API如下:
ZoneId: 时区ID,用来确定Instant和LocalDateTime互相转换的规则
Instant: 用来表示时间线上的一个点(瞬时)
LocalDate: 表示没有时区的只含年月日的日期, LocalDate是不可变并且线程安全的
LocalTime: 表示没有时区的只含时分秒的时间, LocalTime是不可变并且线程安全的
LocalDateTime: 表示没有时区的日期时间,同时含有年月日时分秒的日期对象, LocalDateTime是不可变并且线程安全的
Clock: 表示真实世界的时钟,可通过时钟访问当前时刻、日期、时间,用到时区。
Duration: 用秒和纳秒表示时间的数量(长短),用于计算两个日期的“时间”间隔
Period: 用于计算两个“日期”间隔
其中,LocalDate、LocalTime、LocalDateTime是新API里的基础对象,绝大多数操作都是围绕这几个对象来进行的。
2. 创建对象
2.1. 获取当前时间
@Test
public void testCurrentTime(){
LocalDate localDate = LocalDate.now();
System.out.println(localDate);
LocalTime localTime = LocalTime.now();
System.out.println(localTime);
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println(localDateTime);
}结果如下:
2022-09-05 17:23:32.168633800 2022-09-05T17:23:32.168633800
2.2. 指定具体日期时间
@Test
public void testCustomTime(){
LocalDate localDate = LocalDate.of(2022,9,5);
LocalTime localTime = LocalTime.of(17,25,52);
LocalDateTime localDateTime = LocalDateTime.of(localDate,localTime);
LocalDateTime localDateTime2 = LocalDateTime.of(2022,9,5,17,25,52);
}结果如下:
2022-09-05 17:25:52 2022-09-05T17:25:52 2022-09-05T17:25:52
3. 修改日期
3.1. 加减日期
对于LocalDate,可以加减年、月、日、周;
对于LocalTime,可以加减时、分、秒、毫秒、纳秒;
对于LocalDateTime,则可以进行任意精度的时间相加减。
@Test
public void testPlusTime(){
LocalDateTime localDateTime = LocalDateTime.now();
LocalDateTime plusYears = localDateTime.plusYears(3L);
LocalDateTime plusMonths = localDateTime.plusMonths(3L);
LocalDateTime plusDays = localDateTime.plusDays(3L);
LocalDateTime plusHours = localDateTime.plusHours(3L);
LocalDateTime plusMinutes = localDateTime.plusMinutes(3L);
LocalDateTime plusSeconds = localDateTime.plusSeconds(3L);
}结果如下:
2022-09-05T17:37:43.311506500 2025-09-05T17:37:43.311506500 2022-12-05T17:37:43.311506500 2022-09-08T17:37:43.311506500 2022-09-05T20:37:43.311506500 2022-09-05T17:40:43.311506500 2022-09-05T17:37:46.311506500
3.2. 修改为指定值
@Test
public void testUpdateTime(){
LocalDate localDate = LocalDate.now();
//指定本年的第300天
LocalDate withDayOfYear = localDate.withDayOfYear(300);
//指定本月的第20天
LocalDate withDayOfMonth = localDate.withDayOfMonth(20);
//当前时间指定月份
LocalDate withMonth = localDate.withMonth(10);
//当前时间指定年份
LocalDate withYear = localDate.withYear(2023);
}结果如下:
2022-09-07 2022-10-27 2022-09-20 2022-10-07 2023-09-07
4. 获取日期的年月日时分秒
@Test
public void testGetDateTime(){
LocalDateTime localDateTime = LocalDateTime.now();
int year = localDateTime.getYear();
Month month = localDateTime.getMonth();
int day = localDateTime.getDayOfMonth();
int hour = localDateTime.getHour();
int minute = localDateTime.getMinute();
int second = localDateTime.getSecond();
int naco = localDateTime.getNano();
int dayOfYear = localDateTime.getDayOfYear();
DayOfWeek dayOfWeek = localDateTime.getDayOfWeek();
System.out.println(year);
System.out.println(month.getValue()+":"+month);
System.out.println(day);
System.out.println(hour);
System.out.println(minute);
System.out.println(second);
System.out.println(naco);
System.out.println(dayOfYear);
System.out.println(dayOfWeek.getValue()+":"+dayOfWeek);
}结果如下:
2022 9:SEPTEMBER 7 9 14 27 226310400 250 3:WEDNESDAY
5. 比较前后
@Test
public void testBeforeAfter(){
LocalDate localDate1 = LocalDate.of(2022,9,9);
LocalDate localDate2 = LocalDate.of(2023,10,10);
System.out.println(localDate1.isEqual(localDate2));
System.out.println(localDate1.isAfter(localDate2));
System.out.println(localDate1.isBefore(localDate2));
}结果如下:
false false true
6. Period日期间隔
Period是由年月日为单位的日期间隔。
6.1. 初始化Period
ofXXX()系列方法: 根据年月日来构造持续时间
from(TemporalAmount amount):根据TemporalAmount实例创建Period对象
parse(CharSequence text):根据ISO-8601持续时间格式字符串创建Period对象
between(LocalDate startDateInclusive, LocalDate endDateExclusive):获取两个日期对象之间的持续时间。
public void testCreatePeriod(){
//根据年月日构造Period
System.out.println(Period.of(1, 2, 3));
System.out.println(Period.ofDays(1));
System.out.println(Period.ofMonths(2));
//根据周数构造
System.out.println(Period.ofWeeks(3));
System.out.println(Period.ofYears(1));
System.out.println(Period.from(Period.ofMonths(1)));
//根据ISO-8601时间格式字符串进行构造
System.out.println(Period.parse("P20Y10M5D"));
//计算两个日期对象之间的持续时间
System.out.println(Period.between(LocalDate.now().minusYears(1).minusDays(1),LocalDate.now() ));
}结果如下:
P1Y2M3D P1D P2M P21D P1Y P1M P20Y10M5D P1Y1D
6.2. 日期间隔
@Test
public void testPeriod(){
LocalDate localDate1 = LocalDate.of(2022,9,9);
LocalDate localDate2 = LocalDate.of(2023,12,15);
Period period = Period.between(localDate1,localDate2);
System.out.println("年份差:"+period.getYears());
System.out.println("月份差:"+period.getMonths());
System.out.println("日数差:"+period.getDays());
System.out.println("年份差:"+period.get(ChronoUnit.YEARS));
System.out.println("月份差:"+period.get(ChronoUnit.MONTHS));
System.out.println("日数差:"+period.get(ChronoUnit.DAYS));
System.out.println();
}结果如下:
年份差:1 月份差:3 日数差:6 年份差:1 月份差:3 日数差:6
6.3. 常用方法
getXXX(): 获取持续时间对象具体的年、月、日
plusXXX(): 给Period对象加上指定精度的值
minusXXX(): 给Period对象减去指定精度的值
withXXX(): 修改Period对象的某一精度值
@Test
public void testPeriodMethods() {
Period p = Period.of(1, 2, 3);
//重设Period的年月日
System.out.println(p.withYears(3).withMonths(2).withDays(1));
//加上1天
System.out.println(p.plusDays(1));
//减去1天
System.out.println(p.minusDays(1));
//判断是否为0
System.out.println(p.isZero());
//判断是否为负
System.out.println(p.isNegative());
//取负
System.out.println(p.negated());
}结果如下:
P3Y2M1D P1Y2M4D P1Y2M2D false false P-1Y-2M-3D
7. Duration时间间隔
Duration通常用秒或者纳秒相结合来表示一个时间量,最高精度为纳秒
通常用作表示两个时间之间的间隔,也称作持续时间。
7.1. 创建Duration实例
ofXXX()系列方法: 根据纳秒、毫秒、秒、分、时、天等时间来构造持续时间
from(TemporalAmount amount):根据TemporalAmount实例创建Duration对象
parse(CharSequence text):根据ISO-8601持续时间格式字符串创建Duration对象
between(Temporal startInclusive, Temporal endExclusive):获取两个时间对象之间的持续时间。
@Test
public void testCreateDuration(){
System.out.println(Duration.ofNanos(1000));
System.out.println(Duration.ofMillis(1000));
System.out.println(Duration.ofSeconds(30));
System.out.println(Duration.ofSeconds(30,12345));
System.out.println(Duration.ofMinutes(1));
System.out.println(Duration.ofHours(1));
System.out.println(Duration.ofDays(1));
System.out.println(Duration.of(1000, ChronoUnit.MILLIS));
System.out.println(Duration.from(ChronoUnit.MINUTES.getDuration()));
System.out.println(Duration.parse("PT20.345S"));
System.out.println(Duration.between(Instant.parse("2022-09-07T10:15:30.00Z"), Instant.now()));
}结果如下:
PT0.000001S PT1S PT30S PT30.000012345S PT1M PT1H PT24H PT1S PT1M PT20.345S PT-3H-23M-58.3512544S
7.2. 时间间隔
@Test
public void testDuration(){
LocalDateTime localDateTime1 = LocalDateTime.of(2008,4,3,8,30,0);
LocalDateTime localDateTime2 = LocalDateTime.now();
Duration duration = Duration.between(localDateTime1,localDateTime2);
System.out.println("天:"+duration.toDays());
System.out.println("时:"+duration.toHours());
System.out.println("分:"+duration.toMinutes());
System.out.println("秒:"+duration.toSeconds());
System.out.println("毫秒:"+duration.toMillis());
System.out.println("纳秒:"+duration.toNanos());
}结果如下:
天:5270 时:126481 分:7588894 秒:455333657 毫秒:455333657609 纳秒:455333657609897200
7.3. 常用方法
getXXX(): 获取持续时间对象具体的秒数或者毫秒数
plusXXX(): 给Duration对象加上指定精度的值
minusXXX(): 给Duration对象减去指定精度的值
withXXX(): 修改Duration对象的秒数or毫秒数
@Test
public void testDurationMethod(){Duration d = Duration.parse("PT20.345S");
System.out.println(d.getSeconds());
System.out.println(d.getNano());
System.out.println(d.withNanos(3456789));//修改纳秒值,返回一个新的Duration
System.out.println(d.withSeconds(22));//修改秒值,返回一个新的Duration
System.out.println(d.plusNanos(1));//加1纳秒,返回一个新的Duration
System.out.println(d.plusMillis(100));//加100毫秒,返回一个新的Duration
System.out.println(d.plusSeconds(1));
System.out.println(d.minusNanos(1));//减去1纳秒,返回一个新的Duration
System.out.println(d.minusMillis(100));//减去10毫秒,返回一个新的Duration
System.out.println(d.minusSeconds(1));
System.out.println(d.isZero());//是否为0
System.out.println(Duration.ZERO.isZero());//是否为0
System.out.println(d.isNegative());//是否为负
System.out.println(d.negated());//求负
System.out.println(d.negated().abs());//求绝对值
}结果如下:
20 345000000 PT20.003456789S PT22.345S PT20.345000001S PT20.445S PT21.345S PT20.344999999S PT20.245S PT19.345S false true false PT-20.345S PT20.345S
8. 时间戳Instant
8.1. 简介
Instant用于记录时间线上某一瞬间的时间点,顾名思义就是时间戳,但它不同于System.currentTimeMillis()精度为秒,Instant可以精确到纳秒,它的取值范围为:-1000000000-01-01T00:00Z到1000000000-12-31T23:59:59.999999999Z。
常用方法:
now(): 获取基于UTC时间的Instant
ofEpochMilli(long milli):根据时间戳(毫秒)创建一个Instant实例
ofEpochSecond(long second): 根据时间戳(秒)创建一个Instant实例
parse(): 根据时间字符串转换为Instant实例
8.2. Instant和Date关系
Instant就是java8以前的java.util.Date,两者可以互相转换。Instant表示的是时间线上的一个点,也就是时刻。Instant获取的是UTC的时间,而Date是根据当前服务器所处的环境的默认时区来获取的当前时间。
@Test
public void testInstantDate(){
System.out.println(Instant.now());
System.out.println(new Date());
}结果如下:
2022-09-07T03:27:36.049386Z Wed Sep 07 11:27:36 CST 2022
8.3. Instant和Date互相转换
相互转换过程中的时区会自动+08:00或者-08:00。 java8没有针对Instant提供一个可供自定义的格式化类,可以先转换成LocalDateTime,再使用DateTimeFormatter来完成格式化。
@Test
public void testInstance(){
Instant instant1 = Instant.now();
Date date = Date.from(instant1);
Instant instant2 = date.toInstant();
System.out.println(instant1);
System.out.println(date);
System.out.println(instant2);
}结果如下:
2022-09-07T02:19:30.821952100Z Wed Sep 07 10:19:30 CST 2022 2022-09-07T02:19:30.821Z
8.4. 计算运行时间
@Test
public void testRunTime(){
Instant instant1 = Instant.now();
for (int i = 0; i < 100000000; i++) {
}
Instant instant2 = Instant.now();
Duration duration = Duration.between(instant1,instant2);
System.out.println(duration.toNanos());
}9. 日期格式化及解析
9.1. DateTimeFormatter
@Test
public void testFormatParse(){
LocalDateTime localDateTime1 = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss SSS");
String dateTimeStr = formatter.format(localDateTime1);
LocalDateTime localDateTime2 = LocalDateTime.parse(dateTimeStr,formatter);
System.out.println(localDateTime1);
System.out.println(dateTimeStr);
System.out.println(localDateTime2);
}结果如下:
2022-09-07T10:32:31.947375600 2022-09-07 10:32:31 947 2022-09-07T10:32:31.947
9.2. long毫秒数转为日期
@Test
public void testLongFormat(){
long timeMillis = System.currentTimeMillis();
System.out.println(timeMillis);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
//String dateTime = formatter.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(timeMillis),ZoneId.of("Asia/Shanghai")));
String dateTime = formatter.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(timeMillis),ZoneId.of("GMT+8")));
System.out.println(dateTime);
}结果如下:
1662521033726 2022-09-07 11:23:53
10. Clock
Clock类提供了访问当前日期和时间的方法,某一个特定的时间点也可以使用Instant类来表示。
Clock表示一个时钟,Clock的实例用于查找当前时刻,可以使用存储的时区来解释当前时刻以查找当前日期和时间。某种程度上可以使用时钟代替System.currentTimeMillis()和TimeZone.getDefault()。
我们可以自定义创建一个指定滴答间隔的时钟,用来获取需要的时间日期。
钟表的滴答间隔(tickDuration):规定了提供下一个读数的时间间隔。比如,滴答间隔为 1 秒的钟表,读数的分辨率就到 1 秒。滴答间隔为 5 秒的钟表,读数的"分辨率" 就到 5 秒。这里,5 秒的"分辨率"是指,当实际时间数据是 0 或 1、2、3、4 秒时,从它那里得到的读数都是 0 秒。当实际时间数据是 5 或 6、7、8、9 秒时,从它那里得到的读数都是 5 秒。
@Test
public void testClock() {
Consumer consumer = System.out::println;
Clock clock = Clock.systemDefaultZone();
consumer.accept("当前时区:" + clock);
long millis = clock.millis();
consumer.accept("当前毫秒:" + millis);
Instant instant = clock.instant();
Date from = Date.from(instant);
consumer.accept("当前时间:" + from);
Supplier supplier = System::currentTimeMillis;
System.out.println(supplier.get());;
}结果如下:
当前时区:SystemClock[Asia/Shanghai] 当前毫秒:1662535519180 当前时间:Wed Sep 07 15:25:19 CST 2022 1662535519186

0条评论
点击登录参与评论