【问题标题】:How to convert java.time.Duration to java.sql.Time?如何将 java.time.Duration 转换为 java.sql.Time?
【发布时间】:2016-10-28 05:42:25
【问题描述】:

java.time.Duration-object 转换为java.sql.Time 的最佳方法是什么?

我得到了一个 ISO8601 字符串,如 PT15M51SDuration.parse(String s) 在这种情况下非常合适。

但现在我正在努力如何将java.sql.Time 转换为PreparedStatementsetTime(java.sql.Time time),以便使用JDBC 将其存储在我的MySQL 数据库中。

我最终写了一个类似于org.apache.commons.lang3.time.DurationFormatUtils 的绦虫:

java.sql.Time.valueOf(DurationFormatUtils.formatDurationHMS(video.getDuration().toMillis())))

对于下一个问题:如何从java.sql.Time 获取java.time.Duration

【问题讨论】:

    标签: java sql jdbc time


    【解决方案1】:

    java.sql.Time不是持续时间,它是一天中的时间(即正常的 24 小时制)。在其中存储持续时间是一种黑客行为,如果该持续时间超过 24 小时,该黑客行为就会中断。您最好将其存储为 ISO 持续时间字符串,或数字数据类型(例如双精度或数字),或者如果您的数据库支持它:在 interval 中。

    但是,如果您仍想将持续时间存储在 sql TIME 中:从 java.timejava.sql.Time 的转换点是 java.time.LocalTime 使用 java.sql.Time.valueOf(LocalTime)。因此,要将 Duration 转换为 java.sql.Time,您可以这样做:

    Duration duration = ..;
    LocalTime localTime = LocalTime.MIDNIGHT.plus(duration);
    java.sql.Time sqlTime = java.sql.Time.valueOf(localTime);
    

    转换回来的是:

    java.sql.Time sqlTime = ..;
    LocalTime localTime = sqlTime.toLocalTime();
    Duration duration = Duration.between(LocalTime.MIDNIGHT, localTime);
    

    请注意,java.sql.Time 可能只有几秒的精度。使用 JDBC 4.2 兼容的驱动程序转换为 java.sql.Time 是不必要的,因为直接使用 setObject(1, <your LocalTime>)getObject(1, java.time.LocalTime.class) 支持存储 java.time.LocalTime

    【讨论】:

    • 虽然我同意不建议将持续时间存储在TIME 列中,但它不会因持续时间超过 24 小时而中断。我用指向 MySQL 文档相应部分的链接更新了我的答案...
    • @dpr 有趣的是,我不知道 MySQL 中的 TIME。但是,我认为 java.sql.Time 不会完全支持这一点。
    • 它似乎是 - 不知道它是否被官方支持。可以使用构造函数Time(long) 创建任意长的java.sql.Time 实例。但是,我不确定在支持其他 DBMS 时会是什么样子......
    【解决方案2】:

    数据库结构是固定的吗?我认为TIMETIMESTAMP 可能不是持续时间最好的数据类型。我会将列类型更改为BIGINT(又名Long)并使用Duration.toMillis() 将持续时间转换为毫秒(或纳秒,具体取决于您的需要)。

    如果这不是一个选项,您可以使用类似的逻辑并将持续时间表示为与某个时间戳的偏移量,例如1970-01-01T00:00:00.000ZDuration.addTo(referenceDate)java.sql.Time(durationInMillis)。要再次获取Duration 的实例,您需要使用Duration.ofMillis(sqlTime.getTime())

    这些基本上是您拥有的选项:

    使用BIGINT 作为列类型(首选解决方案):

    // 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);
            ...
        }
    }
    

    使用TIMETIMESTAMP 作为列类型。您可以根据您的实际列类型在下面的代码中将java.sql.Time 替换为java.sql.Timestamp

    // 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());
            ...
        }
    }
    

    根据 MySQL 的文档,TIME 类型支持从-838:59:59838:59:59 的范围(参见here)。但默认情况下,TIMEDATETIMESTAMP 类型都不支持小数秒,除非在创建数据库列时指定了所需的精度(请参阅here)。即在TIME列中存储毫秒,需要这样创建表:

    CREATE TABLE t1 (t TIME(3));
    

    更新:

    • 添加了更详细的代码示例
    • 添加了有关TIME 支持的最小最大值的 MySQL 文档链接

    【讨论】:

      猜你喜欢
      • 2020-02-26
      • 2022-01-28
      • 1970-01-01
      • 2015-07-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-13
      • 2018-10-13
      相关资源
      最近更新 更多