内容纲要

LocalDateTime是Java中常用的时间类,用于取代Date类。其中包括年月日时分秒的信息,支持不同时区之间的转换。

作为常用的时间类型,下面记录了一些常见用法。

获取时间

  1. 获取当前时间
LocalDateTime now = LocalDateTime.now()                                 //当前时间
  1. 获取特定时间
LocalDateTime time = LocalDateTime.of(2024, Month.JANUARY, 16, 20, 0 ,0);   //2024年1月16日20:00:00
  1. 获取当前日期的0点和24点
LocalDateTime.of(now.toLocalDate(), LocalTime.MIN));            //当天0点
LocalDateTime.of(LocalDate.now(), LocalTime.MIN);                   //当天0点
LocalDateTime.of(now.toLocalDate(), LocalTime.MAX);             //当天23点59分59秒
LocalDateTime.of(LocalDate().now(), LocalTime.MAX);             //当天23点59分59秒
  1. 获取某个时区的时间
LocalDateTime now = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));        //当前上海的时间
  1. 对时间进行年月日时分秒的修改
LocalDateTime now = LocalDateTime.now();
LocalDateTime localDateTime = now.withYear(2023);
LocalDateTime localDateTime1 = now.withMonth(2);
LocalDateTime localDateTime2 = now.withDayOfMonth(15);
LocalDateTime localDateTime3 = now.withHour(20);
LocalDateTime localDateTime4 = now.withMinute(16);
  1. 取某个点位,eg:最近的5分钟点位,比如5分/10分/15分
Integer minute = now.getMinute();
minute = minute/5*5;
LocalDateTime.of(now.getYear(), now.getMonth(), now.getDayOfMonth(), now.getHour(), minute, 0);

日期计算

  1. 获取特定日期的年月日时分秒
LocalDateTime now = LocalDateTime.now();
int year = now.getYear();
Month month = now.getMonth();
int dayOfYear = now.getDayOfYear();
int dayOfMonth = now.getDayOfMonth();
DayOfWeek dayOfWeek = now.getDayOfWeek();           //星期X
int hour = now.getHour();
int minute = now.getMinute();
int second = now.getSecond();
  1. 时间的增加与减少
LocalDateTime now = LocalDateTime.now();
LocalDateTime localDateTime = now.plusDays(1);
LocalDateTime localDateTime1 = now.minusDays(1);
LocalDateTime localDateTime2 = now.plusMonths(1);
LocalDateTime localDateTime3 = now.minusMonths(1);
LocalDateTime localDateTime4 = now.plusYears(1);
LocalDateTime localDateTime5 = now.minusYears(1);
LocalDateTime localDateTime6 = now.plusMinutes(1);
LocalDateTime localDateTime7 = now.minusMinutes(1);

注意:当进行月份的加减时会涉及到该日期有效性的计算,比如对3月31日加1个月会成为哪个日期的问题。LocalDateTime的逻辑会在进行月份加减后判断该日期是否有效,比如示例中4月31日显然就是无效的,这时返回值会取最近的有效值,为4月30日。

  1. 时间的比较
LocalDateTime now = LocalDateTime.now();
LocalDateTime tomorrow = now.plusDays(1);
boolean isBefore = now.isBefore(tomorrow);
boolean isAfter = tomorrow.isAfter(now);
  1. 时间间隔的计算
LocalDateTime now = LocalDateTime.now();
LocalDateTime tomorrow = now.plusDays(1);
Duration duration = Duration.between(now, tomorrow);
long days = duration.toDays();
long hours = duration.toHours();
long minutes = duration.toMinutes();

可以用Period计算LocalDate的间隔

LocalDate today = LocalDate.now();
LocalDate tomorrow = today.plusDays(1);
Period period = Period.between(today, tomorrow);

时间格式化

  1. LocalDateTime转字符串
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String now = LocalDateTime.now().format(formatter);
  1. 字符串转换成LocalDateTime
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String now = LocalDateTime.now().format(formatter);                                
LocalDateTime now = LocalDateTime.parse(now, formatter);      
  1. 使用注解进行格式化
@JsonSerialize(using = LocalDateTimeSerializer.class)
private LocalDateTime time;
@JsonFormat(shape=JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss")
private LocalDateTime time;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime time;

LocalDateTime与Date转换

  1. Date转为LocalDateTime
Date date = new Date();
Instant instant = date.toInstant();
LocalDateTime time = instant.atZone(ZoneId.systemDefault()).toLocalDateTime()
  1. LocalDateTime转为Date
LocalDateTime now = LocalDateTime.now();
Date date = Date.from(now.toInstant(ZoneOffset.of("+8")));

时区转换

该场景常用于系统需要进行多时区适配的场景。在这种场景下,数据库中存放的数据为UTC时区的时间,而针对每个时区的用户都需要显示该时区的时间。同时在用户根据时间范围进行搜索时,也需要转化成UTC时间后在数据库中进行检索。

LocalDate now = LocalDate.now(ZoneId.of("Asia/Shanghai"));
//获取上海时区今日0点时的UTC时间
LocalDateTime startTime = ZonedDateTime.of(now, LocalTime.MIN, ZoneId.of("Asia/Shanghai"))
  .withZoneSameInstant(ZoneId.of("UTC"))
  .toLocalDateTime();
//获取上海时区今日23:59时的UTC时间
LocalDateTime endTime = ZonedDateTime.of(thirtyDays, LocalTime.MAX, ZoneId.of("Asia/Shanghai"))
  .withZoneSameInstant(ZoneId.of("UTC"))
  .toLocalDateTime();

数据库中的LocalDateTime

当我们定义了一个包含LocalDateTime类型字段的类后,若这个类需要在数据库中持久化,那么我们也可以在创建表时指定该字段为datetime以存储LocalDateTime字段。

示例如下:

public class User {
  private Long id;
  private String name;
  private LocalDateTime createdTime;
  private LocalDateTime updatedTime;
}

对于这样一个用户类,我们定义了两个LocalDateTime的字段,分别是记录创建的时间和记录更新的时间。那么对于这个类做持久化的话,创建表的sql可以这样写:

create table user
(
    id bigint auto_increment comment '主键ID',
    name varchar(32) not null comment '用户名',
    created_time datetime default now() not null comment '创建时间',
    updated_time datetime default now() not null comment '更新时间',
    constraint user_pk
        primary key (id)
);

datetime和timestamp的区别

看到上面的sql后可能会有人有疑问,为什么是使用datetime而不是timestamp呢?那么我们就稍微看一下在这个示例场景下的datetime和timestamp的区别和使用问题。

相同点

timestamp和datetime都是表示日期和时间的数据类型,都可用于Mysql,也都可存储LocalDateTime的字段。

不同点
  1. 时区问题:timestamp通常存储的是UTC的时间戳,而datetime则可存放指定时区的时间。
  2. 范围问题:这也是我在选择时考虑的重点。timestamp作为时间戳形式存在的时间类型,自然有一个最大值和最小值。转换为时间的话,timestamp只能存放1970-01-01 08:00:012038年1月19日03:14:07的时间,超出这个时间则无法成功存储。但datetime就没有这个问题。

当然除了上述的相同点和不同点外,timestamp和datetime还有更多的区别,只不过那些不同点并不在该场景下进行考虑。

最后修改日期: 2024年1月18日

留言

撰写回覆或留言

发布留言必须填写的电子邮件地址不会公开。