java8时间相关api
一. java8时间相关api出现的原因
1. 偏移量问题: 例如通过Date构造器创建指定年份,月份的时间对象时,由于Date对象年份是从1900年开始,月份是从0开始,则需
要在构造器中指定时间减去开始时间
2. 格式化问题: 在工作中经常会遇到日期类型数据与字符串的相互转换,只能通过Date,但是java在1.1版本不推荐使用Date,
推荐Calendar,Calendar中又没有相关转换api
3. Date与Calendar不是线程安全的,不能处理闰秒(闰秒由于地区自转的不均匀性等,世界不同国家在年末时会添加或减去一定的时间
如果开发的是国际相关软件,需要处理)
4. 为解决以上问题java8吸收了Joda-Time,在java.time包中创建了新的api,
5. 关于本地日期 LocalDate, 本地时间 LocalTime, 本地日期时间 LocalDateTime与时区相关的 ZoneDateTime,持续时间相关的 Duration 类
在下面的操作中若调用的方法需要传递TemporalAccessor类型参数时,实际就是需要一个LocalDate,或LocalTime,或LocalDateTime,这三个类实现了Temporal接口,而Temporal接口继承了TemporalAccessor接口
二. LocalDate, LocalTime, LocalDateTime的使用
1. 解释:
通过这几个类可以操作时间日期相关数据,获取,设置,运算等
2. 学习点:
- 实例化创建对象的方式,不同方式实例化的对象的特点
- 获取时间日期数据的方法
- 设置时间日期数据的方法
- 加减
- 两个时间的间隔计算
- 各种类型时间数据相互转换
3. 代码示例
此处大部分以 LocalDateTime 作为示例演示,其他对象也可以调用这些大部分的方法
public class ArrayTest {
public static void main(String[] args) {
//1.实例化:
//方式一: 通过now()静态方法实例化,该方法可以为空参当前时间,可以传递Zoneld对象指定时区
//实例化LocalDate,LocalTime,LocalDateTime对象
LocalDate localDate1 = LocalDate.now();
LocalTime localTime1 = LocalTime.now();
LocalDateTime localDateTime1 = LocalDateTime.now();
//方式二: 通过of()抽象方法创建指定日期时间对象
//of()为多参数重载方法根据具体需求选择调用,并且在月时分秒设置的不符合规定时间例如
//月份大于12,时间大于等于24,分秒超过大于等于60时会报错
LocalDate localDate2 = LocalDate.of(2020,12,4);
LocalTime localTime2 = LocalTime.of(0,59,59);
LocalDateTime localDateTime2 = LocalDateTime.of(2020,2,24,15,58,59);
//2.通过对象调用getXxx()方法获取时间
int m1 = localDateTime2.getMonthValue(); //获取月份
int m2 = localDateTime2.getDayOfMonth();//获取几号(所在月的第几天)
Month m3 = localDateTime2.getMonth(); //获取Month对象
int y1 = localDateTime2.getYear(); //获取年份
int y2 = localDateTime2.getDayOfYear(); //获取当前年份的第几天
DayOfWeek dayOfWeek= localDateTime2.getDayOfWeek();
int w1 = dayOfWeek.getValue();//获取当前时间星期几
int h = localDateTime2.getHour();//获取小时
int minute = localDateTime2.getMinute();//获取分
int se = localDateTime2.getSecond();//获取秒
//3.通过withXxx()方法设置指定时间(返回新的)
LocalDateTime localDT = localDateTime1.withYear(2021);//设置年份
LocalDateTime localDT1 = localDT.withDayOfYear(238);//设置是当前年份的第几天
LocalDateTime localDT2 = localDT1.withDayOfMonth(3);//设置是第几个月
LocalDateTime localDT3 = localDT1.withHour(12);//设置时
LocalDateTime localDT4 = localDT3.withMinute(12);//设置分
LocalDateTime localDT5 = localDT4.withSecond(59);//设置秒
//4.通过plusXxx()对当前时间进行累加操作
LocalDateTime localDT6 = localDT5.plusYears(1);//累加年
//plusMonths(2);累加月
//plusWeeks(2);累加周
//plusDays(2);累加天
//plusHours(2);累加小时
//plusMinutes(2);累加分钟
//plusSeconds(2);累加秒
//plusNanos(2);累加纳秒
//5.通过minusXxx()做累减的操作
LocalDateTime localDT7 = localDT6.minusMonths(2);//减去2个月
localDT6.minusYears(2);//减去2年..
//6.毫秒数Long与日期时间类型相互转换
//LocalDateTime转Long
Long newSecond1 = localDT7.toInstant(ZoneOffset.of("+8")).toEpochMilli();
//long转LocalDateTime
LocalDateTime localDateTime = new Date(1535444725000L).toInstant().atOffset(ZoneOffset.of("+8")).toLocalDateTime();
//7.将Long毫秒数先转换为 Instant 类型,然后将Instant转换为 LocalDateTime
Instant instant = Instant.ofEpochMilli(1535444725000L);
LocalDateTime lot = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
//8.Date与LocalXxxXxx间的相互转换
Date date = Date.from(localDT7.atZone(ZoneId.systemDefault()).toInstant());
LocalDateTime dateTime = LocalDateTime.ofInstant(date.toInstant(),ZoneId.systemDefault());
}
}
三. Instant
1. 解释
1) 对于程序而言需要用到的时间类型通常为毫秒数,java8提供了Instant,
2) 时间线上的瞬时点,记录应用程序中的时间戳,通过这个对象可以获取到指定时间的毫秒数,纳秒数等数据
3) 注意获取Instant示例时时区问题,
2. 学习点
1) 实例化方式,不同方式的特点
2) 获取时间戳,也就是毫秒数
3) 注意时区问题
4) Instant对象与Long类型毫秒数的相互转换
3. 代码示例
//1.实例化Instant
//通过now()静态方法进行实例化,注意默认返回的是utc时区的
//由于获取的时间是utc时区的,中国需要加8个小时后才是当前时间
Instant instant1 = Instant.now();
//2.通过Instant实例对象调用,atOffset(ZoneOffset)方法设置时区,修改为当前时间
//该方法中传递一个ZoneOffset,8为中国时区
OffsetDateTime offsetDateTime = instant1.atOffset(ZoneOffset.ofHours(8));
System.out.println( offsetDateTime );//此时返回的OffsetDateTime为正确的时间
//3.获取毫秒数时间戳(距离1970-01-1 00:00:00到Instant所代表时间的毫秒数)
long milli = instant1.toEpochMilli();
//4.通过long类型毫秒数获取Instant实例
long l = 1550475314878L;
Instant instant2 = Instant.ofEpochMilli(l);
System.out.println( instant2 );
四. DateTimeFormatter 日期格式化类
1. 解释:
1) 在工作中通常会碰到前台向后台传递的日期类型数据一个字符串,或者前台需要的日期数据为字符串类型有固定格式,
此时就需要将日期类型转换为字符串类型
2) 在开发时按照预定义格式,或自定义格式使用 DateTimeFormatter,对时间类型数据与字符串进行相互转换
3) 预定义格式 ISO_LOCAL_DATE_TIME, ISO_LOCAL_DATE, ISO_LOCAL_TIME
4) 本地化相关格式 如: ofLocalizedDateTime(FormatStyle.LONG)
4) 自定义格式 如: ofPattern("yyyy-MM-dd HH:mm:ss E")
2. 学习点
1) 获取指定字符串格式的 DateTimeFormatter 实例对象的方式
2) 格式化日期时间对象,返回字符串
3) 将代表日期时间的字符串格式化为日期时间类型
3. 代码示例
//1.实例化对象(实例化对象可以看为获取对象并设置指定的转换格式)
//方式一: 自定义格式化 (E代表中文的星期几)
String s = "yyyy-MM-dd HH:mm:ss E";
DateTimeFormatter formatter1 = DateTimeFormatter.ofPattern(s);
//方式二: 本地化格式实例化
//本地化常量(括号中是该常量转换后的样式): LONG(2020年2月23日 下午08时35分59秒),
//MEDIUM(2020-2-23 20:36:28), SHORT(20-2-23 下午8:37)
//FULL 用于ofLocalizedDate()方法
DateTimeFormatter formatter2 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT);
//方式三: 预定义格式实例化,通过DateTimeFormatter调用预定义的常量
//预定义常量(括号中是该常量转换后的样式): ISO_LOCAL_DATE_TIME(2020-02-23T20:38:20.265),
//ISO_LOCAL_DATE(2020-02-23), ISO_LOCAL_TIME(20:39:10.022)
DateTimeFormatter formatter3 = DateTimeFormatter.ISO_LOCAL_TIME;
//2.将日期对象转换为日期字符串
//获取时间对象
LocalDateTime time = LocalDateTime.now();
//通过 DateTimeFormatter 示例对象调用 format() 方法
//按照创建 DateTimeFormatter 对象时指定的格式转换为字符串
String dateTimeStr1 = formatter1.format(time);
System.out.println(dateTimeStr1);
//3.将字符串转换为日期格式对象,字符串要与实例化DateTimeFormatter对象时的格式一一对应
String dateStr = "2020-02-23 09:22:39 星期日";//(上面带E,此处字符串要带星期几)
//使用DateTimeFormatter实例对象调用parse()方法将字符串转换为TemporalAccessor
TemporalAccessor t = formatter1.parse(dateStr);
//使用LocalDateTime,日期时间对象调用parse("时间字符串",DateTimeFormatter)
//方法将字符串转换为指定的日期时间对象
LocalDateTime dateTime = LocalDateTime.parse(dateStr,formatter1);
五. 时间间隔计算
1. 解释:
在某些时候会计算两个时间的间隔,或两个时间的大小
1) 计算两个时间的时分秒间隔使用 Duration
2) 计算两个时间的年月日间隔使用 Period
3) 判断两个时间的先后顺序
2. 示例
计算两个时间间隔的年月日
//开始时间,前面的时间
LocalDate startDate = LocalDate.of(1993, Month.OCTOBER, 19);
//结束时间,后面的时间
LocalDate endDate = LocalDate.now();
//计算: 通过Period调用 between(前面的时间对象,后面的时间对象) 方法计算
//返回 Period 实例,两个日期的间隔数据保存在该实例中
//(若不知道两个时间的前后顺序,后面再获取间隔数据时可以通过Math.abs()取绝对值)
Period p = Period.between(startDate, endDate);
System.out.printf("间隔 %d 年 %d 个月 %d 日", p.getYears(), p.getMonths(), p.getDays());
计算两个时间的间隔包括时分秒
//开始时间,前面的时间
LocalDateTime startDateTime = LocalDateTime.of(2019,4,24,15,58,59);
//结束时间,后面的时间
LocalDateTime endDateTime = LocalDateTime.now();
//通过 Duration 调用 between(前面的时间, 后面的时间) 方法计算间隔
//返回 Duration 实例对象,间隔数据保存在这个对象中
Duration duration = Duration.between(startDateTime,endDateTime);
System.out.println(duration);
long days = duration.toDays(); //相差的天数
long hours = duration.toHours();//相差的小时数
long minutes = duration.toMinutes();//相差的分钟数
long millis = duration.toMillis();//相差毫秒数
long nanos = duration.toNanos();//相差的纳秒数
System.out.println(nanos);
判断两个时间的先后顺序
String time1 = "2019-06-26 19:00:00";
DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime localDateTime = LocalDateTime.parse(time1, dtf2);
boolean b1 = localDateTime.isBefore(LocalDateTime.now());//你的时间在当前时间之前是true
boolean b2 = localDateTime.isAfter(LocalDateTime.now());//在当前时间之后是false