日期相关
前言
java8的日期相关类做了很多升级。解决了很多java8之前使用日期类的痛点:
util
包下的Date
和Calendar
类不支持时区,线程不安全。- 格式化类
java.text.SimpleDateFormat
线程不安全(相关资料)。 - API调用繁琐。
java8新增的日期类:
- java8新增的日期类都在
java.time
包中,时间日期类包含LocalDate
、LocalTime
、LocalDateTime
、Instant
、Duration
以及Period
。日期格式化类DateTimeFormatter
。 - 新的时区类
java.time.ZoneId
替代原有的java.util.TimeZone;ZoneId
对象可以通过ZoneId.of()
方法创建,也可以通过ZoneId.systemDefault()
获取系统默认时区。
Java8 常用日期类概述
Instant类
Instant类对时间轴上的单一瞬时点建模,可以用于记录应用程序中的事件时间戳,之后学习的类型转换中,均可以使用Instant类作为中间类完成转换。
封装的是UTC(格林威治时间),比我们晚8小时。
Duration类
Duration类表示秒或纳秒时间间隔,适合处理较短的时间,需要更高的精确性。
Period类
Period类表示一段时间的年、月、日。
使用例子如下,作用是给日期加上指定的年月日。
public static void main(String[] args) {
LocalDateTime localDateTime = LocalDateTime.of(2020, 1, 1, 10, 10);
System.out.println(localDateTime); // 2020-01-01T10:10
Period of = Period.of(3, 1, 2);
System.out.println(localDateTime.plus(of)); // 2023-02-03T10:10
}
LocalDate类
LocalDate是一个不可变的日期时间对象,表示日期,通常被视为年月日。默认当前系统时区。
LocalTime类
LocalTime是一个不可变的日期时间对象,代表一个时间,通常被看作是小时-秒,时间表示为纳秒精度。默认当前系统时区。
LocalDateTime类
LocalDateTime类是一个不可变的日期时间对象,代表日期时间,通常被视为年-月-日=时-分-秒。默认当前系统时区。
如果需要手动指定时区,可以向下方这样实现。先打印可用的时区id字符串,再通过
ZoneId.of()
获取对应的时区对象。public static void main(String[] args) { // System.out.println(ZoneId.systemDefault()); // 获取当前系统默认时区字符串 ZoneId.getAvailableZoneIds().stream().forEach(System.out::println); System.out.printf("now%s\n", LocalDateTime.now(ZoneId.of("Asia/Shanghai"))); }
查看给定的LocalDateTime在其他时区的时间
public static void main(String[] args) { LocalDateTime localDateTime = LocalDateTime.of(2020, 10, 10, 11, 20, 30); // 获取指定参数对应的上海时区的时间 ZonedDateTime shanghaiTime = localDateTime.atZone(ZoneId.of("Asia/Shanghai")); // 获取指定ZoneDateTime,在另一个时区对应的时间 ZonedDateTime tokyoDateTime = shanghaiTime.withZoneSameInstant(ZoneId.of("Asia/Tokyo")); System.out.printf("shanghaiTime %s\n", shanghaiTime); System.out.printf("tokyoDateTime %s\n", tokyoDateTime); }
修改时间格式
withXXX()
系列方法,可以在不知道时间值的情况下,把对应的年月日时分秒等修改为想要的值。
Year
YearMonth
MonthDay
- 上述这些类均提供了静态的
now()
方法,可以根据当前日期或时间创建实例。- 上述这些类均提供了静态的
of()
方法可以根据给定的参数生成对应的日期/时间对象,基本上每个基本类都有of方法用于生成的对应的对象,而且重载形式对边,可以根据不同的参数生成对应的数据。- LocalDate与LocalTime都是不可变对象(确保线程安全),它们中有
plus()/minus()
系列方法,可以在已有对象上进行年月日时分秒/纳秒的加减。
Month
是一个枚举。Month中包含标准日历中的12个月份的常量(从JANUARY
到DECEMEBER
),也提供了一些方便的方法供我们使用。
推荐在初始化LocalDate和LocalDateTime对象的时候,月份的参数使用枚举的方式传入,这样更简单易懂而且不易出错。如果是老的思维,Calendar传入0的话,会出现异常。
其他相关类/接口
时间单位
TemporalUnit
:接口,主要实现类是ChronoUnit
ChronoUnit
:枚举,实现了TemporalUnit
。主要是提供一些时间单位,如时分秒,半天,年月日,四年,百年,千年...等。用法参考:public static void main(String[] args) { LocalDateTime localDateTime = LocalDateTime.of(2020, 1, 1, 10, 10); LocalDateTime localDateTime1 = localDateTime.plus(1, ChronoUnit.MILLENNIA); // 加一千年 System.out.println(localDateTime1); // 3020-01-01T10:10 }
TemporalAdjuster 调节器
使用形式:with(TemporalAdjuster adjuster)
我们可以通过with
方法修改日期时间对象中封装的数据,但是有一些时候可能会做一些复杂的操作,比如说将时间调整到下个周的周日,下一个工作日,或者本月中的某一天,这个时候可以使用调节器TemporalAdjuster
来更方便的处理日期。
如上方的使用形式,with方法有一个重载形式,需要传入一个TemporalAdjuster
对象,通过查看发现TemporalAdjuster
是一个接口,那么实际上传入的是这个接口的实现类对象,通常使用TemporalAdjusters
来生成。
如下图第3行,表示把日期修改为当月的第一天;第4行表示改为下一个周日。
public static void main(String[] args) {
LocalDateTime localDateTime = LocalDateTime.of(2020, 3, 16, 10, 10);
LocalDateTime localDateTime1 = localDateTime.with(TemporalAdjusters.firstDayOfMonth());
LocalDateTime localDateTime2 = localDateTime.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
System.out.println(localDateTime); // 2020-03-16T10:10
System.out.println(localDateTime1); // 2020-03-01T10:10
System.out.println(localDateTime2); // 2020-03-22T10:10
}
其他
Date转换为LocalDate
使用Instant中转,如下所示。
public static void main(String[] args) {
Date date = new Date();
Instant instant = date.toInstant();
ZonedDateTime zonedDateTime = instant.atZone(ZoneId.systemDefault());
LocalDate localDate = zonedDateTime.toLocalDate();
System.out.println(date);
System.out.println(localDate);
}
线程安全的日期解析与格式化工具
DateTimeFormatter
DateTimeFormatter
类提供了大量预定义格式化器,包括常量(如ISO_LOCAL_DATE
),模式字母(如yyyy-MM-dd
)以及本地化样式。
与SimpleDateFormat
不同的是,新版本的日期/时间API的格式化与解析不需要再创建转换器对象了,通过时间日期对象的parse/format
方法可以直接进行转换。
public static void main(String[] args) {
LocalDateTime localDateTime = LocalDateTime.of(2020, 3, 3, 1, 1, 1);
String s1 = localDateTime.format(DateTimeFormatter.ISO_DATE);
String s2 = localDateTime.format(DateTimeFormatter.ISO_DATE_TIME);
String s3 = localDateTime.format(DateTimeFormatter.ofPattern("yyyy,MM,dd...hh:mm:ss:SSS"));
System.out.println(s1); // 2020-03-03
System.out.println(s2); // 2020-03-03T01:01:01
System.out.println(s3); // 2020,03,03...01:01:01:000
LocalDateTime parse = LocalDateTime.parse(s3);
System.out.println(parse); // 2020-03-03T01:01:01
}
FormatStyle:
public static void main(String[] args) {
LocalDateTime localDateTime = LocalDateTime.of(2020, 3, 3, 1, 1, 1);
System.out.println(localDateTime.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL))); // 2020年3月3日 星期二
System.out.println(localDateTime.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG))); // 2020年3月3日
System.out.println(localDateTime.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM))); // 2020-3-3
System.out.println(localDateTime.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT))); // 20-3-3
}
注意
这种方式中,FULL
、LONG
在不同时区下显示的效果会不一样!
其他工具类
hutool
中关于时间的API。Joda-Time
。在java8之前就出现的一个开源包,用来解决之前的日期类相关的问题。其团队也参与了java.time
包的开发。
- 0很棒
- 0不错
- 0一般
- 0???