将java.sql.Timestamp转换为java.util.Calendar而不会丢失精度

时间:2012-11-06 09:25:14

标签: java calendar timestamp

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

以下是重现问题的代码

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

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

2 个答案:

答案 0 :(得分:30)

您将时间设置为毫秒,但您的输入精度为微秒,因此您将失去任何精度超过毫秒的精度。

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

答案 1 :(得分:8)

java.time

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

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

Image

使用Java 8,旧类获得了转换为/从java.time转换的新方法。在java.sql.Timestamp上使用新的toInstantfromInstant方法。 Instant类包含来自纪元,1970年UTC的第一时刻的纳秒数(基本上,请参阅类doc以获取详细信息)。

Instant您可以获得ZonedDateTime个对象。

java.sql.Timestamp ts = myResultSet.getTimestamp( 1 );
Instant instant = ts.toInstant();
ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone( zoneId );