【问题标题】:How does java.sql.Date work with negative dates?java.sql.Date 如何处理负日期?
【发布时间】:2016-05-12 17:05:48
【问题描述】:

当从数据库(java.sql.Date)中读取日期时,Java 运行时返回了某种“反转”毫秒值。毫秒值与天数大致相同,但从第 0 年开始倒数。

只需重新启动 Java 运行时即可解决问题。

但是:我发现除了工作日之外,Java 几乎可以正确处理这些“反转”值。

当你运行以下代码时:

System.out.println(new java.util.Date(253402214400000l));
System.out.println(new java.util.Date(-377648784000000l));

你会得到以下输出:

Fri Dec 31 01:00:00 CET 9999
Tue Dec 31 01:00:00 CET 9999

另一个例子:

System.out.println(new java.util.Date(-294192000000l));
System.out.println(new java.util.Date(-123967324800000l));

结果:

Mon Sep 05 01:00:00 CET 1960
Mon Sep 05 01:00:00 CET 1960

使用在线转换器时,特定第二行的结果会有所不同。这将导致负日期(年份为负)接近真实的正日期:

Example1:
253402214400000 = Fri Dec 31 9999 01:00:00
-377648784000000 = Tue Oct 15 -9998 02:00:00

Example 2:
-294192000000 = Mon Sep 05 1960 02:00:00
-123967324800000 = Mon Aug 19 -1959 02:00:00

我没有找到关于这个“主题”的任何信息。

那么,“倒转”日期背后的神话是什么?为什么 Java 几乎可以正确处理它们?调用 resultSet.getDate(1).getTime() 时,JDBC ResultSet 返回“反转”毫秒值是什么意思?

【问题讨论】:

  • 你说的是java.util.Date还是java.sql.Date?意识到 JDBC 结果集的行为是特定于驱动程序的,因为每个驱动程序都为其特定的数据库实现它。
  • 这是一个java.sql.Date(java.util.Date的子类)
  • 我不知道你所说的“倒置”是什么意思。
  • “倒置”是指 - 如果数据库包含 1960 年以内的日期,我收到的毫秒值对应于 -1959 年的日期,或者 9999 被接收为 -9998。因此,比较 validFrom/validTo-Dates,validFrom-Dates 大于 validTo-Dates,因为毫秒值已反转。 253402214400000 返回为 -377648784000000,当转换为 Java 日期时,会导致完全相同的日期,但使用在线转换器会导致 0 年之前的相同日期。
  • java.sql.Date 并不是一个很好的用于推理 Java 中日期的方法,因为 toString 的实现之一是 java.sql.Date 仅打印 4 位数的年份。

标签: java date time long-integer


【解决方案1】:

当您在 Date 构造函数中传递负数时,它被视为 1970 年 1 月 1 日之前的毫秒数。 Javadoc 说:

日期 - 自 1970 年 1 月 1 日 00:00:00 GMT 以来的毫秒数,不得超过 8099 年的毫秒表示。一个负数 表示 1970 年 1 月 1 日之前的毫秒数,

您可以看到当您尝试在 Date 构造函数中提供 Long.MIN_VALUELong.MAX_VALUE 时得到的结果。

DateFormat df = new SimpleDateFormat("d MMM yyyy G, HH:mm:ss.S Z");
System.out.println(df.format(new Date(Long.MIN_VALUE)));
System.out.println(df.format(new Date(Long.MAX_VALUE)));

Ideone Demo

【讨论】:

  • 这如何回答问题?
  • 谢谢,我知道了。问题不是关于 1970 年之前的负毫秒值,而是关于 0 年之前的反转毫秒值。
【解决方案2】:

我发现除了工作日之外,Java 几乎可以正确处理这些“反转”值。

在您的第一个示例中,两个日期不同 - 一个是 BC,另一个是 AD(这解释了为什么一周中的日期不同):

Date d1 = new Date(253402214400000l);
Date d2 = new Date(-377648784000000l);
DateFormat fmt = new SimpleDateFormat("yyyy G");
System.out.println(fmt.format(d1)); //9999 AD
System.out.println(fmt.format(d2)); //9999 BC

所以您的观察只是一个巧合(但是可能有一个日期格式化程序在某处变得疯狂并否定年份或年份实际上可能在您的数据库中为负数)。

与在线转换器的差异可能是由于如何考虑第 0 年和/或用于计算的日历的变化。

【讨论】:

  • 但是重新启动 Java 运行时解决了这个问题 :-) 所以数据库中没有错误的值,没有使用特殊的日期格式化程序。
  • @praisezh 你能找到重现问题的方法吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-02
  • 2014-09-20
相关资源
最近更新 更多