无法使用dividedBy(long)时java.time.Duration带余数除法实现方案
Duration除法精确实现方案
完全符合你的限制要求:无需调用受限的Duration#dividedBy(long)方法、不会丢弃精度、也不需要将Duration转换为毫秒等单序数值。
核心思路是直接操作Duration原生存储的两个字段:秒部分(long)和纳秒部分(int,范围0~999999999),分别做除法运算后重新组装结果,全程精度无损。
场景1:Duration除以long,返回精确Duration结果
实现代码如下:
public static Duration divideByLong(Duration dividend, long divisor) { if (divisor == 0) { throw new ArithmeticException("除数不能为0"); } // 计算秒部分的商和余数 long secQuotient = dividend.getSeconds() / divisor; long secRemainder = dividend.getSeconds() % divisor; // 剩余秒转换为纳秒,叠加原有纳秒部分后计算纳秒商 long totalNano = secRemainder * 1_000_000_000L + dividend.getNano(); long nanoQuotient = totalNano / divisor; // 组装结果,无需处理纳秒进位,总纳秒小于divisor*1e9,商必然小于1e9 return Duration.ofSeconds(secQuotient, nanoQuotient); }
测试验证:divideByLong(Duration.ofHours(1), 7L)返回结果为PT8M34.285714285S,和预期结果完全一致。
场景2:两个Duration相除,返回带余数的精确结果
可以自定义结果类同时返回整数商和余数Duration,也可以按需计算浮点商:
// 自定义除法结果类 public class DurationDivideResult { // 整数商 private final long quotient; // 余数部分 private final Duration remainder; public DurationDivideResult(long quotient, Duration remainder) { this.quotient = quotient; this.remainder = remainder; } public long getQuotient() { return quotient; } public Duration getRemainder() { return remainder; } // 按需获取精确浮点商 public BigDecimal getDecimalQuotient(Duration divisor) { BigDecimal divisorTotal = BigDecimal.valueOf(divisor.getSeconds()) .multiply(BigDecimal.valueOf(1_000_000_000L)) .add(BigDecimal.valueOf(divisor.getNano())); BigDecimal remainderTotal = BigDecimal.valueOf(remainder.getSeconds()) .multiply(BigDecimal.valueOf(1_000_000_000L)) .add(BigDecimal.valueOf(remainder.getNano())); return BigDecimal.valueOf(quotient) .add(remainderTotal.divide(divisorTotal, 9, RoundingMode.HALF_UP)); } } // 除法实现方法 public static DurationDivideResult divideByDuration(Duration dividend, Duration divisor) { if (divisor.isZero()) { throw new ArithmeticException("除数不能为0"); } // 先计算最大整数商 long quotient = 0; Duration temp = Duration.ZERO; while (temp.plus(divisor).compareTo(dividend) <= 0) { temp = temp.plus(divisor); quotient++; } Duration remainder = dividend.minus(temp); return new DurationDivideResult(quotient, remainder); }
测试验证:divideByDuration(Duration.ofHours(1), Duration.ofSeconds(7))返回的整数商为514,余数为PT2S,完全保留精度没有丢失。
提示:如果需要处理超大时长的除法场景,可将上述循环改为二分法计算最大整数商,性能会有明显提升。
内容的提问来源于stack exchange,提问作者Ankit
相关产品推荐
相关产品推荐

