java.sql.Timestamp存储NanoSeconds的方式

Vic*_*cky 7 java timestamp jdbc nanotime

java.sql.Timestamp构造函数如下:

public Timestamp(long time) {
    super((time/1000)*1000);
    nanos = (int)((time%1000) * 1000000);
    if (nanos < 0) {
        nanos = 1000000000 + nanos;     
        super.setTime(((time/1000)-1)*1000);
    }
}
Run Code Online (Sandbox Code Playgroud)

它基本上以毫秒为单位接受时间,然后提取最后3位数并使其成为纳米级.因此,对于毫秒值1304135631 421,我得到Timestamp.getnanos()为 421000000.这是简单的计算(最后添加6个零)......似乎不是最佳的.

一种更好的方法可能是Timestamp构造函数,它接受以纳秒为单位的时间,然后计算出纳秒值.

如果您运行以下程序,您将看到实际纳秒与Timestamp计算纳秒标记返回的纳秒之间的差异.

long a = System.currentTimeMillis();
    for(;;){
        long b = System.currentTimeMillis();
        Timestamp tm = new Timestamp(System.currentTimeMillis());
        System.out.println(tm.getTime());
        System.out.println(tm.getNanos());
        System.out.println("This is actual nanos" + System.nanoTime()%1000000000);
        System.out.println("--------------------------");
        if(b-a >= 1)
            break;
    }
Run Code Online (Sandbox Code Playgroud)

所以关于时间戳的所有讨论都表示它存储时间长达纳秒,似乎不是那么正确..不是吗?

Bal*_*usC 6

以毫秒计的时间并不代表纳米时间.更精确它根本不可能.你应该用来Timestamp#setNanos()设置真正的纳米.

long timeInMillis = System.currentTimeMillis();
long timeInNanos = System.nanoTime();

Timestamp timestamp = new Timestamp(timeInMillis);
timestamp.setNanos((int) (timeInNanos % 1000000000));

// ...
Run Code Online (Sandbox Code Playgroud)

  • 不,这不安全!它包裹起来!问题是 `currentTimeMillis` 和 `nanoTime` 可能无法就更大的分辨率达成一致。例如 `nanoTime` 返回值 12:06:30.9999, 12:06: **31** .1111 但 `currentTimeMillis` 返回 12:06:30.666 12:06: **30** .777,然后使用上面的初始化时间戳的代码将导致时间戳 12:06:30.9999, 12:06: **30** .1111。另外,重新@Vicky 的评论,您将如何在 1970 年之前初始化时间戳? (2认同)
  • 确实,设置纳秒必须单独设置,但是像这样使用“System#nanoTime()”是不正确的。`System#nanoTime()` 的 API 文档说:“此方法只能用于测量经过的时间,与系统或挂钟时间的任何其他概念无关。返回的值代表纳秒,因为某些固定但任意时间(可能在未来,因此值可能为负)。” (参见 http://download.oracle.com/javase/6/docs/api/java/lang/System.html#nanoTime%28%29) (2认同)

小智 5

自从引入以来java.time.*,有一个新的工厂方法java.sql.TimestampTimestamp.from(Instant.now())will 完成这项工作(具有纳秒精度)。也有Timestamp.toInstant()相反的转换方式。