【Java】日付の型変換を楽に一括管理するためのクラスを考えてみた

javaでは日付を扱う型が色々ありややこしいため、統合して管理できるパースクラスのようなものを用意できないか考えてみました。
* java.util.Date
* java.sql.Date
* java.Timestamp
* java.time.LocalDate
* java.time.LocalDateTime

今回はクラスのフィールドに`long time;`のようなミリ秒の情報を保持し、これを経由してそれぞれの型変換を実現してみます。
作成したクラスが以下です。

```java
import java.sql.Timestamp;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;

public class DateParser {

	private ZoneId zoneId;
	private final long time;

	public DateParser(long time) {
		this.time = time;
		this.zoneId = ZoneId.systemDefault();
	}

	public DateParser(long time, ZoneId zoneId) {
		this.time = time;
		this.zoneId = zoneId;
	}

	public void setZoneId() {
		this.zoneId = ZoneId.systemDefault();
	}

	public static DateParser fromDate(java.util.Date src) {
		long time = src.getTime();
		return new DateParser(time);
	}

	public static DateParser fromSqlDate(java.sql.Date src) {
		long time = src.getTime();
		return new DateParser(time);
	}

	public static DateParser fromTimestamp(Timestamp src) {
		long time = src.getTime();
		return new DateParser(time);
	}

	public static DateParser fromLocalDateTime(LocalDateTime src, ZoneId zoneId) {
		java.util.Date date = java.util.Date.from(src.atZone(zoneId).toInstant());
		long time = date.getTime();
		return new DateParser(time, zoneId);
	}
	
	public static DateParser fromLocalDate(LocalDate src, ZoneId zoneId) {
		java.sql.Date sqlDate = java.sql.Date.valueOf(src);
		long time = sqlDate.getTime();
		return new DateParser(time, zoneId);
	}

	public java.util.Date toDate() {
		return new java.util.Date(time);
	}

	public java.sql.Date toSqlDate() {
		return new java.sql.Date(time);
	}

	public Timestamp toTimestamp() {
		return new Timestamp(time);
	}

	public LocalDateTime toLocalDateTime() {
		java.util.Date date = new java.util.Date(time);
		return date.toInstant().atZone(zoneId).toLocalDateTime();
	}
	
	public LocalDate toLocalDate() {
		java.util.Date date = new java.util.Date(time);
		return date.toInstant().atZone(zoneId).toLocalDate();
	}

	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append("time: ").append(time).append(", ");
		sb.append("zoneId: ").append(zoneId.toString()).append(", ");
		sb.append("date: ").append(toDate().toString()).append(", ");
		sb.append("sqlDate: ").append(toSqlDate().toString()).append(", ");
		sb.append("timestamp: ").append(toTimestamp().toString()).append(", ");
		sb.append("localDateTime: ").append(toLocalDateTime().toString()).append(", ");
		sb.append("localDate: ").append(toLocalDate().toString());
		return sb.toString();
	}

    @Override
	public boolean equals(Object obj) {
		if (obj == null)
			return false;
		if (this == obj)
			return true;
		if (this.getClass() != obj.getClass())
			return false;
		DateParser dp = (DateParser) obj;
		return this.time == dp.time && this.zoneId.equals(dp.zoneId);
	}

	@Override
	public int hashCode() {
		return Objects.hash(time, zoneId);
	}
}
```

こちらを使ってテストしてみます
```java
public void test() {
	ZoneId zoneId = ZoneId.systemDefault();
	long time = System.currentTimeMillis();

	DateParser dp0 = new DateParser(time);
	System.out.println(dp0.toString());

	DateParser dp1 = DateParser.fromDate(new Date(time));
	System.out.println(dp1.toString());

	DateParser dp2 = DateParser.fromSqlDate(new java.sql.Date(time));
	System.out.println(dp2.toString());

	DateParser dp3 = DateParser.fromTimestamp(new Timestamp(time));
	System.out.println(dp3.toString());

	DateParser dp4 = DateParser.fromLocalDateTime(LocalDateTime.now(), zoneId);
	System.out.println(dp4.toString());

	DateParser dp5 = DateParser.fromLocalDate(LocalDate.now(), zoneId);
	System.out.println(dp5.toString());

}
```

実行結果
```
time: 1720417306474, zoneId: Asia/Tokyo, date: Mon Jul 08 14:41:46 JST 2024, sqlDate: 2024-07-08, timestamp: 2024-07-08 14:41:46.474, localDateTime: 2024-07-08T14:41:46.474, localDate: 2024-07-08
time: 1720417306474, zoneId: Asia/Tokyo, date: Mon Jul 08 14:41:46 JST 2024, sqlDate: 2024-07-08, timestamp: 2024-07-08 14:41:46.474, localDateTime: 2024-07-08T14:41:46.474, localDate: 2024-07-08
time: 1720417306474, zoneId: Asia/Tokyo, date: Mon Jul 08 14:41:46 JST 2024, sqlDate: 2024-07-08, timestamp: 2024-07-08 14:41:46.474, localDateTime: 2024-07-08T14:41:46.474, localDate: 2024-07-08
time: 1720417306474, zoneId: Asia/Tokyo, date: Mon Jul 08 14:41:46 JST 2024, sqlDate: 2024-07-08, timestamp: 2024-07-08 14:41:46.474, localDateTime: 2024-07-08T14:41:46.474, localDate: 2024-07-08
time: 1720417306491, zoneId: Asia/Tokyo, date: Mon Jul 08 14:41:46 JST 2024, sqlDate: 2024-07-08, timestamp: 2024-07-08 14:41:46.491, localDateTime: 2024-07-08T14:41:46.491, localDate: 2024-07-08
time: 1720364400000, zoneId: Asia/Tokyo, date: Mon Jul 08 00:00:00 JST 2024, sqlDate: 2024-07-08, timestamp: 2024-07-08 00:00:00.0, localDateTime: 2024-07-08T00:00, localDate: 2024-07-08
```
現時点では想定通り動いているように見えます。
注意点としては`LocalDate`からインスタンス生成した場合は時間以降の情報が失われることでしょうか（`LocalDate`のインスタンスを生成した段階で時間以降の情報はそもそもないので変換しようとしてもないままであるのは必然ですが）