LocalDateTime是Java中常用的时间类,用于取代Date类。其中包括年月日时分秒的信息,支持不同时区之间的转换。
作为常用的时间类型,下面记录了一些常见用法。
获取时间
- 获取当前时间
LocalDateTime now = LocalDateTime.now() //当前时间
- 获取特定时间
LocalDateTime time = LocalDateTime.of(2024, Month.JANUARY, 16, 20, 0 ,0); //2024年1月16日20:00:00
- 获取当前日期的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秒
- 获取某个时区的时间
LocalDateTime now = LocalDateTime.now(ZoneId.of("Asia/Shanghai")); //当前上海的时间
- 对时间进行年月日时分秒的修改
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);
- 取某个点位,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);
日期计算
- 获取特定日期的年月日时分秒
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();
- 时间的增加与减少
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日。
- 时间的比较
LocalDateTime now = LocalDateTime.now();
LocalDateTime tomorrow = now.plusDays(1);
boolean isBefore = now.isBefore(tomorrow);
boolean isAfter = tomorrow.isAfter(now);
- 时间间隔的计算
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);
时间格式化
- LocalDateTime转字符串
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String now = LocalDateTime.now().format(formatter);
- 字符串转换成LocalDateTime
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String now = LocalDateTime.now().format(formatter);
LocalDateTime now = LocalDateTime.parse(now, formatter);
- 使用注解进行格式化
@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转换
- Date转为LocalDateTime
Date date = new Date();
Instant instant = date.toInstant();
LocalDateTime time = instant.atZone(ZoneId.systemDefault()).toLocalDateTime()
- 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的字段。
不同点
- 时区问题:timestamp通常存储的是UTC的时间戳,而datetime则可存放指定时区的时间。
- 范围问题:这也是我在选择时考虑的重点。timestamp作为时间戳形式存在的时间类型,自然有一个最大值和最小值。转换为时间的话,timestamp只能存放1970-01-01 08:00:01至2038年1月19日03:14:07的时间,超出这个时间则无法成功存储。但datetime就没有这个问题。
当然除了上述的相同点和不同点外,timestamp和datetime还有更多的区别,只不过那些不同点并不在该场景下进行考虑。
留言