SimpleDateFormat 不解析毫秒,MySql 正在舍入日期

Posted

技术标签:

【中文标题】SimpleDateFormat 不解析毫秒,MySql 正在舍入日期【英文标题】:SimpleDateFormat not parsing milliseconds and MySql is rounding Date 【发布时间】:2018-09-17 17:15:33 【问题描述】:

我正在使用 SimpleDateFormat 将字符串解析为日期。 解析后,我将此日期加载到 mysql。问题是毫秒没有被解析为日期,当我在 Mysql 上插入对象时,它会被四舍五入。

myStringDate = "2018-02-02 23:59:59.700"
SimpleDateFormat fmt = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss.SSS");
myObject.setDate(fmt.parse(myStringDate );

当我调试代码时,我可以看到日期为 Sun Feb 02 23:59:59 BRST 2018(它不存储毫秒)

数据在mysql上存储为'2017-02-03 00:00:00'

我的模型映射为:

import javax.persistence.*;
import java.util.Date;

@Temporal(TemporalType.TIMESTAMP)
@Column(name = "date")
private Date date;

MySqls 上的列是 TYPE DATETIME。

【问题讨论】:

Spring 不支持现代的java.time 日期和时间类型吗?我会使用LocalDateTime 而不是Date。该课程和SimpleDateFormat 早已过时。现代 API 更易于使用。 【参考方案1】:

我认为实际上是在解析毫秒,只是在显示用于调试目的的日期时没有使用默认格式看到它们。

使用此代码:

SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
String myStringDate = "2018-02-02 23:59:59.700";
Date date = fmt.parse(myStringDate);
System.out.println(date);
System.out.println(fmt.format(date));

我得到这个输出:

Fri Feb 02 23:59:59 EST 2018
2018-02-02 23:59:59.700

更新:请确保您在本月使用大写字母 MM,而不是 mm

【讨论】:

注意小数部分是微秒(不是毫秒)。 “一个 DATETIME 或 TIMESTAMP 值可以包括一个尾随小数秒部分,精度高达微秒(6 位)...... DATETIME 值的范围是 '1000-01-01 00:00:00.000000' 到 '9999-12-31 23:59:59.999999'"dev.mysql.com/doc/refman/8.0/en/datetime.html 虽然 MySQL 可能以微秒为单位处理,但 Java 的原始日期/时间 API(OP 正在使用)仅处理毫秒分辨率。 Java 8 引入的日期/时间 API 可以达到纳秒级分辨率(尽管实际上,对于来自系统时钟的当前时间,您可能只能获得毫秒级分辨率)。【参考方案2】:

tl;博士

myPreparedStatement.setObject(
    … ,
    LocalDateTime.parse( 
        "2017-02-03 00:00:00".replace( " " , "T" ) 
    )
)

智能类型,而不是哑字符串

数据在mysql上存储为'2017-02-03 00:00:00'

不,数据不是以这种方式存储的。你说:

MySqls 的列是 TYPE DATETIME。

这意味着日期时间存储为文本,并且没有“格式”。

正如the documentation 所说:

DATETIME 类型用于同时包含日期和时间部分的值。 MySQL 以 'YYYY-MM-DD HH:MM:SS' 格式检索和显示 DATETIME 值。

关键词有:检索和展示。提取日期时间值后,构造一些文本来表示该值。 不要将日期时间值的文本表示与日期时间值混为一谈。 您的数据库和 Java 都有自己内部定义的日期时间存储方式,但都不使用纯文本.您的数据库和 Java 都可以根据需要生成文本以显示日期时间值。

未分区

我是Postgres 用户,而不是MySQL,但它的DATETIME 类型似乎类似于SQL 标准的TIMESTAMP WITHOUT TIME ZONE 类型。这意味着它确实代表一个实际的时刻,不是时间线上的一个点。它代表了大约 26-27 小时范围内的潜在时刻。如果没有time zone 或offset-from-UTC 的上下文,它就没有真正的意义。

java.time 类

避免使用旧的日期时间类型。请仅使用 java.time 类。根据this Question,JPA 和 Hibernate 现在支持 java.time 类型。

如果您确实有输入文本,例如 2018-02-02 23:59:59.700,则解析为 LocalDateTime,因为缺少区域/偏移信息。与 MySQL 类型 DATETIME 和 SQL 类型 TIMESTAMP WITHOUT TIME ZONE 一样,此类缺少任何区域/偏移量的概念。要进行解析,请将中间带有 SPACE 的 SQL 样式转换为中间带有 T 的 ISO 8601 标准格式。

String input = "2018-02-02 23:59:59.700".replace( " " , "T" ) ;

java.time 类在解析/生成字符串时默认使用 ISO 8601 格式。所以不需要定义格式化模式。

LocalDateDate ldt = LocalDateTime.parse( input ) ;

与数据库通信时不需要字符串。从 JDBC 4.2 及更高版本开始,您可以直接交换 java.time 对象。 (或者让 JPA/Hibernate 在幕后进行。)

myPreparedStatement.setObject( … , ldt ) ;

和检索。

LocalDateTime ldt = myResultSet.getObject( … , LocalDateTime.class ) ;

仅供参考,如果您实际上是在尝试及时跟踪特定时刻,则说明您使用了错误的类型。您应该在 MySQL 中使用 TIMESTAMP 或在标准 SQL 中使用 TIMESTAMP WITH TIME ZONE,在 Java 中使用 InstantZonedDateTime


关于java.time

java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.DateCalendarSimpleDateFormat

Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。

要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310。

您可以直接与您的数据库交换 java.time 对象。使用符合JDBC 4.2 或更高版本的JDBC driver。不需要字符串,不需要java.sql.* 类。

从哪里获得 java.time 类?

Java SE 8Java SE 9 及更高版本 内置。 标准 Java API 的一部分,带有捆绑实现。 Java 9 添加了一些小功能和修复。 Java SE 6Java SE 7 ThreeTen-Backport 中的大部分 java.time 功能都向后移植到 Java 6 和 7。 Android java.time 类的 android 捆绑包实现的更高版本。 对于早期的 Android (ThreeTenABP 项目采用 ThreeTen-Backport(如上所述)。见How to use ThreeTenABP…

ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuarter 和more。

【讨论】:

【参考方案3】:

如果您使用 MySQL 的 5.6.4 版,您可以通过声明具有小数秒时间数据类型的列来看到这种情况。

This 文档显示了有关此功能的更多详细信息,并且就快速检查而言 - 您可以尝试 SELECT NOW(3) 应该以毫秒精度为您提供 MySQL 服务器操作系统的当前时间,而不是如果您出现错误,那么您没有使用正确的版本。

除此之外,非常建议从旧的 Connector/J 驱动程序迁移到 mysql-connector-java-5.1.26.jar

希望这有助于回答您的问题!

【讨论】:

【参考方案4】:

一年中月份的模式应该是MM(大写)而不是mm(小写)SimpleDateFormat。您的代码可能会将月份读取为分钟值。

【讨论】:

【参考方案5】:

SQL 中的日期格式为 YY-MM-dd hh24:mi:ss:mmm,而 Java 中的日期格式为 YY-MM-dd HH:mm:ss.SSS

【讨论】:

【参考方案6】:

我使用了 LocalDateTime:

@Column(name = "date", columnDefinition = "DATETIME(3)") 私有 LocalDateTime 日期;

【讨论】:

以上是关于SimpleDateFormat 不解析毫秒,MySql 正在舍入日期的主要内容,如果未能解决你的问题,请参考以下文章

将时间戳(字符串)转换为毫秒(长)

Date和SimpleDateFormat

SimpleDateFormat.format的简单使用小结

java===Date,DateFormat,SimpleDateFormat,Calendar类

java中Date类DateFormat及SimpleDateFormat简介

java中Date类DateFormat及SimpleDateFormat简介