Skip to content

fix(jdbc): read date and time getters by SQLite storage class - #136

Merged
magnusp merged 1 commit into
mainfrom
fix/i102-datetime-storage-class
Oct 22, 2026
Merged

magnusp merged 1 commit into
mainfrom
fix/i102-datetime-storage-class

Conversation

@magnusp

@magnusp magnusp commented Oct 22, 2026

Copy link
Copy Markdown
Owner

Fixes #102

Contract: Hrana 3 carries only INTEGER, FLOAT, TEXT, and BLOB, so date/time meaning is a local SQLite convention; java.sql defines the getter surface; sqlite-jdbc is the behavioral reference, not the contract.

Base: 168f69aff4cebe175699bf5b421decf6a49c3b09
Head: fb993bd06de73bef417193faa803949cd24fe8e8

What changed

getDate, getTime, and getTimestamp now switch on the Value storage class instead of parsing getString():

  • INTEGER: milliseconds since the Unix epoch.
  • FLOAT: Julian day.
  • TEXT: SQLite date/time formats, including yyyy-MM-dd HH:mm:ss.SSS, bare dates, bare times, optional fractional digits, and an optional time-zone suffix.
  • BLOB: Bad value for type <target>; NULL: null.

LocalDate, LocalTime, and LocalDateTime are built from the same storage-class result, so getObject(column, X.class) agrees with the corresponding java.sql getter. The #69 conversion table now documents these SQLite conventions instead of text parsing.

Evidence

  • Red: ./mvnw -pl libsql-jdbc test -Dtest=LibsqlResultSetTest at base + new tests -> 3 failures, all new cases (/tmp/xerial-parity-i102/lane-1-regression.log).
  • Green: same command at head -> 24 tests, 0 failures; with LibsqlResultSetGetObjectTest -> 43 tests, 0 failures (/tmp/xerial-parity-i102/green-unit.log).
  • Lane 2 exact inputs: TEXT 2024-01-02 10:00:00 and INTEGER 1700000000000 pass (lane-2-specific.log); xerial reference probe output recorded in reference-probe.log (TEXT -> 2024-01-02; INTEGER -> 2023-11-14 in Europe/Stockholm).
  • Lane 3: all valid datetime cases assert non-null across all six targets (lane-3-specific.log).
  • Lane 4 full module: BUILD SUCCESS, 238 tests (lane-4-module-suite.log).
  • Lane 5 conformance: BUILD SUCCESS, 123 tests, 1 pre-existing skip, no new divergence (lane-5-conformance.log).
  • Lane 6 xerial control: BUILD SUCCESS, 100 tests, 1 pre-existing skip (lane-6-control.log).
  • Lane 7 spotless:check: BUILD SUCCESS (lane-7-spotless.log).
  • Lane 8 full reactor: BUILD SUCCESS (lane-8-reactor.log).
  • Lane 9 LibsqlResultSet*: 116 tests, 0 failures (lane-9-specific.log).
  • Lane 10 package: BUILD SUCCESS (lane-10-package.log).
  • Perf: ./mvnw -pl libsql-jdbc test 3x interleaved. Trunk median 2.12 s, head median 2.15 s, +1.4% (within 10%).

Divergences

  • INTEGER is epoch milliseconds, not SQLite unixepoch seconds. sqlite-jdbc's default date_precision is MILLISECONDS, and the issue's 1700000000000 case requires it.
  • REAL Julian days convert as a UTC instant and are then rendered in the JVM default zone. xerial decomposes the Julian day into local calendar fields; SQLite Julian days are UTC-based, and no conformance test asserts REAL.
  • Bare-time TEXT uses SQLite's 2000-01-01 default date, so getDate/LocalDate return that date where xerial throws. This follows SQLite's time-value rule.
  • BLOB date/time targets throw Bad value instead of xerial's numeric fallback; BLOB is not a SQLite datetime storage class.
  • getTime returns a time-of-day, so Time does not carry the source date as xerial's TEXT path does. JDBC defines getTime as the time component.

INTEGER is epoch milliseconds, FLOAT is a Julian day, and TEXT uses SQLite date and time formats. All java.sql and java.time targets now share the same storage-class conversion, and the #69 conversion table documents the SQLite conventions.
@magnusp
magnusp merged commit aad9c7e into main Oct 22, 2026
5 checks passed
@magnusp
magnusp deleted the fix/i102-datetime-storage-class branch October 22, 2026 23:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

getDate, getTime, getTimestamp, and the java.time getObject targets do not follow SQLite storage classes

1 participant