1use std::{
8 cmp::Ordering,
9 fmt,
10 io::{Read, Write},
11 ops::{Add, Sub},
12 str::FromStr,
13};
14
15use chrono::{Datelike, Duration, SecondsFormat, TimeZone, Timelike, Utc};
16use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer};
17
18use crate::types::encoding::*;
19
20const NANOS_PER_SECOND: i64 = 1_000_000_000;
21const NANOS_PER_TICK: i64 = 100;
22const TICKS_PER_SECOND: i64 = NANOS_PER_SECOND / NANOS_PER_TICK;
23
24const MIN_YEAR: u16 = 1601;
25const MAX_YEAR: u16 = 9999;
26
27pub type DateTimeUtc = chrono::DateTime<Utc>;
28
29#[derive(PartialEq, Debug, Clone, Copy)]
32pub struct DateTime {
33 date_time: DateTimeUtc,
34}
35
36impl Serialize for DateTime {
37 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
38 where
39 S: Serializer,
40 {
41 serializer.serialize_str(&self.to_rfc3339())
42 }
43}
44
45impl<'de> Deserialize<'de> for DateTime {
46 fn deserialize<D>(deserializer: D) -> Result<DateTime, D::Error>
47 where
48 D: Deserializer<'de>,
49 {
50 let v = String::deserialize(deserializer)?;
51 let dt = DateTime::parse_from_rfc3339(&v)
52 .map_err(|_| D::Error::custom("Cannot parse date time"))?;
53 Ok(dt)
54 }
55}
56
57impl BinaryEncoder<DateTime> for DateTime {
59 fn byte_len(&self) -> usize {
60 8
61 }
62
63 fn encode<S: Write>(&self, stream: &mut S) -> EncodingResult<usize> {
64 let ticks = self.checked_ticks();
65 write_i64(stream, ticks)
66 }
67
68 fn decode<S: Read>(stream: &mut S, decoding_options: &DecodingOptions) -> EncodingResult<Self> {
69 let ticks = read_i64(stream)?;
70 let date_time = DateTime::from(ticks);
71 Ok(date_time - decoding_options.client_offset)
74 }
75}
76
77impl Default for DateTime {
78 fn default() -> Self {
79 DateTime::epoch()
80 }
81}
82
83impl Add<Duration> for DateTime {
84 type Output = Self;
85
86 fn add(self, duration: Duration) -> Self {
87 DateTime::from(self.date_time + duration)
88 }
89}
90
91impl Sub<DateTime> for DateTime {
92 type Output = Duration;
93
94 fn sub(self, other: Self) -> Duration {
95 self.date_time - other.date_time
96 }
97}
98
99impl Sub<Duration> for DateTime {
100 type Output = Self;
101
102 fn sub(self, duration: Duration) -> Self {
103 DateTime::from(self.date_time - duration)
104 }
105}
106
107impl PartialOrd for DateTime {
108 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
109 Some(self.date_time.cmp(&other.date_time))
110 }
111}
112
113impl From<(u16, u16, u16, u16, u16, u16)> for DateTime {
115 fn from(dt: (u16, u16, u16, u16, u16, u16)) -> Self {
116 let (year, month, day, hour, minute, second) = dt;
117 DateTime::from((year, month, day, hour, minute, second, 0))
118 }
119}
120
121impl From<(u16, u16, u16, u16, u16, u16, u32)> for DateTime {
123 fn from(dt: (u16, u16, u16, u16, u16, u16, u32)) -> Self {
124 let (year, month, day, hour, minute, second, nanos) = dt;
125 if month < 1 || month > 12 {
126 panic!("Invalid month");
127 }
128 if day < 1 || day > 31 {
129 panic!("Invalid day");
130 }
131 if hour > 23 {
132 panic!("Invalid hour");
133 }
134 if minute > 59 {
135 panic!("Invalid minute");
136 }
137 if second > 59 {
138 panic!("Invalid second");
139 }
140 if nanos as i64 >= NANOS_PER_SECOND {
141 panic!("Invalid nanosecond");
142 }
143 let dt = Utc.ymd(year as i32, month as u32, day as u32).and_hms_nano(
144 hour as u32,
145 minute as u32,
146 second as u32,
147 nanos,
148 );
149 DateTime::from(dt)
150 }
151}
152
153impl From<DateTimeUtc> for DateTime {
154 fn from(date_time: DateTimeUtc) -> Self {
155 let year = date_time.year();
157 let month = date_time.month();
158 let day = date_time.day();
159 let hour = date_time.hour();
160 let minute = date_time.minute();
161 let second = date_time.second();
162 let nanos = (date_time.nanosecond() / NANOS_PER_TICK as u32) * NANOS_PER_TICK as u32;
163 let date_time = Utc
164 .ymd(year, month, day)
165 .and_hms_nano(hour, minute, second, nanos);
166 DateTime { date_time }
167 }
168}
169
170impl From<i64> for DateTime {
171 fn from(value: i64) -> Self {
172 if value == i64::max_value() {
173 Self::endtimes()
175 } else {
176 let secs = value / TICKS_PER_SECOND;
177 let nanos = (value - secs * TICKS_PER_SECOND) * NANOS_PER_TICK;
178 let duration = Duration::seconds(secs) + Duration::nanoseconds(nanos);
179 Self::from(Self::epoch_chrono() + duration)
180 }
181 }
182}
183
184impl Into<i64> for DateTime {
185 fn into(self) -> i64 {
186 self.checked_ticks()
187 }
188}
189
190impl Into<DateTimeUtc> for DateTime {
191 fn into(self) -> DateTimeUtc {
192 self.as_chrono()
193 }
194}
195
196impl fmt::Display for DateTime {
197 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
198 write!(f, "{}", self.date_time.to_rfc3339())
199 }
200}
201
202impl FromStr for DateTime {
203 type Err = ();
204
205 fn from_str(s: &str) -> Result<Self, Self::Err> {
206 DateTimeUtc::from_str(s).map(DateTime::from).map_err(|e| {
207 error!("Cannot parse date {}, error = {}", s, e);
208 })
209 }
210}
211
212impl DateTime {
213 pub fn now() -> DateTime {
215 DateTime::from(Utc::now())
216 }
217
218 #[cfg(test)]
221 pub fn rfc3339_now() -> DateTime {
222 use chrono::NaiveDateTime;
223 use std::time::{SystemTime, UNIX_EPOCH};
224
225 let duration = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
226 let naive = NaiveDateTime::from_timestamp(duration.as_secs() as i64, 0);
227 let now = DateTimeUtc::from_utc(naive, Utc);
228 DateTime::from(now)
229 }
230
231 pub fn now_with_offset(offset: Duration) -> DateTime {
233 DateTime::from(Utc::now() + offset)
234 }
235
236 pub fn null() -> DateTime {
238 DateTime::epoch()
240 }
241
242 pub fn is_null(&self) -> bool {
244 self.ticks() == 0i64
245 }
246
247 pub fn epoch() -> DateTime {
249 DateTime::from(Self::epoch_chrono())
250 }
251
252 pub fn endtimes() -> DateTime {
254 DateTime::from(Self::endtimes_chrono())
255 }
256
257 pub fn endtimes_ticks() -> i64 {
259 Self::duration_to_ticks(Self::endtimes_chrono().signed_duration_since(Self::epoch_chrono()))
260 }
261
262 pub fn ymd(year: u16, month: u16, day: u16) -> DateTime {
264 DateTime::ymd_hms(year, month, day, 0, 0, 0)
265 }
266
267 pub fn ymd_hms(
269 year: u16,
270 month: u16,
271 day: u16,
272 hour: u16,
273 minute: u16,
274 second: u16,
275 ) -> DateTime {
276 DateTime::from((year, month, day, hour, minute, second))
277 }
278
279 pub fn ymd_hms_nano(
281 year: u16,
282 month: u16,
283 day: u16,
284 hour: u16,
285 minute: u16,
286 second: u16,
287 nanos: u32,
288 ) -> DateTime {
289 DateTime::from((year, month, day, hour, minute, second, nanos))
290 }
291
292 pub fn to_rfc3339(&self) -> String {
294 self.date_time.to_rfc3339_opts(SecondsFormat::Millis, true)
295 }
296
297 pub fn parse_from_rfc3339(s: &str) -> Result<DateTime, ()> {
299 let date_time = chrono::DateTime::parse_from_rfc3339(s).map_err(|_| ())?;
300 let mut date_time = date_time.with_timezone(&Utc);
302 if date_time < Self::epoch_chrono() {
303 date_time = Self::epoch_chrono();
304 }
305 if date_time > Self::endtimes_chrono() {
307 date_time = Self::endtimes_chrono();
308 }
309
310 Ok(Self { date_time })
311 }
312
313 pub fn ticks(&self) -> i64 {
315 Self::duration_to_ticks(self.date_time.signed_duration_since(Self::epoch_chrono()))
316 }
317
318 pub fn checked_ticks(&self) -> i64 {
321 let nanos = self.ticks();
322 if nanos < 0 {
323 return 0;
324 }
325 if nanos > Self::endtimes_ticks() {
326 return i64::max_value();
327 }
328 nanos
329 }
330
331 pub fn as_chrono(&self) -> DateTimeUtc {
333 self.date_time
334 }
335
336 fn epoch_chrono() -> DateTimeUtc {
338 Utc.ymd(MIN_YEAR as i32, 1, 1).and_hms(0, 0, 0)
339 }
340
341 fn endtimes_chrono() -> DateTimeUtc {
344 Utc.ymd(MAX_YEAR as i32, 12, 31).and_hms(23, 59, 59)
345 }
346
347 fn duration_to_ticks(duration: Duration) -> i64 {
349 let seconds_part = Duration::seconds(duration.num_seconds());
352 let seconds = seconds_part.num_seconds();
353 let nanos = (duration - seconds_part).num_nanoseconds().unwrap();
354 seconds * TICKS_PER_SECOND + nanos / NANOS_PER_TICK
356 }
357}