From 7fcd2b8c9925cc95b4dcb94c170bd42bc6b0d5bf Mon Sep 17 00:00:00 2001 From: NetterSilver <133535268+Silvertree2010@users.noreply.github.com> Date: Thu, 22 Oct 2026 17:32:10 +0000 Subject: [PATCH] Write capture time UTC offset and sub-seconds in write_exif Found while testing crates/meta/src/exif.rs:462 (write_exif; compare the reader in from_tiff at crates/meta/src/exif.rs:96-107) Co-Authored-By: Claude Haiku 5.5 Co-Authored-By: Claude Opus 5.5 Co-Authored-By: Claude Sonnet 5.5 --- crates/meta/src/exif.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/crates/meta/src/exif.rs b/crates/meta/src/exif.rs index cb45274d1..ab2691c30 100644 --- a/crates/meta/src/exif.rs +++ b/crates/meta/src/exif.rs @@ -496,6 +496,19 @@ pub fn write_exif(meta: &Metadata) -> Vec { ex.set(tag, v); } } + if let Some(d) = meta.capture_time { + let offset = d.offset_minutes.map(|o| { + let sign = if o < 0 { '-' } else { '+' }; + format!("{sign}{:02}:{:02}", o.abs() / 60, o.abs() % 60) + }); + let subsec = (d.millis != 0).then(|| format!("{:03}", d.millis)); + for (tag, v) in [(t::OFFSET_TIME, &offset), (t::OFFSET_TIME_ORIGINAL, &offset), (t::SUBSEC_TIME, &subsec), (t::SUBSEC_TIME_ORIGINAL, &subsec)] + { + if let Some(v) = v { + ex.set(tag, Value::Ascii(v.clone())); + } + } + } ifd0.set_child(t::EXIF_IFD, ex); if let Some(g) = meta.gps { let dms = |v: f64| { @@ -524,6 +537,14 @@ pub fn write_exif(meta: &Metadata) -> Vec { mod write_tests { use super::*; + #[test] + fn capture_time_offset_and_subsec_round_trip() { + for iso in ["2026-09-20T05:40:00.250+02:00", "2026-09-20T05:40:00.005-03:30", "2026-09-20T05:40:00"] { + let m = Metadata { capture_time: DateTime::parse_iso(iso), ..Default::default() }; + assert_eq!(read_exif(&write_exif(&m)).capture_time, m.capture_time, "{iso}"); + } + } + #[test] fn exif_round_trips() { let m = Metadata {