【问题标题】:How to Round Up Years in Joda-Time如何在 Joda-Time 中总结年份
【发布时间】:2016-10-18 22:31:27
【问题描述】:

Joda-Time 中是否有现有的方法来汇总年份?

假设您有一个 DateTime startDate = 10-18-2016 和一个 DateTime endDate = 12-18-2017。我希望将其舍入到 2 年。

目前,当我这样做时:

Years yearsBetween = Years.yearsBetween(startDate, endDate);

我得到 yearsBetween = 1。有没有使用 Joda Time 解决此问题的简单方法,还是我需要编写自定义方法来处理此问题?

【问题讨论】:

  • 您可以在 endDate 中加上一年减去一天。
  • 为什么不使用简单的计算? int years = (int) Math.ceil((double) Days.daysBetween(startDate, endDate).getDays()/365);

标签: java date datetime rounding jodatime


【解决方案1】:

tl;博士

  • 将开始日期移至当年的第一天。
  • 将结束日期移至其下一年的第一年。

半开

Joda-Time 对时间跨度使用半开放方法,其中开始是包含,结束是专有。因此,一年从相关年份的 1 月 1 日开始,一直持续到但不包括下一年的 1 月 1 日。

因此,您希望 2016-2017 年的日期为两年,将开始日期移至该年的第一天,并将结束日期移至其下一年的第一年。

我们转换为LocalDate,因为我们不关心这种年计算的时间。

LocalDate start = startDate.toLocalDate().withDayOfMonth( 1 ).withMonthOfYear( 1 );  // Move to first of same year.
LocalDate stop = endDate.toLocalDate().withDayOfMonth( 1 ).withMonthOfYear( 1 ).plusYears(1);  // Move to first of *following* year.

然后使用Years 执行相同的计算。

Years yearsBetween = Years.yearsBetween( start , stop );  // Half-Open, beginning is inclusive while ending is exclusive.
int years = yearsBetween.getYears();  // Plain integer.

2016 年(移至 2016 年 1 月 1 日)和 2017 年(移至 2018 年 1 月 1 日)的任何日期的结果为 2


java.time

仅供参考,Joda-Time 项目现在位于maintenance mode,团队建议迁移到java.time 类。

这个工作在java.time中稍微简单一些。 TemporalAdjuster 接口提供类来操作日期时间值。 TemporalAdjusters 类(注意复数 s)提供了几个实现。这些为获得第一年和明年的第一年做好了准备。

这里的Zdt 指的是您可能手头上的ZonedDateTime 对象。此类表示特定时区 (ZoneId) 时间线上的时刻,分辨率为纳秒。从ZonedDateTime 对象我们转换为LocalDate,然后应用一对TemporalAdjuster 对象移动到第一年和第二年。

LocalDate start = yourStartingZdt.toLocalDate().with( TemporalAdjusters.firstDayOfYear() );
LocalDate stop = yourEndingZdt.toLocalDate().with( TemporalAdjusters.firstDayOfNextYear() );

java.time 类不包括 Joda-Time Years 类的等效项。如果需要,您可以将 ThreeTen-Extra 项目添加到您的应用程序中,以使用包含 Years 类的其他类来扩展 java.time。

或者,我们可以通过Period 类获取年数。

与 Joda-Time 一样,包括 Period 在内的 java.time 类使用半开放方法来处理时间跨度。我建议您在所有日期时间工作中始终使用 Half-Open,因为它会使您的代码更加简单且不易出错。

Period p = Period.between( start , stop );
int years = p.getYears();

2016 年(移至 2016 年 1 月 1 日)和 2017 年(移至 2018 年 1 月 1 日)的任何日期的结果为 2

关于java.time

java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.Date.Calendarjava.text.SimpleDateFormat

Joda-Time 项目现在位于maintenance mode,建议迁移到 java.time。

要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310

从哪里获得 java.time 类?

ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

【讨论】:

  • 用详尽的 API 覆盖率很好地解释了答案,但没有按照原始海报的要求进行汇总。两个相差正好一年或不到一年的日期也计算为 2。幸运的是,您的回答中清楚地说明了这种行为。但对于我和所有寻求总结的人来说,乔纳森·多伊尔的答案是正确的。
【解决方案2】:

这在上面的其中一个 cmets 中提到并且对我有用:

LocalDate startLocalDate = new LocalDate(startDate)
LocalDate endLocalDate = new LocalDate(endDate).plusYears(1).minusDays(1)

int yearsBetween = Years.yearsBetween(startLocalDate, endLocalDate).Years

【讨论】:

  • 这是每个人在几年内寻找总结的正确答案。
  • @Gandalf 这段代码是如何四舍五入的? Javadoc 表示此方法计算整年。这意味着没有四舍五入。
  • 最后一行末尾的.Years 是错字吗?
  • @BasilBourque 你是对的,yearsBetween 计算整年。 “舍入”是通过结合endDate 上的.plusYears(1).minusDays(1) 来实现的。 .Years 最后是一个错字。它必须是.getYears()
  • 使用与 JodaTime 非常相似的java.time API 的方法可以实现相同的“向上取整”。 int yearsBetween = Period.between(startDate, endDate.plusYears(1).minusDays(1)).getYears()
猜你喜欢
  • 2014-06-25
  • 2010-12-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-02
  • 2020-12-25
  • 1970-01-01
相关资源
最近更新 更多