Message-ID: From: "m-van-tilburg (@m-van-tilburg)" To: "pgjdbc/pgjdbc" Date: Mon, 13 Oct 2025 11:45:56 +0000 Subject: Re: [pgjdbc/pgjdbc] issue #3837: ResultSet.getTimestamp() returns incorrect point in time for historical dates In-Reply-To: References: List-Id: X-GitHub-Author-Login: m-van-tilburg X-GitHub-Comment-Id: 3397178571 X-GitHub-Comment-Type: issue_comment X-GitHub-Edited-At: 2025-12-05T18:11:30Z X-GitHub-Issue: 3837 X-GitHub-Repo: pgjdbc/pgjdbc X-GitHub-Type: comment X-GitHub-Url: https://github.com/pgjdbc/pgjdbc/issues/3837#issuecomment-3397178571 Content-Type: text/plain; charset=utf-8 > his issue seems unrelated to JDBC. I observed that `TIMESTAMP_LOCAL_1000_AD` is already incorrect. It also seems to be caused by JDK behavior. You are correct that the issue is not in the JDBC API itself, the created point in time in the test code is correct however. You can verify this by inputting the value of `TIMESTAMP_LOCAL_1000_AD.getTime()` into a website like https://www.epochconverter.com/. I suspect you came to your conclusion because you saw the the result of `Timestamp.toString()` in your debugger, which will interpret this (historic) point in time using the Julian calendar. `java.util.Date` and `java.sql.Timestamp` store points in time just like `java.time.Instant`, the important part is how these points in time are parsed/formatted from/to actual calendar dates. The following additional code using the legacy `java.util.Calendar` class demonstrates this: ``` @Test void legacyCalendarExamples() { // NOTE: it may appear this creates a (proleptic) Gregorian calendar but for historic dates it is Julian! GregorianCalendar calGregorianJulianHybrid = new GregorianCalendar(); calGregorianJulianHybrid.setTime(TIMESTAMP_LOCAL_1000_AD); System.out.println("Julian calendar date and time: " + formatCalendar(calGregorianJulianHybrid)); GregorianCalendar calProlepticGregorian = new GregorianCalendar(); // This will make the calendar pure (proleptic) Gregorian calProlepticGregorian.setGregorianChange(new Date(Long.MIN_VALUE)); calProlepticGregorian.setTime(TIMESTAMP_LOCAL_1000_AD); System.out.println("(proleptic) Gregorian calendar date and time: " + formatCalendar(calProlepticGregorian)); } private String formatCalendar(Calendar cal) { // NOTE: Calendar.MONTH is zero based return cal.get(Calendar.YEAR) + "-" + (cal.get(Calendar.MONTH) + 1) + "-" + cal.get(Calendar.DAY_OF_MONTH) + "T" + cal.get(Calendar.HOUR_OF_DAY) + ":" + cal.get(Calendar.MINUTE) + ":" + cal.get(Calendar.SECOND); } ``` On my system with time zone set to "Europe/Amsterdam" this produces the following result: Julian calendar date and time: 999-12-27T0:42:30 (proleptic) Gregorian calendar date and time: 1000-1-1T0:42:30 Note that although `java.util.GregorianCalendar` by default uses the system default time zone the results are not always identical to when `java.time.ZonedDateTime` with the system default time zone is used. The reason for this is that the time zone rule handling for historical dates can be different between `java.util.TimeZone` and `java.time`.