【问题标题】:Java Time period in decimal number of years十进制年数的 Java 时间段
【发布时间】:2017-10-02 20:44:12
【问题描述】:

如果我使用以下方法计算 java.time 中的 2 个 LocalDate 之间的差异:

Period p = Period.between(testDate, today);

然后我得到一个包含年数、月数、天数的输出,例如:

Days = 9
Months = 6
Years = 18

有没有人知道一种将其表示为十进制类型值的简洁方法(即,上面将是 18.5... 附近的东西)?

【问题讨论】:

  • 这可能对你有帮助:stackoverflow.com/questions/1555262/…
  • 问题是这些单位没有固定的长度。一年可以有 365 或 366 天,一个月可以有 28 到 31 天,由于夏令时的变化,甚至几天也不总是有 24 小时(LocalDate 会忽略这一点,但无论如何......)任何您所做的计算将是任意近似值

标签: java date java-time period


【解决方案1】:

您在其中一个 cmets 中提到,如果您需要当前季度,则需要季度年精度,您可以使用 IsoFields.QUARTER_YEARS

double yearAndQuarter = testDate.until(today, IsoFields.QUARTER_YEARS) / 4.0;

这样你将真正使用时间 api,总是得到正确的结果,@Mike 不必讨厌任何东西。

【讨论】:

    【解决方案2】:

    请不要这样做。

    将两个日期之间的差异表示为“年数”乘数是有问题的,因为两个日期之间一年的平均长度取决于您要比较的日期。这很容易出错,而想出所有必要的测试用例来证明你做对了就更难了。

    大多数程序员不应该手动执行日期/时间计算。您几乎保证会弄错。说真的,有so many ways 的东西可以去horribly wrong。地球上只有少数程序员完全理解其中的许多微妙之处。你问这个问题的事实证明你不是他们中的一员,这没关系——我也不是。你和我们绝大多数人一样,应该依赖像java.util.time 这样的可靠日期/时间 API。

    如果您真的需要单个数值,那么我能想到的最安全的选择是使用天数,因为LocalDate API 可以为您计算该数字:

    long differenceInDays = testDate.until(today, ChronoUnit.DAYS)
    

    请注意,此差异对用于产生它的两个日期有效。往返转换很简单:

    LocalDate today = testDate.plus(differenceInDays, ChronoUnit.DAYS)
    

    不要尝试手动将包含年、月和日组件的Period 转换为整数天数。正确答案取决于所涉及的日期,这就是为什么我们要让LocalDate API 为我们计算它。


    当精度不重要时

    根据您的 cmets,精度对您来说不是问题,因为您只想将某人的年龄显示为最接近的四分之一年左右。您不是在尝试表示准确的时间差异;只是一个近似值,误差较大。您也不需要能够执行任何往返计算。这大大改变了事情。

    类似@VGR 的近似值对于这些目的应该绰绰有余:“年数”应该精确到 3 天内(double ;)。

    @Oleg 的方法也很有效,会给你一个整个季度的日期差异,你可以将它除以 4 以转换为年份。这可能是最简单的解决方案,因为您不需要舍入或截断结果。我认为,这是最接近您从java.util.time 获得直接解决方案的方法。 Java Time API(以及一般的日期/时间 API)是为正确性而设计的:它们会为您提供完整的单位,但由于浮动涉及的固有错误,它们通常会避免为您提供小数近似值-点类型(也有例外,例如 .NET 的 System.TimeSpan)。

    但是,如果您的目标是向人类用户显示某人的年龄,并且您希望比整年更精确,我认为18 years, 9 months(或类似18 yr, 9 mo 的缩写形式)比18.75 years 更好。

    【讨论】:

    • 我同意以这种方式表示程序中的时间量是非常不可取的。但是,需要以这种方式显示它(此人的年龄为 18.25、18.5 等)。所以我只是在寻找 Java Time API 是否有一种简单的方法来解决这个问题。我没有在问题中提到它,但由于它对 Java Time 来说并不是微不足道的,我可能不会去计算精确的十进制表示,而是去检查月数。
    • 您需要多少精度?如果您只是将年份显示为最接近的半年或季度年,并且仅用于显示目的(例如,您不需要能够进行往返),那么任何“错误”的答案都应该是好的足够的。即使某人已经 120 岁,天真的计算也不应该相差超过 1 个月。但将年龄显示为“x 年,y 月”可能更“友好”。
    • 那么@VGR 的答案应该足够好(我认为无论多少年,准确到大约 3 天内)。只需四舍五入到最近的0.25f
    • @Luke 如果您编辑包含这些 cmets 的信息,您的问题将会大大改善。
    • 在我的回答中解决了一些评论讨论,但只是为了满足我自己的完整性感。如果这是您采用的解决方案,您应该将@VGR 的答案保留为“已接受”。
    【解决方案3】:

    我会避免使用 Period,而是只计算天数的差异:

    float years = testDate1.until(today, ChronoUnit.DAYS) / 365.2425f;
    

    【讨论】:

    • 虽然我不喜欢鼓励基于日期/时间的手动计算,但我认为使用天数和固定除数应该没问题。但是,使用浮点值存在固有错误。更完整的答案将显示在转换回全天时如何纠正此问题。
    猜你喜欢
    • 1970-01-01
    • 2020-02-09
    • 2015-03-12
    • 2011-07-09
    • 1970-01-01
    • 2011-10-05
    • 1970-01-01
    • 2021-11-15
    • 2011-03-07
    相关资源
    最近更新 更多