Give the calendar one reading of a capture instant

The era-based conversion sat in library_ui.rs with two readers: the
timeline's month headings and, through format_date, the exporter's {date}
token. Import folder templates are a third, and three copies of a date
calculation that could drift apart is one too many — an image filed under a
date the timeline does not show it on is a file the user cannot find.

Moved to dr_types::time, which is where shared vocabulary lives, and given
the offset-aware reading an import needs: a shot taken at 23:30 in Tokyo
belongs in Tokyo's day, and filing by UTC would split one night's
photographs across two folders at whatever hour the offset happens to be.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-22 14:00:26 +02:00
co-authored by Claude Opus 5
parent 5945f7420a
commit c36d4c80c8
3 changed files with 145 additions and 17 deletions
+8 -17
View File
@@ -3428,27 +3428,18 @@ fn format_bucket(t: i64, g: dr_catalog::Granularity) -> String {
/// reading so a filename and the timeline cannot disagree about what day a
/// photograph was taken.
pub fn format_date(t: i64) -> String {
let (y, m, d, _) = civil_from_unix(t);
format!("{y}-{m:02}-{d:02}")
dr_types::format_date(t)
}
/// Unix seconds to a civil date, via the usual era-based algorithm.
/// Unix seconds to a civil date, in the tuple shape this module reads it in.
///
/// Hand-rolled rather than pulling in chrono for four fields — the same
/// reasoning as the connector's HTTP date parsing.
/// The algorithm moved to `dr_types::time` when import folder templates
/// (FR-CAT-10) became a third caller. Three readings of the same instant that
/// could drift apart is one too many: an image filed under a date the timeline
/// does not show it on is a file the user cannot find.
fn civil_from_unix(t: i64) -> (i64, i64, i64, i64) {
let days = t.div_euclid(86_400);
let secs = t.rem_euclid(86_400);
let z = days + 719_468;
let era = if z >= 0 { z } else { z - 146_096 } / 146_097;
let doe = z - era * 146_097;
let yoe = (doe - doe / 1460 + doe / 36524 - doe / 146_096) / 365;
let y = yoe + era * 400;
let doy = doe - (365 * yoe + yoe / 4 - yoe / 100);
let mp = (5 * doy + 2) / 153;
let d = doy - (153 * mp + 2) / 5 + 1;
let m = if mp < 10 { mp + 3 } else { mp - 9 };
(if m <= 2 { y + 1 } else { y }, m, d, secs / 3600)
let c = dr_types::civil_from_unix(t);
(c.year, c.month, c.day, c.hour)
}
/// Copy decoded RGBA into a Slint image.