{"record":{"id":"834bb3f0c12e1b34","repo":"spacedriveapp/spacedrive","slug":"invalid-time-format","errorCode":null,"errorMessage":"Invalid time format: {}","messagePattern":"Invalid time format: (.+?)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"apps/cli/src/domains/sync/mod.rs","lineNumber":149,"sourceCode":"\t}\n}\n\nfn parse_time_filter(time_str: &str) -> Result<DateTime<Utc>> {\n\t// Try parsing as relative time first\n\tif time_str.ends_with(\" ago\") {\n\t\tlet duration_str = &time_str[..time_str.len() - 4];\n\t\tlet duration = parse_duration(duration_str)?;\n\t\tOk(Utc::now() - duration)\n\t} else {\n\t\t// Try parsing as absolute time\n\t\tDateTime::parse_from_rfc3339(time_str)\n\t\t\t.map(|dt| dt.with_timezone(&Utc))\n\t\t\t.or_else(|_| {\n\t\t\t\t// Try common formats\n\t\t\t\tDateTime::parse_from_str(time_str, \"%Y-%m-%d %H:%M:%S\")\n\t\t\t\t\t.map(|dt| dt.with_timezone(&Utc))\n\t\t\t})\n\t\t\t.map_err(|_| anyhow::anyhow!(\"Invalid time format: {}\", time_str))\n\t}\n}\n\nfn parse_duration(duration_str: &str) -> Result<chrono::Duration> {\n\tlet parts: Vec<&str> = duration_str.split_whitespace().collect();\n\tif parts.len() != 2 {\n\t\treturn Err(anyhow::anyhow!(\"Invalid duration format: {}\", duration_str));\n\t}\n\n\tlet value: i64 = parts[0]\n\t\t.parse()\n\t\t.map_err(|_| anyhow::anyhow!(\"Invalid number: {}\", parts[0]))?;\n\tlet unit = parts[1].to_lowercase();\n\n\tlet seconds = match unit.as_str() {\n\t\t\"second\" | \"seconds\" | \"sec\" | \"s\" => value,\n\t\t\"minute\" | \"minutes\" | \"min\" | \"m\" => value * 60,\n\t\t\"hour\" | \"hours\" | \"h\" => value * 3600,","sourceCodeStart":131,"sourceCodeEnd":167,"githubUrl":"https://github.com/spacedriveapp/spacedrive/blob/6dfeccf2113039e35f2ce735f945e70dc3e4ea45/apps/cli/src/domains/sync/mod.rs#L131-L167","documentation":"Thrown by parse_time_filter() (used for --since on 'sd sync metrics') when the string is not a relative '<N> <unit> ago' duration and also fails both absolute formats tried: RFC 3339 (DateTime::parse_from_rfc3339) and '%Y-%m-%d %H:%M:%S'. Note that a string ending in ' ago' is routed to parse_duration() instead and produces that function's errors, not this one.","triggerScenarios":"Passing --since 2024-01-01 (date only, no time), --since '01/02/2024', --since 'yesterday', or any timestamp with a format outside the two accepted ones.","commonSituations":"Users assume natural-language dates or locale formats (MM/DD/YYYY) work; ISO date without time component; timezone-suffix variants like '+02:00' are fine in RFC 3339 but a missing 'T' separator is not.","solutions":["Use RFC 3339: --since 2024-06-01T12:00:00Z","Or 'YYYY-MM-DD HH:MM:SS': --since '2024-06-01 12:00:00' (quote it)","Or a relative duration: --since '30 minutes ago', '2 hours ago', '7 days ago'","Double-check for stray characters, missing seconds, or a date-only string"],"exampleFix":"// accepted inputs\n//   RFC 3339:              2024-06-01T12:00:00Z\n//   common format:        \"2024-06-01 12:00:00\"\n//   relative:             \"30 minutes ago\"\n// before (fails): sd sync metrics --since 2024-06-01\n// after:           sd sync metrics --since '2024-06-01 00:00:00'","handlingStrategy":"validation","validationCode":"fn is_valid_time_filter(s: &str) -> bool {\n    if s.ends_with(\" ago\") {\n        let d = &s[..s.len() - 4];\n        let mut it = d.split_whitespace();\n        matches!((it.next(), it.next(), it.next()), (Some(n), Some(_), None))\n            && n.parse::<i64>().is_ok()\n    } else {\n        chrono::DateTime::parse_from_rfc3339(s).is_ok()\n            || chrono::DateTime::parse_from_str(s, \"%Y-%m-%d %H:%M:%S\").is_ok()\n    }\n}\n\nif !is_valid_time_filter(&since_str) {\n    eprintln!(\"--since accepts RFC 3339, 'YYYY-MM-DD HH:MM:SS', or '<N> <unit> ago'\");\n}","typeGuard":"fn is_valid_time_filter(s: &str) -> bool {\n    if s.ends_with(\" ago\") {\n        let d = &s[..s.len() - 4];\n        let mut it = d.split_whitespace();\n        matches!((it.next(), it.next(), it.next()), (Some(n), Some(_), None))\n            && n.parse::<i64>().is_ok()\n    } else {\n        chrono::DateTime::parse_from_rfc3339(s).is_ok()\n            || chrono::DateTime::parse_from_str(s, \"%Y-%m-%d %H:%M:%S\").is_ok()\n    }\n}","tryCatchPattern":"match parse_time_filter(&since_str) {\n    Ok(t) => t,\n    Err(e) if e.to_string().starts_with(\"Invalid time format\") => {\n        eprintln!(\"Supported: RFC 3339, 'YYYY-MM-DD HH:MM:SS', or e.g. '30 minutes ago'\");\n        return Err(e);\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Standardize on RFC 3339 timestamps in scripts - they always parse","Quote --since values in the shell to protect spaces","Remember date-only strings ('2024-06-01') are NOT accepted; add a time component"],"tags":["cli","sync","time-parsing","arguments"],"backgroundTag":null,"analyzedSha":"6dfeccf2113039e35f2ce735f945e70dc3e4ea45","analyzedAt":"2026-08-16T11:26:17.074Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}