简体   繁体   中英

How to convert java.time.Duration to java.sql.Time?

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 .

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) .

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:

  • Added more detailed code examples
  • Added link to MySQL documentation regarding the supported min max values for TIME

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM