【问题标题】:javax.xml.datatype.Duration to nanosecondsjavax.xml.datatype.Duration 到纳秒
【发布时间】:2020-01-28 13:48:41
【问题描述】:

我有一个 javax.xml.datatype.Duration,其中包含毫秒的一小部分,例如1.5 毫秒(1500 微秒)的持续时间:

Duration duration = DatatypeFactory.newInstance().newDuration("PT0.0015S");

我需要以纳秒为单位获取此值,但Duration 提供的最小时间单位似乎是getTimeInMillis,它返回long 并削减任何小于毫秒的时间。

如何获得以纳秒为单位的持续时间?

【问题讨论】:

  • 您是否有可能避免使用javax.xml.datatype.Duration?我会发现 java.time.Duration 更好用(它接受相同的 ISO 8601 语法)。
  • @OleV.V.我希望我能改变它,但不幸的是它是一个重要的第三方 API 的一部分:(

标签: java date duration


【解决方案1】:

您可以将持续时间解析为java.time.Duration。然后调用toNanos()方法。

Duration duration = DatatypeFactory.newInstance().newDuration("PT0.0015S");
java.time.Duration.parse(duration.toString()).toNanos();

【讨论】:

  • 不幸的是,这似乎并不可靠。在解析DatatypeFactory.newInstance().newDuration("P0Y0M0DT0H0M1S").toString() 时,它会抛出一个java.time.format.DateTimeParseException: Text cannot be parsed to a Duration。我觉得这可能是特定于实现的,具体取决于所使用的 XML 实现。
【解决方案2】:

Duration API 有点让我感到惊讶,因为您必须使用Duration.getField(Field) 获得持续时间的部分。该方法返回一个Number,它可以是BigInteger(用于天、小时、分钟等)或BigDecimal(仅用于秒)。

所以要获得几分之一秒,您可以使用getField(DatatypeConstants.SECONDS) 然后转换值:

Duration duration = DatatypeFactory.newInstance().newDuration("PT0.0015S");
BigDecimal seconds = (BigDecimal) duration.getField(DatatypeConstants.SECONDS);
// Note that `getField` will return `null` if the field is not defined.
if(seconds != null) {
    System.out.println(seconds + "s");                    // 0.0015s
    System.out.println(seconds.movePointRight(9) + "ns"); // 1500000ns
}

但这些不是持续时间的总秒数。这只是秒字段的值,其他字段被忽略。对于像P1M0.0015(1 分钟和 1.5 毫秒)这样的持续时间,这将忽略分钟并仅返回 1.5 毫秒。

将持续时间的所有其他字段转换为秒并将它们加起来会起作用。或者使用getTimeInMillis,返回持续时间的总毫秒数:

Duration duration = DatatypeFactory.newInstance().newDuration("PT1M0.0015S");
BigDecimal seconds = (BigDecimal) duration.getField(DatatypeConstants.SECONDS);

// only keep the fractional part
BigDecimal fractionalSeconds = seconds.remainder(BigDecimal.ONE);

long totalMillis = duration.getTimeInMillis(new Date(0));
// convert total millis to whole seconds (removes fractional part)
BigDecimal totalIntegerSeconds = 
    new BigDecimal(totalMillis).movePointLeft(3).setScale(0, RoundingMode.FLOOR);

// add both to get total seconds 
BigDecimal totalSeconds = totalIntegerSeconds.add(fractionalSeconds);

System.out.println(totalSeconds + "s");                     // 60.0015s
System.out.println(totalSeconds.movePointRight(9) + "ns");  // 60001500000ns

这似乎可行,但太复杂了。必须有更简单的方法来做到这一点。

@hasnae's answer 如果您使用的是 Java 1.8,解决方案看起来会好很多。我想知道 API 设计者想要获得纳秒级精度的方法是什么,因为 java.time.Duration 的引入比 javax.xml.datatype.Duration 晚了几年。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-05-17
    • 1970-01-01
    • 2019-11-25
    • 2019-07-13
    • 2014-03-12
    • 2018-12-14
    • 2015-04-21
    • 1970-01-01
    相关资源
    最近更新 更多