无法插入零秒的 java.time.LocalDateTime
Cannot insert java.time.LocalDateTime with zero seconds
科特林:1.6.20
Ktorm: 3.4.1
MySQL Connector/J: 8.0.28
C3P0 连接池:0.9.5.5
我似乎对零秒的“日期时间”(LocalDateTime) 有疑问。我知道这看起来像是 JDBC 驱动程序的问题,但我测试了该驱动程序,它甚至不接受 LocalDateTime(仅 java.util.Date)。如果 LDT 确实有秒数,则不会出现此问题。
- 我是不是做错了什么?
- 我是不是缺少一些配置?
- 我是不是弄错了类型?
- 有人知道解决方法吗?
我用来隔离问题的最低测试
const val tableName = "test"
const val fieldName = "ldt"
interface TestRecord : Entity<TestRecord> {
companion object : Entity.Factory<TestRecord>()
val ldt: LocalDateTime
}
object TestTable : Table<TestRecord>(tableName) {
val ldt = datetime(fieldName).bindTo { it.ldt }
}
class BlahTest {
@Test
fun a() {
val dataSource = DbConfig.from("test.properties").provideDataSource()
dataSource.connection.use {
it.prepareStatement("DROP TABLE IF EXISTS $tableName").execute()
it.prepareStatement("CREATE TABLE IF NOT EXISTS $tableName ($fieldName TIMESTAMP)").execute()
}
val db = Database.connect(dataSource = dataSource, dialect = MySqlDialect())
val tb = TestTable
val ldt = LocalDateTime.ofEpochSecond(0, 0, ZoneOffset.UTC)
.truncatedTo(ChronoUnit.SECONDS)
//.plusSeconds(1) // with anything but 0 it will work
db.insertOrUpdate(TestTable) {
set(tb.ldt, ldt)
}
}
}
产生错误
com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Incorrect datetime value: '1970-01-01 00:00:00' for column 'ldt' at row 1
异常是将时间戳值 0 格式化为“1970-01-01 00:00:00”,但 MySQL 不是。
https://dev.mysql.com/doc/refman/8.0/en/datetime.html 说:
MySQL converts TIMESTAMP
values from the current time zone to UTC for storage, and back from UTC to the current time zone for retrieval. (This does not occur for other types such as DATETIME
.)
例如,我在 PDT,所以当我尝试插入时间戳值 0 时,它会将其调整 8 小时为“1969-12-31 16:00:00”,这是不合法的TIMESTAMP
类型范围内的值。
mysql> create table tablename (ldt timestamp);
mysql> insert into tablename values (from_unixtime(0));
ERROR 1292 (22007): Incorrect datetime value: '1969-12-31 16:00:00' for column 'ldt' at row 1
因此,当您生成要插入 TIMESTAMP
的“零”值时,您可以确保考虑时区。
或者您可以使用 DATETIME
.
mysql> alter table tablename modify ldt datetime;
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> insert into tablename values (from_unixtime(0));
Query OK, 1 row affected (0.00 sec)
我还是推荐使用 DATETIME
,因为它支持比 TIMESTAMP
更大的日期范围。这将变得很重要 if you need to store dates past 2038-01-19.
科特林:1.6.20
Ktorm: 3.4.1
MySQL Connector/J: 8.0.28
C3P0 连接池:0.9.5.5
我似乎对零秒的“日期时间”(LocalDateTime) 有疑问。我知道这看起来像是 JDBC 驱动程序的问题,但我测试了该驱动程序,它甚至不接受 LocalDateTime(仅 java.util.Date)。如果 LDT 确实有秒数,则不会出现此问题。
- 我是不是做错了什么?
- 我是不是缺少一些配置?
- 我是不是弄错了类型?
- 有人知道解决方法吗?
我用来隔离问题的最低测试
const val tableName = "test"
const val fieldName = "ldt"
interface TestRecord : Entity<TestRecord> {
companion object : Entity.Factory<TestRecord>()
val ldt: LocalDateTime
}
object TestTable : Table<TestRecord>(tableName) {
val ldt = datetime(fieldName).bindTo { it.ldt }
}
class BlahTest {
@Test
fun a() {
val dataSource = DbConfig.from("test.properties").provideDataSource()
dataSource.connection.use {
it.prepareStatement("DROP TABLE IF EXISTS $tableName").execute()
it.prepareStatement("CREATE TABLE IF NOT EXISTS $tableName ($fieldName TIMESTAMP)").execute()
}
val db = Database.connect(dataSource = dataSource, dialect = MySqlDialect())
val tb = TestTable
val ldt = LocalDateTime.ofEpochSecond(0, 0, ZoneOffset.UTC)
.truncatedTo(ChronoUnit.SECONDS)
//.plusSeconds(1) // with anything but 0 it will work
db.insertOrUpdate(TestTable) {
set(tb.ldt, ldt)
}
}
}
产生错误
com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Incorrect datetime value: '1970-01-01 00:00:00' for column 'ldt' at row 1
异常是将时间戳值 0 格式化为“1970-01-01 00:00:00”,但 MySQL 不是。
https://dev.mysql.com/doc/refman/8.0/en/datetime.html 说:
MySQL converts
TIMESTAMP
values from the current time zone to UTC for storage, and back from UTC to the current time zone for retrieval. (This does not occur for other types such asDATETIME
.)
例如,我在 PDT,所以当我尝试插入时间戳值 0 时,它会将其调整 8 小时为“1969-12-31 16:00:00”,这是不合法的TIMESTAMP
类型范围内的值。
mysql> create table tablename (ldt timestamp);
mysql> insert into tablename values (from_unixtime(0));
ERROR 1292 (22007): Incorrect datetime value: '1969-12-31 16:00:00' for column 'ldt' at row 1
因此,当您生成要插入 TIMESTAMP
的“零”值时,您可以确保考虑时区。
或者您可以使用 DATETIME
.
mysql> alter table tablename modify ldt datetime;
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> insert into tablename values (from_unixtime(0));
Query OK, 1 row affected (0.00 sec)
我还是推荐使用 DATETIME
,因为它支持比 TIMESTAMP
更大的日期范围。这将变得很重要 if you need to store dates past 2038-01-19.