Kotlin: org.jetbrains.exposed.sql で日付型をINSERTするときにちょっとはまった話

Kotlin初心者が Exposed を使ってMySQLに日付型をINSERTするときにしばらくはまったのでメモしておきます。

# はまった経緯
こんな感じのテーブルをつくりまして、

```sql
create table app_test_logs (
  id integer auto_increment primary key,
  log_datetime datetime not null,
  ops_id int not null,
  created_at datetime not null,
  updated_at datetime not null
);
```

Ktではこんなオブジェクトを書きまして、

```kotlin
object AppTestLogs : Table("app_test_logs") {
    val id = integer("id").autoIncrement().primaryKey()
    val logDatetime = datetime("log_datetime")
    val opsId = integer("ops_id")
    val createdAt = datetime("created_at")
    val updatedAt = datetime("updated_at")
}
```

実際にこんな感じで登録してみようとしたときに、

```kotlin
AppTestLogs.insert {
   val cal = Calendar.getInstance()
   cal.set(Calendar.YEAR, 2017)
   cal.set(Calendar.MONTH, 8 -1)
   cal.set(Calendar.DAY_OF_MONTH, 25)
   cal.set(Calendar.HOUR_OF_DAY, 12)
   cal.set(Calendar.MINUTE, 11)
   cal.set(Calendar.SECOND, 15)

   it[logDatetime] = cal.time // <- エラーになる
   it[opsId] = 1
}
```

InteliJさんがいうには、Column<T> / DateTime にそんなものはいらないぞ、と言われているようでした。

# 試行錯誤

ならば、これでどうか。

```kotlin
it[logDatetime] = java.util.Date(cal.timeInMillis) // <- エラー :(
```

じゃあこんどこそ！

```kotlin
it[logDatetime] = java.sql.Date(cal.timeInMillis) // <- エラー :(
```
あれー？

いろいろぐぐってみたのですが、はまっている人がいないようだったのでじゃあソース見てみるかと。


```kotlin
import org.joda.time.DateTime
```
https://github.com/JetBrains/Exposed/blob/master/src/main/kotlin/org/jetbrains/exposed/sql/ColumnType.kt#L8


あ、このひとInteliJさんもサジェストしてた。

```kotlin
import org.joda.time.DateTime

...

it[logDatetime] = DateTime(cal.timeInMillis) // 通った！！！
```


https://github.com/JetBrains/Exposed/blob/master/src/main/kotlin/org/jetbrains/exposed/sql/ColumnType.kt#L223

```kotlin
    override fun notNullValueToDB(value: Any): Any {
        if (value is DateTime) {
            val millis = value.millis
            if (time) {
                return java.sql.Timestamp(millis)
            }
            else {
                return java.sql.Date(millis)
            }
        }
        return value
    }

```

この辺ですかね。

https://github.com/JetBrains/Exposed/blob/master/src/main/kotlin/org/jetbrains/exposed/sql/ColumnType.kt#L208

こっちみると、`java.sql.Date` / `java.sql.Timestamp` もごにょごにょしてるので、なんか入れてくれても良さそうなのに。

とりあえず、Exposedライブラリの日付型使うときは、 `org.joda.time.DateTime` 使うと良さそうというお話でした。

## コードサンプル
だいたいこんな感じです。

```kotlin
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.transactions.transaction
import org.joda.time.DateTime

object AppTestLogs : Table("app_test_logs") {
  val id = integer("id").autoIncrement().primaryKey()
  val logDatetime = datetime("log_datetime")
  val opsId = integer("ops_id")
  val createdAt = datetime("created_at")
  val updatedAt = datetime("updated_at")
}

fun main(args: Array<String>) {
  loadLogData()
}

fun loadLogData () {
  Database.connect("jdbc:mysql://localhost/mydb", "com.mysql.jdbc.Driver","myuser","password")
  transaction {
    AppTestLogs.insert {
      val cal = Calendar.getInstance()
      cal.set(Calendar.YEAR, 2017)
      cal.set(Calendar.MONTH, 8 -1)
      cal.set(Calendar.DAY_OF_MONTH, 25)
      cal.set(Calendar.HOUR_OF_DAY, 12)
      cal.set(Calendar.MINUTE, 11)
      cal.set(Calendar.SECOND, 15)

      it[logDatetime] = DateTime(cal.timeInMillis)
      it[opsId] = 1
      val currentTime = DateTime(Calendar.getInstance().timeInMillis)
      it[createdAt] = DateTime(currentTime)
      it[updatedAt] = DateTime(currentTime)
    }
  }
}
```