Understanding java.util.Calendar WEEK_OF_YEAR
I'm trying to understand how
java.util.Calendar.get(java.util.Calendar.WEEK_OF_YEAR) works, but it seems that I'm missing some points.
String time = "1998-12-31"; // year month day java.util.Calendar date = java.util.Calendar.getInstance(); date.setTime((new java.text.SimpleDateFormat("yyyy-MM-dd")).parse(time)); System.err.println("Week of year = " + date.get(java.util.Calendar.WEEK_OF_YEAR)); // Week of year = 1 Why ???
date.get(java.util.Calendar.WEEK_OF_YEAR) returns 1 for the last week of the year?
"1998-01-01" is 1 and for
"1998-12-23" it is 52.
Does anybody have an explanation for this behavior?
Calendar defines a locale-specific seven day week using two parameters: the first day of the week and the minimal days in first week (from 1 to 7). These numbers are taken from the locale resource data when a Calendar is constructed. They may also be specified explicitly through the methods for setting their values.
When setting or getting the WEEK_OF_MONTH or WEEK_OF_YEAR fields, Calendar must determine the first week of the month or year as a reference point. The first week of a month or year is defined as the earliest seven day period beginning on getFirstDayOfWeek() and containing at least getMinimalDaysInFirstWeek() days of that month or year. Weeks numbered ..., -1, 0 precede the first week; weeks numbered 2, 3,... follow it. Note that the normalized numbering returned by get() may be different. For example, a specific Calendar subclass may designate the week before week 1 of a year as week n of the previous year.
So it's locale-specific. In your case, if the week contains days from new year, it is counted as week 1 from the new year.
You can change this behavior by using Calendar#setMinimalDaysInFirstWeek(int).Автор: npe Размещён: 05.06.2012 08:02
java.time.LocalDate.parse( "1998-12-31" ) .get( IsoFields.WEEK_OF_WEEK_BASED_YEAR )
Or, add a library, and then…
org.threeten.extra.YearWeek.from( // Convert from a `LocalDate` object to a `YearWeek` object representing the entire week of that date’s week-based year. LocalDate.parse( "1998-12-31" ) // Parse string into a `LocalDate` objects. ).getWeek() // Extract an integer number of that week of week-based-year, either 1-52 or 1-53 depending on the year.
I'm trying to understand how java.util.Calendar.get(java.util.Calendar.WEEK_OF_YEAR) works
Don’t! That class is a bloody mess, and best left forgotten.
The answer by npe is correct. In
Calendar, the definition of a week varies by locale. A well-intentioned feature, but confusing.
Standard week definition
There are many ways to define “a week” and “first week of the year”.
the week with the year's first Thursday
A standard week begins with Monday and ends with Sunday.
Week # 1 of a standard week-based-year has the first Thursday of the calendar-year.
The java.time classes supplanted the troublesome legacy date-time classes. These modern classes support the ISO 8601 week through the
IsoFields class, holding three constants that implement
LocalDate::get to access the
LocalDate ld = LocalDate.parse( "1998-12-31" ) ; int weekOfWeekBasedYear = ld.get( IsoFields.WEEK_OF_WEEK_BASED_YEAR ) ; int yearOfWeekBasedYear = ld.get( IsoFields.WEEK_BASED_YEAR ) ;
Notice the day after, the first day of the new calendar year 1999, also is in the same week, week # 53 of week-based 1998.
LocalDate firstOf1999 = ld.plusDays( 1 ); int weekOfWeekBasedYear_FirstOf1999 = firstOf1999.get( IsoFields.WEEK_OF_WEEK_BASED_YEAR ) ; int yearOfWeekBasedYear_FirstOf1999 = firstOf1999.get( IsoFields.WEEK_BASED_YEAR ) ;
ISO 8601 string format
The ISO 8601 standard defines a textual format as well as a meaning for week-based-year values:
yyyy-Www. For a specific date, add day-of-week numbered 1-7 for Monday-Sunday:
Construct such a string.
String outputWeek = ld.format( DateTimeFormatter.ISO_WEEK_DATE ) ; // yyyy-Www
String outputDate = outputWeek + "-" + ld.getDayOfWeek().getValue() ; // yyyy-Www-d
YearWeek yw = YearWeek.from( ld ) ; // Determine ISO 8601 week of a `LocalDate`.
Generate the standard string.
String output = yw.toString() ;
YearWeek yearWeek = YearWeek.parse( "1998-W53" ) ;
Determine a date. Pass a
java.time.DayOfWeek enum object for day-of-week Monday-Sunday.
LocalDate localDate = yw.atDay( DayOfWeek.MONDAY ) ;
I strongly recommending adding this library to your project. Then you can pass around smart objects rather than dumb ints. Doing so makes your code more self-documenting, provides type-safety, and ensures valid values.
Where to obtain the java.time classes?
- Java SE 8, Java SE 9, 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
- Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
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
YearQuarter, and more.
The excellent Joda-Time framework uses ISO 8601 for its defaults. Its classes include this week-of-year information. Joda-Time is a popular replacement for the notoriously troublesome java.util.Date & java.util.Calendar classes bundled with Java.
Here is some example code to get first moment of the first day of the first week of the year of the current date-time.
Note the call to
withTimeAtStartOfDay to get the first moment of the day.
DateTimeZone timeZone = DateTimeZone.forID( "Europe/Paris" ); DateTime now = new DateTime( timeZone ); DateTime firstWeekStart = now.withWeekOfWeekyear(1).withDayOfWeek(1).withTimeAtStartOfDay(); DateTime firstWeekStop = firstWeekStart.plusWeeks( 1 ); Interval firstWeek = new Interval( firstWeekStart, firstWeekStop );
Dump to console…
System.out.println( "now: " + now ); System.out.println( "firstWeekStart: " + firstWeekStart ); System.out.println( "firstWeekStop: " + firstWeekStop ); System.out.println( "firstWeek: " + firstWeek );
Автор: Basil Bourque Размещён: 07.02.2014 11:57
now: 2014-02-07T12:49:33.623+01:00 firstWeekStart: 2013-12-30T00:00:00.000+01:00 firstWeekStop: 2014-01-06T00:00:00.000+01:00 firstWeek: 2013-12-30T00:00:00.000+01:00/2014-01-06T00:00:00.000+01:00