关于LocalDateTime使用详解

 更新时间:2024年08月02日 10:30:45   作者:Gambler_Tu  
这篇文章主要介绍了关于LocalDateTime使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

使用 LocalDateTime 替代 Date

JDK 中的 Date 的缺点:

  • Date 如果不格式化,打印出的日期可读性差;
  • 使用 SimpleDateFormat 可以对日期时间进行格式化,但是 SimpleDateFormat 并非线性安全;
  • Date 对时间处理比较麻烦;
  • Date 这个类名的命名并不严谨。

另外,《阿里巴巴开发手册》中明确禁用 static 关键字修饰 SimpleDateFormat

Java 官方请著名的第三方日期时间包 joda-time 的作者重新设计了与日期时间有关的 API 部分,并把它们放在了 jdk 8 的 java.time 包下。

新增了:LocalDate、LocalTime、LocalDateTime 三个类及相关新的 API 用以替代 Date 及其旧的使用方式。

1. LocalDate

只会获取 年月日 信息。

LocalDate 中并不包含『时区』信息。即,一个单独的 LocalDate 对象所表达的含义是不严谨的。 LocalTime 和 LocalDateTime 也一样。

  • 创建 LocalDate 对象
LocalDate localDate = LocalDate.now();
LocalDate localDate = LocalDate.of(2000, 1, 1);
  • 获取年、月、日、星期几
LocalDate localDate = LocalDate.now();

int year = localDate.getYear();
int year = localDate.get(ChronoField.YEAR);

Month month = localDate.getMonth();
int month = localDate.get(ChronoField.MONTH_OF_YEAR);

int day = localDate.getDayOfMonth();
int day = localDate.get(ChronoField.DAY_OF_MONTH);

DayOfWeek dayOfWeak = localDate.getDayOfWeek();
int dayOfWeak = localDate.get(ChronoField.DAY_OF_WEEK);

2. LocalTime

只会获取 时分秒 信息。

  • 创建 LocalTime 对象
LocalTime localTime = LocalTime.now();
LocalTime localTime = LocalTime.of(17, 30, 0);
  • 获取时分秒
int hour = localTime.getHour();
int hour = localTime.get(ChronoField.HOUR_OF_DAY);

int minute = localTime.getMinute();
int minute = localTime.get(ChronoField.MINUTE_OF_HOUR);

int second = localTime.getSecond();
int second = localTime.get(ChronoField.SECOND_OF_MINUTE);

3. LocaDateTime

获取 年月日时分秒,等于 LocalDate + LocalTime

  • 创建 LocalDateTime
LocalDateTime localDateTime = LocalDateTime.now();
LocalDateTime localDateTime = LocalDateTime.of(2019, Month.SEPTEMBER, 10, 14, 46, 56);
LocalDateTime localDateTime = LocalDateTime.of(localDate, localTime);
LocalDateTime localDateTime = localDate.atTime(localTime);
LocalDateTime localDateTime = localTime.atDate(localDate);
  • 获取 LocalDate
LocalDate localDate = localDateTime.toLocalDate();
  • 获取 LocalTime
LocalTime localTime = localDateTime.toLocalTime();

4. Instant

在 Java 中,一个 Instant 对象标识时间轴上的一个点,代表着一个概念上的瞬间。

原点』是众所周知的 1970 年 1 月 1 日的午夜,此时本初子午线正在穿过伦敦格林威治皇家天文台。

从『原点』开始,时间按照每天 86400 秒进行正向、反向计算,向前、向后分别以纳秒为单位。

  • warning 注意:
  • Instant 是有时区概念的,在你未指定时,它的默认时区时 0 时区,即,格林威治时间。

虽然 Instant 内部是以纳秒为单位进行存储、运算的,但是很显然你可以将它转换成相较于『原点 (epoch) 』的时、分、秒。

在编程世界中,我们日常生活中所说的『』使用的是 second ;而『相较于原点的秒』使用的是 epoch secondepoch 是时代、纪元等含义。

另外,在 Java 8 中,使用 Duration 对象来代表两个 Instant 之间的时间跨度。

  • 创建 Instant 对象
Instant instant = Instant.now();
  • 获取秒数
long currentSecond = instant.getEpochSecond();
  • 获取毫秒数
long currentMilli = instant.toEpochMilli();

个人觉得如果只是为了获取秒数或者毫秒数,使用 System.currentTimeMillis() 来得更为方便。

5. 修改 LocalDate、LocalTime、LocalDateTime、Instant

LocalDate、LocalTime、LocalDateTime、Instant 为『不可变对象』,修改这些对象对象会返回一个副本,即生成并返回一个新对象。

  • 增加、减少年数、月数、天数等 以 LocalDateTime 为例
LocalDateTime localDateTime = LocalDateTime.of(2019, Month.SEPTEMBER, 10, 14, 46, 56);

// 增加一年
localDateTime = localDateTime.plusYears(1);
localDateTime = localDateTime.plus(1, ChronoUnit.YEARS);

// 减少一个月
localDateTime = localDateTime.minusMonths(1);
localDateTime = localDateTime.minus(1, ChronoUnit.MONTHS);
  • 通过 with 修改某些值
// 修改年为 2019
localDateTime = localDateTime.withYear(2020);
// 修改为 2022
localDateTime = localDateTime.with(ChronoField.YEAR, 2022);

// 还可以修改月、日

6. 使用 TemporalAdjuster 和 TemporalAdjusters

有的时候,你需要进行一些更加复杂的日期操作,比如,将日期调整到下个周日、下个工作日,或者是本月的最后一天。这时,你可以使用重载版本的 withXXX 方法,向其传递一个提供了更多定制化选择的 TemporalAdjuster 对象, 更加灵活地处理日期。

比如有些时候想知道这个月的最后一天是几号、下个周末是几号,通过提供的时间和日期API可以很快得到答案。

对于最常见的用例,日期和时间 API 已经提供了大量预定义的 TemporalAdjuster 对象。你可以通过 TemporalAdjusters (注意,此处有 s) 类的静态工厂方法访问它们。

TemporalAdjusters 类中的常用工厂方法:

  • dayOfWeekInMonth 创建一个新的日期,它的值为同一个月中每一周的第几天
  • firstDayOfMonth 创建一个新的日期,它的值为当月的第一天
  • firstDayOfNextMonth 创建一个新的日期,它的值为下月的第一天
  • firstDayOfNextYear 创建一个新的日期,它的值为明年的第一天
  • firstDayOfYear 创建一个新的日期,它的值为当年的第一天
  • firstInMonth 创建一个新的日期,它的值为同一个月中,第一个符合星期几要求的值
  • lastDayOfMonth 创建一个新的日期,它的值为当月的最后一天
  • lastDayOfNextMonth 创建一个新的日期,它的值为下月的最后一天
  • lastDayOfNextYear 创建一个新的日期,它的值为明年的最后一天
  • lastDayOfYear 创建一个新的日期,它的值为今年的最后一天
  • lastInMonth 创建一个新的日期,它的值为同一个月中,最后一个符合星期几要求的值
  • next / previous 创建一个新的日期,并将其值设定为日期调整后或者调整前,第一个符合指定星 期几要求的日期
  • nextOrSame / previousOrSame 创建一个新的日期,并将其值设定为日期调整后或者调整前,第一个符合指定星 期几要求的日期,如果该日期已经符合要求,直接返回该对象

7. 格式化时间

DateTimeFormatter 默认提供了多种格式化方式,如果默认提供的不能满足要求,可以通过 DateTimeFormatter 的 ofPattern 方法创建自定义格式化方式。

LocalDate localDate = LocalDate.of(2019, 9, 10);
String s1 = localDate.format(DateTimeFormatter.BASIC_ISO_DATE);
String s2 = localDate.format(DateTimeFormatter.ISO_LOCAL_DATE);

// 自定义格式化
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
String s3 = localDate.format(dateTimeFormatter);

8. 解析时间

相较于传统的 SimpleDateFormat,DateTimeFormatter 是线程安全的

LocalDate localDate1 = LocalDate.parse("20190910", DateTimeFormatter.BASIC_ISO_DATE);
LocalDate localDate2 = LocalDate.parse("2019-09-10", DateTimeFormatter.ISO_LOCAL_DATE);

Date 与 LocalDate 互转:

  • Date 转 LocalDate
// Date 转 LocalDate
public static LocalDate date2LocalDate(Date date) {
  return (date == null) ? (null) : (date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate());
}
  • LocalDate 转 Date
//  LocalDate转Date
public static Date localDate2Date(LocalDate localDate) {
  return (localDate == null) ? (null) : (Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant()));
}

9. 带时区的时间

LocalDate、LocalTime 和 LocalDateTime 是不带时区信息的。在 JDK 8 中,带有时区信息的日期时间类是 ZonedDateTime

因特网编号管理局 (IANA) 维护着一份全球所有已知时区的数据库(http://www.iana.org/time-zones),每年会更新几次(这些更新主要处理夏令时规则的改变)。Java 就是使用了 IANA 的数据库。

在 Java 中,每个时区都有一个 ID,例如 Asia/Shanghai 。想要获得所有可用的时区,你可以调用 ZoneId.getAvailableZoneIds() 。 大概有 600 个。

如果你想获得 ZonedDateTime 对象,你有 2 种途径:

  • 直接使用 ZonedDateTime.of() 方法创建;
  • 先创建一个 LocalDateTime 对象 (它不含时区概念) ,再调用它的 atZone 方法,赋予它时区的概念,生成 ZonedDateTime 对象。

10. SpringBoot 中应用 LocalDateTime

将 LocalDateTime 字段以时间戳的方式返回给前端。

添加日期转化类:

public class LocalDateTimeConverter extends JsonSerializer<LocalDateTime> {

    @Override
    public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        gen.writeNumber(value.toInstant(ZoneOffset.of("+8")).toEpochMilli());
    }
}

并在 LocalDateTime 字段上添加 @JsonSerialize(using = LocalDateTimeConverter.class) 注解,如下:

@JsonSerialize(using = LocalDateTimeConverter.class)
protected LocalDateTime gmtModified;

将 LocalDateTime 字段以指定格式化日期的方式返回给前端

在 LocalDateTime 字段上添加 @JsonFormat(shape=JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss") 注解即可,如下:

@JsonFormat(shape=JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss")
protected LocalDateTime gmtModified;

对前端传入的日期进行格式化

在 LocalDateTime 字段上添加 @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") 注解即可,如下:

@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
protected LocalDateTime gmtModified;

Java Date and Time API 用在持久层

LocalDateTime in Mybatis

MyBatis 从 3.4.5 版本开始就完全支持这种类型了,不在需要自己去写类型转换 。

LocalDateTime in spring-data-jpa

<dependency>
  <groupId>org.hibernate</groupId>
  <artifactId>hibernate-java8</artifactId>
</dependency>

LocalDateTime in spring-data-redis

<dependency>
  <groupId>com.fasterxml.jackson.datatype</groupId>
  <artifactId>jackson-datatype-jsr310</artifactId>
</dependency>

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • 一文带你了解Spring中存入Bean和获取Bean的方式

    一文带你了解Spring中存入Bean和获取Bean的方式

    这篇文章主要带大家了解Spring中存入Bean和获取Bean的方式,文中的代码示例讲解的非常详细,对我们的学习或工作有一定的帮助,需要的朋友可以参考下
    2023-07-07
  • spring boot高并发下耗时操作的实现方法

    spring boot高并发下耗时操作的实现方法

    这篇文章主要给大家介绍了关于spring boot高并发下耗时操作的实现方法,文中通过示例代码介绍的非常详细,对大家学习或者使用spring boot具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-11-11
  • 深入理解Java中的Properties类

    深入理解Java中的Properties类

    Properties类是Java中用于处理配置文件的工具类,它继承自 Hashtable类,实现了Map接口,本文主要介绍了Java中的Properties类,感兴趣的可以了解一下
    2024-01-01
  • Java利用Spire.XLS for Java实现自动化生成PDF文档

    Java利用Spire.XLS for Java实现自动化生成PDF文档

    在 Java 后端高效灵活地实现 PDF 文档的生成,常常是困扰开发者的一个痛点,本文将为您介绍如何利用 Spire.XLS for Java 轻松驾驭 Java 中的 PDF 文档生成,感兴趣的小伙伴可以了解下
    2026-02-02
  • Java之Set String List互转方式

    Java之Set String List互转方式

    文章总结了Java中Set与String以及List之间的相互转换方法,通过代码示例展示了如何将Set转为List,再将List转为Set,以及如何将List转为String,最后又将String转为List的过程
    2026-04-04
  • SpringSecurity实现登陆认证并返回token方式

    SpringSecurity实现登陆认证并返回token方式

    这篇文章主要介绍了SpringSecurity实现登陆认证并返回token方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-03-03
  • SpringBoot整合SpringAI配置多平台API密钥的解决方案

    SpringBoot整合SpringAI配置多平台API密钥的解决方案

    本文介绍了如何在SpringBoot项目中整合SpringAI配置平台API密钥,包括添加依赖、配置文件、配置属性类及核心配置类等,通过动态切换不同AI平台,实现统一接口调用,此外,支持YAML配置和环境变量,便于灵活配置和扩展新平台,需要的朋友可以参考下
    2026-05-05
  • 关于SpringBoot整合RabbitMQ实现死信队列

    关于SpringBoot整合RabbitMQ实现死信队列

    这篇文章主要介绍了关于SpringBoot整合RabbitMQ实现死信队列,死信队列实际上就是一个普通的队列,只是这个队列跟死信交换机进行了绑定,用来存放死信而已,需要的朋友可以参考下
    2023-05-05
  • 2020最新eclipse安装过程及细节

    2020最新eclipse安装过程及细节

    这篇文章主要介绍了2020最新eclipse安装过程及细节,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-08-08
  • 浅谈Java内部类——静态内部类

    浅谈Java内部类——静态内部类

    这篇文章主要介绍了Java静态内部类的相关资料,帮助大家更好的理解和学习Java内部类的相关知识,感兴趣的朋友可以了解下
    2020-08-08

最新评论