Help us understand the problem. What is going on with this article?

SpringのLocalTimeをMySQLのTimeでINSERTしたい(millisecondsも)

概要

String型で取得した 11:12:13.14 (時間:分:秒.ミリ秒)を
MySQLにINSERTして
image.png
とミリ秒まで表示させる方法についてです。(日付情報はいらない)

そんなの普通に実装すればできそうじゃない?
って思うじゃないですか。

簡単そうに見えて面倒くさい処理を挟まないとうまくいきませんでした。。。
もっとスマートな方法をお存じの方がいましたら、教えていただけるととっても嬉しいです!!

バージョン

Spring

build.gradle
id 'org.springframework.boot' version '2.2.2.BUILD-SNAPSHOT'
sourceCompatibility = '1.8'

    runtimeOnly('mysql:mysql-connector-java')
    implementation 'org.springframework.boot:spring-boot-starter'
    implementation('org.springframework.boot:spring-boot-starter-web')
    implementation('org.springframework.boot:spring-boot-starter-data-jpa')

データベース

MySQL 8.0

ステップその1 テーブル作成

小数点3桁まで対応
MySQL :: MySQL 5.6 リファレンスマニュアル :: 11.1.2 日付と時間型の概要

create table timesample( 
    ...
    start_time TIME(3)
);

ステップその2 AttributeConverterの作成

JPA がエンティティのフィールドの型としてjava.time.LocalDate、java.time.LocalTime、java.time.LocalDateTimeは対応していないため、次のようなAttributeConverterを作成する必要があります。

package app.entities.converter;

import java.time.LocalTime;

import javax.persistence.AttributeConverter;
import javax.persistence.Converter;

@Converter(autoApply = true)
public class LocalTimeConverter implements AttributeConverter<LocalTime,  java.sql.Time> {

    @Override
    public java.sql.Time convertToDatabaseColumn(LocalTime time) {
        return time == null ? null : java.sql.Time.valueOf(time);
    }

    @Override
    public LocalTime convertToEntityAttribute(java.sql.Time  value) {
        return value == null ? null : value.toLocalTime();
    }
}
Entity
    @Column(name = "start_time")
    private LocalTime startTime;
entity.setStartTime(LocalTime.of(11, 12, 13, 14*10000000));

repository.save(entity);

image.png

ミリ秒が入ってないぞ!

ステップその3 ミリ秒を保有してjava.sql.Timeに変換する

先程作成したLocalTimeConverterのconvertToDatabaseColumnメソッドを変更
spring-ミリ秒のjava.time.LocalTimeをミリ秒のjava.sql.Timeにマッピングする方法

LocalTimeConverter
package app.entities.converter;

import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalTime;

import javax.persistence.AttributeConverter;
import javax.persistence.Converter;

@Converter(autoApply = true)
public class LocalTimeConverter implements AttributeConverter<LocalTime,  java.sql.Time> {

    @Override
    public java.sql.Time convertToDatabaseColumn(LocalTime time) {
        if(time == null) return null;

        // この日付はコンバートで捨てられるので何でもOK
        long epochMilli = time.atDate(LocalDate.of(2019, 1, 1)).atZone(java.time.ZoneId.systemDefault())
                .toInstant().toEpochMilli();
        java.sql.Time sqlTime = new java.sql.Time(epochMilli);
        return sqlTime;
    }

    @Override
    public LocalTime convertToEntityAttribute(java.sql.Time  value) {
        if (value == null) return null;

        String localTimeStr = new SimpleDateFormat("HH:mm:ss.SSS").format(value);
        LocalTime localTime = LocalTime.parse(localTimeStr);
        return localTime;
    }
}

image.png

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした