You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@arrow.apache.org by ko...@apache.org on 2026/10/20 11:51:23 UTC
(arrow) branch main updated: GH-54641: [C++] Support locale directives in the vendored strptime on Windows (#54656)
This is an automated email from the ASF dual-hosted git repository.
kou pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow.git
The following commit(s) were added to refs/heads/main by this push:
new a907fbc6461 GH-54641: [C++] Support locale directives in the vendored strptime on Windows (#54656)
a907fbc6461 is described below
commit a907fbc6461fe888c238c06db97edb16cef0d003
Author: Pearu Peterson <pe...@gmail.com>
AuthorDate: Tue Oct 20 14:51:15 2026 +0300
GH-54641: [C++] Support locale directives in the vendored strptime on Windows (#54656)
### Rationale for this change
On Windows, the vendored musl `strptime` does not handle `%a`, `%A`, `%b`, `%B`, `%h`, `%c`, `%p`, `%r`, `%x` and `%X`, because they need `nl_langinfo()`, which is not available there.
### What changes are included in this PR?
A C-locale replacement for `nl_langinfo()`, restricted to the items the vendored `strptime` uses, with the values of the POSIX locale.
### Are these changes tested?
Yes, `TimestampParser.StrptimeLocaleDirectives` covers each of these directives. On Windows it exercises the vendored `strptime`; elsewhere it runs against the system `strptime`.
### Are there any user-facing changes?
On Windows, `strptime` formats with these directives now parse.
### AI usage disclosure
Developed with AI assistance (Claude Code): the fix, the test and this description were AI-generated under my direction and reviewed line by line by me. I own and can debug these changes. No copyrighted material is included.
* GitHub Issue: #54641
Authored-by: Pearu Peterson <pe...@gmail.com>
Signed-off-by: Sutou Kouhei <ko...@clear-code.com>
---
cpp/src/arrow/util/value_parsing_test.cc | 32 ++++++++++++++++++++++++++++
cpp/src/arrow/vendored/musl/strptime.c | 19 +++++++++++++++++
r/tests/testthat/test-dplyr-funcs-datetime.R | 2 --
3 files changed, 51 insertions(+), 2 deletions(-)
diff --git a/cpp/src/arrow/util/value_parsing_test.cc b/cpp/src/arrow/util/value_parsing_test.cc
index b61f777685b..6eb387fc031 100644
--- a/cpp/src/arrow/util/value_parsing_test.cc
+++ b/cpp/src/arrow/util/value_parsing_test.cc
@@ -876,6 +876,38 @@ TEST(TimestampParser, StrptimeParser) {
}
}
+TEST(TimestampParser, StrptimeLocaleDirectives) {
+ // Directives that use the names and formats of the C locale
+ struct Case {
+ std::string format;
+ std::string value;
+ std::string iso8601;
+ };
+
+ std::vector<Case> cases = {
+ {"%a %d %b %Y", "Sun 15 Feb 2015", "2015-02-15 00:00:00"},
+ {"%A %d %B %Y", "Sunday 15 February 2015", "2015-02-15 00:00:00"},
+ {"%d %h %Y", "15 Feb 2015", "2015-02-15 00:00:00"},
+ {"%d-%b-%Y", "15-feb-2015", "2015-02-15 00:00:00"},
+ {"%c", "Sun Feb 15 14:30:00 2015", "2015-02-15 14:30:00"},
+ {"%m/%d/%Y %I:%M %p", "02/15/2015 02:30 PM", "2015-02-15 14:30:00"},
+ {"%Y-%m-%d %r", "2015-02-15 02:30:00 PM", "2015-02-15 14:30:00"},
+ {"%x", "02/15/15", "2015-02-15 00:00:00"},
+ {"%Y-%m-%d %X", "2015-02-15 14:30:00", "2015-02-15 14:30:00"},
+ };
+
+ for (const auto& case_ : cases) {
+ SCOPED_TRACE(case_.format);
+ auto parser = TimestampParser::MakeStrptime(case_.format);
+ int64_t converted, expected;
+ ASSERT_TRUE(
+ (*parser)(case_.value.c_str(), case_.value.size(), TimeUnit::SECOND, &converted));
+ ASSERT_TRUE(ParseTimestampISO8601(case_.iso8601.c_str(), case_.iso8601.size(),
+ TimeUnit::SECOND, &expected));
+ ASSERT_EQ(expected, converted);
+ }
+}
+
TEST(TimestampParser, StrptimeZoneOffset) {
if (!kStrptimeSupportsZone) {
GTEST_SKIP() << "strptime does not support %z on this platform";
diff --git a/cpp/src/arrow/vendored/musl/strptime.c b/cpp/src/arrow/vendored/musl/strptime.c
index 41912fd1bbf..eb325108b8a 100644
--- a/cpp/src/arrow/vendored/musl/strptime.c
+++ b/cpp/src/arrow/vendored/musl/strptime.c
@@ -23,6 +23,25 @@
#ifdef HAVE_LANGINFO
#include <langinfo.h>
+#else
+// C-locale replacement for nl_langinfo(), restricted to the items used below.
+// The values are those of the POSIX locale (LC_TIME in POSIX.1, chapter 7),
+// as in musl's own C locale (c_time in src/locale/langinfo.c), and in the
+// same order, which the symbolic_range loop relies on: full names directly
+// follow the abbreviated ones.
+enum { ABDAY_1 = 0, DAY_1 = 7, ABMON_1 = 14, MON_1 = 26, AM_STR = 38, PM_STR = 39,
+ D_T_FMT = 40, D_FMT = 41, T_FMT = 42, T_FMT_AMPM = 43 };
+static const char *arrow_c_langinfo[] = {
+ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
+ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday",
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
+ "January", "February", "March", "April", "May", "June",
+ "July", "August", "September", "October", "November", "December",
+ "AM", "PM",
+ "%a %b %e %T %Y", "%m/%d/%y", "%H:%M:%S", "%I:%M:%S %p"};
+#define nl_langinfo(x) arrow_c_langinfo[x]
+#define HAVE_LANGINFO 1
#endif
#define strptime arrow_strptime
diff --git a/r/tests/testthat/test-dplyr-funcs-datetime.R b/r/tests/testthat/test-dplyr-funcs-datetime.R
index db036bcdea1..2f99b6d7502 100644
--- a/r/tests/testthat/test-dplyr-funcs-datetime.R
+++ b/r/tests/testthat/test-dplyr-funcs-datetime.R
@@ -238,8 +238,6 @@ test_that("strptime works for individual formats", {
collect()
)
- # Some formats are not supported on Windows
- skip_on_os("windows")
expect_equal(
strptime_test_df |>
arrow_table() |>