Date32 getDateDay silently loses precision for dates outside ~1685-2255
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Newbie friendliness
- 50/100
- Issue type
- Bug
- Clarity
- Mostly clear
- Activity status
- Quiet
- Tech stack
- javascript
- Domain
- data
Research direction
Start in visitor/get.mjs by reading epochDaysToMs and getDateDay, then compare their behavior with visitInt32. Confirm how the getter currently represents Date32 values and determine whether returning raw int32 day counts preserves the intended range; done means the precision loss is eliminated without leaving the breaking-change behavior unresolved.
Written by the indexing model from the issue text.
Description
Summary
getDateDay converts int32 day values to epoch milliseconds via 86400000 * data[index]. This overflows Number.MAX_SAFE_INTEGER for dates far from epoch, silently returning incorrect values.
Root cause
In visitor/get.mjs:
const epochDaysToMs = (data, index) => 86400000 * data[index];
const getDateDay = ({ values }, index) => epochDaysToMs(values, index);
Date32 stores days as int32, supporting a range of ±2^31 days (~5.8 million years in each direction). But 86400000 * 2147483647 = 1.855e17, which exceeds Number.MAX_SAFE_INTEGER (9.007e15).
The precision boundary is Math.floor(Number.MAX_SAFE_INTEGER / 86400000) = 104,249,991 days ≈ ±285,420 years from epoch. Dates outside roughly 283,400 BC – 287,400 AD silently return incorrect millisecond values due to floating-point precision loss.
Impact
Unlike the timestamp overflow (which throws — see #421), this silently returns wrong data. DuckDB's DATE type supports dates from 5,877,642 BC to 5,881,580 AD. DuckDB's test_all_types() produces min/max dates well outside the safe conversion range. Consumers displaying these dates get subtly wrong output with no error.
Additionally, DuckDB uses date infinity sentinels (INT32_MAX and -INT32_MAX) which also overflow when multiplied by 86400000.
Proposal
Return the raw int32 day count instead of converting to milliseconds:
const getDateDay = ({ values }, index) => values[index];
This is lossless, never overflows, and consistent with how visitInt32 already returns the raw value. Callers that want a JS Date can convert explicitly:
new Date(days * 86400000) // fine for dates within ±285k years
As with #421, this is a breaking change for code that expects get() to return epoch milliseconds. The same resolution options apply (major version bump, opt-in flag, etc.).
Context
We hit this building a DuckDB WASM frontend that renders test_all_types(). Our workaround reads raw int32 values from the underlying Int32Array:
if (typeStr.includes("Date32")) {
const chunk = column.data?.[0] ?? column.data;
if (chunk?.values instanceof Int32Array) {
return chunk.values[row - (chunk.offset ?? 0)]; // raw days
}
}
This bypasses Arrow's getter entirely. We then format using Howard Hinnant's civil calendar algorithm, which handles the full int32 day range correctly with pure arithmetic.
- Dominant language
- TypeScript
- Stars
- 112
- Forks
- 23
- Avg merge
- 17h 55m
- Merged PRs (30d)
- 10
Getting set up
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from apache/arrow-js
-
Difficulty 3/5 1-2 days Newbie friendliness 68/100
apache/arrow-js#484 · 1 comment · 1 reaction ·
Maintainers usually reply within 1 day
-
Difficulty 3/5 1-2 days Newbie friendliness 55/100
apache/arrow-js#468 · 2 comments ·
Maintainers usually reply within 1 day
-
Difficulty 3/5 1-2 days Newbie friendliness 35/100
Maintainers usually reply within 1 day
-
Difficulty 5/5 Over a week Newbie friendliness 35/100
apache/arrow-js#423 · 1 reaction ·
Maintainers usually reply within 1 day
-
Difficulty 5/5 Over a week Newbie friendliness 35/100
apache/arrow-js#421 · 1 reaction ·
Maintainers usually reply within 1 day
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
opengovsg/FormSG#10118 · 1 comment ·
Maintainers usually reply within 1 day
-
ai-driven-qa bug claude
Difficulty 1/5 Under an hour Newbie friendliness 75/100
linagora/twake-calendar-frontend#1434 · 1 comment ·
Maintainers usually reply within 1 day
-
check:passed streams:add
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
iptv-org/iptv#52824 · 2 comments ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 Half a day Newbie friendliness 78/100
jaegertracing/jaeger-ui#4512 ·
Maintainers usually reply within 1 day
-
area:ide documentation enhancement platform:macos platform:vscode
Difficulty 1/5 1-3 hours Newbie friendliness 88/100
anthropics/claude-code#97389 ·
Maintainers usually reply within 1 day