Java8新版本时间、日期处理
发布日期:2021-11-04 11:54:25 浏览次数:0 分类:技术文章

目录


一、java.time.LocalDateTime

1.1 基本使用

public static void main(String[] args){    LocalDate d = LocalDate.now();          // 当前日期    LocalTime t = LocalTime.now();          // 当前时间    LocalDateTime dt = LocalDateTime.now(); // 当前日期和时间    System.out.println(d);  // 严格按照ISO 8601格式打印    System.out.println(t);  // 严格按照ISO 8601格式打印    System.out.println(dt); // 严格按照ISO 8601格式打印    System.out.println("-----------------------");    LocalDateTime pdt = LocalDateTime.parse("2019-11-19T15:16:17");    LocalDate pd = LocalDate.parse("2019-11-19");    LocalTime pt = LocalTime.parse("15:16:17");    System.out.println(pdt);    System.out.println(pd);    System.out.println(pt);}

测试输出:

2019-10-29
11:54:32.796
2019-10-29T11:54:32.796
-----------------------
2019-11-19T15:16:17
2019-11-19
15:16:17


从上述的测试可以发现:

1.LocalDateTimeLocalDateLocalTime默认严格按照规定的日期和时间格式进行打印。

ISO 8601规定的日期和时间分隔符是T。标准格式如下:

  • 日期:yyyy-MM-dd
  • 时间:HH:mm:ss
  • 带毫秒的时间:HH:mm:ss.SSS
  • 日期和时间:yyyy-MM-dd'T'HH:mm:ss
  • 带毫秒的日期和时间:yyyy-MM-dd'T'HH:mm:ss.SSS

2. 通过指定的日期和时间创建LocalDateTime可以通过of()方法,of()方法有许多重载方式。

// 指定日期和时间:LocalDate d2 = LocalDate.of(2019, 11, 30); // 2019-11-30, 注意11=11月LocalTime t2 = LocalTime.of(15, 16, 17); // 15:16:17LocalDateTime dt2 = LocalDateTime.of(2019, 11, 30, 15, 16, 17);LocalDateTime dt3 = LocalDateTime.of(d2, t2);

 3. 可以直接将标准格式的字符串传入LocalDateTime,调用parse()方法就可以直接解析。

 

1.2 加减调整

LocalDateTime提供了对日期和时间进行加减和指定调整的的非常简单的链式调用:

public static void main(String[] args){    LocalDateTime dt = LocalDateTime.of(2019, 10, 26, 20, 30, 59);    System.out.println("dt = " + dt);                // 加6天减3小时:    LocalDateTime dt2 = dt.plusDays(6).minusHours(3);    System.out.println("dt2 = " + dt2); // 2019-11-01T17:30:59    // 减1月:    LocalDateTime dt3 = dt.minusMonths(1);    System.out.println("dt3 = " + dt3); // 2019-09-26T20:30:59    // 日期变为31日:    LocalDateTime dt4 = dt.withDayOfMonth(31);    System.out.println("dt4 = " + dt4); // 2019-10-31T20:30:59                // 月份变为9:    LocalDateTime dt5 = dt.withMonth(9);    System.out.println("dt5 = " + dt5); // 2019-09-26T20:30:59}

测试输出:

dt = 2019-10-26T20:30:59
dt2 = 2019-11-01T17:30:59
dt3 = 2019-09-26T20:30:59
dt4 = 2019-10-31T20:30:59
dt5 = 2019-09-26T20:30:59


从上述的测试可以发现:

1. 对日期的加减会自动调整月份,其实对月份的加减也会自动调整日期。

2. 对日期和时间的调整使用withXxx()方法,例如withHour(15)会把“10:11:12”变为“15:11:12”

调整年、月、日、时、分、秒的方法:

  • 调整年:withYear()
  • 调整月:withMonth()
  • 调整日:withDayOfMonth()
  • 调整时:withHour()
  • 调整分:withMinute()
  • 调整秒:withSecond()

 

1.3 复杂运算

实际上,LocalDateTime还有一个通用的with()方法允许我们做更复杂的运算:

public static void main(String[] args){    System.out.println("current date is " + LocalDate.now());    // 本月第一天0:00时刻:    LocalDateTime firstDay = LocalDate.now().withDayOfMonth(1).atStartOfDay();    System.out.println(firstDay);    // 本月最后1天:    LocalDate lastDay = LocalDate.now().with(TemporalAdjusters.lastDayOfMonth());    System.out.println(lastDay);    // 下月第1天:    LocalDate nextMonthFirstDay = LocalDate.now().with(TemporalAdjusters.firstDayOfNextMonth());    System.out.println(nextMonthFirstDay);    // 本月第1个工作日:    LocalDate firstWeekday = LocalDate.now().with(TemporalAdjusters.firstInMonth(DayOfWeek.MONDAY));    System.out.println(firstWeekday);    System.out.println("-----------------------");    LocalDateTime now = LocalDateTime.now();    System.out.println(now);    LocalDateTime target = LocalDateTime.of(2019, 11, 19, 8, 15, 0);    System.out.println(now.isBefore(target));    System.out.println(LocalDate.now().isBefore(LocalDate.of(2019, 11, 19)));    System.out.println(LocalTime.now().isAfter(LocalTime.parse("08:15:00")));}

测试输出:

2019-10-01T00:00
2019-10-31
2019-11-01
2019-10-07
-----------------------
2019-10-29T13:39:39.426
true
true
true


从上述的测试可以发现:

1. 要判断两个LocalDateTime的时间先后,可以使用isBefore()isAfter()方法。

2. LocalDateTime有许多with一类的方法,可以完成一些特定的操作。

 

1.4 区间间隔

Duration表示两个时刻之间的时间间隔。另一个类似的Period表示两个日期之间的天数:

public static void main(String[] args){    LocalDateTime start = LocalDateTime.of(2019, 11, 19, 8, 15, 0);    LocalDateTime end = LocalDateTime.of(2020, 1, 9, 19, 25, 30);    Duration d = Duration.between(start, end);    System.out.println(d); // PT1235H10M30S        Period p = LocalDate.of(2019, 11, 19).until(LocalDate.of(2020, 1, 9));    System.out.println(p); // P1M21D}

测试输出:

PT1235H10M30S
P1M21D


从上述的测试可以发现:

1. 两个LocalDateTime之间的差值使用Duration表示,类似PT1235H10M30S,表示1235小时10分钟30秒。

2. 两个LocalDate之间的差值用Period表示,类似P1M21D,表示1个月21天。

3. DurationPeriod的表示方法也符合ISO 8601的格式,它以P...T...的形式表示,P...T之间表示日期间隔,T后面表示时间间隔。

 

二、java.time.ZonedDateTime

2.1 基本操作

LocalDateTime总是表示本地日期和时间,要表示一个带时区的日期和时间,我们就需要ZonedDateTime

public static void main(String[] args){    // 默认时区    ZonedDateTime zbj = ZonedDateTime.now();    System.out.println(zbj);    // 用指定时区获取当前时间    ZonedDateTime zny = ZonedDateTime.now(ZoneId.of("America/New_York"));    System.out.println(zny);}

测试输出:

2019-10-29T14:11:47.361+08:00[Asia/Shanghai]
2019-10-29T02:11:47.364-04:00[America/New_York]


从上述的测试可以发现:

1. ZonedDateTime和LocalDateTime一样,都是通过now()方法返回当前时间,只不过LocalDateTime没有时区信息。

 

public static void main(String[] args){    LocalDateTime ldt = LocalDateTime.of(2019, 9, 15, 15, 16, 17);    System.out.println(ldt);    ZonedDateTime zbj = ldt.atZone(ZoneId.systemDefault());    System.out.println(zbj);    ZonedDateTime zny = ldt.atZone(ZoneId.of("America/New_York"));    System.out.println(zny);}

测试输出:

2019-09-15T15:16:17
2019-09-15T15:16:17+08:00[Asia/Shanghai]
2019-09-15T15:16:17-04:00[America/New_York]


从上述的测试可以发现:

1. 给LocalDateTime附加一个ZoneId,就可以变为ZonedDateTime

 

2.2 时区转换

public static void main(String[] args){    // 以中国时区获取当前时间:    ZonedDateTime zbj = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));    System.out.println(zbj);            // 转换为东京时间:    ZonedDateTime zny = zbj.withZoneSameInstant(ZoneId.of("Asia/Tokyo"));    System.out.println(zny);    // 丢弃了时区信息    System.out.println(zny.toLocalDateTime());}

测试输出:

2019-10-29T14:47:04.234+08:00[Asia/Shanghai]
2019-10-29T15:47:04.234+09:00[Asia/Tokyo]
2019-10-29T15:47:04.234


从上述的测试可以发现:

1. 要转换时区,首先我们需要有一个ZonedDateTime对象,然后,通过withZoneSameInstant()将关联时区转换到另一个时区,转换后日期和时间都会相应调整。

2. 将ZonedDateTime转换为LocalDateTime时,直接丢弃时区信息。将LocalDateTime添加时区信息,就可以转换为ZonedDateTime了。

 

三、java.time.format.DateTimeFormatter

3.1 基本操作

public static void main(String[] args){    // 自定义格式化:    DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");    System.out.println(dtf.format(LocalDateTime.now()));    // 用自定义格式解析:    LocalDateTime dt2 = LocalDateTime.parse("2019/11/30 15:16:17", dtf);    System.out.println(dt2);}

测试输出:

2019/10/29 11:27:08
2019-11-30T15:16:17


从上述的测试可以发现:

1. 对于自定义的日期时间格式,可以使用DateTimeFormatter来将其转换为ISO 8601格式。

2. 当我们直接调用System.out.println()对一个ZonedDateTime或者LocalDateTime实例进行打印的时候,实际上,调用的是它们的toString()方法,默认的toString()方法显示的字符串就是按照ISO 8601格式显示的。

 

四、java.time.Instant

4.1 基本操作

public static void main(String[] args) {    Instant now = Instant.now();    System.out.println(now.getEpochSecond()); // 秒    System.out.println(now.toEpochMilli()); // 毫秒    System.out.println(System.currentTimeMillis());}

测试输出:

1572334867
1572334867288
1572334867288


从上述的测试可以发现:

1. 用Instant.now()获取当前时间戳,效果和System.currentTimeMillis()类似,只是多了更高精度的纳秒。

2. toEpochMilli()表示获取毫秒值时间戳,完全等同于System.currentTimeMillis()

 

时间戳是一个不断递增的整数,没有时区属性;对Instance附加一个时区,就可以创建出ZonedDateTime:

public static void main(String[] args){    // 以指定时间戳创建Instant:    Instant ins = Instant.ofEpochMilli(1572334867288L);    ZonedDateTime zdt = ins.atZone(ZoneId.systemDefault());    System.out.println(zdt); // 2019-10-29T15:41:07.288+08:00[Asia/Shanghai]}

测试输出:

2019-10-29T15:41:07.288+08:00[Asia/Shanghai]


从上述的测试可以发现:

1. 对于某一个时间戳,给它关联上指定的ZoneId,就得到了ZonedDateTime,继而可以获得了对应时区的LocalDateTime

2. LocalDateTimeZoneIdInstantZonedDateTimelong都可以互相转换的。

3. Instant表示高精度时间戳,它可以和ZonedDateTime以及long互相转换。

 

 

上一篇:新旧版本Java时间、日期API转化
下一篇:Java旧版本时间、日期处理