16

These are the two fields in the package java.time.temporal:

IsoFields.WEEK_BASED_YEAR

WeekFields.ISO.weekBasedYear()

ISO-8601 defines a so-called week date besides the other two kinds of date, namely the usual calendar date (consisting of year, month and day-of-month) and the ordinal date (consisting of year and day-of-year). A weekdate is defined in the format YYYY-'W'ww-e. w stands for the week-of-year, e for the numerical ISO-day-of-week. Y stands for the week-based-year and is identical to calendar year with the exception at the begin or end of calendar year, because a week-based-year is bound to the week cycle which can eventually start in the previous year. Two rules are important to understand how a week date is formed:

  1. Weeks always start at Monday.
  2. The first week of a calendar year is the week which contains at least four days.

At first glance both JSR-310-fields appear to be identical because ISO-8601 only mentions one kind of week-based-year. But wait, surprise. Let's consider following code example:

LocalDate date1 = 
  LocalDate.of(2000, 2, 29).with(IsoFields.WEEK_BASED_YEAR, 2014);
System.out.println("IsoFields-Test: " + date1); // output: 2014-03-01

LocalDate date2 = 
  LocalDate.of(2000, 2, 29).with(WeekFields.ISO.weekBasedYear(), 2014);
System.out.println("WeekFields-Test: " + date2); // output: 2014-02-25

While I very well understand the second variation I am really astonished to see the different result for first date which is using the "official" ISO-8601-reference in its classname. To explain the calculated results:

The date 2000-02-29 corresponds to 2000-W09-2 in ISO-weekdate-notation while 2014-02-25 corresponds to 2014-W09-2 preserving the week-of-year and the day-of-week. So far so fine. This preserving characteristics for smaller fields is similar to the rule how to change the calendar year (which should in most cases keep the month and day-of-month in a calendar date unchanged).

But what is about the result 2014-03-01? Here the algorithm has simply added four days to the corresponding week-date in order to take in account the difference in the field "day-of-month" (29 versus 25). I have not found any source or official documentation for this behaviour. Does anybody know where we can find the justification for the difference between these two fields? Any documentation available about the algorithmic behaviour?

UPDATE:

Now I tried to test the self-consistency of the new API with this expression in order to find out which of the two fields is better supported:

System.out.println(
  "14 week-based-years later = "
  + LocalDate.of(2000, 2, 29).plus(14, IsoFields.WEEK_BASED_YEARS));

The output is 2014-03-01 similar to the described case of IsoFields.WEEK_BASED_YEAR, although I still find the result 2014-02-25 (=2014-W09-2) much more logical. Since this temporal unit is also found in the class IsoFields so far the behaviour is self-consistent within the class IsoFields. Looks like an undocumented and non-intuitive "feature".

I am using the version: java.runtime.version=1.8.0-b132

More testing:

LocalDate d = LocalDate.of(2014, 3, 1); // 2014-W09-6
System.out.println(
  "week-of-year in 2014-03-01: " 
  + d.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR));
System.out.println(
  "day-of-week in 2014-03-01: " 
  + d.get(ChronoField.DAY_OF_WEEK));

LocalDate later = d.plus(14, IsoFields.WEEK_BASED_YEARS); // 2028-03-02 = 2028-W09-4
System.out.println(
  "14 week-based-years later = " 
  + later);
System.out.println(
  "week-of-year in " + later + ": " 
  + later.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR));
System.out.println(
  "day-of-week in " + later + ": " 
  + later.get(ChronoField.DAY_OF_WEEK));

Output:

week-of-year in 2014-03-01: 9
day-of-week in 2014-03-01: 6
14 week-based-years later = 2028-03-02
week-of-year in 2028-03-02: 9
day-of-week in 2028-03-02: 4

I do not recognize any clear rule. Neither the day-of-week is preserved nor the day-of-month is preserved while adding 14 week-based-years. So this is an extra question: What is the rule behind IsoFields.WEEK_BASED_YEARS? Maybe JSR-310-team can enlighten us?

JodaStephen
  • 60,927
  • 15
  • 95
  • 117
Meno Hochschild
  • 42,708
  • 7
  • 104
  • 126
  • If you found a bug I suggest you submit a bug report. – assylias Apr 05 '14 at 08:31
  • @assylias thanks for hint, about the rule for week-based-years-unit it seems to be a bug, for the first question I am not so sure if JSR-310-team qualifies it as bug or as feature. – Meno Hochschild Apr 05 '14 at 09:19
  • 2014-W09-6 + 14 week years should produce 2028-W09-6, anything else is a bug! You wouldn't accept 2014-03-01 + 14 calendar years to produce anything but 2028-03-01, would you? – chansen Apr 07 '14 at 09:07
  • @chansen I share your view regarding my second question. – Meno Hochschild Apr 07 '14 at 09:11

1 Answers1

9

This is a bug in IsoFields which managed to slip through because this method was untested (sorry about that). There should be very little observable difference between IsoFields and WeekFields.ISO when implemented correctly.

See the bug report and patch which will eventually work through the system and be fixed.

Note, testing revealed that getting the field is fine, the bug only affected the with/adjustInto method of WEEK_BASED_YEAR. The unit WEEK_BASED_YEARS is affected because the addition is implemented internally by reusing the broken WEEK_BASED_YEAR.

Update 2014-08-28: This was one of 14 java.time bugs fixed in 8u20.

JodaStephen
  • 60,927
  • 15
  • 95
  • 117
  • 2
    Thanks for clarification. One question left: What exactly do you mean by saying "very little observable difference"? Should there be a difference at all? I am still wondering why there are two classes where `IsoFields` (the week-related fields in class `IsoFields`) could just be seen as specialized week-fields for the ISO-case of the class `WeekFields`. – Meno Hochschild Apr 12 '14 at 19:55
  • 1
    One could argue that there should not be two implementations at all, but we have them now and they cannot be removed. The only observable difference was that WeekFields operates on all calendar systems (by converting to ISO) whereas IsoFields only operates on ISO (and rejects other calendar systems). – JodaStephen Apr 14 '14 at 08:54
  • 1
    Right, I have not thought of the general calendar-system-support in `WeekFields`. Well, the french revolutionary calendar with its 10-day-week is surely not supported, but upvoted your enlightening answer. – Meno Hochschild Apr 14 '14 at 16:34
  • is it really so that these kind of things won't be fixed in java 8 at all, but have to wait until java 9? – eis Apr 28 '14 at 11:25
  • I would imagine that this will be backported to 8, but it is not under my control – JodaStephen Apr 28 '14 at 11:39