Dates: true_instant on metadata responses for instant matching
The mobile viewer anchored its "messages around this photo" window on the legacy date_taken (a wall clock stored as UTC for EXIF rows), while SMS-API dates are true instants: the window was off by the photo's UTC offset (4-5 h for photos taken at home; ImageApi #113 user story 3). Verified SMS-API side: importers store backup epochs as UTC, and 40/40 sampled rows equal their source epochs exactly. `/image/metadata` (+ GPS / date mutation responses) now carries `true_instant` from `date_view::file_true_instant`: `row_true_instant`, else the filename-class instant, else the earliest fs time. Server-side for the same reason as `wall_clock`: the drain's permanent floor rows have no `date_utc`. `set_capture_dates` fills both fields at all four response sites. dev/e2e: the manifest records each fixture's expected instant (the wall read in its GPS zone, else America/New_York) and `e2e.sh check` asserts it (97/97). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
bc41c737e5
commit
9269b5c9fd
5 files changed
+117
-18
No files matched your search
+24
-13
@@ -528,12 +528,11 @@ pub async fn get_file_metadata(
|
||||
.lock()
|
||||
.ok()
|
||||
.and_then(|mut dao| dao.get_exif(&path.path).ok().flatten());
|
||||
response.wall_clock = crate::date_view::file_wall_clock(
|
||||
set_capture_dates(
|
||||
&mut response,
|
||||
row.as_ref(),
|
||||
&path.path,
|
||||
earliest_fs_time(&response),
|
||||
crate::date_view::owner_display_zone(&app_state.user_ai_prefs_dao),
|
||||
crate::camera_tz::server_zone(),
|
||||
);
|
||||
response.exif = row.map(Into::into);
|
||||
|
||||
@@ -714,14 +713,14 @@ pub async fn set_image_gps(
|
||||
library_id: None,
|
||||
library_name: None,
|
||||
wall_clock: None,
|
||||
true_instant: None,
|
||||
},
|
||||
};
|
||||
response.wall_clock = crate::date_view::file_wall_clock(
|
||||
set_capture_dates(
|
||||
&mut response,
|
||||
Some(&row),
|
||||
&normalized_path,
|
||||
earliest_fs_time(&response),
|
||||
crate::date_view::owner_display_zone(&app_state.user_ai_prefs_dao),
|
||||
crate::camera_tz::server_zone(),
|
||||
);
|
||||
response.exif = Some(row.into());
|
||||
response.library_id = Some(resolved_library.id);
|
||||
@@ -881,15 +880,10 @@ fn build_metadata_response_for_date_mutation(
|
||||
library_id: None,
|
||||
library_name: None,
|
||||
wall_clock: None,
|
||||
true_instant: None,
|
||||
},
|
||||
};
|
||||
response.wall_clock = crate::date_view::file_wall_clock(
|
||||
Some(&exif),
|
||||
rel_path,
|
||||
earliest_fs_time(&response),
|
||||
display_zone,
|
||||
crate::camera_tz::server_zone(),
|
||||
);
|
||||
set_capture_dates(&mut response, Some(&exif), rel_path, display_zone);
|
||||
response.exif = Some(exif.into());
|
||||
response.library_id = Some(library.id);
|
||||
response.library_name = Some(library.name.clone());
|
||||
@@ -898,6 +892,23 @@ fn build_metadata_response_for_date_mutation(
|
||||
response
|
||||
}
|
||||
|
||||
/// Fill the capture-date fields every metadata response carries (ADR-0001):
|
||||
/// `wall_clock` to display and `true_instant` to match against. Needs the
|
||||
/// fs times already on the response (the unindexed-file fallback).
|
||||
fn set_capture_dates(
|
||||
response: &mut MetadataResponse,
|
||||
row: Option<&ImageExif>,
|
||||
rel_path: &str,
|
||||
display_zone: chrono_tz::Tz,
|
||||
) {
|
||||
let server_zone = crate::camera_tz::server_zone();
|
||||
let fs_earliest = earliest_fs_time(response);
|
||||
response.wall_clock =
|
||||
crate::date_view::file_wall_clock(row, rel_path, fs_earliest, display_zone, server_zone);
|
||||
response.true_instant =
|
||||
crate::date_view::file_true_instant(row, rel_path, fs_earliest, display_zone, server_zone);
|
||||
}
|
||||
|
||||
/// Earlier of the file's created / modified times — the ingest waterfall's
|
||||
/// `fs_time` rule — for the wall-clock fallback of unindexed files.
|
||||
fn earliest_fs_time(response: &MetadataResponse) -> Option<i64> {
|
||||
|
||||
Reference in new issue
Block a user