ScalikeJDBCで時刻を扱う際のミリ秒以下の精度


ScalikeJDBCでSQLServerからZonedDateTimeを取り出す際に、ミリ秒以下の値がうまく取り出せない

追記
@xuwei_k さんに頂いたコメント通り、3.4.0にバージョンを上げるとZonedDateTimeで直接取得してもナノ秒精度が保たれるようになりました

検証環境

  • Scala
    • 2.12.10
  • JDK
    • OpenJDK 8
  • ScalikeJDBC
    • 3.3.1
  • JDBC
    • mssql-jdbc 7.2.1.jre8
  • SQLServer
    • 2017-GA

SQLServerでの時刻は datetimeoffset(7) を使用しているので100ナノ秒の精度で扱いたい

調査

ZonedDateTimeを入れる

100ナノ秒精度、JSTの値を扱う

  val date: ZonedDateTime = ZonedDateTime.parse("2019-09-05T12:34:56.1234567+09:00")

DBにも100ナノ秒の精度で保存される。

2019-09-05 12:34:56.1234567 +09:00

ZonedDateTimeで取り出す

def * : WrappedResultSet => ZonedDateTime =
    (set: WrappedResultSet) => set.zonedDateTime(columnName)

ミリ秒以下が落ちてしまう。

2019-09-06T12:34:56.123+09:00[Asia/Tokyo]

ZonedDateTimeで取り出す その2

別メソッドで取り出してみる

def * : WrappedResultSet => ZonedDateTime =
    (set: WrappedResultSet) => set.dateTime(columnName)

同様にミリ秒以下が落ちてしまう。

2019-09-06T12:34:56.123+09:00[Asia/Tokyo]

TimeStampで取り出す

def * : WrappedResultSet => Timestamp =
    (set: WrappedResultSet) => set.timestamp(columnName)

ナノ秒まで取り出せる。

2019-09-06 12:34:56.1234567

が、タイムゾーンは取得できない。

OffsetDateTimeで取り出す

def * : WrappedResultSet => OffsetDateTime =
    (set: WrappedResultSet) => set.offsetDateTime(columnName)

ミリ秒以下が落ちてしまう。

2019-09-06T12:34:56.123+09:00

LocalDateTimeで取り出す

def * : WrappedResultSet => LocalDateTime =
    (set: WrappedResultSet) => set.localDateTime(columnName)

ミリ秒以下が落ちてしまう。

2019-09-06T12:34:56.123

Stringで取り出す

def * : WrappedResultSet => String =
    (set: WrappedResultSet) => set.string(columnName)

ナノ秒まで取り出せる。

2019-09-06 12:34:56.1234567 +09:00

が、そのままZonedDateTimeにパースさせることはできない.

結論

Java 8では一部の時刻型の精度が低い様子。
java 9以上に上げると解決するかも?
rf: https://github.com/h2database/h2database/issues/1178#issuecomment-397500855

ということで、Java 8ではStringで取り出し、フォーマットを指定してZonedDateTimeにパースするのが確実っぽい。

  def fromSqlServer(date: String): ZonedDateTime = {
    val format = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.SSSSSSS xxxxx")
    ZonedDateTime.parse(date, format)
  }