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 中使用 Instant 和 ZonedDateTime。
关于java.time
java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.Date、Calendar 和 SimpleDateFormat。
Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。
要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310。
您可以直接与您的数据库交换 java.time 对象。使用符合JDBC 4.2 或更高版本的JDBC driver。不需要字符串,不需要java.sql.* 类。
从哪里获得 java.time 类?
ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如Interval、YearWeek、YearQuarter 和more。