在Java中计算一年中的天数,或者计算两个日期之间的天数。

23

有没有任何原生Java类中的方法,可以计算特定年份有多少天?就是说,它是一个闰年(366天)还是普通年(365天)?

还是说我需要自己编写代码?

我正在计算两个日期之间的天数,例如我生日前还有多少天。我想考虑闰年二月29日。除了那一天以外,我都已经搞定了。

9个回答

50

另一种方法是询问 Calendar 类在给定年份中的实际最大天数:

Calendar cal = Calendar.getInstance();
cal.setTime(new Date());

int numOfDays = cal.getActualMaximum(Calendar.DAY_OF_YEAR);
System.out.println(numOfDays);

这将返回闰年366天,普通年365天。

请注意,我使用了getActualMaximum而不是getMaximum,后者总是返回366。


1
@NoodleofDeath 实际上,这个答案在2014年的Java 8中已经过时了。麻烦的旧日期时间类,如 java.util.Datejava.util.Calendarjava.text.SimpleTextFormat现在已经成为遗留系统,被Java.time类所取代。请参阅Oracle的教程 - Basil Bourque
3
我同意如果可能的话,你应该使用java.time类。但对于那些还没有使用Java 8的人来说,这个答案并不过时。OP指的是java.util.Calendar和java.util.Date,这个答案仍然适用于我们中的许多人。这正是我在寻找的答案。 - Samurai Soul
@SamuraiSoul 很多java.time的功能在ThreeTen-Backport项目中被移植到Java 6和Java 7中。在ThreeTenABP项目中进一步适用于Android。因此,没有理由再使用可怕的旧版Date/Calendar等类。详情请参见我的回答 - Basil Bourque

28

简而言之

Year.of( 2015 ).length()

…和…

Year.isLeap( 2015 )

java.time.Year

在Java 8及更高版本中,我们有java.time包。( 教程)

length

Year类表示单个年份值。您可以查询其长度。

int daysInYear = Year.of( 2015 ).length();

isLeap

您还可以询问一年是否为闰年。

Boolean isLeapYear = Year.isLeap( 2015 );

作为一个例子,使用Java的三元运算符来获取一年中的天数,例如:

minVal = (a < b) ? a : b;

在我们的例子中,我们想要得到一年中的天数。对于非闰年来说,这是365天,而对于闰年来说,是366天。
int daysInYear = ( Year.isLeap( 2015 ) ) ? 366 : 365 ;

年中日

您可以获取日期的年中日数字。该数字从1到365,或在闰年中为366。

int dayOfYear = LocalDate.now( ZoneId.of( "America/Montreal" ).getDayOfYear() ;

往另一个方向,获取一年中某一天的日期。

Year.now( ZoneId.of( "America/Montreal" ) ).atDay( 159 ) ;

你可以通过比较这些一年中的日数来确定经过的天数。但是有一种更简单的方法,请继续阅读。
经过的天数
使用ChronoUnit枚举来计算经过的天数。
LocalDate start = LocalDate.of( 2017 , 2 , 23 ) ;
LocalDate stop = LocalDate.of( 2017 , 3 , 11 ) ;
int daysBetween = ChronoUnit.DAYS.between( start , stop );

自动处理闰年


关于java.time

java.time框架内置于Java 8及更高版本中。这些类替代了麻烦的旧版遗留日期时间类,如java.util.DateCalendarSimpleDateFormat

Joda-Time项目现在处于维护模式,建议迁移到java.time类。

为了了解更多信息,请查看Oracle教程。并在Stack Overflow上搜索许多示例和解释。规范是JSR 310
哪里可以获取java.time类? 这个 ThreeTen-Extra 项目扩展了 java.time 的额外类。该项目是 java.time 可能未来增加的一个试验场。您可能会在此处找到一些有用的类,例如 Interval, YearWeek, YearQuarter更多

很好,但请不要“扭曲”我的英语。 - jurchiks
3
您,先生,赢得了奖牌。谢谢! - Peter Perháč

15

GregorianCalendar标准类有一个isLeapYear()方法。如果你只想获得一个年份(比如说2008),那么可以使用这个构造函数构造一个日期,然后在之后检查isLeapYear()方法。


7
啊,该死的Java和它的库无所不包。 :-P (+1) - Platinum Azure
5
是的,使用日期库很烦人。自己编写测试来处理闰年、不同月份、闰秒和加法计算才是...算了,还是算了吧。 :) - Jeff Ferland
@Autocracy:只有内置的日期库不太好用。问问Jon Skeet就知道了。 - Gabe
是的,我是在晚上晚些时候写的,我忘了提到我正在使用 Calendar 类和 Calendar.get(Calendar.DAY_OF_YEAR) 来计算差异。我只有一个疑问 - 如果我执行 Calendar.add(Calendar.MONTH, 14),它会将结果年份设置为闰年吗?或者所有年份都只有 365 天? - jurchiks
是的,没错。那么就不需要使用GregorianCalendar了,我将继续使用到目前为止一直在用的方法,并使用TimeUnit.DAYS.convert()计算余数。 - jurchiks
显示剩余2条评论

7

自从 JAVA 8以来

一年中的天数:

LocalDate d = LocalDate.parse("2020-12-31");                   // import java.time.LocalDate;
return d.lengthOfYear();                                       // 366

距离我的生日还有几天:

LocalDate birth = LocalDate.parse("2000-02-29");
LocalDate today = LocalDate.now();                             // or pass a timezone as the parameter

LocalDate thisYearBirthday = birth.withYear(today.getYear());  // it gives Feb 28 if the birth was on Feb 29, but the year is not leap.
LocalDate nextBirthday = today.isAfter(thisYearBirthday)
    ? birth.withYear(today.getYear() + 1)
    : thisYearBirthday;

return DAYS.between(today, nextBirthday);                      // import static java.time.temporal.ChronoUnit.DAYS;

OP说:“计算两个日期之间的天数”。 - epox
1
您说得对。我已经纠正并删除了我的评论。我编辑了问题的标题,使其更加明确和完整。 - Basil Bourque

6

对于日期时间计算,我强烈推荐使用JodaTime库。特别是对于你所需的情况,这只需要一行代码:

Days.daysBetween(date1, date2).getDays();

我希望这可以帮到你。

2
不想为了做一个简单的计算而实现整个库。 - jurchiks


3
你可以查看维基百科页面上的一些非常好的伪代码:
if year modulo 400 is 0
       then is_leap_year
else if year modulo 100 is 0
       then not_leap_year
else if year modulo 4 is 0
       then is_leap_year
else
       not_leap_year

我相信你可以想办法在Java中实现这个逻辑。 :-)

2
那看起来像是在重复造轮子。 - Waldheinz
是的,同意,这是在我了解Java的GregorianCalendar类之前。除了Java的许多其他日期/时间问题之外,在这种情况下那是正确的选择! - Platinum Azure
为什么要踩这个帖子?这是寻找闰年的“绝佳”算法。 - Cem Catikkas
1
@Cem Catikkas:它肯定是正确的,但问题是“它是否是一个有用的答案”。这是一个Java问题,因此我认为使用Java库作为更好的答案并且重新发明轮子是不好的。不过感谢你的点赞! :-) - Platinum Azure

3

您的具体用例可能最好使用Joda和这个特定的示例来解决。


1
你可以使用 TimeUnit 类。对于你的特定需求,这应该足够了:
public static int daysBetween(Date a, Date b) {
    final long dMs = a.getTime() - b.getTime();
    return TimeUnit.DAYS.convert(dMs, TimeUnit.MILLISECONDS);
}

说实话,我不知道闰年在这个计算中起到什么作用。可能是我错过了你问题的某些方面吗?
编辑:我真蠢,闰年魔法发生在Date.getTime()中。无论如何,你不必用这种方式来处理它。

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