有没有一种方法可以创建一个Java8持续时间为一年且考虑闰年的方式?

39

我需要知道一年有多少天,并且想要使用Java8的新时间api。

然而,我无法使用Duration.ofDays(365),因为它没有考虑闰年。而Duration.of(1, ChronoUnit.YEARS)也无法使用,因为出现了java.time.temporal.UnsupportedTemporalTypeException: Unit must not have an estimated duration

我已经研究了Period,但似乎不能从年转换为天数。

感觉好像还缺点什么?如果一年是闰年,我可以编写代码添加一天,但这似乎应该已经被包含在内了。


2
可能是使用新的dateTime API获取持续时间的重复问题。 - Christoffer Hammarström
2个回答

49

根据在使用新的dateTime API获取持续时间中的回答,你应该使用

Period p = Period.ofYears(1);

了解 Duration(精确不足1天的纳秒数)和 Period(大于1天的可变时间段)之间的区别非常重要。

例如,Duration 不会考虑闰日、夏令时或者闰秒,适用于少于一天、最多几天的时间段。

因此,应该使用 Period

由于不同的年份有不同数量的天数,如果您想要找到一年中的天数,就需要指定您所讨论的是哪一年。

如果您想要特定年份的天数,可以使用:

Year.of(year).length()

如果您想要一年后的日期,您可以使用

LocalDate.now().plusYears(1)
或者
LocalDate.now().plus(Period.ofYears(1))

如果你需要计算两个日期之间的天数,你可以使用

ChronoUnit.DAYS.between(start, end)

因此,要找到距离现在一年后的日期所需的天数,您可以使用以下方法:

LocalDate today = LocalDate.now();
long days = ChronoUnit.DAYS.between(today, today.plusYears(1));

如果您想查看一年的会员资格是否仍然有效,您可以使用

Period membershipLength = Period.ofYears(1);
LocalDate membershipStart = ...;
LocalDate membershipEnd = membershipStart.plus(membershipLength);

LocalDate today = LocalDate.now();
boolean memberShipEnded = today.isAfter(membershipEnd);
boolean membershipValid = !membershipEnded;

2
由于一年的天数是可变的,所以这是不可能的。请告诉我,您将使用天数进行下一次计算,也许我们可以找到另一种方法? - Christoffer Hammarström
5
@user2272115:你需要指明你感兴趣的年份,因为不同的年份长度是不同的。所以对于“今天”,可以使用Year.now().length()来获取年份长度。如果你想要知道会员资格结束的日期,可以使用LocalDate.now().plusYears(1) - Christoffer Hammarström
3
你似乎不需要知道一年有多少天,而是需要使用LocalDate.now().isBefore(membershipStart.plusYears(1))。下一个计算是“会员资格何时结束”? - Christoffer Hammarström
1
Christoffer Hammarstrom最终使用了Duration.ofDays(DAYS.between(startDate, startDate.plusYears(1))) - user2272115
1
明确一点,在这种情况下,“Period”比“Duration”更合适。 - Christoffer Hammarström
显示剩余2条评论

9

看起来,您并不是想要一个持续时间(即两个日期之间的时间),而是要求某个具体日期的年份长度。

LocalDate dateLeap = LocalDate.of(2004, Month.MARCH, 1);
System.out.println("leap year of " + dateLeap
    + " has days: " + dateLeap.lengthOfYear());

2004年闰年的03-01有366天。

Java 8日期和时间功能非常完整。


如果您指的是从2004年1月5日到2005年1月5日= 366,以及从2004年3月2日到2005年3月2日= 365

int lengthOfYear(LocalDate date) {
    return date.getMonthValue() <= 2
        ? date.lengthOfYear()               // Count Feb in this year
        : date.plusYears(1).lengthOfYear(); // Count Feb in next year
}

解释:基本上长度是365天。但如果日期 >= 3月,则下一年的2月也会被计算在内,否则仅计算今年的2月。

请注意,plusYears(1) 不会改变日期或月份。

同时,不考虑闰秒或2月29日的小时/分钟。


5
你可以执行Year.of(2004).length() - Christoffer Hammarström
@ChristofferHammarström 最简单的解决方案要记住。 - Joop Eggen
我需要一个时间间隔。从今天到今天一年后的时间间隔,我想要以天数表示。有几种方法可以确定哪些年份有366天。 - user2272115
5
关于您的扩展,最好使用ChronoUnit.DAYS.between(date, date.plusYears(1))。这样您就不需要手动测试月份了。 - Christoffer Hammarström
@ChristofferHammarström 那可能是对这个问题最好的答案。 - Joop Eggen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接