can1357/oh-my-pi · error · io::Error
invalid date: {value}
Error message
invalid date: {value} What it means
`parse_utc_datetime` rejects the date string with `invalid date: {value}` when the `YYYY-MM-DD` portion splits into more than three `-`-separated parts. After consuming year, month, and day, any leftover component (a fourth part) means the format isn't a supported calendar date, so the library returns `InvalidInput`. It's a strict format check: exactly `year-month-day` is expected.
Source
Thrown at crates/pi-builtins/src/fd.rs:1385
"h" | "hr" | "hrs" | "hour" | "hours" => count.saturating_mul(60 * 60),
"d" | "day" | "days" => count.saturating_mul(24 * 60 * 60),
"w" | "week" | "weeks" => count.saturating_mul(7 * 24 * 60 * 60),
_ => return Ok(None),
};
Ok(Some(Duration::from_secs(seconds)))
}
fn parse_utc_datetime(value: &str) -> io::Result<SystemTime> {
let (date, time) = value
.trim()
.split_once(' ')
.unwrap_or_else(|| (value.trim(), "00:00:00"));
let mut date_parts = date.split('-');
let year = parse_i32_part(date_parts.next(), "year")?;
let month = parse_u32_part(date_parts.next(), "month")?;
let day = parse_u32_part(date_parts.next(), "day")?;
if date_parts.next().is_some() {
return Err(io::Error::new(io::ErrorKind::InvalidInput, format!("invalid date: {value}")));
}
let mut time_parts = time.split(':');
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)))View on GitHub (pinned to 9690622007)
Solutions
- Use exactly `YYYY-MM-DD` (optionally followed by a space and `HH:MM:SS`) in UTC: `2024-01-15` or `2024-01-15 10:30:00`.
- Remove timezone-offset suffixes; the parser has no timezone support — convert to UTC first.
- If you have a `T`-separated ISO string like `2024-01-15T10:30:00Z`, rewrite it as `2024-01-15 10:30:00` before passing it.
- For epoch input, use the `@<seconds>` form instead of a calendar date.
Example fix
// before (extra hyphenated segment from ISO offset) find --changed 2024-01-15T10:30:00-05:00 // after (UTC, space-separated) find --changed 2024-01-15 15:30:00
Defensive patterns
Strategy: validation
Validate before calling
fn validate_utc_date(value: &str) -> Result<(), String> {
let trimmed = value.trim();
let (date, time) = trimmed
.split_once(' ')
.unwrap_or((trimmed, "00:00:00"));
let parts: Vec<&str> = date.split('-').collect();
if parts.len() != 3 {
return Err(format!("expected exactly YYYY-MM-DD, got '{date}'"));
}
parts.iter().all(|p| !p.is_empty() && p.bytes().all(|b| b.is_ascii_digit()))
.then_some(())
.ok_or_else(|| format!("non-numeric date component in '{value}'"))
} Type guard
fn is_supported_utc_datetime(value: &str) -> bool {
let (date, _) = value.trim().split_once(' ').unwrap_or((value.trim(), ""));
let parts: Vec<&str> = date.split('-').collect();
parts.len() == 3
&& parts.iter().all(|p| !p.is_empty() && p.bytes().all(|b| b.is_ascii_digit()))
} Try / catch
match parse_time_filter(input) {
Ok(time) => use_time(time),
Err(e) if e.to_string().starts_with("invalid date") => {
eprintln!("'{input}' is not YYYY-MM-DD [HH:MM:SS] (UTC); convert timezones and strip ISO-8601 suffixes first");
}
Err(e) => return Err(e),
} Prevention
- Always convert to UTC and strip timezone offsets before passing a datetime string.
- Rewrite `T`-separated ISO-8601 timestamps to the space-separated form the parser expects.
- Regex-check user input: `^\d{4}-\d{2}-\d{2}( \d{2}:\d{2}:\d{2})?$`.
- Prefer `@<epoch-seconds>` for programmatically sourced timestamps.
When it happens
Trigger: Passing a date with extra hyphen-separated segments, e.g. `2024-01-15-05` or an ISO-8601 datetime with `T`/timezone encoded via hyphens like `2024-01-15T10:30:00Z` only if it contains extra `-` fields (e.g. `2024-01-15-10:30`); also values like `2024-01-15-extra`.
Common situations: Using an ISO 8601 timestamp containing timezone-offset hyphens (e.g. `2024-01-15T10:30:00-05:00`) — the `-05:00` lands in the date section; passing `YYYY-MM-DD` output from tools that append a suffix; mixing the datetime space-separated form (`2024-01-15 10:30:00`) with a `T` separator plus offset.
Related errors
- date is out of range
- err.to_string() (timestamp parse error)
- duration is too large: {value}
- dates before 1970 are unsupported
- missing {name}
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/a8444e3fe183bdf9.
Report an issue: GitHub.