This is an automated email from the ASF dual-hosted git repository.
lidavidm pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-adbc.git
The following commit(s) were added to refs/heads/main by this push:
new c711561fe9 fix(c/driver/sqlite): format extreme time/date values
properly (#4841)
c711561fe9 is described below
commit c711561fe929d9426249176761805306183af3a5
Author: David Li <[email protected]>
AuthorDate: Wed Sep 30 16:14:23 2026 -0700
fix(c/driver/sqlite): format extreme time/date values properly (#4841)
This is already tested by/discovered via the validation suite.
Generated-by: GPT-6 Astra
---
c/driver/sqlite/statement_reader.c | 30 ++++++++++++++++++++----------
1 file changed, 20 insertions(+), 10 deletions(-)
diff --git a/c/driver/sqlite/statement_reader.c
b/c/driver/sqlite/statement_reader.c
index 7c2cae682c..96bcbae96b 100644
--- a/c/driver/sqlite/statement_reader.c
+++ b/c/driver/sqlite/statement_reader.c
@@ -143,7 +143,7 @@ static AdbcStatusCode ArrowDate32ToIsoString(int32_t value,
char** buf,
}
time_t time = (time_t)(value * SECONDS_PER_DAY);
#else
- time_t time = value * SECONDS_PER_DAY;
+ time_t time = (int64_t)value * SECONDS_PER_DAY;
#endif
struct tm broken_down_time;
@@ -169,9 +169,14 @@ static AdbcStatusCode ArrowDate32ToIsoString(int32_t
value, char** buf,
return ADBC_STATUS_IO;
}
- if (strftime(tsstr, strlen + 1, "%Y-%m-%d", &broken_down_time) == 0) {
- InternalAdbcSetError(error, "Call to strftime for date %" PRId32 " with
failed",
- value);
+ // Whether %Y pads years < 1000 is platform dependent
+ // https://github.com/python/cpython/issues/120713
+ // Specifiers like %04Y are not portable; format manually instead
+ int written = snprintf(tsstr, strlen + 1, "%04" PRId64 "-%02d-%02d",
+ (int64_t)broken_down_time.tm_year + 1900,
+ broken_down_time.tm_mon + 1,
broken_down_time.tm_mday);
+ if (written != strlen) {
+ InternalAdbcSetError(error, "Could not format date %" PRId32, value);
free(tsstr);
return ADBC_STATUS_INVALID_ARGUMENT;
}
@@ -207,14 +212,14 @@ static AdbcStatusCode ArrowTimestampToIsoString(int64_t
value, enum ArrowTimeUni
break;
}
+ int64_t seconds = value / scale;
rem = value % scale;
if (rem < 0) {
- value -= scale;
+ // Floor the quotient without subtracting from a possibly INT64_MIN value.
+ seconds--;
rem = scale + rem;
}
- const int64_t seconds = value / scale;
-
#if SIZEOF_TIME_T < 8
if ((seconds > INT32_MAX) || (seconds < INT32_MIN)) {
InternalAdbcSetError(
@@ -253,9 +258,14 @@ static AdbcStatusCode ArrowTimestampToIsoString(int64_t
value, enum ArrowTimeUni
return ADBC_STATUS_IO;
}
- if (strftime(tsstr, strlen, "%Y-%m-%dT%H:%M:%S", &broken_down_time) == 0) {
- InternalAdbcSetError(error,
- "Call to strftime for timestamp %" PRId64 " with unit
%d failed",
+ // %Y does not consistently pad early years across platforms (see above)
+ int written =
+ snprintf(tsstr, strlen + 1, "%04" PRId64 "-%02d-%02dT%02d:%02d:%02d",
+ (int64_t)broken_down_time.tm_year + 1900,
broken_down_time.tm_mon + 1,
+ broken_down_time.tm_mday, broken_down_time.tm_hour,
+ broken_down_time.tm_min, broken_down_time.tm_sec);
+ if (written != 19) {
+ InternalAdbcSetError(error, "Could not format timestamp %" PRId64 " with
unit %d",
value, unit);
free(tsstr);
return ADBC_STATUS_INVALID_ARGUMENT;