SpringのLocalTimeをMySQLのTimeでINSERTしたい（millisecondsも）

## 概要

String型で取得した  ```11:12:13.14``` （時間:分:秒.ミリ秒）を
MySQLにINSERTして
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33237/080f5da5-0b53-2f27-2bf1-80b2ce500196.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
```

## ステップその１ テーブル作成
小数点３桁まで対応
[MySQL :: MySQL 5.6 リファレンスマニュアル :: 11.1.2 日付と時間型の概要](https://dev.mysql.com/doc/refman/5.6/ja/date-and-time-type-overview.html)

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

```

## ステップその２ AttributeConverterの作成

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

```java
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();
    }
}
```

```java:Entity
	@Column(name = "start_time")
	private LocalTime startTime;
```

```java
entity.setStartTime(LocalTime.of(11, 12, 13, 14*10000000));

repository.save(entity);
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33237/99bac1b1-87df-664e-647e-12e1d86d1a5d.png)

ミリ秒が入ってないぞ！

## ステップその３ ミリ秒を保有してjava.sql.Timeに変換する
先程作成したLocalTimeConverterのconvertToDatabaseColumnメソッドを変更
[spring-ミリ秒のjava.time.LocalTimeをミリ秒のjava.sql.Timeにマッピングする方法](https://stackoverflow.com/questions/51182366/how-to-map-java-time-localtime-with-milliseconds-to-a-java-sql-time-with-milisec)

```java: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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33237/080f5da5-0b53-2f27-2bf1-80b2ce500196.png)