Michi
Michi

Reputation: 577

Why is java.util.Calendar returning 31 for Feb 2021?

The following snippet returns:

28
31

I can't figure out, why. I tried so set the calendar object to Feb 2021 in two ways, what am I doing wrong? Month is zero-based, so Feb is "1".

import java.util.Calendar;
import java.util.GregorianCalendar;

public class HelloWorld{

     public static void main(String []args){
        Calendar g = new GregorianCalendar(2021, 1, 28);
        System.out.println(g.getActualMaximum(Calendar.DAY_OF_MONTH));
        

        int year = 2021;
        int month = 1;
        Calendar c = Calendar.getInstance();
        c.set(Calendar.YEAR, year);
        c.set(Calendar.MONTH, month);
        System.out.println(c.getActualMaximum(Calendar.DAY_OF_MONTH));
     }
}

Or does this only happen, because I call Calendar.getInstance() on March 29, 30 or 31 and I don't call

c.set(Calendar.DAY_OF_MONTH, {any day below 29});

Upvotes: 1

Views: 1410

Answers (2)

Arvind Kumar Avinash
Arvind Kumar Avinash

Reputation: 79075

java.util date-time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern date-time API* .

Using modern date-time API:

import java.time.Month;
import java.time.Year;

public class Main {
    public static void main(String[] args) {
        System.out.println(YearMonth.of(2021, Month.FEBRUARY).lengthOfMonth());
    }
}

Output:

28

Learn more about the modern date-time API from Trail: Date Time.

Using legacy API:

import java.util.Calendar;
import java.util.GregorianCalendar;

public class Main {
    public static void main(String[] args) {
        // 1st Feb 2021
        Calendar cal = new GregorianCalendar(2021, Calendar.FEBRUARY, 1);
        System.out.println(cal.getActualMaximum(Calendar.DAY_OF_MONTH));
    }
}

Output:

28

* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

Upvotes: 6

Andreas
Andreas

Reputation: 159086

You call Calendar.getInstance(), which returns a Calendar object initialized to the current time, which today means Mar 31, 2021.

You then set YEAR to 2021 and MONTH to 1 (Feb), leaving DAY_OF_MONTH at 31. If you asked the Calendar object for the date, it would resolve the fields and return a date value that explains the issue:

System.out.println(c.getTime()); // prints: Wed Mar 03 11:51:55 EST 2021

See how it says Mar 3, 2021? That is because Feb 31 rolls over after Feb 28 and becomes Mar 3.

Since the Calendar object is now in March, the c.getActualMaximum(Calendar.DAY_OF_MONTH) correctly returns 31.

To do it right, call clear() and set DAY_OF_MONTH to 1, which is much easier when you use the nice set(year, month, date) helper method.

int year = 2021;
int month = Calendar.FEBRUARY/*1*/;
Calendar c = Calendar.getInstance();
c.clear();
c.set(year, month, 1);
System.out.println(c.getTime()); // prints: Mon Feb 01 00:00:00 EST 2021
System.out.println(c.getActualMaximum(Calendar.DAY_OF_MONTH)); // prints: 28

Upvotes: 5

Related Questions