简体   繁体   中英

Java Calendar WEEK_OF_YEAR not ISO-8601compliant?

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?

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 technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM