Hello!

This is meant as a comment on JDK-8249280 (Date and Timestamp valueOf
wrong for BCE years) and/or JDK-8272194 (java.sql.Date::toLocalDate()
broken for dates before 1 A.D.) as I can't comment directly.

The direct consequence of the bug is that using big negative timestamps
it's possible to construct invalid java.sql.Date or java.sql.Timestamp
instances that throw when toLocalDate() or toLocalDateTime() is called
on them.

The following code:
```
var millis = -9223371997689600000L;
var timestamp = new Timestamp(millis);
var localDateTime = timestamp.toLocalDateTime(); // throws
```

throws
```
Exception in thread "main" java.time.DateTimeException:
        Invalid date 'February 29' as '292269053' is not a leap year
    at java.base/java.time.LocalDate.create(LocalDate.java:459)
    at java.base/java.time.LocalDate.of(LocalDate.java:273)
    at java.base/java.time.LocalDateTime.of(LocalDateTime.java:363)
    at java.sql/java.sql.Timestamp.toLocalDateTime(Timestamp.java:519)
    at [...]
```

Obviously `new java.sql.Date(millis).toLocalDate()` fails the same way,
and this happens for all timestamps for a day every 4 years, so fairly
often.


This makes the bug much worse than implied by their descriptions as
it's unintuitive to assume that `new Timestamp(any).toLocalDateTime()`
could ever throw. All the values are naively valid and possible. Is it
a good time to reevaluate the bugs' priority? Returning a bad value is
one thing, throwing is another.


The workaround is clear - just use Instant instead:
```
var instant = Instant.ofEpochMilli(millis);
var localDateTime = LocalDateTime.ofInstant(instant, utcOrDefaultZone);
```

I'm sure this never happens, but perhaps the old-timey Date/Timestamp
should be reimplemented using the new java.time types?


Thank you,
Petr Janeček

Reply via email to