开发中时间变换问题汇总
各个时间类型概念及转换
1. 数据库中的时间类型
1.1 DATE类型
DATE
只表示日期,检索以YYYY-MM-DD
的格式显示,范围是1000-01-01到9999-12-31。因为没有时分秒,所以会损失时间精度。
1.2 DATETIME类型
DATETIME
表示了日期和时间,检索以YYYY-MM-DD HH:MM:SS
格式显示。
时间范围是 “1000-00-00 00:00:00” 到 “9999-12-31 23:59:59”。
1.3 TIME类型
TIME
只表示时间,检索以HH:MM:SS
格式显示,范围是00:00:00到23:59:59
1.4 TIMESTAMP类型
TIMESTAMP
似于linux系统 中的unix timestamp,是一个记录了从格林威治时间 1970 年 01 月 01 日 00 时 00 分 00 秒(北京时间 1970 年 01 月 01 日 08 时 00 分 00 秒)起至现在的总秒数
。
此外还可以精确到毫秒
、微秒
,timestamp(3)指毫秒,timestamp(6)微秒。
支持的时间范围是 “1970-01-01 00:00:01” 到 “2038-01-19 03:14:07”。
TIMESTAMP
和DATETIME
表示格式一样两者的不同点如下
- 当使用
TIMESTAMP
的时候,数据有更新的时候这个字段自动更新为当前时间,所以可以作为lastmodify使用,这个变化是默认设置,如果想使时间不更新可以设置DEFAULT CURRENT_TIMESTAMP TIMESTAMP
的范围不能早于1970或者晚于2037,超过这个时间范围的话为0TIMESTAMP
存储的时候是转为UTC存储的,获取的时候根据客户端所在时区进行展示timestamp占4个字节
,datetime占8个字节
2. Java中的时间类型
2.1 yyyy-MM-dd HH:mm:ss代表的意义
字符 | 意义 | 时间 |
---|---|---|
yyyy | 年 | 2018 |
MM`` | 月 |
01 |
dd | 天 | 16 |
hh |
12小时制 |
03 |
HH |
24小时制 |
15 |
mm |
分 | 59 |
ss | 秒 | 59 |
SSS | 毫米 | 333 |
2.2 java.util.Date类
Java
的java.util.Date
类是Java
最初的时间类之一。今天该类的大部分方法已不推荐使用,取而代之的是java.util.Calendar
类。
@Test
public void testDateTime(){
Date date = new Date();
date; // 默认使用当前的系统时间:Tue Oct 06 18:56:37 CST 2020
date.getTime(); // 获取当前对象距离1970年1月1日0时0分0秒的毫秒数:1601981797012
SimpleDateFormat dateFormat1 = new SimpleDateFormat("yyyy-MM-dd"); // 用来格式化时间
SimpleDateFormat dateFormat2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
dateFormat1.format(date); // 返回的是字符串格式:2020-10-06
dateFormat2.format(date); // 返回的是字符串格式:2020-10-06 18:56:37
}
2.2 java.sql中的时间类型
java.sql包中有三种时间类型:
Date
:表示日期。如:2018-08-26,只有年月日。
Time
:表示时间。如:11:52:08,只有时分秒。
Timestamp
:表示时间戳。如:2018-08-26 11:52:08.896,有年月日时分秒,以及毫秒。
这三种时间类型都是继承于java.util.Date
类,所以sql中的时间类型是对父类的引用,不需要进行转换
public class Date extends java.util.Date{}
public class Time extends java.util.Date {}
public class Timestamp extends java.util.Date {}
java.sql包下的Date、Time、TimeStamp三个类的构造器都需要一个long类型的参数,表示毫秒值。
java.util.Date d = new java.util.Date();
//时间的long型数据
long longtime = d.getTime();
//Date日期: 2020-10-06
java.sql.Date date = new java.sql.Date(longtime);
//Time时间: 19:06:45
java.sql.Time time = new java.sql.Time(longtime);
//Timestamp时间戳,有年月日时分秒,以及毫秒 : 2020-10-06 19:06:45.603
java.sql.Timestamp timestamp = new java.sql.Timestamp(longtime);
2.3 java.time
Java的 Date,Calendar类型与前端和数据库交互起来较为麻烦,而且Date类线程不安全等诸多弊端。
在Java8时推出了线程安全、简易、高可靠的time
包。并且数据库中也支持LocalDateTime类型,在数据存储时候使时间变得简单。
time包中有三个重要的时间类型:年月日时分秒毫秒类型LocalDateTime
、年月日类型LocalDate
、时分秒毫秒类型LocalTime
和数据库中的时间类型一致。
简单使用
- 获取当前时间
LocalDate.now(); // 2020-10-06
LocalTime.now(); // 19:13:49.696 时分秒毫秒
LocalDateTime.now(); // 2020-10-06T19:13:49.696
- 时间格式化:使用
DateTimeFormatter
是线程安全的,而SimpleDateFormat
是线程不安全的。
// 2020-10-06T19:21:39.254
LocalDateTime now = LocalDateTime.now();
// 年月日: 2020-10-06
String format = now.format(DateTimeFormatter.ISO_LOCAL_DATE);
// 时分秒毫秒 : 2020-10-06
String format1 = now.format(DateTimeFormatter.ISO_TIME);
// 2020-10-06 19:21:39
String format2 = now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
2.4 Date与LocalDateTime转换
参考:https://www.cnblogs.com/huanshilang/p/12013386.html
/**
* LocalDateTime转毫秒时间戳
* @param localDateTime LocalDateTime
* @return 时间戳
*/
public static Long localDateTimeToTimestamp(LocalDateTime localDateTime) {
try {
ZoneId zoneId = ZoneId.systemDefault();
Instant instant = localDateTime.atZone(zoneId).toInstant();
return instant.toEpochMilli();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 时间戳转LocalDateTime
* @param timestamp 时间戳
* @return LocalDateTime
*/
public static LocalDateTime timestampToLocalDateTime(long timestamp) {
try {
Instant instant = Instant.ofEpochMilli(timestamp);
ZoneId zone = ZoneId.systemDefault();
return LocalDateTime.ofInstant(instant, zone);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* Date转LocalDateTime
* @param date Date
* @return LocalDateTime
*/
public static LocalDateTime dateToLocalDateTime(Date date) {
try {
Instant instant = date.toInstant();
ZoneId zoneId = ZoneId.systemDefault();
return instant.atZone(zoneId).toLocalDateTime();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* LocalDateTime转Date
* @param localDateTime LocalDateTime
* @return Date
*/
public static Date localDateTimeToDate(LocalDateTime localDateTime) {
try {
ZoneId zoneId = ZoneId.systemDefault();
ZonedDateTime zdt = localDateTime.atZone(zoneId);
return Date.from(zdt.toInstant());
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
2.5 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 createdTime;
方式二:
将LocalDateTime字段
以指定格式化
日期的方式返回给前端
在LocalDateTime字段上添加
@JsonFormat(shape = JsonFormat.Shape.STRING,
pattern = "yyyy-MM-dd HH:mm:ss",
timezone = "GMT+8")
protected LocalDateTime createdTime;
对前端传入的日期进行格式化
在LocalDateTime字段
上添加
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
protected LocalDateTime gmtModified;
2.6 MybatisPlus操作时间数据类型
假如数据库中的时间类型为datetime
,那么使用高版本
的MybatisPlus生成器生成的实体类的时间类型为LocalDateTime
例如:
// 数据库中的时间类型
`created_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '文件创建时间',
// java中的时间类型
private LocalDateTime createdTime;
BUG:
当使用MP操作数据库进行数据查询时,如果druid
数据库连接池的版本低于1.1.18
将会因为时间格式不匹配而报错
Error attempting to get column 'create_time' from result set.
Cause: java.sql.SQLFeatureNotSupported
解决:
将druid
数据库连接池升级到1.1.18版本以上
即可正常操作,不需要转换实体类中的时间类型为Date