32

我正在尝试从数据库中获取时间戳值,将它们转换为日历,然后将它们转换回时间戳,但它们会失去精度。

这是重现问题的代码

import java.sql.Timestamp;
import java.util.Calendar;

public class Test {
    public static void main(String[] args)
    {
        Timestamp timestamp = new Timestamp(112, 10, 5, 15, 39, 11, 801000000);
        System.out.println("BEFORE "+timestamp.toString());
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(timestamp.getTime());
        timestamp = new Timestamp(calendar.getTimeInMillis());
        System.out.println("AFTER "+timestamp.toString());
    }
}

这是转换的示例结果

BEFORE 2012-10-18 14:30:13.362001
AFTER 2012-10-18 14:30:13.362

它失去了精确性。我该怎么做才能保持十进制值不变?

4

2 回答 2

30

您以毫秒为单位设置时间,但您的输入精度以微秒为单位,因此您当然会失去任何比毫秒更精细的精度。

日历不支持比毫秒更精细的粒度。没有变通方法。

于 2012-11-06T10:06:58.200 回答
8

java.time

在 Java 8 及更高版本中,我们现在有了一个解决方案:内置了新的java.time框架。由JSR 310定义,受Joda-Time启发,由ThreeTen-Extra项目扩展。

这个新框架具有纳秒级分辨率。这足以处理旧的 java.util.Date 值、Joda-Time 值,它们都是毫秒。并且足以处理某些数据库(例如Postgres )使用的微秒。某些数据库(例如H2 )使用纳秒。所以 java.time 可以处理这一切,或者至少可以处理所有主流情况。唯一的例外是利基科学或工程情况。

图片

在 Java 8 中,旧类获得了与 java.time 相互转换的新方法。在java.sql.Timestamp上使用新的toInstantfromInstant方法。该类Instant包含从纪元开始的纳秒计数,即 1970 UTC 的第一刻(基本上,有关详细信息,请参见类文档)。

从一个Instant你可以得到一个ZonedDateTime对象。

java.sql.Timestamp ts = myResultSet.getTimestamp( 1 );
Instant instant = ts.toInstant();
ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone( zoneId );
于 2015-09-02T16:46:44.757 回答