Java强化知识Day03----------Java 8 新的时间和日期API(LocalDate,LocalTime,LocalDateTime,Instant,Duration)

旧的时间和日期的API的缺陷

Java 的 java.util.Date 和 java.util.Calendar 类易用性差,不支持时区有下列缺陷

可读性差

 Date如果不格式化,打印出的日期可读性差。并且对时间处理很麻烦,比如想获取某年、某月、某星期,以及 n 天以后的时间,如果用Date来处理的话真是太难了,并且 Date 类的 getYear、getMonth 这些方法都被弃用了。

线程不安全

在多并发情况下使用 SimpleDateFormat 需注意。
SimpleDateFormat 除了 format 是线程不安全以外,parse 方法也是线程不安全的。parse 方法实际调用 alb.establish(calendar).getTime() 方法来解析,alb.establish(calendar) 方法里主要完成了

  • 1.重置日期对象cal的属性值
  • 2.使用calb中中属性设置cal
  • 3.返回设置好的cal对象

但是这三步不是原子操作,导致解析出来的时间可以是错误的。

Java 8 新的时间和日期API

Java 8的日期和时间类包含 LocalDate、LocalTime、LocalDateTime、Instant、Duration 以及 Period,这些类都包含在 java.time 包中
本文主要是对上述Api的使用作说明

LocalDate(年月日)

LocalDate 只会获取年月日,具有以下API

创建

// 创建 LocalDate
// 获取当前年月日
LocalDate localDate = LocalDate.now();
// 构造指定的年月日
LocalDate localDate1 = LocalDate.of(2019, 12, 31);

获得年、月、日、星期几

//获得年份,下面两个方法等同
int year = localDate.getYear();
int year1 = localDate.get(ChronoField.YEAR);

//获得月份
Month month = localDate.getMonth();     //英文字符的月份,可以当做一个字符串使用
int month1 = localDate.get(ChronoField.MONTH_OF_YEAR);     //数字形式的月份

//获得日期,下面两个方法等同
int day = localDate.getDayOfMonth();
int day1 = localDate.get(ChronoField.DAY_OF_MONTH);

//获得星期几
DayOfWeek dayOfWeek = localDate.getDayOfWeek();     //英文字符串形式,可以当做字符串使用
int dayOfWeek1 = localDate.get(ChronoField.DAY_OF_WEEK);     //数字形式

LocalTime(时分秒)

LocalTime 只会获取时分秒

创建对象

// 创建 LocalTime
LocalTime localTime = LocalTime.of(13, 0, 0);	//指定时间13:00
LocalTime localTime1 = LocalTime.now();			//当前时间

获得时、分、秒

// 获取小时
int hour = localTime.getHour();
int hour1 = localTime.get(ChronoField.HOUR_OF_DAY);
// 获取分
int minute = localTime.getMinute();
int minute1 = localTime.get(ChronoField.MINUTE_OF_HOUR);
// 获取秒
int second = localTime.getSecond();
int second1 = localTime.get(ChronoField.SECOND_OF_MINUTE);

LocalDateTime(年月日时分秒)

LocalDateTime 获取年月日时分秒,相当于 LocalDate + LocalTime

创建对象

// 创建 LocalDateTime
LocalDateTime localDateTime = LocalDateTime.now();    //根据当前时间创建
LocalDateTime localDateTime1 = LocalDateTime.of(2019, Month.SEPTEMBER, 1, 12, 0, 59);//根据自定义时间创建
LocalDateTime localDateTime2 = LocalDateTime.of(localDate, localTime);//根据localTime+根据localDate创建创建

//localTime和localDate根据对方互相创建
LocalDateTime localDateTime3 = localDate.atTime(localTime); //根据localTime创建
LocalDateTime localDateTime4 = localTime.atDate(localDate); //根据localDate创建

// 获取LocalDate
LocalDate localDate2 = localDateTime.toLocalDate();
// 获取LocalTime
LocalTime localTime2 = localDateTime.toLocalTime();

Instant(时间戳)

注意,本文的时间戳都是以1970-01-01T00:00:00为标准计算
Instant 获取秒数,用于表示一个时间戳(精确到纳秒)
代码示例

// 创建Instant对象
Instant instant = Instant.now();
// 获取秒数
long currentSecond = instant.getEpochSecond();
// 获取毫秒数(完整的毫秒级别时间戳)
long currentMilli = instant.toEpochMilli();
//获取纳秒数(只取单位秒,以后的值)
long currentNano = instant.getNano()

注意:如果只是为了获取秒数或者毫秒数,可以使用 System.currentTimeMillis()。

时间戳与LocalDateTime的互相转换

毫秒时间戳转换为LocalDateTime

long millis = System.currentTimeMillis();     //得到当前系统时间

/*方法1:LocalDateTime.ofEpochSecond(epochSecond,nanoOfSecond,ZoneOffset)
epochSecond:秒数,也就是我们的时间戳,但是因为我们的时间戳一般用的毫秒,所以这里设置为Milli/1000
nanoOfSecond:纳秒数,十亿分之一秒,如果不是对时间非常精确的,可以填0
ZoneOffset:时区设置,可以使用ZoneOffset.ofHours(8),的到中国的时区(中国在东八区)
*/
//转为LocalDateTime(这里如果对时间要求不高第二个参数可以写0(只精确到秒级别))
LocalDateTime localDateTime = LocalDateTime.ofEpochSecond(millis / 1000, (int) (millis%1000*1000000), ZoneOffset.ofHours(8));
     
//方法2,先将毫秒转为instant再转为LocalDateTime
//ZoneId.systemDefault()为获得系统默认时区,当然也可以跟上面方法一样手动设置
LocalDateTime.ofInstant(Instant.ofEpochMilli(millis), ZoneId.systemDefault());

LocalDateTime转为毫秒时间戳

//LocalDateTime再转为毫秒时间戳
LocalDateTime localDateTime = LocalDateTime.now();
Instant instant = localDateTime.toInstant(ZoneOffset.ofHours(8));       //先转为Instant对象
long millis = instant.toEpochMilli();                                   //再获得毫秒数
Duration(时间段)
// Duration.between()方法创建 Duration 对象
LocalDateTime from = LocalDateTime.now();  //起始时间
LocalDateTime to = LocalDateTime.of(2019, 12, 1, 14, 28, 0);    // 结束时间:2019-12-1 14:28:00
Duration duration = Duration.between(from, to);    // 表示从 from 到 to 这段时间,如果结束时间在过去,就以负数表示
long days = duration.toDays();              // 这段时间的总天数
long hours = duration.toHours();            // 这段时间的小时数
long minutes = duration.toMinutes();        // 这段时间的分钟数
long seconds = duration.getSeconds();      // 这段时间的秒数
long milliSeconds = duration.toMillis();    // 这段时间的毫秒数
long nanoSeconds = duration.toNanos();      // 这段时间的纳秒数

不可变性

LocalDate、LocalTime、LocalDateTime、Instant 为不可变对象,修改这些对象对象会返回一个副本。
增加、减少年数、月数、天数等,以LocalDateTime为例:

// Duration.between()方法创建 Duration 对象
LocalDateTime localDateTime = LocalDateTime.of(2020,1,1,0,0);  //2020-1-1T00:00
// 增加一年
LocalDateTime newLocalDate = localDateTime.plusYears(1);  //会返回一个新的对象,当然也可以直接覆盖原对象
System.out.println(localDateTime);     //输出:2020-1-1T00:00
System.out.println(newLocalDate);     //输出:2021-1-1T00:00

TemporalAdjusters(工具类)

TemporalAdjusters 包含许多静态方法,可以直接调用,以下列举一些(方法名):

dayOfWeekInMonth:返回同一个月中每周的第几天

firstDayOfMonth:返回当月的第一天

firstDayOfNextMonth:返回下月的第一天

firstDayOfNextYear:返回下一年的第一天

firstDayOfYear:返回本年的第一天

firstInMonth:返回同一个月中第一个星期几

lastDayOfMonth:返回当月的最后一天

lastDayOfNextMonth:返回下月的最后一天

lastDayOfNextYear:返回下一年的最后一天

lastDayOfYear:返回本年的最后一天

lastInMonth:返回同一个月中最后一个星期几

next / previous:返回后一个/前一个给定的星期几

nextOrSame / previousOrSame:返回后一个/前一个给定的星期几,如果这个值满足条件,直接返回

示例(返回同一个月中最后一个星期几 ):

// 返回同一个月中最后一个星期几
TemporalAdjuster temporalAdjuster = TemporalAdjusters.lastInMonth(DayOfWeek.FRIDAY);  //同月最后一个星期5(需要使用枚举类)
LocalDateTime localDateTime = LocalDateTime.of(2020,1,1,0,0);// 2020-1-1T00:00
LocalDateTime newLocalDateTime = localDateTime.with(temporalAdjuster);  //原时间依旧不可变
System.out.println(localDateTime);      //2020-1-1T00:00
System.out.println(newLocalDateTime);  //2020-01-31T00:00(31号刚好是星期5)

这里使用对应方法后,会的的到一个TemporalAdjuster对象,然后LocalDateTime使用with传入该对象,会的到一个你指定的新日期

格式化时间

新的日期API当然也能按照指定格式,格式化或者解析(String)时间
他们都具有format方法
序列化

LocalDateTime localDate = LocalDateTime.of(2020, 1, 1,0,0,0);
String s1 = localDate.format(DateTimeFormatter.BASIC_ISO_DATE);     //格式:yyyyMMdd
String s2 = localDate.format(DateTimeFormatter.ISO_LOCAL_DATE);     //格式:yyyy-MM-dd
// 自定义格式化
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String s3 = localDate.format(dateTimeFormatter);
System.out.println(s1);    //20200101
System.out.println(s2);    //2020-01-01
System.out.println(s3);    //2020-01-01 00:00:00

反序列化

LocalDate localDate1 = LocalDate.parse("20191231", DateTimeFormatter.BASIC_ISO_DATE);        //yyyyMMdd
LocalDate localDate2 = LocalDate.parse("2019-12-31", DateTimeFormatter.ISO_LOCAL_DATE);      //yyyy-MM-dd
//自定义格式反序列化
LocalDateTime localDate3 = LocalDateTime.parse("2019-09-12 00:00:59", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
格式化的采坑

YYYY和yyyy
直接看代码

LocalDateTime localDate = LocalDateTime.of(2019, 12, 31,0,0,0);
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
DateTimeFormatter dateTimeFormatter2 = DateTimeFormatter.ofPattern("YYYY-MM-dd HH:mm:ss");
String s3 = localDate.format(dateTimeFormatter);
String s4 = localDate.format(dateTimeFormatter2);
System.out.println(s3);    //2019-12-31 00:00:00
System.out.println(s4);    //2020-12-31 00:00:00

 注意看上面代码,使用大写的YYYY作为年份,会将最后一天给格式化到明年年底去,这是因为YYYY,week-based year 是 ISO 8601 规定的,2019-12-31号这一天,安周算年份已经属于2020年了,格式化之后就变成2020年,后面的月份日期不变。所以要注意,尽量使用yyyy
另外
1.使用SimpleDateFormat同样有这个问题
2.dd 和 DD也是同理,也有转换问题,大写的DD代表的是处于这一年中那一天,不是处于这个月的那一天。所以也一定要区分好大小写

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值