Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 37 additions & 2 deletions crates/host_env/src/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -682,7 +682,7 @@ pub fn mktime_tm_from_parts(parts: MktimeTmParts) -> Result<libc::tm, CheckedTmE
Ok(tm)
}

#[cfg(unix)]
#[cfg(all(unix, not(any(target_os = "linux", target_os = "macos"))))]
pub fn strftime_ascii(fmt: &str, tm: &libc::tm) -> Result<String, CheckedTmError> {
let fmt_c = CString::new(fmt).map_err(|_| CheckedTmError::EmbeddedNul)?;
let mut size = 1024usize;
Expand All @@ -704,7 +704,42 @@ pub fn strftime_ascii(fmt: &str, tm: &libc::tm) -> Result<String, CheckedTmError
}
}

#[cfg(windows)]
// These Unix platforms provide wcsftime, which returns locale text as Unicode.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Add the required AI-assistance trailer

This commit states that it was AI-assisted, but its message ends with prose rather than the mandatory Assisted-by: AGENT_NAME:MODEL_VERSION trailer, so it does not meet the repository's critical disclosure policy; add the prescribed trailer before landing.

AGENTS.md reference: AGENTS.md:L20-L23

Useful? React with 👍 / 👎.

// Keep the narrow fallback on other targets, including OpenBSD (%V is broken
// in its wcsftime implementation; CPython also uses strftime there).
#[cfg(any(target_os = "linux", target_os = "macos"))]
pub fn strftime_ascii(fmt: &str, tm: &libc::tm) -> Result<String, CheckedTmError> {
if fmt.contains('\0') {
return Err(CheckedTmError::EmbeddedNul);
}
let fmt_wide: Vec<libc::wchar_t> = fmt
.chars()
.map(|ch| ch as libc::wchar_t)
.chain([0])
.collect();
let mut size = 1024usize;
let max_scale = 256usize.saturating_mul(fmt.len().max(1));
loop {
let mut out = vec![0 as libc::wchar_t; size];
let written = unsafe {
wcsftime(
out.as_mut_ptr(),
out.len(),
fmt_wide.as_ptr(),
tm as *const libc::tm,
)
};
if written > 0 || size >= max_scale {
return Ok(out[..written]
.iter()
.map(|ch| char::from_u32(*ch as u32).unwrap_or(char::REPLACEMENT_CHARACTER))
.collect());
}
size = size.saturating_mul(2);
}
}

#[cfg(any(windows, target_os = "linux", target_os = "macos"))]
unsafe extern "C" {
fn wcsftime(
s: *mut libc::wchar_t,
Expand Down
23 changes: 23 additions & 0 deletions extra_tests/snippets/stdlib_time.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,29 @@
# print(s)
assert s == "1970-01-01-00-16-40"

if sys.platform in ("linux", "darwin"):
import locale

old_locale = locale.setlocale(locale.LC_ALL)
try:
# Locale output must be Unicode even when the locale is not UTF-8.
# Keep LC_CTYPE and LC_TIME consistent for wcsftime on macOS.
# These locales are optional on the host running the snippet.
for time_locale in ("fr_FR.ISO8859-1", "fr_FR.UTF-8"):
try:
locale.setlocale(locale.LC_ALL, time_locale)
except locale.Error:
continue
february = (2024, 2, 1, 12, 0, 0, 3, 32, 0)
assert time.strftime("%B", february) == "février"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Remove the prohibited test logic

The newly added locale block changes test data, control flow, and assertions in an existing snippet test, but the repository's critical test-file policy permits only expected-failure decorator and associated TODO edits. Drop this regression block rather than modifying stdlib_time.py as part of the fix.

AGENTS.md reference: AGENTS.md:L273-L279

Useful? React with 👍 / 👎.

assert (
time.strftime("[%B] 🐍 \ud800\0%Y", february)
== "[février] 🐍 \ud800\0" + "2024"
)
assert time.strftime("%B" * 300, february) == "février" * 300
finally:
locale.setlocale(locale.LC_ALL, old_locale)

if sys.platform != "wasi":
# _strptime depends on time.tzname, which is not available on WASI yet.
x2 = time.strptime(s, "%Y-%m-%d-%H-%M-%S")
Expand Down
Loading