aede_core/
clock.rs

1//! Unix timestamps shared by catalog and conclusion stores.
2//!
3//! Small enough to be tempting to rewrite on the spot — which is exactly what
4//! had happened, in three places, each with its own answer to "and if the clock
5//! is before 1970?". A scan date, an integrity date and an import date have to
6//! be comparable, so they come from here.
7
8use std::time::{SystemTime, UNIX_EPOCH};
9
10/// Now, in seconds since the Unix epoch.
11///
12/// A clock set before 1970 yields `0` rather than an error: nothing in the
13/// catalog can act on that failure, and a date of zero reads as "unknown"
14/// everywhere a date is shown.
15pub fn now_seconds() -> u64 {
16    SystemTime::now()
17        .duration_since(UNIX_EPOCH)
18        .map(|d| d.as_secs())
19        .unwrap_or(0)
20}
21
22/// Now with subsecond precision, for ordering analysis results produced in
23/// quick succession. File identity stores seconds and the fractional part
24/// separately so both integers survive the JSON representation exactly.
25pub fn now_nanoseconds() -> u64 {
26    nanoseconds(SystemTime::now())
27}
28
29/// A report file's modification time, with the same precision as new results.
30pub fn mtime_nanoseconds(meta: &std::fs::Metadata) -> u64 {
31    meta.modified().map(nanoseconds).unwrap_or(0)
32}
33
34fn nanoseconds(time: SystemTime) -> u64 {
35    time.duration_since(UNIX_EPOCH)
36        .ok()
37        .and_then(|duration| u64::try_from(duration.as_nanos()).ok())
38        .unwrap_or(0)
39}
40
41/// Modification date of a file, in seconds since the Unix epoch.
42///
43/// The scanner also compares [`mtime_subseconds`]. Keeping the parts separate
44/// avoids rounding epoch nanoseconds through JSON's floating-point numbers.
45pub fn mtime_seconds(meta: &std::fs::Metadata) -> u64 {
46    meta.modified()
47        .ok()
48        .and_then(|t| t.duration_since(UNIX_EPOCH).ok())
49        .map(|d| d.as_secs())
50        .unwrap_or(0)
51}
52
53/// Nanosecond fraction of a file's modification date, or `0` when unavailable.
54pub fn mtime_subseconds(meta: &std::fs::Metadata) -> u32 {
55    meta.modified()
56        .ok()
57        .and_then(|time| time.duration_since(UNIX_EPOCH).ok())
58        .map(|duration| duration.subsec_nanos())
59        .unwrap_or(0)
60}