【问题标题】:Merge java.util.date with java.sql.Time将 java.util.date 与 java.sql.Time 合并
【发布时间】:2011-08-22 11:45:18
【问题描述】:

我有一个广泛的日期时间转换类,但我遇到了一个我无法解决的场景:

我有一个 java.util.date:2011 年 5 月 10 日星期二 00:00:00 BST
我有一个 java.sql.time: 03:58:44

我需要创建一个 java.util.date:Tue May 10 03:58:44 BST 2011

我想出的唯一方法是:

public static Date getDate(Date date, Time time) {
    Calendar calendar=Calendar.getInstance();
    calendar.set(date.getYear(), date.getMonth(), date.getDay(), time.getHours(), time.getMinutes(), time.getSeconds());
    return calendar.getTime();
}

完全弃用的代码,并且不起作用: java.sql.Time.getYear 处的 java.lang.IllegalArgumentException(未知来源)

有什么想法吗?

【问题讨论】:

  • 如果您在该代码上遇到了该异常,那么您实际上在第一个参数上传入了 Time 实例!
  • joda-time 始终是在 java joda-time.sourceforge.net 中处理日期的最佳方法
  • 在一个部分相关的说明中:虽然java.util.Date API 的构造非常糟糕,并且应该很久以前就应该被一个健全的 API 替换(例如 Joda Time),但 java.sql.Datejava.sql.Time“扩展”更糟糕:他们不遵循Liskov substitution principle,更糟糕的是java.sql.Date甚至与它的基类有相同的简单名称。
  • 我同意,我必须创建一个优化的转换类,它包含我需要的一切,并且对我来说很有意义...... java.util.date 很痛苦......但现在我只是需要一个简单的解决方案来解决这种情况。

标签: java sql date time merge


【解决方案1】:

可以吗

java.util.Date newDate = new java.util.Date(sqlDate.getTime());

【讨论】:

  • 那是我的第一次尝试......它返回:Thu Jan 01 03:59:26 GMT 1970 :-\ 所以,时间没问题,但会重置所有其他字段。
  • java.sql.Time 是一个 java.util.Date ;-)
【解决方案2】:

java.sql.Time 只是 java.util.Date 的一个包装器。您可以像添加两个 java.util.Date 对象一样使用它。

例如,将 Calendar 设置为 java.sql.Time:

calendar.setTime(time);

现在提取小时/分钟/秒字段,即:

calendar.get(Calendar.HOUR);

接下来,将 Calendar 设置为 java.util.Date 对象并将这三个字段添加到它的时间,即:

calendar.add(Calendar.HOUR, hour);

然后取回日期:

calendar.getTime();

【讨论】:

  • 请注意:我们必须使用 HOUR_OF_DAY 来尊重 24 小时格式。
【解决方案3】:

相反,您可以使用它。

   public static Date getDate(Date date, Time time) {
        Calendar calendar=Calendar.getInstance();
        calendar.setTimeZone(TimeZone.getTimeZone("UTC"));
        calendar.setTime(date);
        calendar.add(Calendar.MILLISECOND, (int) time.getTime());
        return calendar.getTime();
    }

【讨论】:

  • 对不起,它有效,但我少了一个小时。 2011 年 5 月 10 日星期二 00:00:00 BST 和 03:58:44 = 2011 年 5 月 10 日星期二 02:58:44 BST
  • 那是因为你需要正确设置时区。使用日历的 setTimezone() 方法。
  • 我很困惑... java.util.date 不包含时区?
【解决方案4】:

最简单的方法是将毫秒加在一起以创建一个新日期,ala

public static Date getDate(Date date, Time time) {
    return new Date(date.getTime() + time.getTime())
}

【讨论】:

  • 工作,但我少了一个小时...... 2011 年 5 月 10 日星期二 00:00:00 BST & 03:58:44 = 2011 年 5 月 10 日星期二 02:58:44 BST
【解决方案5】:

vickirk 的解决方案还不错,但存在时区问题,导致您观察到的时间减少了一小时。

我想,BST 表示British Summer Time,即 GMT +0100。现在,java.util.Date 及其后代在内部使用自 1970 年 1 月 1 日午夜 GMT 以来的毫秒数。在您使用toString() 对日期/时间进行字符串化之前,不会考虑时区。他们使用您当地的时区,显然是 BST。这意味着,真正存储在这些对象中的是

java.util.date:星期一 09 23:00:00 GMT 2011
java.sql.time: 02:58:44 GMT

当您像 vickirk 建议的那样添加内部值(由 getTime() 检索)时,您会获得一个包含
的日期 2011 年 5 月 10 日星期二 01:58:44 GMT,结果
2011 年 5 月 10 日星期二 02:58:44 BST 关于字符串化。

因此,减少一小时的解释是,当您分别对值进行字符串化时,时区偏移量应用了两次,而在添加后它仅应用一次,因为您现在只进行一次字符串化。或者换个角度看,加上时间点 03:58:44 BST的内部值,相当于加上了一个时间跨度 2h 58m 44s。

所以要在 java.sql.Time 中获得 3h 58m 44s 的时间 span,您必须手动弥补时区偏移。您可以通过使用 java.sql.Time 解析时间字符串“00:00:00”来做到这一点,这将导致内部值 -3600000 相当于 1969 年 12 月 31 日 23:00:00 GMT,即一小时时代之前。这是时区偏移的负数。

public static Date mergeDate(Date date, Time time) {
    long tzoffset = -(Time.valueOf("00:00:00").getTime());
    return new Date(date.getTime() + time.getTime() + tzoffset);
}

当然,这一切都是一个肮脏的技巧,这是必要的,因为你坚持将 Time 的值解释为一个时间跨度,而它实际上是一个时间点。

【讨论】:

  • 我想不出更好的方法来“合并”日期(没有“时间”信息)和 Sql 时间(没有“日期”信息)。我需要比较日期,其中一个来源是一个 SQL 表,它给了我一个 DATE 和一个我必须放在一起的 TIME。
【解决方案6】:

试试这些

 public static Date getDate(Date date, Time time) {
            Calendar calendar=Calendar.getInstance();
            calendar.setTime(date);
            Calendar calendar1=Calendar.getInstance();
            calendar1.setTime(time);
            calendar.set(Calendar.MINUTE, calendar1.get(Calendar.MINUTE));
            calendar.set(Calendar.SECOND, calendar1.get(Calendar.SECOND));
            calendar.set(Calendar.HOUR_OF_DAY, calendar1.get(Calendar.HOUR_OF_DAY));
            return calendar.getTime();
        }

【讨论】:

    【解决方案7】:

    我建议您使用现代 Java 日期和时间 API java.time 进行日期和时间工作。如果您无法避免将日期作为 java.util.Date(不代表日期的类)并将您的一天中的时间作为 java.sql.Time,则将两者都转换为现代类型并从那里合并它们。

    Java 8 及更高版本

        // Time zone to use throughout
        ZoneId zone = ZoneId.systemDefault();
        
        // Initialize values to be used for demonstration
        Instant startOfDay = LocalDate.of(2011, Month.MAY, 10)
                .atStartOfDay(zone)
                .toInstant();
        Date date = Date.from(startOfDay);
        Time time = Time.valueOf(LocalTime.of(3, 58, 44));
        
        // Do work
        LocalTime localTime = time.toLocalTime();
        LocalDateTime combination = date.toInstant()
                .atZone(zone)
                .toLocalDate()
                .atTime(localTime);
        
        // Print result
        System.out.println(combination);
    

    输出:

    2011-05-10T03:58:44

    仅当您必不可少地需要 Date,通常是您现在无法升级到 java.time 的遗留 API 时,才转换回来:

        Instant inZone = combination.atZone(zone).toInstant();
        Date oldfashionedDate = Date.from(inZone);
        System.out.println(oldfashionedDate);
    

    在我的时区输出是:

    2011 年 5 月 10 日星期二 03:58:44 CEST

    Java 6 和 7

    对于 Java 6 和 7,使用 java.time 的 backport,ThreeTen Backport(底部的链接)。对于 backport,我们需要使用 DateTimeUtils 来转换为现代类型:

        LocalTime localTime = DateTimeUtils.toLocalTime(time);
        LocalDateTime combination = DateTimeUtils.toInstant(date)
                .atZone(zone)
                .toLocalDate()
                .atTime(localTime);
    

    输出与以前相同。此外,如果您需要转换回Date,请使用DateTimeUtils

        Instant inZone = combination.atZone(zone).toInstant();
        Date oldfashionedDate = DateTimeUtils.toDate(inZone);
    

    再次输出和以前一样。

    链接

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-09-25
      • 1970-01-01
      • 2011-01-19
      • 2018-12-13
      • 2022-01-28
      • 1970-01-01
      相关资源
      最近更新 更多