In java.util.Calendar, January is defined as month 0, not month 1. Is there any specific reason to that ?
I have seen many people getting confused about that...
It's just part of the horrendous mess which is the Java date/time API. Listing what's wrong with it would take a very long time (and I'm sure I don't know half of the problems). Admittedly working with dates and times is tricky, but aaargh anyway.
Do yourself a favour and use Joda Time instead, or possibly JSR-310.
EDIT: As for the reasons why - as noted in other answers, it could well be due to old C APIs, or just a general feeling of starting everything from 0... except that days start with 1, of course. I doubt whether anyone outside the original implementation team could really state reasons - but again, I'd urge readers not to worry so much about why bad decisions were taken, as to look at the whole gamut of nastiness in java.util.Calendar and find something better.
One point which is in favour of using 0-based indexes is that it makes things like "arrays of names" easier:
// I "know" there are 12 months
String[] monthNames = new String[12]; // and populate...
String name = monthNames[calendar.get(Calendar.MONTH)];
Of course, this fails as soon as you get a calendar with 13 months... but at least the size specified is the number of months you expect.
This isn't a good reason, but it's a reason...
EDIT: As a comment sort of requests some ideas about what I think is wrong with Date/Calendar:
Surprising bases (1900 as the year base in Date, admittedly for deprecated constructors; 0 as the month base in both)
Mutability - using immutable types makes it much simpler to work with what are really effectively values
An insufficient set of types: it's nice to have Date and Calendar as different things,
but the separation of "local" vs "zoned" values is missing, as is date/time vs date vs time
An API which leads to ugly code with magic constants, instead of clearly named methods
An API which is very hard to reason about - all the business about when things are recomputed etc
The use of parameterless constructors to default to "now", which leads to hard-to-test code
The Date.toString() implementation which always uses the system local time zone (that's confused many Stack Overflow users before now)
Because doing math with months is much easier.
1 month after December is January, but to figure this out normally you would have to take the month number and do math
12 + 1 = 13 // What month is 13?
I know! I can fix this quickly by using a modulus of 12.
(12 + 1) % 12 = 1
This works just fine for 11 months until November...
(11 + 1) % 12 = 0 // What month is 0?
You can make all of this work again by subtracting 1 before you add the month, then do your modulus and finally add 1 back again... aka work around an underlying problem.
((11 - 1 + 1) % 12) + 1 = 12 // Lots of magical numbers!
Now let's think about the problem with months 0 - 11.
(0 + 1) % 12 = 1 // February
(1 + 1) % 12 = 2 // March
(2 + 1) % 12 = 3 // April
(3 + 1) % 12 = 4 // May
(4 + 1) % 12 = 5 // June
(5 + 1) % 12 = 6 // July
(6 + 1) % 12 = 7 // August
(7 + 1) % 12 = 8 // September
(8 + 1) % 12 = 9 // October
(9 + 1) % 12 = 10 // November
(10 + 1) % 12 = 11 // December
(11 + 1) % 12 = 0 // January
All of the months work the same and a work around isn't necessary.
C based languages copy C to some degree. The tm structure (defined in time.h) has an integer field tm_mon with the (commented) range of 0-11.
C based languages start arrays at index 0. So this was convenient for outputting a string in an array of month names, with tm_mon as the index.
There has been a lot of answers to this, but I will give my view on the subject anyway.
The reason behind this odd behavior, as stated previously, comes from the POSIX C time.h where the months were stored in an int with the range 0-11.
To explain why, look at it like this; years and days are considered numbers in spoken language, but months have their own names. So because January is the first month it will be stored as offset 0, the first array element. monthname[JANUARY] would be "January". The first month in the year is the first month array element.
The day numbers on the other hand, since they do not have names, storing them in an int as 0-30 would be confusing, add a lot of day+1 instructions for outputting and, of course, be prone to alot of bugs.
That being said, the inconsistency is confusing, especially in javascript (which also has inherited this "feature"), a scripting language where this should be abstracted far away from the langague.
TL;DR: Because months have names and days of the month do not.
In Java 8, there is a new Date/Time API JSR 310 that is more sane. The spec lead is the same as the primary author of JodaTime and they share many similar concepts and patterns.
I'd say laziness. Arrays start at 0 (everyone knows that); the months of the year are an array, which leads me to believe that some engineer at Sun just didn't bother to put this one little nicety into the Java code.
Probably because C's "struct tm" does the same.
Because programmers are obsessed with 0-based indexes. OK, it's a bit more complicated than that: it makes more sense when you're working with lower-level logic to use 0-based indexing. But by and large, I'll still stick with my first sentence.
java.time.Month
Java provides you another way to use 1 based indexes for months. Use the java.time.Month enum. One object is predefined for each of the twelve months. They have numbers assigned to each 1-12 for January-December; call getValue for the number.
Make use of Month.JULY (Gives you 7)
instead of Calendar.JULY (Gives you 6).
(import java.time.*;)
Personally, I took the strangeness of the Java calendar API as an indication that I needed to divorce myself from the Gregorian-centric mindset and try to program more agnostically in that respect. Specifically, I learned once again to avoid hardcoded constants for things like months.
Which of the following is more likely to be correct?
if (date.getMonth() == 3) out.print("March");
if (date.getMonth() == Calendar.MARCH) out.print("March");
This illustrates one thing that irks me a little about Joda Time - it may encourage programmers to think in terms of hardcoded constants. (Only a little, though. It's not as if Joda is forcing programmers to program badly.)
For me, nobody explains it better than mindpro.com:
Gotchas
java.util.GregorianCalendar has far fewer bugs and gotchas than the
old java.util.Date class but it is still no picnic.
Had there been programmers when Daylight Saving Time was first
proposed, they would have vetoed it as insane and intractable. With
daylight saving, there is a fundamental ambiguity. In the fall when
you set your clocks back one hour at 2 AM there are two different
instants in time both called 1:30 AM local time. You can tell them
apart only if you record whether you intended daylight saving or
standard time with the reading.
Unfortunately, there is no way to tell GregorianCalendar which you
intended. You must resort to telling it the local time with the dummy
UTC TimeZone to avoid the ambiguity. Programmers usually close their
eyes to this problem and just hope nobody does anything during this
hour.
Millennium bug. The bugs are still not out of the Calendar classes.
Even in JDK (Java Development Kit) 1.3 there is a 2001 bug. Consider
the following code:
GregorianCalendar gc = new GregorianCalendar();
gc.setLenient( false );
/* Bug only manifests if lenient set false */
gc.set( 2001, 1, 1, 1, 0, 0 );
int year = gc.get ( Calendar.YEAR );
/* throws exception */
The bug disappears at 7AM on 2001/01/01 for MST.
GregorianCalendar is controlled by a giant of pile of untyped int
magic constants. This technique totally destroys any hope of
compile-time error checking. For example to get the month you use
GregorianCalendar. get(Calendar.MONTH));
GregorianCalendar has the raw
GregorianCalendar.get(Calendar.ZONE_OFFSET) and the daylight savings
GregorianCalendar. get( Calendar. DST_OFFSET), but no way to get the
actual time zone offset being used. You must get these two separately
and add them together.
GregorianCalendar.set( year, month, day, hour, minute) does not set
the seconds to 0.
DateFormat and GregorianCalendar do not mesh properly. You must
specify the Calendar twice, once indirectly as a Date.
If the user has not configured his time zone correctly it will default
quietly to either PST or GMT.
In GregorianCalendar, Months are numbered starting at January=0,
rather than 1 as everyone else on the planet does. Yet days start at 1
as do days of the week with Sunday=1, Monday=2,… Saturday=7. Yet
DateFormat. parse behaves in the traditional way with January=1.
The true reason why
You would think that when we deprecated most of Date and added the new
Calendar class, we would have fixed Date's biggest annoyance: the fact
that January is month 0. We certainly should have, but unfortunately
we didn't. We were afraid that programmers would be confused if Date
used zero-based months and Calendar used one-based months. And a few
programmers probably would have been. But in hindsight, the fact that
Calendar is still zero-based has caused an enormous amount of
confusion, and it was probably the biggest single mistake in the Java
international API's.
Quoted from International Calendars in Java by Laura Werner, link at the bottom.
The better alternative: java.time
This may just be repeating what others have said, throw the old and poorly designed Calendar class overboard and use java.time, the modern Java date and time API. There months are consistently sanely numbered from 1 for January through 12 for December.
If you are getting a Calendar from a legacy API not yet upgraded to java.time, the first thing to do is to convert to a modern ZonedDateTime. Depending on your needs you may do further conversions from there. In most of the world the Calendar object you get will virtually always be an instance of the GregorianCalendar subclass (since the Calendar class itself is abstract). To demonstreate:
Calendar oldfashionedCalendarObject = Calendar.getInstance();
ZonedDateTime zdt
= ((GregorianCalendar) oldfashionedCalendarObject).toZonedDateTime();
System.out.println(zdt);
System.out.format("Month is %d or %s%n", zdt.getMonthValue(), zdt.getMonth());
Output when I ran just now in my time zone:
2021-03-17T23:18:47.761+01:00[Europe/Copenhagen]
Month is 3 or MARCH
Links
International Calendars in Java by Laura Werner
Oracle tutorial: Date Time explaining how to use java.time.
tl;dr
Month.FEBRUARY.getValue() // February → 2.
2
Details
The Answer by Jon Skeet is correct.
Now we have a modern replacement for those troublesome old legacy date-time classes: the java.time classes.
java.time.Month
Among those classes is the Month enum. An enum carries one or more predefined objects, objects that are automatically instantiated when the class loads. On Month we have a dozen such objects, each given a name: JANUARY, FEBRUARY, MARCH, and so on. Each of those is a static final public class constant. You can use and pass these objects anywhere in your code. Example: someMethod( Month.AUGUST )
Fortunately, they have sane numbering, 1-12 where 1 is January and 12 is December.
Get a Month object for a particular month number (1-12).
Month month = Month.of( 2 ); // 2 → February.
Going the other direction, ask a Month object for its month number.
int monthNumber = Month.FEBRUARY.getValue(); // February → 2.
Many other handy methods on this class, such as knowing the number of days in each month. The class can even generate a localized name of the month.
You can get the localized name of the month, in various lengths or abbreviations.
String output =
Month.FEBRUARY.getDisplayName(
TextStyle.FULL ,
Locale.CANADA_FRENCH
);
février
Also, you should pass objects of this enum around your code base rather than mere integer numbers. Doing so provides type-safety, ensures a valid range of values, and makes your code more self-documenting. See Oracle Tutorial if unfamiliar with the surprisingly powerful enum facility in Java.
You also may find useful the Year and YearMonth classes.
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, & java.text.SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to java.time.
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?
Java SE 8 and SE 9 and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
The ThreeTenABP project adapts ThreeTen-Backport (mentioned above) for Android specifically.
See How to use….
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.
Set the month to Calendar.MARCH, or compare to see if it == Calendar.JUNE, for example.
The Date and Calendar classes date back to the very early days of Java, when folks were still figuring things out, and they are widely regarded as not very well designed.
If Calendar were created today with the same design, rather than ints for Calendar.JUNE, etc., they'd use enums.
It isn't exactly defined as zero per se, it's defined as Calendar.January. It is the problem of using ints as constants instead of enums. Calendar.January == 0.
Because language writing is harder than it looks, and handling time in particular is a lot harder than most people think. For a small part of the problem (in reality, not Java), see the YouTube video "The Problem with Time & Timezones - Computerphile" at https://www.youtube.com/watch?v=-5wpm-gesOY. Don't be surprised if your head falls off from laughing in confusion.
In addition to DannySmurf's answer of laziness, I'll add that it's to encourage you to use the constants, such as Calendar.JANUARY.
Because everything starts with 0. This is a basic fact of programming in Java. If one thing were to deviate from that, then that would lead to a whole slue of confusion. Let's not argue the formation of them and code with them.
When you look at the javadoc of the java.util.Date class, most of the methods are deprecated. Why was this done?
Well, for two related reasons. It was a very poor implementation of the concept of Dates and Times and it was replaced by the Calendar class.
The Calendar class, although an improvement, leaves a lot to be desired as well, so for serious Date/Time work, everyone recommends Joda-Time. Java 8 brings the new java.time.* package, inspired by Joda-Time, defined by JSR-310, and intended to supplant the old Date/Calendar classes.
Edit: In response to the specific question of why the implementation is poor, there are many reasons. The JavaDoc sums it up as follows:
Unfortunately, the API for these functions was not amenable to internationalization.
In addition to this general deficiency (which covers issues like the lack of a Time Zone component as well as the date formatting which is better handled in DateFormat and the inability to have a non-Gregorian calendar representation), there are specific issues which really hurt the Date class, including the fact that year is presented in an offset of 1900 from Common Era year.
Calendar has its own problems, but even as early as JDK 1.1 it was obvious that java.util.Date was not going to cut it. Even though Calendar is arguable the worst JDK API, it has taken until version 7 to attempt to address it.
Date is mutable
Date doesn't have support for time zones
The latter led to it being replaced by Calendar. And the former, combined with the ease-of-use, lead to both being replaced by Joda-Time / JSR-310 (java.time.* package)
They're deprecated because Date was written as fast as possible back in the day when they wanted to rush the JDK out the door.
It turns out the Dates and Calendars are Hard. So, they created the Calendar class, which much more thought, in order to handle the Hard Parts of working with calendars.
They deprecated the Date methods and delegated to Calendar because they didn't want to change the behavior of the existing Date methods, and possibly break existing applications.
Here's a good answer straight from Oracle: http://www.oracle.com/technetwork/articles/java/jf14-date-time-2125367.html
A long-standing bugbear of Java developers has been the inadequate support for the date and time use cases of ordinary developers.
For example, the existing classes (such as java.util.Date and SimpleDateFormatter) aren’t thread-safe, leading to potential concurrency issues for users—not something the average developer would expect to deal with when writing date-handling code.
Some of the date and time classes also exhibit quite poor API design. For example, years in java.util.Date start at 1900, months start at 1, and days start at 0—not very intuitive.
... java.util.Date represents an instant on the timeline—a wrapper around the number of milli-seconds since the UNIX epoch—but if you call toString(), the result suggests that it has a time zone, causing confusion among developers.
I don't know the official reason why it has been deprecated, but as far as I can tell GregorianCalendarand Joda-Time support operations on dates, meaning that you can add, for instance, a day to a date and have its month and year updated accordingly.
For instance, say you want to compute the day after the current date and today is May 31st; with java.util.Date, you just have getDays() +1, which returns 32, and you have to handle the knowledge that the current month doesn't have 32 days by yourself; with GregorianCalendaror Joda.time, adding a day to May 31st results in an object representing June 1st, hiding the complexity from your sight.
I use the Joda time package to calculate durations between two historic instances in times in an Android application/activity. The two instances may for example have happened in the 19th century in Russia (Julian calendar system – before Russia adopted the Gregorian calendar system) and 20th Century western Europe (Gregorian calendar).
The inconvenience is that I now have to choose Julian or Gregorian chronologies based on my knowledge on specific countries actual cutover dates. These individual cutover dates can be found at Wikipedia or in the litterature.
As I see it, there are three solutions to my problems:
1) Look up all the cutover dates for the countries in literature. Then manually punch in the specific cutover date/time for the individual time zones. And use the factory setting in GJChronology.getInstance(zone, factorySettingCutoverDateTimeMillis, 4) where factorySettingCutoverDateTimeMillis is a long containing the milliseconds value of the specific instance in time when the cutover between Julian and Gregorian calendars happened in the specific DateTimeZone zone.
2) Identify where the specific cutover dates eventually are located in Jodatime (or elsewhere accessible in Android), and then make use of them.
3) Use the dafault GJChronology.getInstance(zone, null, 4) that specifies the default date in October 1582 (that is correct for many countries, but not all).
Solution 1) is possible, but require some manual labour to implement. Solution 2 is best, while solution 3) is where I am now using the default in the GJChronology or picking Julian or Gregorian if I know the particular calendar system used at that time.
I hope for help to arrive at solution 2) or get help to direct me to the best compiled cutover date/time list online to save work implementing solution 1). Thanks for your help.
I don't believe that Joda Time has that information within it - I certainly haven't come across it. The idea of a "country" doesn't really exist in Joda Time, and the cutover is not necessarily associated with a time zone either. That rules out solution 2, I believe.
I don't know of any official source of this information - I don't believe it's in the Unicode CLDR, for example... but could this page be useful to you? I have no idea of its reliabilty of completeness, but I guess it's a start :)
The code below demonstrates the problematic joda-time implementation of week calculation. This behavior is not a bug but a design decision Joda-Time uses the ISO standard Monday to Sunday week. (perhaps it should be a bug?)
Given a date I need to calculate the week number, this calculation must be i18n in nature. Meaning I must take into consideration the correct week numbering based on the regional settings of the user.
The demo code below shows wrong calculation by Joda-Time and correct calculation by the JDK, in the application we try to stick with Joda-Time being a superior solution for date manipulations. So, should I be mixing the two Time calculation libraries? I would obviously prefer not to, is this even a safe thing to do or would I come into corner cases (having experience with Date, Calendar I know for a fact that this is a painful issue for Java).
Bottom line: What is the recommended best-practice for the described requirement?
Problem demonstration code
Please see this online calendar displaying week numbers for correct week calculation example.
public class JodaTest {
static DateTimeFormatter formatter = DateTimeFormat.forPattern("ww yyyy");
static SimpleDateFormat jdkFormatter = new SimpleDateFormat("ww yyyy");
public static void main(String[] args) {
DateTime time = new DateTime(/*year*/2009, /*monthOfYear*/12, /*dayOfMonth*/6, /*hourOfDay*/23, /*minuteOfHour*/0, /*secondOfMinute*/0, /*millisOfSecond*/0);
StringBuilder buffer = new StringBuilder()
.append("Testing date ").append(time.toString()).append("\n")
.append("Joda-Time timezone is ").append(DateTimeZone.getDefault()).append(" yet joda wrongly thinks week is ").append(formatter.print(time)).append("\n")
.append("JDK timezone is ").append(TimeZone.getDefault().getID()).append(" yet jdk rightfully thinks week is ").append(jdkFormatter.format(time.toDate())).append(" (jdk got it right ?!?!)");
System.out.println(buffer.toString());
}
}
Output:
Testing date 2009-12-06T23:00:00.000+02:00
Joda-Time timezone is Asia/Jerusalem yet joda wrongly thinks week is 49 2009
JDK time zone is Asia/Jerusalem yet jdk rightfully thinks week is 50 2009 (jdk got it right ?!?!)
The best available solution is to write an implementation of DateTimeField that wraps up the logic to extract the value you need based on a locale. Internally, you'll probably still rely on the JDK data. The aim is to wrap all the JDK code in a single reusable class. You then use it like this:
int value = dateTime.get(new LocaleAwareWeekField("en_GB"));
This is a follow up question (and possibly should have been asked before it) to this question:
Subclasses of java.util.Calendar.
I'm internationalising a large Java app that uses dates fairly regularly since a lot of the data has dates associated with it. One of the first languages that it will be translated into is Arabic.
Currently I'm having trouble contacting an Arabic speaking person so am asking you; will business users understand and be familiar with the Gregorian calendar?
I guess that the answer could depend on the data which is only supported in one locale (chosen at time of setup), despite being stored as a timestamp.
If data is localised for a locale that commonly uses the Gregorian calendar, but the user is Arabic, do I display the data dates using the Hijri calendar system or will they be familiar with the Gregorian calendar system? And vice-versa?
It depends on how "interationalized" the context of your application is.
If it is some international business application, i.e. for handling imports and exports your customers most likely would expect a Gregorian calendar. Before the Euro (€) many European businesses used the Dollar ($) as default currency, because it simplified many things. The same could apply to the calendar.
On the other hand a highly localized application, like a TV schedule or birthday reminder, you should most certainly use the local calendar.
In other words: Ask you customer or make it user-defineable.
One other thing: Even if most of your users would know the Gregorian calendar, you should think of whether a localized calendar would be an improvement. A few years ago when the whole IT marked was undisputably dominated by the US I was thrilled whenever I used an application which supported Umlauts (äöü). The same concept might give you an edge over your competitors. Delight your customers :)
And as always: Use Joda time.
First, concerning dates use Joda time if you can.
Second, I believe the Gregorian calendar is used for international business and the Islamic calendar is used for purposes of religious holidays & ceremonies; depending on the country, the Islamic calendar may also be the "official" calendar.
For example, in Saudi Arabia the official calendar is indeed the Islamic calendar but by law they do maintain dual calendars for purposes of international business.