> Also covers: [8249280](https://bugs.openjdk.org/browse/JDK-8249280)
> 
> I will first give a quick summary of the problem.
> Put simply, the `LocalDate` form of the `java.sql.Date` is derived using the 
> `getYear` method of `java.util.Date`. This in turn returns the year of the 
> normalised internal calendar.
> However, the internal calendar `getYear` has an extra layer of complexity.
> The calendar has an additional era field, which captures BC/AD.
> `getYear` therefore just returns the year _of that era_.
> For example, the year 6BC and the year 6AD both return `getYear` as 6.
> 
> **This means that for BC dates, our `LocalDate` conversion loses the sign of 
> the year.**
> 
> This leads to additional problems down the line, as the year 1BC is for 
> calculations sake is considered to be year 0 (and 2BC us considered year -1 
> and so on). As a result, the various leap year calculations are WRONG for 
> these years, causing year format validation failures in situations like 
> marshalling/unmarshalling the dates with a DB.
> 
> There are two seemingly obvious fixes here, however I will attempt to explain 
> why I did not proceed with them.
> 
> Firstly, it seems sensible is to derive the `LocalDate` from an `Instant` 
> created from the millisecond representation of the `Date`. After all, why we 
> are having to use the deprecated `getYear`, `getMonth` and `getDay` methods 
> anyway?
> The answer lies in [8061577](https://bugs.openjdk.org/browse/JDK-8061577).
> The underlying millisecond representation between `java.time.Instant` and 
> `java.util.Date` is fundamentally different. Read that ticket for a greater 
> explanation.
> Ultimately though, it means that the for older dates, the only real way to 
> bridge between the two calendar systems is to use these year/month/day 
> methods.
> 
> This is where the second possible solution appears.
> The underlying calendar representation that `java.util.Date` uses actually 
> does have a year method which gives you the correctly signed year, that being 
> `getNormalizedYear`.
> In fact, `java.util.Date` uses the setter counterpart `setNormalizedYear` is 
> its `setYear` method.
> Given this, it seems natural that `getYear` should similarly call 
> `getNormalizedYear`.
> I think this would be my ideal solution, however I recognise that `get`Year 
> only returning a positive year is very long standing behaviour. Given how 
> widely spread `java.util.Date` is, I felt it was perhaps better not to rock 
> the boat too much.
> 
> I have therefore taken the decision to add an equivalent `getNormalizedYear` 
> method to `java.util.Da...

Sholto has updated the pull request incrementally with one additional commit 
since the last revision:

  8272194: remove added getNormalizedYear from Date and derive 
LocalDate/LocalDateTime from calendar
  
  It was decided that adding a new protected method to java.util.Date isn’t the 
safest thing to do as it is a widely extended class. The new method could 
unintentionally break the java.time conversion for these classes.
  
  The conversion still cannot by using Instant due to the difference between 
the milli representations as stated in 8061577.
  
  Therefore, constructing a new GregorianCalendar is the next best way to get 
the correct year/month/day values.

-------------

Changes:
  - all: https://git.openjdk.org/jdk/pull/31808/files
  - new: https://git.openjdk.org/jdk/pull/31808/files/ac5f59de..97c5704d

Webrevs:
 - full: https://webrevs.openjdk.org/?repo=jdk&pr=31808&range=01
 - incr: https://webrevs.openjdk.org/?repo=jdk&pr=31808&range=00-01

  Stats: 52 lines in 3 files changed: 30 ins; 14 del; 8 mod
  Patch: https://git.openjdk.org/jdk/pull/31808.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/31808/head:pull/31808

PR: https://git.openjdk.org/jdk/pull/31808

Reply via email to