有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

如何在Java中将十进制时间戳转换为带尾随小数的日期

我一直在试图找出如何将时间戳转换为日期,但末尾有尾随的小数,例如: 时间戳-C50204EC EC42EE92相当于2004年9月27日03:18:04.922896299 UTC

时间戳格式包括作为跨越136年的字段的前32位无符号秒和解析232picoseconds的32位分数字段。在时间戳格式中,原始历元或纪元0的基准日期为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); 

我的想法是,使用日历可能是不可能的,所以我必须从头开始,但我不知道如何去做


共 (1) 个答案

  1. # 1 楼答案

    爪哇。时间

    使用解释中的示例:

    Timestamp - C50204EC EC42EE92 is equivalent to Sep 27, 2004 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.922896384Z

    它关闭了85纳秒。可能更好的浮点运算可以做得更好。编辑:由于原始时间戳的分辨率为2^-32秒,这是纳秒(10^-9秒)分辨率Instant的4倍多,因此精度的损失是不可避免的

    您试图使用的Calendar类的设计总是很糟糕,现在已经过时很久了。相反,我按照Amongalen在评论中的建议做了,我使用的是java。时间,现代Java日期和时间API。编辑:为了进行比较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 tutorial: Date Time解释如何使用java。时间