从java.util.Date创建的java.sql.Timestamp,为什么总是在()之前呢?

时间:2012-10-30 14:27:59

标签: java time

在发现错误之后,我注意到如果我使用占用毫秒的构造函数从java.util.Date创建java.sql.Timestamp,则Date实例总是在()时间戳之后。这是令人费解的,因为(a)before()的合同指定了严格的比较,(b)如果不相等,Timestamp,因为它有纳秒,可能本身就是在Date之后。但结果是相反且可重复的(使用JDK 1.6和1.7,具有不同的JVM时区)。比较两个日期可以正常工作,但在Date上调用before()或after()并给出Timestamp参数会产生意外结果。

下面的示例代码有两个Date和一个Timestamp实例,所有这些实例都具有相同的毫秒值。然而,将Date与Timestamp进行比较会显示Date()为时间戳后的日期。

import java.util.Date;
import java.sql.Timestamp;

public class X extends Date {

    public static void main(String[] args) {
        Date d1 = new Date();
        Date d2 = new Date(d1.getTime());
        Timestamp t = new Timestamp (d1.getTime());
        System.out.println ("date1 = " + d1 + " (" + d1.getTime() + ")" );
        System.out.println ("date2 = " + d2 + " (" + d2.getTime() + ")" );
        System.out.println ("timestamp = " + t + "  (" + t.getTime() + ")" );
        System.out.println ("d1 before d2: " + d1.before(d2));
        System.out.println ("d1 after  d2: " + d1.after(d2));
        System.out.println ("d1 before ts: " + d1.before(t));
        System.out.println ("d1 after  ts: " + d1.after(t)); //why true?
    }
}

示例输出:

C:\>\Java\jdk1.7.0_05\bin\java X
date1 = Tue Oct 30 10:15:59 EDT 2012 (1351606559812)
date2 = Tue Oct 30 10:15:59 EDT 2012 (1351606559812)
timestamp = 2012-10-30 10:15:59.812  (1351606559812)
d1 before d2: false
d1 after  d2: false
d1 before ts: false
d1 after  ts: true

最后一行是好奇的。

谢谢。

2 个答案:

答案 0 :(得分:6)

如果您查看内部表示以及after()方法中的比较,您会看到例如

millis = 1351607849957

你得到Date

fastTime = 1351607849957

Timestamp

fastTime = 1351607849000
nanos = 957000000

由于所有比较的是fastTime部分,因此您可以获得观察到的行为。 正如@ user714965指出的那样,您不应该将Timestamp视为Date

答案 1 :(得分:4)

java.sql.Timestamp的API文档说:

  

注意:此类型是java.util.Date和单独的纳秒值的组合。只有整数秒存储在java.util.Date组件中。分数秒 - 纳米 - 是分开的。

(这与Keppil的答案一致)。

它还说:

  

由于上面提到的Timestamp类和java.util.Date类之间存在差异,因此建议代码不要将Timestamp值一般视为java.util.Date的实例。 Timestampjava.util.Date之间的继承关系实际上表示实现继承,而不是类型继承。

这意味着您不应将Timestamp视为java.util.Date,如果您将其传递给java.util.Date.after(),那就是您正在做的事情(该方法需要java.util.Date - 您'传递Timestamp,将其视为java.util.Date,此评论说你不应该这样做。

这是标准Java库中的错误设计。如果您需要使用日期和时间,请使用Joda Time,这是一个设计得更好,功能更强大的库。