java8新推出了日期的API,我们知道在这之前,都是使用Date和Calender类处理日期。那么,首先一个问题是,为什么要使用新的日期API?
1.最主要的,原来的日期API是线程不安全的。类的实例变量可以被多线程修改。而新的API则是不可变对象,成员变量是final的,所以是线程安全的;
2.新的API更易于使用,职责划分更清晰。如果只关心日期,使用LocalDate即可,如果只关心时间,使用LocalTime即可,如果都关心,使用LocalDateTime。如果想用时间戳,使用Instant。
3.每一种时间类都提供了各自的format和parse实现。
4.支持时区。有专门的ZoneId和ZoneOffset类处理时区问题。
5.提供了丰富易用的工具类API,比如日期上加一天,减一天等。
下面看下基本的使用:
1.LocalDate
//构建方式一
LocalDate now = LocalDate.now();
System.out.println(now);
LocalDate date = LocalDate.now(ZoneId.of("UTC")); //指定0时区
System.out.println(date);
//构建方式二
LocalDate date1 = LocalDate.parse("2018-12-18"); //默认必须是“-”分割
System.out.println(date1);
LocalDate date2 = LocalDate.parse("2018/12/18", DateTimeFormatter.ofPattern("yyyy/MM/dd"));
System.out.println(date2);
//构建方式三
LocalDate date3 = LocalDate.of(1992, 05, 30);
System.out.println(date3);
//日期操作
LocalDate yesterday = now.minusDays(1);
System.out.println(yesterday);
//格式化
System.out.println(yesterday.format(DateTimeFormatter.ofPattern("yyyy@MM@dd")));
//计算日期差 不能用Period的getDays()方法
System.out.println(ChronoUnit.DAYS.between(LocalDate.of(1992,05,30), LocalDate.now()));
LocalDate只表示日期的字面量,并不是真正意义上的日期,因为它没有与时区关联,无法转成时间戳。LocalDate可以通过now方法直接获得,parse方法从字符串格式化获得或者of方法直接构建。now方法可以指定时区,但注意,这里并不意味着这个localDate与时区绑定,仅仅是赋值。另外,获取两个date之间的天数,不能通过Period类。
2.LocalTime
LocalTime localTime = LocalTime.now();
System.out.println(localTime);
LocalTime localTime1 = LocalTime.now(ZoneId.of("UTC"));
System.out.println(localTime1);
与LocalDate的使用类似,只表示时间的字面量,没有与时区绑定。
3.LocalDateTime
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println(localDateTime);
ZonedDateTime localDateTime1 = localDateTime.atZone(ZoneId.of("UTC"));
System.out.println(localDateTime1);
System.out.println(localDateTime.toInstant(ZoneOffset.ofHours(8)).getEpochSecond());
System.out.println(localDateTime1.toInstant().getEpochSecond());
LocalDateTime与前两者使用类似,表示时间+日期的字面量,没有与时区绑定。对其调用atZone方法,传入一个时区参数,即可与特定时区绑定,结果生成了一个ZonedTimeDate实例。该实例才是真正的时间,能够转换成时间戳。上面的例子也可以看出LocalDateTime是无法直接转时间戳的,必须传入zone的参数。
4.Zone相关
ZoneId zoneId1 = ZoneId.of("Asia/Shanghai");
System.out.println(zoneId1);
ZoneId zoneId2 = ZoneId.of("UTC+01:00");
System.out.println(zoneId2);
ZoneOffset offset1 = ZoneOffset.of("Z");// UTC 0
System.out.println(offset1);
ZoneOffset offset2 = ZoneOffset.of("+01:00");
System.out.println(offset2);
与时区先关的两个类:ZoneId和ZoneOffset。
ZoneId表示一个时区的id。有两种表示法,一种是通过与UTC0时区时间差的方式,比如“UTC+01:00”,“UTC-13:00”这种。另一种是通过地域,比如“Asia/Shanghai”,以上两种都可以。如果是想指定服务的时区,通常用后者;如果需要考虑时差,通常用前者。
ZoneOffset表示与UTC0时区的时间差。与前者作用上等价。可以通过of或者ofHours等方法构建。
一般用ZoneId就可以。
5.Instant
Instant instant1 = Instant.now();
System.out.println(instant1);
System.out.println(instant1.getEpochSecond());
System.out.println(instant1.toEpochMilli());
Instant instant2 = ZonedDateTime.now().toInstant();
System.out.println(instant2);
Instant instant3 = Instant.parse("2018-12-20T12:39:20.194Z");
System.out.println(instant3);
System.out.println(instant3.atZone(ZoneId.of("UTC+08:00")));
System.out.println(LocalDateTime.now(ZoneId.of("UTC")));
Instant表示时间戳,可以直接now构建,也可以从字符串格式化得到,或者从zonedDateTime转换得到。