Java Calendar WEEK_OF_YEAR not ISO-8601compliant? - java

The ISO-8601 standard states that
"The first week of a year is the week that contains the first Thursday
of the year (and, hence, always contains 4 January)."
Meaning the first week of the year is not that which contains January the 1st but the first one that contains at leat four days into the new year.
Acording to that Mon, January 11 2016 is on week #2. Here is a list of week numbers for 2016.
Ubuntu reflects that in its time widget:
And the cal command does also:
Oracle supports it with the "iw" parameter of TO_CHAR:
> select to_char(to_date('11/01/2016','dd/mm/yyyy'),'iw') weekno from dual;
> WEEKNO
02
But Java says Mon, January 11 2016 is week #3
Calendar c = Calendar.getInstance();
System.out.println(c.getTime());
System.out.println(c.get(Calendar.WEEK_OF_YEAR));
Output:
Mon Jan 11 09:02:35 VET 2016
3
Java thinks the first week of the year is the one that contains January the 1st.
- Is there a way for Java to use the ISO-8601-copliant week numbering?

As I noted in my comment, the default behavior is locale specific. Some locales will give 3, some will give 2.
Luckily, you can specify the number of days that has to be present in the first week of the year, for a given Calendar. As you write above, for ISO 8601, this number is 4, thus the following code should work:
Calendar c = Calendar.getInstance();
c.setMinimalDaysInFirstWeek(4); // For ISO 8601
System.out.println(c.getTime());
System.out.println(c.get(Calendar.WEEK_OF_YEAR));
This should make the output correct regardless of locale.
Test output:
Mon Jan 11 14:54:22 CET 2016
2

tl;dr
myZonedDateTime.get( IsoFields.WEEK_OF_WEEK_BASED_YEAR )
…and…
myZonedDateTime.get( IsoFields.WEEK_BASED_YEAR )
Avoid legacy date-time classes
As the correct Answer by haraldK explains, the Calendar class’s definition of week varies by locale. While well-intentioned, this is confusing.
You should be avoiding Calendar and related classes such as Date. They are now supplanted by the java.time classes.
ISO 8601 week
As for ISO 8601 week, be clear that means:
The first day is Monday, running through Sunday.
Week number one of a week-based year contains the first Thursday of the calendar year.
A week-based year has either 52 or 53 weeks.
The first/last few days of a calendar year may appear in the previous/next week-based year.
java.time
The java.time classes include limited support for ISO 8601 standard weeks. Call the get method on various classes such as LocalDate and ZonedDateTime. Pass the TemporalField implementations found as constants in the IsoFields class.
int week = myZonedDateTime.get( IsoFields.WEEK_OF_WEEK_BASED_YEAR ) ;
int weekBasedYear = myZonedDateTime.get( IsoFields.WEEK_BASED_YEAR ) ;
ThreeTen-Extra
Even better, add the ThreeTen-Extra library to your project to use YearWeek class.
org.threeten.extra.YearWeek yw = YearWeek.from( myZonedDateTime ) ;
Beware of calendaring software settings
Never assume the definition of a week number. Be sure the source of such a number has the same definition of week as you, such as ISO 8601 definition.
For example, the Calendar app supplied by Apple with macOS defaults to a "Gregorian" calendar definition of week. As for what that means, I do not know as I could not find any documentation about their intent/definition. For ISO 8601 weeks, you must change a setting away from default.
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.
Using a JDBC driver compliant with JDBC 4.2 or later, you may exchange java.time objects directly with your database. No need for strings nor java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java 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 Java SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android, the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
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.

Related

Adding a month to a date in Java two ways gives two different results (leap year philosophy?)

Assuming Jan 31, 2000, a leap year, the following two ways of adding a month give me different results. Am I doing something wrong or are these two different philosophies of handling leap-year months? And, if these two approaches are just a philosophy difference, how would you know which method to pick?
Method 1: using LocalDate plusMonths():
LocalDate atestDate = LocalDate.parse("2000-01-31");
System.out.println("One month in future using LocalDate.addMonths() " + atestDate.plusMonths(1));
Output:
One month in future using LocalDate.addMonths() 2000-02-29
Method 2: using Calendar:
Calendar zcal = Calendar.getInstance();
zcal.set(Calendar.DAY_OF_MONTH, 31);
zcal.set(Calendar.MONTH, 1);
zcal.set(Calendar.YEAR, 2000);
zcal.add(Calendar.MONTH, 0);
System.out.println("ONE MONTH IN FUTURE using Calendar: "
+ zcal.getTime());
Output:
ONE MONTH IN FUTURE using Calendar: Thu Mar 02 2000
Why are these two dates' output not the same?
Thanks.
zcal.set(Calendar.DAY_OF_MONTH, 31);
zcal.set(Calendar.MONTH, 1);
zcal.set(Calendar.YEAR, 2000);
This defines the date of February 31st, 2000, which, due to lenient measuring, is equated to March 2nd, 2000. Month values are zero-indexed.
Setting strict:
zcal.setLenient(false);
We get an exception:
Exception in thread "main" java.lang.IllegalArgumentException: MONTH: 1 -> 2
at java.util.GregorianCalendar.computeTime(GregorianCalendar.java:2829)
at java.util.Calendar.updateTime(Calendar.java:3393)
at java.util.Calendar.getTimeInMillis(Calendar.java:1782)
at java.util.Calendar.getTime(Calendar.java:1755)
at Employee.Tester.main(Tester.java:19)
So you can see that the interpolation was shifted over to March. If you wish to hard-code dates for testing purposes, I would recommend using strict validation to avoid these cases. There have been other documented issues related to setting values that make things messy.
tl;dr
Just use LocalDate and forget all about Calendar (troublesome legacy class).
LocalDate.parse( "2000-01-31" ).plusMonths( 1 ).toString()
2000-02-29
Method 1
Method 1: using LocalDate plusMonths():
The LocalDate class documentation explains that it first adds the month-number, and leaves the day-of-month alone. If that day-of-month is not valid in that month (29, 30, or 31), then it adjusts backwards to the last valid day-of-month.
This method adds the specified amount to the months field in three steps:
Add the input months to the month-of-year field
Check if the resulting date would be invalid
Adjust the day-of-month to the last valid day if necessary
For example, 2007-03-31 plus one month would result in the invalid date 2007-04-31. Instead of returning an invalid result, the last valid day of the month, 2007-04-30, is selected instead.
Seems like a smart approach to me.
In your example, LocalDate first changed 2000-01-31 to 2000-02-31. There is no 31st in February, so it walked back to 30. But no Feb 30th either. So it walked further back to 29. Bingo! In that year in that month, there is indeed a 29th day because the year 2000 is a Leap Year. So the answer is 2000-02-29.
LocalDate.parse( "2000-01-31" )
.plusMonths( 1 )
.toString()
2000-02-29
Method 2
Method 2: using Calendar:
Don’t bother.
This terribly troublesome old Calendar class is now legacy, supplanted entirely by the java.time classes as defined in JSR 310. Specifically, replaced by ZonedDateTime.
Never touch Calendar class again. Save yourself some pain and headache, and pretend this class never existed.
Furthermore, Calendar was a date-with-time value. Not appropriate for a date-only value like yours in the Question.
Convert legacy <–> modern
If you must inter-operate with code not yet updated to java.time, convert between the legacy classes and java.time by calling new conversion methods added to the old classes. For more info, see the Question, Convert java.util.Date to what “java.time” type?
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.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, 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 Java SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
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.
The problem I had in the posting above turned out to be a typo.
Calendar zcal = Calendar.getInstance();
zcal.set(Calendar.DAY_OF_MONTH, 31);
zcal.set(Calendar.MONTH, 1);
zcal.set(Calendar.YEAR, 2000);
zcal.add(Calendar.MONTH, 0);
System.out.println("ONE MONTH IN FUTURE using Calendar: "
+ zcal.getTime());
Should have been:
Calendar zcal = Calendar.getInstance();
zcal.set(Calendar.DAY_OF_MONTH, 31);
zcal.set(Calendar.MONTH, Calendar.JANUARY);
zcal.set(Calendar.YEAR, 2000);
zcal.add(Calendar.MONTH, 1);
System.out.println("ONE MONTH IN FUTURE using Calendar: "
+ zcal.getTime());
Then I get the expected matching date.
Thanks to all who answered! :)

LocalDate cannot parse 'ww' with 'yyyy'

I have to parse date using the following format: "201710" where 10 - week of year number. I tried to implement it in this way:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyw");
java.time.LocalDate startDate = java.time.LocalDate.parse("201710", formatter);
System.out.println(startDate);
But it throws exception:
java.time.format.DateTimeParseException: Text '201710' could not be parsed at index 0
And after that I need to get first and last day of week from LocalDate object.
e.g "201710" - 05.03 12.03 (first day of week needs to be Sunday).
The accepted answer of #Kayaman is not correct because you cannot mix standard date representations (using yyyy = year-of-era) and week-date representations (using ww = week of week-based year). The subtile difference between a standard calendar year and a weekbased year is relevant near the start or end of a calendar year. Conclusion: Don't use the symbol "y", but rather the symbol "Y". Counter example for the input "201501":
Correct solution
DateTimeFormatter formatter =
new DateTimeFormatterBuilder()
.appendValue(WeekFields.ISO.weekBasedYear(), 4)
.appendValue(WeekFields.ISO.weekOfWeekBasedYear(), 2)
.parseDefaulting(ChronoField.DAY_OF_WEEK, 1)
.toFormatter();
LocalDate startDate = LocalDate.parse("201501", formatter);
System.out.println(startDate); // 2014-12-29
Based on the proposal of #Kayaman:
DateTimeFormatter dtf =
new DateTimeFormatterBuilder()
.appendValue(ChronoField.YEAR, 4)
.appendValue(ChronoField.ALIGNED_WEEK_OF_YEAR, 2)
.parseDefaulting(WeekFields.ISO.dayOfWeek(), 1)
.toFormatter();
System.out.println(LocalDate.parse("201501", dtf)); // 2015-01-05 (wrong)
The resulting dates are different! The difference is caused by the definition of the calendar year which always starts on first of January while a week-based year always starts on Monday (ISO-8601-definition) using the first week of calendar year which has at least 4 days.
Additional note a): Java-8 does not manage adjacent digit parsing of localizible fields like the week-based fields (see also the associated JDK issue), therefore I have chosen the builder-based solution instead of defining the pattern "YYYYww" (Java-9 promises a solution, however). But even with Java-9, a build-based approach is still necessary because of the need to define a default for the missing day-of-week (here: setting to Monday).
Additional note b): If you are looking for a true type for the combination of week-based year and week-of-year and use LocalDate just as a workaround for this missing type, well, you can find such a type in 3rd-party libraries, either in Threeten-Extra or in my library Time4J. Example:
ChronoFormatter<CalendarWeek> cf =
ChronoFormatter.ofPattern(
"YYYYww",
PatternType.CLDR,
Locale.ROOT,
CalendarWeek.chronology()
);
CalendarWeek cw = cf.parse("201501");
System.out.println(cw); // 2015-W01
System.out.println(cw.at(Weekday.MONDAY)); // 2014-12-29
The (previous) duplicate works if there's a space between the values, however without a space the following parses nicely.
DateTimeFormatter dtf = new DateTimeFormatterBuilder()
.appendValue(ChronoField.YEAR, 4)
.appendValue(ChronoField.ALIGNED_WEEK_OF_YEAR, 2)
.parseDefaulting(WeekFields.SUNDAY_START.dayOfWeek(), 1)
.toFormatter();
System.out.println(LocalDate.parse("201710", dtf));
// 2017-03-05
Replacing the SUNDAY_START with ISO will give you weeks starting with mondays (so it will print 2017-03-06).
ThreeTen-Extra
The ThreeTen-Extra project adds functionality to the java.time classes.
YearWeek
This library offers the YearWeek class that may prove useful to you. This class uses the ISO 8601 standard definition of a week.
If possible, I suggest you change your own strings to use the standard format: yyyy-Www such as 2018-W07. The standard format is used by default in the YearWeek class for generating/parsing stings.
YearWeek yw = YearWeek.parse( "2018-W07" );
But if you insist on your own non-standard format, we must define our own DateTimeFormatter to match your input. I took one line of the YearWeek.parse method from the YearWeek.java source code, and modified to fit your case by disabling two method calls.
DateTimeFormatter f =
new DateTimeFormatterBuilder()
// .parseCaseInsensitive()
.appendValue( WEEK_BASED_YEAR , 4 , 10 , SignStyle.EXCEEDS_PAD )
// .appendLiteral("-W")
.appendValue( WEEK_OF_WEEK_BASED_YEAR , 2 )
.toFormatter();
Let’s try it.
YearWeek yw = YearWeek.parse( "201807" , f );
yw.toString(): 2018-W07
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.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
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.

Julian date to regular date conversion

How do i convert a julian date 2456606 which stands for Nov 18 2013 to the string format 18/11/2013 using java APIs? I tried executing the below code but it is not giving me the right answer. Any corrections to the below code are welcome
String j = "2456606";
Date date = new SimpleDateFormat("yyyyD").parse(j);
String g = new SimpleDateFormat("dd.MM.yyyy").format(date);
System.out.println(g);
tl;dr
LocalDate.MIN.with (
java.time.temporal.JulianFields.MODIFIED_JULIAN_DAY ,
2_456_606L
)
2013-11-09
Other direction, from modern date to Julian Day.
LocalDate.of( 2013 , 11 , 9 )
.getLong ( java.time.temporal.JulianFields.JULIAN_DAY )
2456606
Details
Firstly, your comment:
the julian date to be 2456606 for nov 18 in the converter link mentioned below aa.usno.navy.mil/data/docs/JulianDate.php
…is incorrect. That web site returns November 9, 2013 for 2456606.
Your Navy web site defines Julian Date as a count of days since January 1, 4713 BC mapped to “Universal Time”. I assume they mean UTC and the modern ISO 8601 calendar system. See Wikipedia.
The java.time classes built into Java make this easy.
long input = 2_456_606L;
LocalDate ld = LocalDate.MIN.with ( java.time.temporal.JulianFields.JULIAN_DAY , input );
Dump to console.
System.out.println ( "input: " + input + " is: " + ld );
input: 2456606 is: 2013-11-09
For more discussion, see my Answer on a duplicate Question.
Going the other direction, converting a modern date to a Julian Day.
long output = ld.getLong ( java.time.temporal.JulianFields.JULIAN_DAY );
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?
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 ThreeTenABP….
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.
The Julian date for Nov 18 2013 is "2013322". The number you used, "2456606", would be the 606th day of 2456, which is Aug 28, 2457.
You might also have intended to use a different date format than "yyyyD" for your input. See http://docs.oracle.com/javase/6/docs/api/java/text/SimpleDateFormat.html for information on possible codes.
Edit
The value that you used for the Julian date is the number of days since January 1, 4713 BCE. To get the Julian date using that system, you'll need to do something like the following:
String j = "2456606";
int day = Integer.parseInt(j) - x; // x == Jan 1, 1970 on the Gregorian
j = Integer.toString(day);
Date date = new SimpleDateFormat("D").parse(j);
String g = new SimpleDateFormat("dd.MM.yyyy").format(date);
System.out.println(g);
Where x is the Julian day corresponding to Jan 1, 1970 on the Gregorian calendar, i.e., the number of days elapsed between January 1, 4713 BCE and Jan 1, 1970.
If you have 7 digit julian date then you can use the following to convert it to Gergorian date.
The longJuliandate is your input and it'd return a String, which you can format for Date. You'd need to use "yyDDD" if you've 5 digit Julian date.
DateFormat dt = new SimpleDateFormat("yyyyDDD");
try
{
Date date = dt.parse(longJulianDate); //2018038
String str = new SimpleDateFormat("yyyyMMdd").format(date);
} catch (ParseException e) {}

Converting Julian date to Java date but still cannot get Month

I am trying to get day ,month and year from a Julian date.
String date = "13136";//Julian date
Date convertedDate = new SimpleDateFormat("yyDDD").parse(date);
System.out.println(convertedDate);
It prints
Thu May 16 00:00:00 BST 2013
which is correct.
Now I want to get Day , Month and Year from it
Calendar cal = Calendar.getInstance();
cal.setTime(convertedDate);
System.out.println(cal.get(Calendar.MONTH));
It prints 4 .
It should print 5 instead of 4 . Why is it not printing as correct ? What I have done wrong here?
As per the javadoc of Calendar.MONTH:
Field number for get and set indicating the month. This is a
calendar-specific value. The first month of the year in the Gregorian
and Julian calendars is JANUARY which is 0; the last depends on the
number of months in a year.
So months starts from zero so your output 4 is correct, for general usecase in your code it would be safe to add 1 to it unless you use this values as MONTH value in Calendar again.
As the javadocs state, months begin at zero: 0 = January, 1 = February, and so on.
tl;dr
LocalDate.parse (
"13136",
DateTimeFormatter.ofPattern ( "uuDDD" )
).getMonthValue()
5
…for month of May 2013.
Ordinal, not Julian
Your use of the word “Julian” is technically incorrect, though common. Folks seem to confuse day-of-year (1-365 or 1-366) with practice of counting the number of days elapsed since January 1, 4713 BC used in some scientific fields.
The terms “ordinal date” or day-of-year are more clear.
ISO 8601
Your format for ordinal dates is not standard. Whenever possible, use the standard ISO 8601 formats:
YYYY-DDD
YYYYDDD
java.time
The modern way is with the java.time classes that supplant the troublesome old legacy date-time classes.
DateTimeFormatter
Note that the formatting pattern codes in DateTimeFormatter class are similar to the legacy class but not exactly the some.
String input = "13136"; //Julian date
DateTimeFormatter f = DateTimeFormatter.ofPattern ( "uuDDD" );
LocalDate
The LocalDate class represents a date-only value without time-of-day and without time zone.
LocalDate localDate = LocalDate.parse ( input, f );
Dump to console.
System.out.println ("localDate: " + localDate );
localDate: 2013-05-16
Month
You can ask about the month of that LocalDate. The Month enum pre-defines a dozen objects, one for each month of the year. And unlike the crazy legacy classes, these are sanely numbered 1-12 for January-December.
If you are passing the month number around your code, I suggest you instead pass around these enum objects. Doing so gives you type-safety, valid values, and self-documenting code.
Month month = localDate.getMonth();
You can get the localized name of that month if needed.
String output = month.getDisplayName( TextStyle.FULL , Locale.CANADA_FRENCH ); // Or Locale.US, Locale.ITALY, whatever.
If you truly do need the number of the month 1-12, ask in either way.
int monthNumber = month.getValue() ;
int monthNumber = localDate.getMonthValue() ;
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?
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 ThreeTenABP….
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.

Calendar returns wrong month [duplicate]

This question already has answers here:
Why is January month 0 in Java Calendar?
(18 answers)
Closed 2 years ago.
Calendar rightNow = Calendar.getInstance();
String month = String.valueOf(rightNow.get(Calendar.MONTH));
After the execution of the above snippet, month gets a value of 10 instead of 11. How come?
Months are indexed from 0 not 1 so 10 is November and 11 will be December.
They start from 0 - check the docs
As is clear by the many answers: the month starts with 0.
Here's a tip: you should be using SimpleDateFormat to get the String-representation of the month:
Calendar rightNow = Calendar.getInstance();
java.text.SimpleDateFormat df1 = new java.text.SimpleDateFormat("MM");
java.text.SimpleDateFormat df2 = new java.text.SimpleDateFormat("MMM");
java.text.SimpleDateFormat df3 = new java.text.SimpleDateFormat("MMMM");
System.out.println(df1.format(rightNow.getTime()));
System.out.println(df2.format(rightNow.getTime()));
System.out.println(df3.format(rightNow.getTime()));
Output:
11
Nov
November
Note: the output may vary, it is Locale-specific.
As several people have pointed out, months returned by the Calendar and Date classes in Java are indexed from 0 instead of 1. So 0 is January, and the current month, November, is 10.
You might wonder why this is the case. The origins lie with the POSIX standard functions ctime, gmtime and localtime, which accept or return a time_t structure with the following fields (from man 3 ctime):
int tm_mday; /* day of month (1 - 31) */
int tm_mon; /* month of year (0 - 11) */
int tm_year; /* year - 1900 */
This API was copied pretty much exactly into the Java Date class in Java 1.0, and from there mostly intact into the Calendar class in Java 1.1. Sun fixed the most glaring problem when they introduced Calendar – the fact that the year 2001 in the Gregorian calendar was represented by the value 101 in their Date class. But I'm not sure why they didn't change the day and month values to at least both be consistent in their indexing, either from zero or one. This inconsistency and related confusion still exists in Java (and C) to this day.
Months start from zero, like indexes for lists.
Therefore Jan = 0, Feb = 1, etc.
From the API:
The first month of the year is JANUARY
which is 0; the last depends on the
number of months in a year.
http://java.sun.com/j2se/1.5.0/docs/api/java/util/Calendar.html
tl;dr
LocalDate.now() // Returns a date-only `LocalDate` object for the current month of the JVM’s current default time zone.
.getMonthValue() // Returns 1-12 for January-December.
Details
Other answers are correct but outdated.
The troublesome old date-time classes had many poor design choices and flaws. One was the zero-based counting of month numbers 0-11 rather than the obvious 1-12.
java.time
The java.time framework is built into Java 8 and later. These classes supplant the old troublesome date-time classes such as java.util.Date, .Calendar, & java.text.SimpleDateFormat.
Now in maintenance mode, the Joda-Time project also advises migration to java.time.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations.
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport and further adapted to Android in ThreeTenABP.
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time.
Months 1-12
In java.time the month number is indeed the expected 1-12 for January-December.
The LocalDate class represents a date-only value without time-of-day and without time zone.
Time zone
A time zone is crucial in determining a date. For any given moment, the date varies around the globe by zone. For example, a few minutes after midnight in Paris France is a new day while still “yesterday” in Montréal Québec.
Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).
LocalDate today = LocalDate.now( ZoneId.of( "America/Montreal" ) );
int month = today.getMonthValue(); // Returns 1-12 as values.
If you want a date-time for a time zone, use ZonedDateTime object in the same way.
ZonedDateTime now = ZonedDateTime.now( ZoneId.of( "America/Montreal" ) );
int month = now.getMonthValue(); // Returns 1-12 as values.
Convert legacy classes
If you have a GregorianCalendar object in hand, convert to ZonedDateTime using new toZonedDateTime method added to the old class. For more conversion info, see Convert java.util.Date to what “java.time” type?
ZonedDateTime zdt = myGregorianCalendar.toZonedDateTime();
int month = zdt.getMonthValue(); // Returns 1-12 as values.
Month enum
The java.time classes include the handy Month enum, by the way. Use instances of this class in your code rather than mere integers to make your code more self-documenting, provide type-safety, and ensure valid values.
Month month = today.getMonth(); // Returns an instant of `Month` rather than integer.
The Month enum offers useful methods such as generating a String with the localized name of the month.
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?
Java SE 8, Java 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 Java 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 ThreeTenABP….
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.
cal.get(Calendar.MONTH) + 1;
The above statement gives the exact number of the month. As get(Calendar.Month) returns month starting from 0, adding 1 to the result would give the correct output. And keep in mind to subtract 1 when setting the month.
cal.set(Calendar.MONTH, (8 - 1));
Or use the constant variables provided.
cal.set(Calendar.MONTH, Calendar.AUGUST);
It would be better to use
Calendar.JANUARY
which is zero ...

Categories

Resources