Reputation: 638
What is the best way to convert a java.time.Duration
-object to java.sql.Time
?
I am getting an ISO8601-String like PT15M51S
and Duration.parse(String s)
is quite suitable in this case.
But now I'm struggling how to get the java.sql.Time
to but it into PreparedStatement
with setTime(java.sql.Time time)
to store it in my MySQL-database using JDBC.
I ended up writing a tapeworm like from org.apache.commons.lang3.time.DurationFormatUtils
:
java.sql.Time.valueOf(DurationFormatUtils.formatDurationHMS(video.getDuration().toMillis())))
And for the next problem: How to get java.time.Duration
from a java.sql.Time
.
Upvotes: 1
Views: 5414
Reputation: 10964
Is the database structure fixed? I think TIME
or TIMESTAMP
is probably not the best data type for duration. I would change the column type to BIGINT
(aka Long
) and convert the duration to milliseconds (or nanoseconds depending on your needs) with Duration.toMillis()
.
If this is not an option, you could use a similar logic and represent the duration as offset from a certain timestamp, such as 1970-01-01T00:00:00.000Z
with Duration.addTo(referenceDate)
or java.sql.Time(durationInMillis)
. To obtain an instance of Duration
again you will need to use Duration.ofMillis(sqlTime.getTime())
.
These are basically the options you have:
Using BIGINT
as column type (preferred solution):
// from java.time.Duration to java.lang.Long
{
final Duration duration = ...
final PreparedStatement pStmnt = con.prepareStatement("...");
pStmnt.setLong(n, duration.toMillis());
}
// from java.lang.Long to java.time.Duration
{
final PreparedStatement pStmnt = con.prepareStatement("...");
final ResultSet resultSet = pStmnt.getResultSet();
while (resultSet.next()) {
final Long durationInMillis = resultSet.getLong(n);
final Duration duration = Duration.ofMillis(durationInMillis);
...
}
}
Using TIME
or TIMESTAMP
as column type. You can replace java.sql.Time
with java.sql.Timestamp
in the below code depending on your actual column type:
// from java.time.Duration to java.sql.Time(stamp)
{
final Duration duration = ...
final Time time = new Time(duration.toMillis());
final PreparedStatement pStmnt = con.prepareStatement("...");
pStmnt.setTime(n, time);
}
// from java.sql.Time(stamp) to java.time.Duration
{
final PreparedStatement pStmnt = con.prepareStatement("...");
final ResultSet resultSet = pStmnt.getResultSet();
while (resultSet.next()) {
final Time time = resultSet.getTime(n);
final Duration duration = Duration.ofMillis(time.getTime());
...
}
}
According to MySQL's documentation the TIME
type supports ranges from -838:59:59
to 838:59:59
(see here). But by default none of the types TIME
, DATE
or TIMESTAMP
support fractional seconds unless the desired precision has been specified at creation time of the database columns (see here). That is to store milliseconds in a TIME
column, the table needs to be created like this:
CREATE TABLE t1 (t TIME(3));
Update:
TIME
Upvotes: 1
Reputation: 108961
A java.sql.Time
is not a duration, it is a time within a day (ie the normal 24 hour clock). Storing a duration in it is a hack and that hack will break if that duration is longer than 24 hours. You are better off storing it as the ISO duration string, or in a number datatype (eg double, or maybe numeric) or if your database supports it: in an interval
.
However if you still want to store the duration in a sql TIME
: The conversion point from java.time
to java.sql.Time
is java.time.LocalTime
using java.sql.Time.valueOf(LocalTime)
. So to convert from a Duration
to java.sql.Time
you can do:
Duration duration = ..;
LocalTime localTime = LocalTime.MIDNIGHT.plus(duration);
java.sql.Time sqlTime = java.sql.Time.valueOf(localTime);
The conversion back would be:
java.sql.Time sqlTime = ..;
LocalTime localTime = sqlTime.toLocalTime();
Duration duration = Duration.between(LocalTime.MIDNIGHT, localTime);
Be aware that a java.sql.Time
might only have precision in seconds. With a JDBC 4.2 compliant driver conversion to java.sql.Time
is not necessary because storing a java.time.LocalTime
is supported directly using setObject(1, <your LocalTime>)
and getObject(1, java.time.LocalTime.class)
.
Upvotes: 3