taos_query/common/
timestamp.rs1use std::fmt::{self, Debug, Display};
2
3use chrono::Local;
4use serde::{Deserialize, Serialize};
5
6use super::Precision;
7
8#[derive(Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
9pub enum Timestamp {
10 Milliseconds(i64),
11 Microseconds(i64),
12 Nanoseconds(i64),
13}
14
15impl Debug for Timestamp {
16 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
17 if f.alternate() {
18 match self {
19 Self::Milliseconds(arg0) => f.debug_tuple("Milliseconds").field(arg0).finish(),
20 Self::Microseconds(arg0) => f.debug_tuple("Microseconds").field(arg0).finish(),
21 Self::Nanoseconds(arg0) => f.debug_tuple("Nanoseconds").field(arg0).finish(),
22 }
23 } else {
24 Debug::fmt(&self.to_naive_datetime(), f)
25 }
26 }
27}
28
29impl Display for Timestamp {
30 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31 Display::fmt(&self.to_datetime_with_tz().to_rfc3339(), f)
32 }
33}
34
35impl Timestamp {
36 pub fn new(raw: i64, precision: Precision) -> Self {
37 match precision {
38 Precision::Millisecond => Timestamp::Milliseconds(raw),
39 Precision::Microsecond => Timestamp::Microseconds(raw),
40 Precision::Nanosecond => Timestamp::Nanoseconds(raw),
41 }
42 }
43
44 pub fn precision(&self) -> Precision {
45 match self {
46 Timestamp::Milliseconds(_) => Precision::Millisecond,
47 Timestamp::Microseconds(_) => Precision::Microsecond,
48 Timestamp::Nanoseconds(_) => Precision::Nanosecond,
49 }
50 }
51 pub fn as_raw_i64(&self) -> i64 {
52 match self {
53 Timestamp::Milliseconds(raw)
54 | Timestamp::Microseconds(raw)
55 | Timestamp::Nanoseconds(raw) => *raw,
56 }
57 }
58 pub fn to_naive_datetime(&self) -> chrono::NaiveDateTime {
59 let duration = match self {
60 Timestamp::Milliseconds(raw) => chrono::Duration::milliseconds(*raw),
61 Timestamp::Microseconds(raw) => chrono::Duration::microseconds(*raw),
62 Timestamp::Nanoseconds(raw) => chrono::Duration::nanoseconds(*raw),
63 };
64 chrono::DateTime::from_timestamp(0, 0)
65 .expect("timestamp value could always be mapped to a chrono::NaiveDateTime")
66 .checked_add_signed(duration)
67 .unwrap()
68 .naive_utc()
69 }
70
71 pub fn to_datetime_with_tz(&self) -> chrono::DateTime<Local> {
73 use chrono::TimeZone;
74 Local.from_utc_datetime(&self.to_naive_datetime())
75 }
76
77 pub fn cast_precision(&self, precision: Precision) -> Timestamp {
78 let raw = self.as_raw_i64();
79 match (self.precision(), precision) {
80 (Precision::Millisecond, Precision::Microsecond) => Timestamp::Microseconds(raw * 1000),
81 (Precision::Millisecond, Precision::Nanosecond) => {
82 Timestamp::Nanoseconds(raw * 1_000_000)
83 }
84 (Precision::Microsecond, Precision::Millisecond) => Timestamp::Milliseconds(raw / 1000),
85 (Precision::Microsecond, Precision::Nanosecond) => Timestamp::Nanoseconds(raw * 1000),
86 (Precision::Nanosecond, Precision::Millisecond) => {
87 Timestamp::Milliseconds(raw / 1_000_000)
88 }
89 (Precision::Nanosecond, Precision::Microsecond) => Timestamp::Microseconds(raw / 1000),
90 _ => Timestamp::new(raw, precision),
91 }
92 }
93}
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98
99 #[test]
100 fn ts_new() {
101 use Precision::*;
102 for prec in [Millisecond, Microsecond, Nanosecond] {
103 let ts = Timestamp::new(0, prec);
104 assert!(ts.as_raw_i64() == 0);
105 assert!(
106 ts.to_naive_datetime()
107 == chrono::DateTime::from_timestamp(0, 0).unwrap().naive_utc()
108 );
109 dbg!(ts.to_datetime_with_tz());
110 }
111 }
112
113 #[test]
114 fn ts_cast_precision() {
115 let precisions = [
116 Precision::Millisecond,
117 Precision::Microsecond,
118 Precision::Nanosecond,
119 ];
120 for (i, prec) in precisions.iter().enumerate() {
121 let ts = Timestamp::new(1_000_000 * (i as i64), *prec);
122 for (_j, new_prec) in precisions.iter().enumerate() {
123 let new_ts = ts.cast_precision(*new_prec);
124 assert_eq!(
125 new_ts.precision(),
126 *new_prec,
127 "from {:?} to {:?}",
128 prec,
129 new_prec
130 );
131 assert_eq!(
132 new_ts.to_naive_datetime(),
133 ts.to_naive_datetime(),
134 "from {:?} to {:?}",
135 prec,
136 new_prec
137 );
138 match (prec, new_prec) {
139 (Precision::Millisecond, Precision::Microsecond) => {
140 assert_eq!(new_ts.as_raw_i64(), 1_000_000 * (i as i64) * 1000);
141 }
142 (Precision::Millisecond, Precision::Nanosecond) => {
143 assert_eq!(new_ts.as_raw_i64(), 1_000_000 * (i as i64) * 1_000_000);
144 }
145 (Precision::Microsecond, Precision::Millisecond) => {
146 assert_eq!(new_ts.as_raw_i64(), 1_000_000 * (i as i64) / 1000);
147 }
148 (Precision::Microsecond, Precision::Nanosecond) => {
149 assert_eq!(new_ts.as_raw_i64(), 1_000_000 * (i as i64) * 1000);
150 }
151 (Precision::Nanosecond, Precision::Millisecond) => {
152 assert_eq!(new_ts.as_raw_i64(), 1_000_000 * (i as i64) / 1_000_000);
153 }
154 (Precision::Nanosecond, Precision::Microsecond) => {
155 assert_eq!(new_ts.as_raw_i64(), 1_000_000 * (i as i64) / 1000);
156 }
157 _ => {
158 assert_eq!(new_ts.as_raw_i64(), 1_000_000 * (i as i64));
159 }
160 }
161 }
162 }
163 }
164
165 #[test]
166 fn ts_debug() {
167 let ts = Timestamp::new(0, Precision::Millisecond);
168 assert_eq!(format!("{:?}", ts), "1970-01-01T00:00:00");
169 assert_eq!(format!("{:#?}", ts), "Milliseconds(\n 0,\n)");
170 assert_eq!(format!("{}", ts), "1970-01-01T08:00:00+08:00");
171 }
172}