新的日期和时间( Java 8 )

为什么我们需要新的Date和Time类!
  • Java8之前所有的日期类都是可变的,这就导致了线程不安全问题;
  • java的日期和时间类的定义不一致,在java.util和java.sql中都包含日期类;
  • java.util.Date同时包含日期和时间,但是java.sql中只包含日期,将其纳入java.sql中的是不合适的,而且更糟糕的是:这两个类中的日期类的名字都是一样的;
  • 对于时间、时间戳、格式化及解析,没有一些明确定义的类,而且对于格式化和解析的需求,Java中有java.text.DateFormat抽象类,但是通常我们用的是SimpleDateFormate类进行格式化和解析
  • 日期类不支持国际化,没有时区支持,即使Java引入了-java.util.Calendar和java.util.TimeZone类,但是问题依然存在。
Java8新的日期和时间API的设计原则

Java8中新的日期和时间是基于JSR-310实现的,参考了绝大多数的joda-timeApi。

  • 不变性:新的日期/时间API中,所有的类都是不可变的,实现了线程安全;
  • 关注点分离:新的API中将人可读的日期时间和机器时间(unix timestamp)明确分离,它为日期(Date)、时间(Time)、日期时间(DateTime)、时间戳(unix timestamp)以及时区定义了不同的类;
  • 清晰明了:新的API中,方法都被明确定义用以完成相同的行为,例如,想要拿到当前实例,可以用new()方法,在所有的类方法中都实现了formate()和parse()方法,不再是之前用单独一个类去解决,而且新的API中所有的类都使用了工厂模式和策略模式;
  • 实用性:所有新的日期和时间API类都实现了一系列方法用以完成通用的需求,例如:加、减、格式化、解析、从日期或时间中提取单独部分等等;
  • 可扩展性:新的日期/时间API是基于国际标准ISO 8601,其实我们也是可以将其用于非IOS的日历上
Java8中的日期和时间API包含以下包
  • java.time包:这是新的Java日期/时间API的基础包,所有的主要基础类都是该包的一部分,例如:LocalDate、LocalTime、LocalDateTime、Instant、Period、Duration等类。这些类都是线程安全的
  • java.time.chrono包:这个包为非ISO的日历标准定义了一些泛化的API,我们可以拓展AbstractChronology来创建自己的日历标准
  • java.time.formate包:这个包包含能够格式化和解析日期时间对象的类,在绝大数情况下,我们不应该直接使用它,因为java.time包中相应的类已经提供了格式化和解析的方法
  • java.time.temporal包:这个包包含一些时态对象,可以用其找出关于某个日期/时间对象的某个特定日期或时间,比如说找到某个月的第一天或最后一天,可以根据withXXX的格式进行区分
  • java.time.zone包:这个包支持不同的时区以及相关规则的类

Java8中引入的关于日期和时间的新类:Period和Duration类,两个类表示两个日期和时间之间的差,Period基于日期,Duration类基于时间

Period类

概述:该类表示一段时间的年、月、日

  1. 使用该类中between()方法获取两个日期之间的差作为Period对像返回;
// 代码示例
LocalDate startTime = LocalDate.of(2020,10,01);
LocalDate endTime = LocalDate.of(2021,11,20);
Period timeSub = Period.between(startTime,endTime);
System.out.println("year:"+timeSub.getYears());
System.out.println("month:"+timeSub.getMonths());
System.out.println("day:"+timeSub.getDays());
  1. 使用该类中的isNegative()方法判断起止日期的大小
    (false为endTime大于startTime,否则相反)原理是根据该该方法(不需要参数)会校验Period对象中的天、月、年是否为负,为负则返回true,为正则返回false
// 代码示例
LocalDate startTime = LocalDate.of(2020,10,01);
LocalDate endTime = LocalDate.of(2021,11,20);
Period timeSub = Period.between(startTime,endTime);
System.out.println(timeSub.isNegative());
  1. 使用该类的plusXXX()方法、minusXXX()方法可以进行日期的增加和减少
// 代码示例
Period periodTime = Period.of(2020,10,26);
//年
String plusYears = periodTime.plusYears(1).toString();
String minusYears = periodTime.minusYears(1).toString();
//月
String plusMonths = periodTime.plusMonths(1).toString();
String minusMonths = periodTime.minusMonths(1).toString();
//日
String plusDays = periodTime.plusDays(1).toString();
String minusDays = periodTime.minusDays(1).toString();

Duration类

概述:表示秒或纳秒的时间间隔,适合处理较短的时间,且需要更高的精确性

  1. 使用该类中between()方法比较两个瞬间的差值
// 代码示例
Instant start = Instant.parse("2020-10-12T10:12:12.00Z");
Instant end = Instant.now();
System.out.println(end.toString());
Duration duration = Duration.between(start,end);
System.out.println(duration.isNegative());
  1. 使用该类中的isNegative()方法判断起止时间的大小
    (false为endTime大于startTime,否则相反)原理是根据该该方法(不需要参数)会校验Duration对象中的天、月、年是否为负,为负则返回true,为正则返回false
// 代码示例(使用LocalTime也可以获取Duration对象)
LocalTime startTime = LocalTime.of(1,10,30,234);
LocalTime endTime  = LocalTime.of(1,20,30,234);
Duration duration = Duration.between(startTime,endTime);
System.out.println(duration.isNegative());
  1. 使用该类的plusXXX()方法、minusXXX()方法可以进行日期的增加和减少
// 代码示例(使用该类中的ofDays方法也可以获取Duration对象)
Duration durationDays = Duration.ofDays(1);
String addDays = durationDays.plusDays(1).toString();
System.out.println(durationDays.getSeconds());

Duration durationHours = Duration.ofHours(3);
String minusHours = durationHours.minusHours(1).toString();
System.out.println(durationHours.getSeconds());

Duration durationMinutes = Duration.ofMinutes(1);
System.out.println(durationMinutes.getSeconds());

Duration durationMillis = Duration.ofMillis(1);
System.out.println(durationMillis.getSeconds());
System.out.println(durationMillis.getNano());

Instant类

概述:表示某个时间,不带时区的即时时间点,精确到纳秒

内部由两个Long字段组成,第一部分保存自标准Java时代到现在的秒数,第二部分保存的是纳秒数(不会超过999,999,999)。注意:通过这种方式获取的时间戳与北京时间相差8个时区,需要修正为北京时间,通过查看源代码发现Instant.now()使用等是UTC时间Clock.systemUTC().instant()。LocalDate、LocalDateTime 的now()方法使用的是系统默认时区 不存在Instant.now()的时间问题。

  1. Instant相当于Date,以下是相互转换
// 代码示例
//类方法java.time.Instant
Instant instant = Instant.now();
System.out.println(instant);
Instant beijingTime = Instant.now().plus(8, ChronoUnit.HOURS);
System.out.println(beijingTime);

//类方法java.util.Date
Date date = new Date();
System.out.println(date);

date = Date.from(instant);
System.out.println(date);

instant = date.toInstant();
System.out.println(instant);
  1. Instant类中通过固定时间转换为Instant对象的方法
//根据Date转换为instant(java.util.Instant中方法)
Date date = new Date();
Instant instant = Instant.ofEpochMilli(date.getTime());
System.out.println(instant);
//根据毫秒转换为instant(java.util.Instant中方法)
instant = Instant.ofEpochMilli(1000 * 60 * 60 * 24);
System.out.println(instant);
//根据秒转换为instant(java.util.Instant中方法)
instant = Instant.ofEpochSecond(60 * 60 * 24 * 5);
System.out.println(instant);
//根据秒和纳秒转换为instant(java.util.Instant中方法),这样得到的instant会包含纳秒的数据 1000000000纳秒(9位)=1秒
instant = Instant.ofEpochSecond(60 * 60 * 24,1000000000*60);
System.out.println(instant);
  1. Instant类中的parse方法
// 代码示例
//该方法的入参仅支持UTC格式的字符串,而且date结果的字符串会报出DateTimeParseException异常
Instant instant = Instant.parse("2020-10-26T12:10:00Z");
System.out.println(instant);
  1. Instant类中的加减日期方法(加)plus()和(减)minus()方法
// 代码示例
//ChronoUnit位于java.time.temporal,Periodjava位于Java.time
//plus()方法会产生一个新的instant对象
//plus()方法给当前日期增加五天
Instant instant = Instant.now();
Instant instantAddDayOne = instant.plus(5, ChronoUnit.DAYS);
Instant instantAddDayTwo = instant.plus(Period.ofDays(5));
Instant instantAddDayTwo1 = instant.plus(Duration.ofDays(5));
System.out.println(instantAddDayOne.toString());
System.out.println(instantAddDayTwo.toString());
System.out.println(instantAddDayTwo1.toString());
System.out.println(instant == instantAddDayOne);
//minus()方法会产生一个新的instant对象
//minus()方法给当前日期减少五天
Instant instantSubDay = instant.minus(5, ChronoUnit.DAYS);
Instant instantSubDayTwo = instant.minus(Period.ofDays(5));
Instant instantSubDayTwo1 = instant.minus(Duration.ofDays(5));
System.out.println(instantSubDay);
System.out.println(instantSubDayTwo);
System.out.println(instantSubDayTwo1);
System.out.println(instant == instantSubDayTwo);
  1. Instant类中比较两个日期的大小
// 代码示例
Instant instantNow = Instant.now();
Instant instantAddDay = instantNow.plus(Duration.ofDays(5));
//isAfter()方法判断instantAddDay是否在instantNow之后
boolean flgAfter = instantAddDay.isAfter(instantNow);
System.out.println(flgAfter);
//isBefore()方法判断instantAddDay是否在instantNow之前
boolean flgBefore = instantAddDay.isBefore(instantNow);
System.out.println(flgBefore);
//compareTo()方法比较,前者时间纳秒值大于后者返回1,小于返回-1,等于返回0
int result1 = instantAddDay.compareTo(instantNow);
System.out.println(result1);
int result2 = instantNow.compareTo(instantAddDay);
System.out.println(result2);
int result3 = instantNow.compareTo(instantNow);
System.out.println(result3);
  1. Instant类计算两个日期的差值
// 代码示例
Instant instantNow = Instant.now();
Instant instantAddDay = instantNow.plus(Duration.ofDays(5));
//between()方法后者比前者大,返回正数,比前者小返回负数,相等返回0(ChronoUnit.DAYS位于java.time.temporal)
long result1 = ChronoUnit.DAYS.between(instantNow, instantAddDay);
System.out.println(result1);
long result2 = ChronoUnit.DAYS.between(instantAddDay, instantNow);
System.out.println(result2);
long result3 = ChronoUnit.DAYS.between(instantNow, instantNow);
System.out.println(result3);

LocalDateTime类

概述:表示不带时区的日期及时间,替换之前的Calendar

**注意:**看上去,LocalDateTime和Instant很象,但记得的是“Instant中是不带时区的即时时间点。可能有人说,即时的时间点 不就是日期+时间么?看上去是这样的,但还是有所区别,比如LocalDateTime对于用户来说,可能就只是一个简单的日期和时间的概念,考虑如下的 例子:两个人都在2013年7月2日11点出生,第一个人是在英国出生,而第二个是在加尼福利亚,如果我们问他们是在什么时候出生的话,则他们看上去都是 在同样的时间出生(就是LocalDateTime所表达的),但如果我们根据时间线(如格林威治时间线)去仔细考察,则会发现在出生的人会比在英国出生的人稍微晚几个小时(这就是Instant所表达的概念,并且要将其转换为UTC格式的时间)。

  1. LocalDateTime获取当前时间(系统自带默认时间)
// 代码示例
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println(localDateTime);
  1. LoclaDateTime类中时间加减计算(加)plusXXX()和(减)minusXXX()方法
// 代码示例
// plus()和minus()方法与Instant类中相同
LocalDateTime localDateTime1 = localDateTime.plusHours(5);
System.out.println(localDateTime1);
System.out.println(localDateTime1 == localDateTime);
LocalDateTime localDateTime2 = localDateTime.minusHours(5);
System.out.println(localDateTime2);
System.out.println(localDateTime2 == localDateTime);
  1. LocalDateTime显示年月日,不显示时间;显示时间,不显示年月
// 代码示例
LocalDateTime localDateTime = LocalDateTime.now();
//显示年月日,且增加两个月
LocalDate localDate = localDateTime.toLocalDate().plusMonths(2);
System.out.println(localDate);
//显示时分秒毫秒,且减少两个小时
LocalTime localTime = localDateTime.toLocalTime().minusHours(2);
System.out.println(localTime);
  1. LocalDateTime类中格式化日期的两种方式
// 代码示例
//通过Instant类获取当前系统时间,ZoneId.systemDefault设置为系统默认时区
//ZoneId位于java.time
LocalDateTime localDateTime1 = LocalDateTime.ofInstant(Instant.now(), ZoneId.systemDefault());
System.out.println(localDateTime1);
//通过DateTimeFormatter类中的ofPattern方法获取自定义格式的系统时间,位于java.time.format
String localDateTimeStr = localDateTime1.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
System.out.println(localDateTimeStr);

文章借鉴处

  • https://blog.csdn.net/fragrant_no1/article/details/83988042
  • https://blog.csdn.net/neweastsun/article/details/88770592
  • https://blog.csdn.net/liubenlong007/article/details/62039628

你可能感兴趣的:(Java,date)