【问题标题】:Converting java.time.LocalTime to java.sql.Time将 java.time.LocalTime 转换为 java.sql.Time
【发布时间】:2022-01-28 01:45:39
【问题描述】:

我目前收到IllegalArgumentException 这些代码行:

Time timeIn = Time.valueOf( res.getCheckInTime().toString());
Time timeOut = Time.valueOf( res.getCheckOutTime().toString());

两个参数都是LocalTime存储本地时间如11:05

  • res.getCheckInTime()
  • res.getCheckOutTime()

谁能帮帮我?

【问题讨论】:

  • 你能分享一下 res.getCheckInTime().toString() 打印出来的内容吗?
  • 11:05 字符串格式
  • 以及已经提到的 - 你可能正在点击这个 else sn-p - github.com/openjdk/jdk/blob/master/src/java.sql/share/classes/…
  • 从 JavaDoc 中,实例本身存储纳秒精度,但 LocalTime.toString() 可能在几秒内省略零(“使用的格式将是输出完整时间值的最短格式省略的部分暗示为零”)。所以它可能无法满足Time.valueOf 的要求。
  • 顺便说一下,java.sql.Time 是与最早的 Java 版本捆绑在一起的存在严重缺陷的日期时间类的一部分。这些类,包括Time,在几年前就被 JSR 310 中定义的现代 java.time 类所取代。如果您的方法已经在使用java.time.LocalTime,您通常应该没有理由转换为Time.

标签: java java-time localtime sql-timestamp


【解决方案1】:

为什么需要使用res.getCheckInTime().toString()?无法使用Time.valueOf(LocalTime s) 方法?

请看下面的例子:

 public static void main(String[] args) {
     LocalTime checkInTime = LocalTime.now();
     LocalTime checkOutTime = LocalTime.now().plusHours(12);

     Time timeIn = Time.valueOf(checkInTime);
     Time timeOut = Time.valueOf(checkOutTime);

     System.out.println("timeIn => " + timeIn);
     System.out.println("timeOut => " + timeOut);
 }

要将java.time.LocalTime 对象转换为java.sql.Time

Time t = Time.valueOf( myLocalTime ) ;

往另一个方向发展,从传统类java.sql.Time 到现代类java.time.LocalTime

LocalTime lt = t.toLocalTime() ;

不涉及字符串。

【讨论】:

  • @Basil 您的添加说明了一个有用的逆转。识别出一个微妙的细节:你为什么将java.sqlTime as_legacy class_ 归为一类。
  • @hc_dev 因为 Sun、Oracle 和 JCP 社区在一致采用 JSR 310 时放弃了这些课程。 java.time 类完全取代了传统日期时间类的功能。无需使用时间、时间戳、日期、日历、SimpleDateFormat 等。
【解决方案2】:

TL;DR: 使用安全简洁的Time.valueOf(LocalTime) 作为suggested by Samuel Cruz,例如Time.valueOf( res.getCheckInTime() ).

使用基于字符串的转换时的陷阱

字符串变体有两个陷阱:

  1. LocalTime.toString() 产生可变的输出格式,当与Time.valueOf(String) 一起使用时可能导致给定IllegalArgumentException - 两个隐含的假设:(a) 非确定性输出导致 (b) 无消息,因此不是很有帮助,异常让用户猜测哪个值作为参数传递以及为什么它是非法的。

  2. 同样,Time.valueOf(String) 的 JavaDoc 为 quoted by Jim Garrison 具有误导性。在current implementation (OpenJDK) 中,您可以传递由2 个冒号分隔的任何其他整数序列,例如-33:9999:88。虽然不是HH:mm:ss 格式的有效 ISO 时间,但它显然被解释为时间值并可能导致严重的副作用!你期待"13:40:28" == Time.valueOf("-33:9999:88") 的结果吗?

time.LocalTime 具有不确定的 toString 格式

不要使用LocalTime.toString(),因为它的输出格式是非确定性的并且精度可能不同,最坏的情况会省略秒!它试图将输出减少到重要部分,最小格式为“HH:mm”,如 JavaDoc 摘要中所示。

对于可靠且符合 SQL 的字符串格式,请使用 LocalTime.format(DateTimeFormatter.ISO_LOCAL_TIME)。根据java.sql.Time 的要求,它可能总是产生HH:mm:ss 这样的格式。

java.sql.Time可以直接转换LocalTime

将参数传递给工厂方法java.sql.Time.valueOf()时应该可以工作:

  • 或者作为 ISO 格式的时间 String("11:05:00")(最多秒!)。 ⚠️ 警告:如果传递的字符串包含无效的 ISO 时间,可能会产生副作用,例如"99:123:88" 甚至 "0:-1:-3"(请参见下面的示例)。
  • 或直接作为java.time.LocalTime。 ✔️ 推荐为最安全的。

解决方案:说明参数变体和副作用

    public static void main(String[] args) throws java.lang.Exception {
        Reservation res = new Reservation("11:05", "18:05");
        System.out.println(res);

        System.out.printf("toString returns '11:05:00' as expected? %s\n", "11:05:00".equals(res.getCheckInTime()));
        String isoTimeFormat = res.getCheckOutTime().format(DateTimeFormatter.ISO_LOCAL_TIME);
        System.out.printf("explicit format() returns '%s' as expected by SQL? %s\n", isoTimeFormat, "18:05:00".equals(isoTimeFormat));
        
        Time timeIn = Time.valueOf(res.getCheckInTime()); // recommended argument type
        Time timeOut = Time.valueOf(res.getCheckOutTime().format(DateTimeFormatter.ISO_LOCAL_TIME));
        Time timeTest = Time.valueOf("33:99:88"); // dangerous fun-fact

        System.out.println("sql.Time in: " + timeIn + " , out: " + timeOut);
    }

    static class Reservation {
        LocalTime checkIn;
        LocalTime checkOut;

        public Reservation(String in, String out) {
            this.checkIn = LocalTime.parse(in);
            this.checkOut = LocalTime.parse(out);
        }

        public LocalTime getCheckInTime() {
            return checkIn;
        }

        public LocalTime getCheckOutTime() {
            return checkOut;
        }

        public String toString() {
            return String.format("Reservation {checkIn: %s, checkOut: %s}", getCheckInTime(), getCheckOutTime());
        }
    }

尝试可运行demo on IDEone

另见:

【讨论】:

    【解决方案3】:

    Javadoc:

    public static Time valueOf​(String s)
    

    将 JDBC 时间转义格式的字符串转换为时间值。

    Parameters:
        s - time in format "hh:mm:ss"
    Returns:
        a corresponding Time object 
    

    唯一接受的格式是hh:mm:ss

    【讨论】:

    • 所以我也试过了... Time timeIn = Time.valueOf( res.getCheckInTime().toString() + ":00");它仍然抛出异常
    • @Fred - 您能否编写一个可重现的测试用例,在其中将字符串文字“11:05:00”传递给 Time.valueOf() 并查看是否仍然遇到相同的异常?如果是 - 尝试附加调试器以查看 Time 类源代码中引发异常的确切位置
    • @Fred,不要使用LocalTime.toString(),因为它的输出格式是非确定性的,并且精度可能会有所不同,最坏的情况会省略秒!对于可靠且符合 SQL 的字符串格式,请使用 ` LocalTime.format(DateTimeFormatter.ISO_LOCAL_TIME)`
    猜你喜欢
    • 1970-01-01
    • 2016-10-28
    • 1970-01-01
    • 2015-07-18
    • 1970-01-01
    • 1970-01-01
    • 2018-10-13
    • 2023-03-07
    • 2011-08-22
    相关资源
    最近更新 更多