1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
use chrono::{DateTime, NaiveDateTime, TimeZone, Utc};
use serde::{Deserialize, Serialize};
use std::convert::TryFrom;
use std::time::{SystemTime, UNIX_EPOCH};
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
pub struct Timestamp {
pub sec: i64,
pub nsec: u32,
}
impl Timestamp {
pub fn now() -> Timestamp {
SystemTime::now().into()
}
}
pub const INVALID_DATETIME: &str = "Invalid DateTime";
impl TryFrom<Timestamp> for DateTime<Utc> {
type Error = &'static str;
fn try_from(ts: Timestamp) -> Result<DateTime<Utc>, Self::Error> {
match NaiveDateTime::from_timestamp_opt(ts.sec, ts.nsec) {
Some(dt) => Ok(Utc.from_utc_datetime(&dt)),
None => Err(INVALID_DATETIME),
}
}
}
impl From<DateTime<Utc>> for Timestamp {
fn from(dt: DateTime<Utc>) -> Timestamp {
const NANOSECONDS_PER_SECOND: i64 = 1_000_000_000;
let nanos = dt.timestamp_nanos();
Timestamp {
sec: nanos / NANOSECONDS_PER_SECOND,
nsec: (nanos % NANOSECONDS_PER_SECOND) as u32,
}
}
}
impl From<SystemTime> for Timestamp {
fn from(st: SystemTime) -> Timestamp {
let d = st
.duration_since(UNIX_EPOCH)
.expect("system time before Unix epoch");
Timestamp {
sec: d.as_secs() as i64,
nsec: d.subsec_nanos() as u32,
}
}
}
#[test]
fn test_timestamp() {
let now = Timestamp::now();
assert!(now.sec > 1600000000 as i64);
}
#[test]
fn timestamp_updates() {
let now = Timestamp::now();
std::thread::sleep(std::time::Duration::from_nanos(5_000));
let then = Timestamp::now();
assert!(then.sec > now.sec || (then.sec == now.sec && then.nsec > now.nsec));
}
#[test]
fn timestamp_to_datetime() {
use chrono::{DateTime, Utc};
use std::convert::TryInto;
let start: Timestamp = Timestamp {
sec: 2_000_000_000,
nsec: 100_000,
};
let dt: DateTime<Utc> = start.try_into().unwrap();
let next: Timestamp = dt.into();
assert_eq!(&start.sec, &next.sec);
assert_eq!(&start.nsec, &next.nsec);
}