Calendar Class in Java – Fields, Date Arithmetic and java.time
java.util.Calendar is an abstract class, introduced in Java 1.1, for working with the fields of a date (year, month, day, hour and so on) and for date arithmetic, things that java.util.Date cannot do well. Its standard implementation is GregorianCalendar.
Like Date, Calendar is now considered legacy: the java.time API introduced in Java 8 is simpler, immutable and thread-safe. This tutorial shows how Calendar works, its pitfalls, and how to convert to java.time.
1. Getting and Setting Fields
Obtain an instance with Calendar.getInstance() (default zone and locale, or the ones you pass). Fields are read and written with constants such as Calendar.YEAR:
import java.util.*;
public class CalendarFields {
public static void main(String[] args) {
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("Asia/Kolkata"), Locale.ENGLISH);
cal.clear();
cal.set(2026, Calendar.OCTOBER, 11, 15, 30, 0); // month constant avoids the 0-based trap
System.out.println("YEAR : " + cal.get(Calendar.YEAR));
System.out.println("MONTH : " + cal.get(Calendar.MONTH) + " (0-based: 9 = October)");
System.out.println("DAY_OF_MONTH : " + cal.get(Calendar.DAY_OF_MONTH));
System.out.println("DAY_OF_WEEK : " + cal.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.LONG, Locale.ENGLISH));
System.out.println("DAY_OF_YEAR : " + cal.get(Calendar.DAY_OF_YEAR));
System.out.println("HOUR_OF_DAY : " + cal.get(Calendar.HOUR_OF_DAY));
System.out.println("WEEK_OF_YEAR : " + cal.get(Calendar.WEEK_OF_YEAR));
System.out.println("max days in month: " + cal.getActualMaximum(Calendar.DAY_OF_MONTH));
System.out.println("class : " + cal.getClass().getSimpleName());
}
}
YEAR : 2026 MONTH : 9 (0-based: 9 = October) DAY_OF_MONTH : 11 DAY_OF_WEEK : Sunday DAY_OF_YEAR : 284 HOUR_OF_DAY : 15 WEEK_OF_YEAR : 42 max days in month: 31 class : GregorianCalendar
| Field constant | Meaning |
|---|---|
YEAR, MONTH, DAY_OF_MONTH | Date parts (MONTH is 0-based) |
HOUR_OF_DAY, HOUR, MINUTE, SECOND, MILLISECOND | Time parts (HOUR is 12-hour) |
DAY_OF_WEEK | SUNDAY (1) to SATURDAY (7) |
DAY_OF_YEAR, WEEK_OF_YEAR | Position in the year (week rules depend on locale) |
AM_PM, ERA, ZONE_OFFSET | Other fields |
Use getTime() to get a Date, getTimeInMillis() for epoch milliseconds, and clear() before set so leftover time fields do not leak into your value.
2. Date Arithmetic: add() vs roll()
import java.text.SimpleDateFormat;
import java.util.*;
public class CalendarArithmetic {
public static void main(String[] args) {
TimeZone ist = TimeZone.getTimeZone("Asia/Kolkata");
SimpleDateFormat fmt = new SimpleDateFormat("EEE dd MMM yyyy", Locale.ENGLISH);
fmt.setTimeZone(ist);
Calendar cal = Calendar.getInstance(ist, Locale.ENGLISH);
cal.clear();
cal.set(2026, Calendar.JANUARY, 31);
System.out.println("start : " + fmt.format(cal.getTime()));
cal.add(Calendar.MONTH, 1); // add: adjusts to the last valid day
System.out.println("add 1 month : " + fmt.format(cal.getTime()));
cal.add(Calendar.DAY_OF_MONTH, 30);
System.out.println("add 30 days : " + fmt.format(cal.getTime()));
cal.roll(Calendar.MONTH, 11); // roll: changes one field without carrying over
System.out.println("roll month +11 : " + fmt.format(cal.getTime()));
Calendar other = (Calendar) cal.clone();
other.add(Calendar.YEAR, -1);
System.out.println("other before cal: " + other.before(cal));
}
}
start : Sat 31 Jan 2026 add 1 month : Sat 28 Feb 2026 add 30 days : Mon 30 Mar 2026 roll month +11 : Sat 28 Feb 2026 other before cal: true
add(field, amount)changes a field and carries over into larger fields; adding a month to 31 January gives 28 February.roll(field, amount)changes only that field and wraps within its range, leaving larger fields (here, the year) unchanged.Calendaris mutable:addmodifies the object.clone()it when you need to keep the original.- Compare with
before,afterandcompareTo.
3. Common Pitfalls
- Zero-based months:
set(2026, 10, 11)means 11 November. Use the constantsCalendar.OCTOBERetc. - Mutability and thread safety: sharing a
Calendarbetween threads or objects leads to surprising changes. - Lenient by default: invalid values such as 32 January silently roll over to 1 February unless you call
setLenient(false). - Locale-dependent: the first day of the week and week numbering vary by locale.
4. Converting to java.time
GregorianCalendar converts directly to ZonedDateTime and back. The same arithmetic in java.time is shorter and works on immutable values:
import java.time.*;
import java.util.*;
public class CalendarToJavaTime {
public static void main(String[] args) {
GregorianCalendar cal = new GregorianCalendar(2026, Calendar.OCTOBER, 11);
cal.setTimeZone(TimeZone.getTimeZone("Asia/Kolkata"));
ZonedDateTime zdt = cal.toZonedDateTime(); // legacy -> modern
System.out.println("toZonedDateTime : " + zdt.toLocalDate());
LocalDate modern = LocalDate.of(2026, 1, 31).plusMonths(1).plusDays(30); // same arithmetic, immutable
System.out.println("java.time result: " + modern);
GregorianCalendar back = GregorianCalendar.from(zdt); // modern -> legacy
System.out.println("round trip year : " + back.get(Calendar.YEAR));
}
}
toZonedDateTime : 2026-10-11 java.time result: 2026-03-30 round trip year : 2026
| Calendar code | java.time equivalent |
|---|---|
Calendar.getInstance() | ZonedDateTime.now() / LocalDateTime.now() |
cal.get(Calendar.YEAR) | date.getYear() |
cal.get(Calendar.MONTH) + 1 | date.getMonthValue() |
cal.add(Calendar.DAY_OF_MONTH, 5) | date.plusDays(5) (returns a new object) |
cal.getActualMaximum(DAY_OF_MONTH) | date.lengthOfMonth() |
5. Summary
Calendar(usually aGregorianCalendar) reads, sets and calculates date fields.addcarries over to larger fields;rolldoes not.- Watch out for zero-based months, mutability and lenient parsing.
- Prefer
java.timein new code and convert withtoZonedDateTime()andGregorianCalendar.from().
Related Tutorials
Frequently Asked Questions (FAQ)
Q1. What is the Calendar class in Java?
An abstract class in java.util for converting between instants and date fields and performing date arithmetic.
Q2. How do I get a Calendar instance?
Calendar.getInstance(), optionally with a TimeZone and Locale. It usually returns a GregorianCalendar.
Q3. Why can't I write new Calendar()?
Calendar is abstract. Use getInstance() or new GregorianCalendar().
Q4. Why are Calendar months zero-based?
A historical design decision copied from C. January is 0 and December is 11, so use the month constants to avoid mistakes.
Q5. What is the difference between add() and roll()?
add updates larger fields when a value overflows; roll wraps within the field and leaves larger fields unchanged.
Q6. How do I convert a Calendar to a Date?
Call cal.getTime(). The reverse is cal.setTime(date).
Q7. Is Calendar thread-safe?
No. It is mutable; do not share instances between threads without synchronization.
Q8. What is GregorianCalendar?
The concrete subclass implementing the Gregorian calendar used in most of the world.
Q9. How do I get the day of the week?
cal.get(Calendar.DAY_OF_WEEK) returns 1 (Sunday) to 7 (Saturday); getDisplayName returns its name.
Q10. How do I find the number of days in a month?
cal.getActualMaximum(Calendar.DAY_OF_MONTH), or LocalDate.lengthOfMonth().
Q11. What does setLenient(false) do?
It makes the calendar reject invalid field values, such as day 32, instead of silently normalising them.
Q12. How do I subtract days with Calendar?
Pass a negative amount: cal.add(Calendar.DAY_OF_MONTH, -7).
Q13. Is Calendar deprecated?
No, but it is legacy. The java.time API is recommended for new code.
Q14. How do I convert Calendar to LocalDate?
((GregorianCalendar) cal).toZonedDateTime().toLocalDate(), or via cal.toInstant().atZone(zone).toLocalDate().
Q15. Does Calendar handle time zones?
Yes. Each instance has a TimeZone used to compute fields from its instant.
Q16. How do I compare two Calendar objects?
Use before, after, compareTo, or compare getTimeInMillis() values.
Q17. What does clear() do?
It resets all fields to undefined, so subsequent set calls produce a clean value without leftover time parts.
Q18. Why do I get a leap-year bug when adding a year?
Adding a year to 29 February gives 28 February in a non-leap year. Both Calendar and java.time clamp to the last valid day.
Q19. What is WEEK_OF_YEAR based on?
The locale's first day of the week and minimal days in the first week. Use java.time's IsoFields for ISO week numbers.
Q20. Which Java version introduced Calendar?
Java 1.1, to address shortcomings of Date.