19

Is there a method in any native Java class to calculate how many days were/will be in a specific year? As in, was it a Leap year (366 days) or a normal year (365 days)?

Or do I need to write it myself?

I'm calculating the number of days between two dates, for example, how many days left until my birthday. I want to take into account the February 29 of Leap year. I have it all done except that 29th.

Basil Bourque
  • 218,480
  • 72
  • 657
  • 915
jurchiks
  • 1,206
  • 3
  • 23
  • 50

9 Answers9

49

Another way to do it is to ask the Calendar class for the actual maximum days in a given year:

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

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

This will return 366 for a bisestile year, 365 for a normal one.

Note, I used getActualMaximum instead of getMaximum, which will always returns 366.

Trasplazio Garzuglio
  • 3,185
  • 2
  • 22
  • 25
  • 1
    @NoodleofDeath Actually, this Answer was outdated as of Java 8 in 2014. The troublesome old date-time classes such as [`java.util.Date`](https://docs.oracle.com/javase/8/docs/api/java/util/Date.html), [`java.util.Calendar`](https://docs.oracle.com/javase/8/docs/api/java/util/Calendar.html), and `java.text.SimpleTextFormat` are now [legacy](https://en.wikipedia.org/wiki/Legacy_system), supplanted by the [java.time](https://docs.oracle.com/javase/8/docs/api/java/time/package-summary.html) classes. See [Tutorial by Oracle](https://docs.oracle.com/javase/tutorial/datetime/TOC.html). – Basil Bourque May 29 '17 at 00:26
  • 3
    @BasilBourque I agree that if at all possible, you should use the java.time classes. But for those of us who don't have the luxury of using Java 8 yet this answer is not outdated. The OP was referring to java.util.Calendar and java.util.Date, and this answer is still very applicable for many of us. It was the answer I was looking for. – Samurai Soul Jul 28 '17 at 15:31
  • @SamuraiSoul Much of the java.time functionality is back-ported to Java 6 and Java 7 in the [***ThreeTen-Backport***](http://www.threeten.org/threetenbp/) project. Further adapted for Android in the [***ThreeTenABP***](https://github.com/JakeWharton/ThreeTenABP) project. So there is no reason to suffer with the wretched legacy `Date`/`Calendar`/etc. classes. See [my Answer](https://stackoverflow.com/a/32322497/642706) for details. – Basil Bourque Jul 28 '17 at 16:59
18

tl;dr

Year.of( 2015 ).length()

…and…

Year.isLeap( 2015 )

java.time.Year

In Java 8 and later we have the java.time package. (Tutorial)

length

The Year class represents a single year value. You can interrogate its length.

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

isLeap

You can also ask if a year is a Leap year or not.

Boolean isLeapYear = Year.isLeap( 2015 );

As an example, get the number of days in year using Java’s ternary operator, such as:

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

In our case, we want number of days of year. That is 365 for non-Leap years, and 366 for Leap year.

int daysInYear = ( Year.isLeap( 2015 ) ) ? 366 : 365 ;

Day-of-year

You can get the day-of-year number of a date. That number runs from 1 to 365, or 366 in a leap year.

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

Going the other direction, get a date for a day-of-year.

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

You could determine elapsed days by comparing these day-of-year numbers when dealing with a single year. But there is an easier way; read on.

Elapsed days

Use the ChronoUnit enum to calculate elapsed days.

LocalDate start = LocalDate.of( 2017 , 2 , 23 ) ;
LocalDate stop = LocalDate.of( 2017 , 3 , 11 ) ;
int daysBetween = ChronoUnit.DAYS.between( start , stop );

Automatically handles Leap Year.


About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

Where to obtain the java.time classes?

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

Basil Bourque
  • 218,480
  • 72
  • 657
  • 915
15

The GregorianCalendar standar class has an isLeapyear() method. If all you've got is a year number (say, 2008), then construct a date using this constructor, and then check the isLeapYear() method afterwards.

Marc B
  • 340,537
  • 37
  • 382
  • 468
  • 7
    Bah. Stupid Java and its libraries for EVERYTHING. :-P (+1) – Platinum Azure Jan 24 '11 at 21:48
  • 5
    Yeah, using libraries for dates SUCKS. Passing your own tests for leap years, varying months, leap seconds, additive math is the way to... nevermind. :) – Jeff Ferland Jan 24 '11 at 21:56
  • But, then you can easily just define the "MyCalendar" as being the new standard, and it'd magically pass all relevant tests. – Marc B Jan 24 '11 at 21:57
  • @Autocracy: Only the built-in date libraries suck. Ask Jon Skeet about it. – Gabe Jan 24 '11 at 22:13
  • Yeah, I wrote this in late evening and I forgot to mention that I'm using the Calendar class and the Calendar.get(Calendar.DAY_OF_YEAR) to calculate the difference. I have only one doubt - if I do, for example, Calendar.add(Calendar.MONTH, 14) will it set the resulting year as a leap year if it is one? Or all years have only 365 days there? – jurchiks Jan 25 '11 at 09:22
  • It should, and it's easy enough to test. Set a date in a known leapyear and cross over the Feb 29th with your addition. – Marc B Jan 25 '11 at 12:15
  • Yeap, it does. No need for GregorianCalendar then, I'll be using what I was using until now and calculate the remainder with the TimeUnit.DAYS.convert(). – jurchiks Jan 25 '11 at 12:56
7

since JAVA 8

Days in a year:

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

Days to my birthday:

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;
epox
  • 4,537
  • 36
  • 26
6

For DateTime calculations I highly recommend using the JodaTime library. For what you need, in particular, it would be a one liner:

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

I hope this helps.

Matthew Sant
  • 1,501
  • 10
  • 10
5

GregorianCalendar.isLeapYear(int year)

brian_d
  • 10,694
  • 4
  • 43
  • 72
3

You can look at the Wikipedia page for some very nice pseudocode:

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

I'm sure you can figure out how to implement that logic in Java. :-)

Platinum Azure
  • 41,456
  • 9
  • 100
  • 130
  • 2
    That looks like re-inventing the wheel. – Waldheinz Jan 24 '11 at 21:49
  • Yes, agreed, this is before I knew about Java's `GregorianCalendar` class. Java's MANY other date/time issues aside, that's the way to go in this case! – Platinum Azure Jan 24 '11 at 21:50
  • why the down-vote? This is "the" algorithm to find leap year. – Cem Catikkas Jan 25 '11 at 19:04
  • 1
    @Cem Catikkas: It's definitely correct, but the question is "was it a helpful answer". This is a Java question, so I can see an argument for using Java libraries being a better answer and reinventing the wheel being bad. Thanks for the upvote though! :-) – Platinum Azure Jan 25 '11 at 19:11
3

You exact use case might be best solved with Joda and this specific example.

Jacob Tomaw
  • 1,221
  • 9
  • 15
1

You can use the TimeUnit class. For your specific needs this should do:

public static int daysBetween(Date a, Date b) {
    final long dMs = a.getTime() - b.getTime();
    return TimeUnit.DAYS.convert(dMs, TimeUnit.MILLISECONDS);
}

Honestly, I don't see where leap years play any role in this calculation, though. Maybe I missed some aspect of your question?

Edit: Stupid me, the leap years magic happens in the Date.getTime(). Anyway, you don't have to deal with it this way.

Waldheinz
  • 10,128
  • 3
  • 29
  • 59