chrome_cache_parser/
time.rs

1use chrono::{DateTime, Local, Utc};
2use zerocopy::{FromBytes, FromZeroes};
3
4use crate::{CCPError, CCPResult};
5
6const MICROSEC_PER_SEC: u64 = 1_000_000;
7const NANOSEC_PER_MICROSEC: u64 = 1_000;
8const WIN_TO_UNIX_EPOCH_DELTA_SEC: u64 = 11_644_473_600;
9const WIN_TO_UNIX_EPOCH_DIFF_MICROSEC: u64 = WIN_TO_UNIX_EPOCH_DELTA_SEC * MICROSEC_PER_SEC;
10
11/// Represents a time in microseconds since the Windows epoch (1601-01-01 00:00:00 UTC) (used in
12/// the chrome cache format).
13#[derive(Debug, FromZeroes, FromBytes, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
14pub struct WindowsEpochMicroseconds(u64);
15
16impl WindowsEpochMicroseconds {
17    pub fn into_datetime_utc(self) -> CCPResult<DateTime<Utc>> {
18        let windows_micro_seconds: u64 = self.0;
19
20        let unix_micro_seconds = windows_micro_seconds
21            .checked_sub(WIN_TO_UNIX_EPOCH_DIFF_MICROSEC)
22            .ok_or(CCPError::InvalidTimestamp(windows_micro_seconds))?;
23        let unix_seconds = unix_micro_seconds / MICROSEC_PER_SEC;
24        let unix_nanoseconds = (unix_micro_seconds % MICROSEC_PER_SEC) * NANOSEC_PER_MICROSEC;
25
26        DateTime::from_timestamp(unix_seconds as i64, unix_nanoseconds as u32)
27            .ok_or(CCPError::InvalidTimestamp(windows_micro_seconds))
28    }
29
30    pub fn into_datetime_local(self) -> CCPResult<DateTime<Local>> {
31        let utc: CCPResult<DateTime<Utc>> = self.into_datetime_utc();
32        Ok(utc?.with_timezone(&Local))
33    }
34}
35
36#[cfg(test)]
37#[test]
38fn test_windows_epoch_microseconds() {
39    use chrono::{Datelike, Timelike};
40    let timestamp = WindowsEpochMicroseconds(13_360_111_021_811_283);
41    let date: CCPResult<DateTime<Utc>> = timestamp.into_datetime_utc();
42    let date = date.unwrap();
43
44    assert_eq!(date.year(), 2024);
45    assert_eq!(date.month(), 5);
46    assert_eq!(date.day(), 13);
47    assert_eq!(date.hour(), 21);
48    assert_eq!(date.second(), 1);
49}
50
51#[test]
52fn test_windows_epoch_from_0_input_returns_error() {
53    let timestamp = WindowsEpochMicroseconds(0);
54    let date: CCPResult<DateTime<Utc>> = timestamp.into_datetime_utc();
55    assert!(date.is_err());
56}