use std::time::{Duration, SystemTime, UNIX_EPOCH};
const UNIX_EPOCH_TIMESTAMP: u64 = 116444736000000000;
pub fn current_timestamp() -> u64 {
timestamp_from_system_time(SystemTime::now())
}
fn timestamp_from_system_time(system_time: SystemTime) -> u64 {
match system_time.duration_since(UNIX_EPOCH) {
Ok(duration) => {
let delta = duration_to_timestamp_delta(duration);
UNIX_EPOCH_TIMESTAMP.saturating_add(delta)
}
Err(err) => {
let delta = duration_to_timestamp_delta(err.duration());
UNIX_EPOCH_TIMESTAMP.saturating_sub(delta)
}
}
}
pub fn system_time_from_timestamp(timestamp: u64) -> SystemTime {
let system_time = if timestamp >= UNIX_EPOCH_TIMESTAMP {
UNIX_EPOCH.checked_add(timestamp_delta_to_duration(
timestamp - UNIX_EPOCH_TIMESTAMP,
))
} else {
UNIX_EPOCH.checked_sub(timestamp_delta_to_duration(
UNIX_EPOCH_TIMESTAMP - timestamp,
))
};
system_time.unwrap_or(UNIX_EPOCH)
}
fn duration_to_timestamp_delta(duration: Duration) -> u64 {
duration
.as_secs()
.saturating_mul(10_000_000)
.saturating_add((duration.subsec_nanos() / 100) as u64)
}
fn timestamp_delta_to_duration(delta: u64) -> Duration {
Duration::new(delta / 10_000_000, (delta % 10_000_000) as u32 * 100)
}
#[cfg(test)]
mod tests {
use super::{
duration_to_timestamp_delta, system_time_from_timestamp,
timestamp_delta_to_duration, timestamp_from_system_time,
UNIX_EPOCH_TIMESTAMP,
};
use std::time::{Duration, UNIX_EPOCH};
#[test]
fn extreme_timestamp_delta() {
let timestamp = u64::MAX;
let duration = timestamp_delta_to_duration(timestamp);
assert_eq!(duration.as_secs(), 1844674407370);
assert_eq!(duration.subsec_nanos(), 955161500);
assert_eq!(duration_to_timestamp_delta(duration), timestamp);
}
#[test]
fn extreme_duration() {
let duration = Duration::new(u64::MAX, 999_999_999);
assert_eq!(duration_to_timestamp_delta(duration), u64::MAX);
}
#[test]
fn unix_epoch() {
assert_eq!(
UNIX_EPOCH_TIMESTAMP,
timestamp_from_system_time(UNIX_EPOCH)
);
assert_eq!(
system_time_from_timestamp(UNIX_EPOCH_TIMESTAMP),
UNIX_EPOCH
);
}
#[test]
fn after_unix_epoch() {
let sat_18_mar_2017_at_18_46_36_utc =
UNIX_EPOCH + Duration::from_secs(1489862796);
assert_eq!(
timestamp_from_system_time(sat_18_mar_2017_at_18_46_36_utc),
131343363960000000,
);
assert_eq!(
system_time_from_timestamp(131343363960000000),
sat_18_mar_2017_at_18_46_36_utc
);
}
#[test]
fn before_unix_epoch() {
let sun_20_jul_1969_at_20_17_00_utc =
UNIX_EPOCH - Duration::from_secs(14182980);
assert_eq!(
timestamp_from_system_time(sun_20_jul_1969_at_20_17_00_utc),
116302906200000000,
);
assert_eq!(
system_time_from_timestamp(116302906200000000),
sun_20_jul_1969_at_20_17_00_utc
);
}
#[test]
fn extreme_timestamps() {
let min_time = system_time_from_timestamp(u64::MIN);
let max_time = system_time_from_timestamp(u64::MAX);
assert!(min_time <= max_time);
}
}