文章目录
1.介绍
如果曾经使用过java8之前处理日期和时间的api,就知道java.util.Date
以及java1.1中引入的java.util.Calendar
类有些许难用。比如Date的年份起始是1900
年,月份的起始是从0
开始的,一周开始是周日
,周日用1
表示。如想要表示2020年1月25日,我们的代码可能写成这样:
Date date = new Date(120,0,25);
//打印结果
Sat Jan 25 00:00:00 CST 2020
这个打印结果可读性极差,你可能想到将日期和时间解析并格式化,那么需要用到一个抽象类DateFormat
,常见到的是它的子类SimpleDateFormat
。SimpleDateFormat
是线程不安全的,如果两个线程同时进行操作,结果可能不符合预期。此外Date和Calendar类都是可变的,也就说我们想要在date加上7天返回日期副本,但此操作会将原先的日期也进行了修改。
java8借鉴了Joda-Time
框架,使我们处理日期和时间更加简单。通过下面一张表看下java8中比较重要的几个类。
类名 | 解释 |
---|---|
LocalDate,LocalTime,LocalDateTime | 本地日期和时间 |
Duration,Period | 日期-时间间隔 |
DateTimeFormatter | 格式化日期和时间 |
Instant | 时刻(时间戳) |
ZoneId,ZoneOffSet | 时区有关变量 |
ZonedDateTime | 带有时区的日期和时间 |
可以看出java8中对日期、时间、带有时区的日期时间、时刻等有了严格的区分。
2.LocalDate、LocalTime、LocalDateTime、Instant、Duration以及Period
2.1 LocalDate、LocalTime和LocalDateTime
LocalDate
提供了简单的日期,不包含时间信息,可以操作年份,月份,日,以及星期几这些日期信息。LocalTime
提供的是一天中的时间,比如13:14:20,可以操作时,分,秒这些时间信息。LocalDateTime
是LocalDate
和LocalTime
的合体,它同时表示了日期和时间,但是不带有时区信息。翻看三个类的api,可以发现它们的大部分方法具有相似性。
————创建对象方式
比较常见的方式有以下几种:
1.通过of()
方法来创建。
LocalDate,LocalTime,LocalDateTime都分别有几种类型的of()
重载方法,比如可以通过LocalDate.of()
方法指定年份,月份,日来返回一个LocalDate,其中月份可以通过数字或者Month
枚举类型来指定。而LocalDateTime由于是日期和时间复合,因此可以通过LocalDateTime.of()
方法指定年份,月份,日,小时,分钟,秒,纳秒来返回LocalDateTime,还可以传入LocalDate和LocalTime来返回一个LocalDateTime。
//指定年份,月份,日
LocalDate localDate = LocalDate.of(2020, 5, 20);
//指定小时,分钟,秒
LocalTime localTime = LocalTime.of(13, 14, 20);
//指定年份,月份,日,小时,分钟,秒
LocalDateTime ldf = LocalDateTime.of(2020, 5, 20, 13, 14, 20);
//参数传入LocalDate,LocalTime
LocalDateTime ldf2 = LocalDateTime.of(localDate ,localTime );
2.通过now()
重载方法创建当前日期-时间。
now()
方法返回当前默认时区日期和时间信息,它还有另外两种重载方法,now(ZoneId zone)
和now(Clock clock)
。实际上now()方法底层会调用now(Clock clock)
方法,参数传入系统默认Clock
。
//获取当前日期
LocalDate ld = LocalDate.now();
//获取当前时间
LocalTime lt = LocalTime.now();
//获取当前日期-时间
LocalDateTime ldt = LocalDateTime.now();
//通过ZoneId来指定时区
LocalDateTime ldt1 = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));
//通过指定一个clock实例
LocalDateTime ldt2 = LocalDateTime.now(Clock.systemDefaultZone());
3.通过parse()
重载方法解析字符串
LocalDate,LocalTime,LocalDateTime默认会按照ISO 8601
日历系统的日期和时间格式解析字符串和打印。日期和时间分隔符是T
,默认带有毫秒的日期时间标准格式为yyyy-MM-dd'T'HH:mm:ss.SSS
。另外parse()
方法也提供了按自定义格式解析的方法parse(CharSequence text, DateTimeFormatter formatter)
。
//按照ISO-8601日期格式解析,如2020-05-20
LocalDate parseDate = LocalDate.parse("2020-05-20");
//按照ISO-8601时间格式解析,如13:14,13:14:20
LocalTime parseTime = LocalTime.parse("13:14:20");
//按照ISO-8601日期时间格式解析,如2020-05-20T13:14:20
LocalDateTime parseDateTime = LocalDateTime.parse("2020-05-20T13:14:20");
//指定日期时间解析格式
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime ldt = LocalDateTime.parse("2020-10-20 13:14:15", dateTimeFormatter);
————获取日期和时间字段值
1、getXXXX()
方法读取字段值
以LocalDateTime为例,LocalDateTime
实例提供了getXXXX()
方法读取日期-时间字段值,如年份,月份,日,周几等。LocalDate
和LocalTime也是类似的。LocalDate
有相应获取日期字段的getXXXX()
方法(如年,月,日等),而LocalTime
则提供了获取时间字段getXXXX()
方法(如时,分,秒等)。
LocalDateTime dateTime = of(2020, 2, 21, 13, 14, 20);
System.out.println(dateTime.getYear());//年份
System.out.println(dateTime.getMonth());//月份
System.out.println(dateTime.getDayOfMonth());//月中第几天
System.out.println(dateTime.getDayOfWeek());//星期几
System.out.println(dateTime.getDayOfYear());//年中第几天
System.out.println(dateTime.getHour());//小时
System.out.println(dateTime.getMinute());//分钟
System.out.println(dateTime.getSecond());//秒
2、通用方法get(TemporalField field)
读取字段值
上面通过getXXXX()
方法获取字段值,可以通过通用方法get(TemporalField field)
来获取同样的字段值,其中TemporalField
是一个接口,它定义了如何访问temporal对象某个字段的值。 ChronoField
枚举实现了这一接口,可以使用 get()
方法得到枚举元素的值。
LocalDateTime localDateTime = of(2020, 2, 21, 13, 14, 20);
System.out.println(dateTime.get(ChronoField.YEAR));
System.out.println(dateTime.get(ChronoField.MONTH_OF_YEAR));
System.out.println(dateTime.get(ChronoField.DAY_OF_MONTH));
LocalTime localTime = LocalTime.of(13,14,20);
System.out.println(localTime.get(ChronoField.HOUR_OF_DAY));
System.out.println(localTime.get(ChronoField.MINUTE_OF_HOUR));
System.out.println(localTime.get(ChronoField.SECOND_OF_MINUTE));
这里需要注意一点的是LocalDate
因为表示的是日期,包含了年,月,日等字段,因此应该向它的get()
方法传入比如ChronoField.HOUR_OF_DAY
日期字段枚举值。同样LocalTime
表示的是时间,可以向它的get()
传入小时,分钟,秒等枚举值,如果传入ChronoField.YEAR
这样的日期枚举类型,将会抛出UnsupportedTemporalTypeException
异常。
————操作日期和时间
1、日期和时间字段修改操作
通过withXXXX()
方法来修改指定字段的值,withXXXX()
方法会创建一个原先对象副本,并按要求修改对应字段值,方法不会改变原来的日期-时间对象。
LocalDateTime dateTime = of(2020, 2, 21, 13, 14, 20);
LocalDateTime changeYear = dateTime.withYear(2008);//2008-02-21T13:14:20
LocalDateTime changeDayOfMonth = dateTime.withDayOfMonth(29);//2020-02-29T13:14:20
LocalTime localTime = LocalTime.of(13,14,20);
LocalTime changeMinute = localTime.withMinute(