can1357/oh-my-pi · error · io::Error
dates before 1970 are unsupported
Error message
dates before 1970 are unsupported
What it means
The fd builtin's date parser converts a parsed civil date/time into a SystemTime by computing seconds since the UNIX epoch. If the computed seconds value is negative (i.e., the parsed timestamp predates 1970-01-01T00:00:00Z), the conversion cannot produce a valid epoch-based SystemTime, so an InvalidInput io::Error with this message is returned.
Source
Thrown at crates/pi-builtins/src/fd.rs:1406
let hour = parse_u32_part(time_parts.next(), "hour")?;
let minute = parse_u32_part(time_parts.next(), "minute")?;
let second = parse_u32_part(time_parts.next(), "second")?;
if time_parts.next().is_some()
|| !(1..=12).contains(&month)
|| !(1..=31).contains(&day)
|| hour > 23
|| minute > 59
|| second > 59
{
return Err(io::Error::new(io::ErrorKind::InvalidInput, format!("invalid date: {value}")));
}
let days = days_from_civil(year, month, day);
let seconds = days
.checked_mul(86_400)
.and_then(|base| base.checked_add(i64::from(hour * 3_600 + minute * 60 + second)))
.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "date is out of range"))?;
if seconds < 0 {
return Err(io::Error::new(io::ErrorKind::InvalidInput, "dates before 1970 are unsupported"));
}
Ok(UNIX_EPOCH + Duration::from_secs(u64::try_from(seconds).unwrap_or(u64::MAX)))
}
fn parse_i32_part(value: Option<&str>, name: &str) -> io::Result<i32> {
value
.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, format!("missing {name}")))?
.parse::<i32>()
.map_err(|err| io::Error::new(io::ErrorKind::InvalidInput, err.to_string()))
}
fn parse_u32_part(value: Option<&str>, name: &str) -> io::Result<u32> {
value
.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, format!("missing {name}")))?
.parse::<u32>()
.map_err(|err| io::Error::new(io::ErrorKind::InvalidInput, err.to_string()))
}
View on GitHub (pinned to 9690622007)
Solutions
- Use a date on or after 1970-01-01T00:00:00 in the date argument
- If you need pre-epoch filtering, implement the comparison outside the builtin using file metadata directly
- Double-check the date string for typos (year digits swapped or truncated)
Example fix
// before fd --newer '1969-12-31 23:59' . // after fd --newer '1970-01-01 00:00' .
Defensive patterns
Strategy: validation
Validate before calling
fn validate_epoch_date(date: &str) -> Result<(), String> {
// crude pre-check: reject years before 1970 before invoking the builtin
let year: i32 = date.split('-').next().unwrap_or("").parse().map_err(|_| "bad year")?;
if year < 1970 {
return Err(format!("year {year} is before 1970; unsupported"));
}
Ok(())
} Try / catch
match builtin_result {
Err(e) if e.to_string().contains("dates before 1970") => eprintln!("adjust date to >= 1970: {e}"),
Err(e) => return Err(e),
Ok(v) => /* ... */,
} Prevention
- Always generate date filter arguments from date/time formatters constrained to >= 1970
- Validate user-supplied date strings with a parser before passing them to the builtin
- Watch for typos in years (4-digit sanity check)
When it happens
Trigger: Calling the in-process fd builtin with a date filter (e.g. --newer or similar timestamp option) whose parsed year/month/day/hour/minute/second components resolve to a timestamp before the UNIX epoch, such as '1969-12-31' or an explicitly negative date string.
Common situations: Users referencing archival files with pre-1970 timestamps; scripts that pass '--newer 1970-01-01' minus one second; locales or fixtures containing historic dates; a typo like '1697' instead of '1997' in a date argument.
Related errors
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/8ab4e23def0f1081.
Report an issue: GitHub.