花了许多时间在JAVA8新特性的学习上,今天算是可以收尾了,今天要说的是JAVA8提供的新时间与日期API,在以前我们对时间进行处理时,会遇上许多小问题,像是格式化的问题,或是时区的问题等等,而JAVA8很好的解决了这些问题,接下来我们看一看:
首先是表示本地时间的三种:LocalDate(本地日期)、LocalTime(本地时间)、LocalDateTime(本地日期+时间),它们使用的是ISO-8601日历系统时间格式,由于此三种使用方法类似,这里我们就用LocalDateTime为例:
比如我们要输出本地时间:
LocalDateTime ldt=LocalDateTime.now();
System.out.println(ldt);
运行结果
这是一个标准的ISO-8601时间+日期的表达格式
我们也可以指定一个时间进行输出:
LocalDateTime ldt2=LocalDateTime.of(2015,10,19,13,22,33);
System.out.println(ldt2);
也可以对当前的时间进行向前向后推算:
LocalDateTime ldt3=ldt.plusYears(2);
System.out.println(ldt3);
当然如果我们想要单独获取当前年、月、日等等,也可以使用以下方法:
System.out.println(ldt.getYear());
System.out.println(ldt.getMonthValue());
System.out.println(ldt.getDayOfMonth());
System.out.println(ldt.getHour());
System.out.println(ldt.getMinute());
System.out.println(ldt.getSecond());
值得注意的是获取月的方法:
第一个是获取月份的数字,返回的是一个int对象,而第二个返回的是一个Month对象,我们可以继续对其进行操作
接下来说一说时间戳Instant类,时间戳指的是以Unix元年:1970年1月1日00:00:00到某个时间之间的毫秒值
同样,使用时间戳也可以表示时间,但带上了时区,有时候会需要我们对时区进行偏移量计算:
Instant ins1=Instant.now();
System.out.println(ins1);
该方法会默认获取UTC时区,写这篇的时候我的时间为21:15,而输出的时间因为是UTC(世界协调时间)时间,会比北京时间早8个小时,Z代表的即是该时间为utc时间
那如果我们想显示当前时区的时间,即北京时间,计算8个小时偏移量即可:
OffsetDateTime odt=ins1.atOffset(ZoneOffset.ofHours(8));
System.out.println(odt);
运行结果如下:
如果我们仅仅想得到毫秒数,调用.toEpochMilli()方法即可:
System.out.println(ins1.toEpochMilli());
当然我们也可以指定时间戳,比如我们想以秒为单位指定一个时间戳:
Instant ins2 = Instant.ofEpochSecond(60);
System.out.println(ins2);
这样我们能够显示距Unix元年后60秒的时间:
接下来我们说一说计算时间间隔的方法,java8提供了两个类Duration、Period分别结算时间间隔以及日期间隔。
比方我们要计算两个相隔一秒的时间间隔,这里我们用毫秒输出:
Instant ins1=Instant.now();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Instant ins2=Instant.now();
Duration duration=Duration.between(ins1,ins2);
System.out.println(duration.toMillis());
运行结果:
接下来我们计算两个日期的时间间隔:
比如我们要计算当前日期与2015年1月1日相差多久:
LocalDate ld1=LocalDate.of(2015,1,1);
LocalDate ld2=LocalDate.now();
Period period=Period.between(ld1,ld2);
System.out.println(period);
运行结果:
该时间格式为ISO-8601日历系统的时间段表示法,Y表示年(year),M表示月(month),D表示天(day),即5年2个月14天,当然我们也可以将其转换成数字形式,只需要使用get方法即可:
System.out.println(period.getYears()+"年"+period.getMonths()+"月"+period.getDays()+"天");
接下来还有一个用于校正时间的函数式接口TemporalAdjuster以及工具类TemporalAdjusters,可以很好的解决一些对时间有操作的需求,比如今天是周日,我们想将当前时间调至下一个周日:
先得到当前时间:
LocalDateTime ldt=LocalDateTime.now();
再使用TemporalAdjusters中的next方法进行时间获取:
LocalDateTime ldt3=ldt.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
System.out.println(ldt3);
运行结果:
当然,我们也可以自定义一个时间规则,比方我们想要获取下一个工作日,TemporalAdjuster是一个函数式接口,含有的方法是这样:
一个返回值和参数均为Temporal类型的方法,那么我们可以借此编写我们自己想要的时间规则:
LocalDateTime ldt5=ldt.with((l) -> {
LocalDateTime ldt4=(LocalDateTime) l;//将l先进性强转
DayOfWeek dow=ldt4.getDayOfWeek();//获取当天是周几
if (dow.equals(DayOfWeek.FRIDAY)){//若是周五,即向后加上3天
return ldt4.plusDays(3);
}else if (dow.equals((DayOfWeek.SATURDAY))){//若是周六,即加上2天
return ldt4.plusDays(2);
}else {//否则向后加一天
return ldt4.plusDays(1);
}
});
System.out.println(ldt5);
最后结果:
接下来我们说一说java8时间API中的时间格式化DateTimeFormatter类,相比于SimpleDateFormate,该类更加的自由,首先我们新建一个实例:
DateTimeFormatter为我们提供了很多种内置的时间格式,这里我们使用ISO_DATE,也就是我们常见的年-月-日的日期格式,打印一个今天的日期:
DateTimeFormatter dtf=DateTimeFormatter.ISO_DATE;
LocalDateTime ldt= LocalDateTime.now();
String strDate=ldt.format(dtf);
System.out.println(strDate);
运行结果:
如果我们想自定义一个时间格式,可以使用ofPattern方法,在括号里编辑自己想要的时间格式:
DateTimeFormatter dtf2=DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
dtf2.format(ldt);
String strDate2=ldt.format(dtf2);
System.out.println(strDate2);
运行结果:
我们也可以进行解析,比如我们想把上面自定义的格式解析成LocalDateTime ,使用parse方法即可:
LocalDateTime newDate=ldt.parse(strDate2,dtf2);
System.out.println(newDate);
运行结果:
最后我们说一说时区,JAVA8的新时间API中将时区封装在了一个set集合中,我们可以选择想要的时区进行时间显示,我们先看一看时区集合:
@Test
public void test7(){
Set<String> set=ZoneId.getAvailableZoneIds();
set.forEach(System.out::println);
}
运行结果:
值得注意的是若我们想要显示北京时间,需要使用"Asia/Shanghai",如果使用"Asia/Beijing"则会报找不到时区的错误:
LocalDateTime ldt1=LocalDateTime.now(ZoneId.of("Asia/Shanghai"));
System.out.println(ldt1);
LocalDateTime ldt3=LocalDateTime.now(ZoneId.of("Asia/Beijing"));
System.out.println(ldt3);
运行结果:
类似于LocalDateTime,时区也有ZonedDate、ZonedTime、ZonedDateTime三种格式,这里我们就以
ZonedDateTime为例,输出一个带时区的时间格式:
LocalDateTime ldt2 = LocalDateTime.now();
ZonedDateTime zdt=ldt2.atZone(ZoneId.of("Pacific/Honolulu"));
System.out.println(zdt);
这里我们指定时区为罗马,运行结果:
除了本地时间,在末尾加上了距离UTC时间的时差以及时区名,同样我们使用上海,结果: