如何使用小数点将十进制时间戳转换为Java



我一直在试图弄清楚如何将时间戳转换为日期,但是最后的小数是:例如:时间戳-C50204EC EC42EE92等于2004年9月27日03:18:04.922896299 UTC。

时间戳格式包括前32位未签名的秒,作为跨越136年的字段和32位分数场解决232 picseconds。以时间戳格式,主要时期或ERA 0的基本日期为1900年1月1日UTC,所有位均为零。

这是我到目前为止为代码写的内容:

    BigDecimal bi = new BigDecimal("1096255084000");
    double decimal_timestamp = bi.doubleValue();
    DateFormat formatter = new SimpleDateFormat("dd/MM/yyyy hh:mm:ss.SSS");
    formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
    Calendar calendar = Calendar.getInstance();
    calendar.setTimeInMillis(decimal_timestamp);
    String date = formatter.format(calendar.getTime());
    System.out.println(decimal_timestamp + " = " + date); 

我的想法是,日历可能是不可能的,所以我必须从头开始做,但是我不知道该怎么做。

java.Time

使用说明中的示例:

TIMESTAMP -C50204EC EC42EE92等于2004年9月27日 03:18:04.922896299 UTC。

    Instant epoch = OffsetDateTime.of(1900, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC).toInstant();
    BigInteger timeStamp = new BigInteger("C50204ECEC42EE92", 16);
    // To get the whole part and the fraction right, divide by 2^32
    double secondsSince1900 = timeStamp.doubleValue() / 0x1_0000_0000L;
    // Convert seconds to nanos by multiplying by 1 000 000 000
    Instant converted = epoch.plusNanos(Math.round(secondsSince1900 * 1_000_000_000L));
    System.out.println(converted);

输出是:

2004-09-27T03:18:04.9222896384Z

它被85纳米秒掉了。更好的浮点算术可能会更好。编辑:不可避免地会损失一些精度,因为原始时间戳的分辨率为2^-32秒,其效果超过纳秒(10^-9秒)Instant的分辨率。

您试图使用的Calendar类的设计始终很差,现在已经过时了。取而代之的是,我在评论中建议的是,我正在使用Java。编辑:有关比较Calendar具有毫秒的分辨率,因此充其量会给您准确的定义损失。

编辑:更精确的数学

我不能让85纳秒。这是一个尽可能保留精度并给出预期结果的版本:

    BigDecimal timeStamp = new BigDecimal(new BigInteger("C50204ECEC42EE92", 16));
    // To get the whole part and the fraction right, divide by 2^32
    BigDecimal bit32 = new BigDecimal(0x1_0000_0000L);
    BigDecimal secondsSince1900 = timeStamp.divide(bit32);
    // Convert seconds to nanos by multiplying by 1 000 000 000; round to long
    long nanosSince1900 = secondsSince1900.multiply(new BigDecimal(TimeUnit.SECONDS.toNanos(1)))
            .setScale(0, RoundingMode.HALF_UP)
            .longValueExact();
    Instant converted = epoch.plusNanos(nanosSince1900);

2004-09-27T03:18:04.922896300Z

1纳米太多?这是因为我在呼叫setScale中使用了一半的舍入。相反,如果我截断(使用RoundingMode.FLOOR),我会从解释中获得确切的结果。因此,我的版本不会损失比他们更精确的。

链接

Oracle教程:说明如何使用Java.Time。

的日期时间

最新更新