LR-LIB-CAPTURETIME: a shift past year 9999 (or before 0000) is refused, not skipped

From final review: photo.setCaptureTime quietly skipped photos whose
shifted date would leave years 0000–9999. It reported success, with
the photo missing from `captured`. Such a shift is now refused for the
whole selection with how many photos it concerns, and nothing changes.
A date that doesn't read at all is still skipped, as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Nathaniel Ledford
2026-10-09 10:54:58 -04:00
co-authored by Claude Opus 5.5
parent cf496fa733
commit 11e36bf060
2 changed files with 20 additions and 4 deletions
+15 -4
View File
@@ -209,17 +209,28 @@ pub fn specs() -> Vec<CommandSpec> {
}
let mut ops = Vec::new();
let mut out = Vec::new();
let mut out_of_range = 0usize;
for id in &targets {
let new = match &each {
Some(t) => shift_iso(t, delta),
None => shift_iso(&base(s, *id), delta),
let from = match &each {
Some(t) => t.clone(),
None => base(s, *id),
};
let Some(new) = shift_iso(&from, delta) else {
// a date that reads but would leave years 0000–9999 is refused below; one
// that doesn't read is skipped, as before
if iso_seconds(&from).is_some() {
out_of_range += 1;
}
continue;
};
let Some(new) = new else { continue };
out.push(json!(new));
if s.catalog.photo(*id).and_then(|p| p.captured.as_deref()) != Some(new.as_str()) {
ops.push(Op::SetCaptured { id: *id, captured: Some(new) });
}
}
if out_of_range > 0 {
return Err(bad(c, format!("the shift would take {out_of_range} photo(s) outside the years 0000–9999; nothing was changed")));
}
let n = ops.len();
if n > 0 {
s.commit("Edit Capture Time", Op::Batch { ops })?;
+5
View File
@@ -492,6 +492,11 @@ fn capture_time_shift_is_bounded() {
}
s.execute("photo.setCaptureTime", &serde_json::json!({"ids": [id.0], "hours": 1})).unwrap();
assert_ne!(s.catalog.photo(id).unwrap().captured, before);
// a shift that would take a photo past year 9999 says so, rather than skipping it quietly
s.execute("photo.setCaptureTime", &serde_json::json!({"ids": [id.0], "time": "9999-12-31T12:00:00"})).unwrap();
let r = s.execute("photo.setCaptureTime", &serde_json::json!({"ids": [id.0], "hours": 24}));
assert!(r.as_ref().is_err_and(|e| e.to_string().contains("9999")), "{r:?}");
assert_eq!(s.catalog.photo(id).unwrap().captured.as_deref(), Some("9999-12-31T12:00:00"), "unchanged");
}
/// Values are checked too: an agent's rule set with a date that isn't one, or a rating of 9, is