为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

墨色风雨 2022-07-20 19:30:58
我一直在试图弄清楚如何将时间戳转换为日期,但末尾带有小数点,例如:时间戳 - C50204EC EC42EE92 相当于 2004 年 9 月 27 日 03:18:04.922896299 UTC。时间戳格式包括作为跨越 136 年的字段的前 32 位无符号秒和解析 232皮秒的 32 位小数字段。在时间戳格式中,时代 0 的主要纪元或基准日期是 UTC 1900 年 1 月 1 日 0 时,此时所有位都为零。到目前为止,这是我为我的代码编写的内容:    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 回答

?
摇曳的蔷薇

TA贡献1793条经验 获得超6个赞

java.time

使用解释中的示例:


时间戳 - 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.922896384Z


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


Calendar您尝试使用的类总是设计得很差,现在已经过时了。相反,我按照评论中建议的那样做,我正在使用 java.time,现代 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),我会从解释中得到确切的结果。所以我的版本不会比他们的更精确。



查看完整回答
反对 回复 2022-07-20
  • 1 回答
  • 0 关注
  • 136 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信