1use std::time::SystemTime;
8
9mod display;
10mod integers;
11mod std_duration;
12
13pub use unix_ts_macros::ts;
14
15#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
19pub struct Timestamp {
20 pub(crate) seconds: i64,
22
23 pub(crate) nanos: u32,
25}
26
27impl Timestamp {
29 pub const fn new(mut seconds: i64, mut nanos: u32) -> Self {
38 while nanos >= 1_000_000_000 {
39 seconds += 1;
40 nanos -= 1_000_000_000;
41 }
42 Timestamp { seconds, nanos }
43 }
44
45 pub const fn from_nanos(nanos: i128) -> Self {
47 let seconds: i64 = (nanos / 1_000_000_000) as i64;
48 let nanos = if seconds >= 0 {
51 (nanos % 1_000_000_000) as u32
52 }
53 else {
54 (1_000_000_000 - (nanos % 1_000_000_000).abs()) as u32
55 };
56 Timestamp { seconds, nanos }
57 }
58
59 pub const fn from_micros(micros: i64) -> Self {
61 Timestamp::from_nanos(micros as i128 * 1_000)
62 }
63
64 pub const fn from_millis(millis: i64) -> Self {
66 Timestamp::from_nanos(millis as i128 * 1_000_000)
67 }
68
69 pub fn now() -> Self {
75 let now_dur = SystemTime::now()
76 .duration_since(SystemTime::UNIX_EPOCH)
77 .expect("System clock set prior to January 1, 1970");
78 Self { seconds: now_dur.as_secs() as i64, nanos: now_dur.subsec_nanos() }
79 }
80}
81
82impl Timestamp {
84 pub const fn seconds(&self) -> i64 {
95 self.seconds
96 }
97
98 pub const fn at_precision(&self, e: u8) -> i128 {
115 (self.seconds as i128) * 10i128.pow(e as u32)
116 + (self.nanos as i128) / 10i128.pow(9 - (e as u32))
117 }
118
119 pub const fn subsec(&self, e: u8) -> u32 {
136 self.nanos / 10u32.pow(9 - e as u32)
137 }
138}
139
140#[cfg(test)]
141#[allow(clippy::inconsistent_digit_grouping)]
142mod tests {
143 use std::time::Duration;
144
145 use assert2::check;
146
147 use super::*;
148
149 #[test]
150 fn test_cmp() {
151 check!(Timestamp::from(1335020400) < Timestamp::from(1335024000));
152 check!(Timestamp::from(1335020400) == Timestamp::from(1335020400));
153 check!(Timestamp::new(1335020400, 500_000_000) < Timestamp::new(1335020400, 750_000_000));
154 check!(Timestamp::new(1, 999_999_999) < Timestamp::from(2));
155 }
156
157 #[test]
158 fn test_from_nanos() {
159 check!(Timestamp::from_nanos(1335020400_000_000_000i128) == Timestamp::new(1335020400, 0));
160 check!(
161 Timestamp::from_nanos(1335020400_500_000_000i128) == Timestamp::new(1335020400, 500_000_000)
162 );
163 check!(Timestamp::from_nanos(-1_750_000_000) == Timestamp::new(-1, 250_000_000));
164 }
165
166 #[test]
167 fn test_from_micros() {
168 check!(Timestamp::from_micros(1335020400_000_000i64) == Timestamp::new(1335020400, 0));
169 check!(
170 Timestamp::from_micros(1335020400_500_000i64) == Timestamp::new(1335020400, 500_000_000)
171 );
172 check!(Timestamp::from_micros(-1_750_000) == Timestamp::new(-1, 250_000_000));
173 }
174
175 #[test]
176 fn test_from_millis() {
177 check!(Timestamp::from_millis(1335020400_000i64) == Timestamp::new(1335020400, 0));
178 check!(Timestamp::from_millis(1335020400_500i64) == Timestamp::new(1335020400, 500_000_000));
179 check!(Timestamp::from_millis(-1_750) == Timestamp::new(-1, 250_000_000));
180 }
181
182 #[test]
183 fn test_seconds() {
184 assert_eq!(Timestamp::from(1335020400).seconds, 1335020400);
185 }
186
187 #[test]
188 fn test_at_precision() {
189 let ts = Timestamp::new(1335020400, 123456789);
190 assert_eq!(ts.at_precision(3), 1335020400123);
191 assert_eq!(ts.at_precision(6), 1335020400123456);
192 assert_eq!(ts.at_precision(9), 1335020400123456789);
193 }
194
195 #[test]
196 fn test_subsec() {
197 let ts = Timestamp::new(1335020400, 123456789);
198 assert_eq!(ts.subsec(3), 123);
199 assert_eq!(ts.subsec(6), 123456);
200 assert_eq!(ts.subsec(9), 123456789);
201 }
202
203 #[test]
204 fn test_add() {
205 let ts = Timestamp::from(1335020400) + Duration::new(86400, 1_000_000);
206 assert_eq!(ts.seconds(), 1335020400 + 86400);
207 assert_eq!(ts.subsec(3), 1);
208 }
209
210 #[test]
211 fn test_sub() {
212 let ts = Timestamp::from(1335020400) - Duration::new(86400, 0);
213 assert_eq!(ts.seconds(), 1335020400 - 86400);
214 assert_eq!(ts.nanos, 0);
215 }
216
217 #[test]
218 fn test_sub_nano_overflow() {
219 let ts = Timestamp::from(1335020400) - Duration::new(0, 500_000_000);
220 assert_eq!(ts.seconds(), 1335020399);
221 assert_eq!(ts.subsec(1), 5);
222 }
223}