1#![cfg(feature = "chrono")]
5
6use crate::{ByteSize, Deserialize, SerializationError, Serialize};
7use byteorder::{LittleEndian, ReadBytesExt};
8use bytes::{BufMut, BytesMut};
9use chrono::{DateTime, Datelike, Duration as CDuration, TimeZone, Timelike, Utc};
10use std::io::Read;
11use std::ops::{Add, Deref};
12use std::time::Duration;
13
14#[derive(Copy, Clone, Debug)]
27pub struct SilkroadTime(DateTime<Utc>);
28
29impl SilkroadTime {
30 pub fn as_u32(&self) -> u32 {
31 ((self.year() - 2000) as u32) & 63
32 | ((self.month() - 1) & 15) << 6
33 | ((self.day() - 1) & 31) << 10
34 | (self.hour() & 31) << 15
35 | (self.minute() & 63) << 20
36 | (self.second() & 63) << 26
37 }
38
39 pub fn from_u32(data: u32) -> Self {
40 let year = (data & 63) + 2000;
41 let month = ((data >> 6) & 15) + 1;
42 let day = ((data >> 10) & 31) + 1;
43 let hours = (data >> 15) & 31;
44 let minute = (data >> 20) & 63;
45 let second = (data >> 26) & 63;
46 SilkroadTime(
47 Utc.with_ymd_and_hms(year as i32, month, day, hours, minute, second)
48 .unwrap(),
49 )
50 }
51}
52
53impl Default for SilkroadTime {
54 fn default() -> Self {
55 SilkroadTime(Utc::now())
56 }
57}
58
59impl From<DateTime<Utc>> for SilkroadTime {
60 fn from(time: DateTime<Utc>) -> Self {
61 Self(time)
62 }
63}
64
65impl From<Duration> for SilkroadTime {
66 fn from(duration: Duration) -> Self {
67 let start = Utc.with_ymd_and_hms(2000, 1, 1, 0, 0, 0).unwrap();
68 let new = start.add(CDuration::from_std(duration).unwrap());
69 SilkroadTime(new)
70 }
71}
72
73impl Deref for SilkroadTime {
74 type Target = DateTime<Utc>;
75
76 fn deref(&self) -> &Self::Target {
77 &self.0
78 }
79}
80
81impl Serialize for SilkroadTime {
82 fn write_to(&self, writer: &mut BytesMut) {
83 self.as_u32().write_to(writer)
84 }
85}
86
87impl ByteSize for SilkroadTime {
88 fn byte_size(&self) -> usize {
89 4
90 }
91}
92
93impl Deserialize for SilkroadTime {
94 fn read_from<T: Read + ReadBytesExt>(reader: &mut T) -> Result<Self, SerializationError>
95 where
96 Self: Sized,
97 {
98 let data = reader.read_u32::<LittleEndian>()?;
99 Ok(SilkroadTime::from_u32(data))
100 }
101}
102
103impl<T: TimeZone> Serialize for DateTime<T> {
104 fn write_to(&self, writer: &mut BytesMut) {
105 let utc_time = self.to_utc();
106 writer.put_u16_le(utc_time.year() as u16);
107 writer.put_u16_le(utc_time.month() as u16);
108 writer.put_u16_le(utc_time.day() as u16);
109 writer.put_u16_le(utc_time.hour() as u16);
110 writer.put_u16_le(utc_time.minute() as u16);
111 writer.put_u16_le(utc_time.second() as u16);
112 writer.put_u32_le(utc_time.timestamp_millis() as u32);
113 }
114}
115
116impl<T: TimeZone> ByteSize for DateTime<T> {
117 fn byte_size(&self) -> usize {
118 16
119 }
120}
121
122impl Deserialize for DateTime<Utc> {
123 fn read_from<T: Read + ReadBytesExt>(reader: &mut T) -> Result<Self, SerializationError> {
124 let timestamp = Utc
125 .with_ymd_and_hms(
126 reader.read_u16::<LittleEndian>()? as i32,
127 reader.read_u16::<LittleEndian>()? as u32,
128 reader.read_u16::<LittleEndian>()? as u32,
129 reader.read_u16::<LittleEndian>()? as u32,
130 reader.read_u16::<LittleEndian>()? as u32,
131 reader.read_u16::<LittleEndian>()? as u32,
132 )
133 .unwrap();
134 Ok(timestamp + Duration::from_millis(reader.read_u32::<LittleEndian>()? as u64))
135 }
136}
137
138#[cfg(test)]
139mod test {
140 use super::*;
141
142 #[test]
143 pub fn test_convert_time() {
144 let one_year = 60 * 60 * 24 * 366u64;
145 let one_day = 60 * 60 * 24u64;
146
147 let time_now = Duration::from_secs(one_year + one_day + 35);
148 let sro_time = SilkroadTime::from(time_now);
149 let mut bytes = BytesMut::new();
150 sro_time.write_to(&mut bytes);
151 let written_bytes = bytes.freeze();
152
153 assert_eq!(written_bytes.len(), 4);
154
155 let lowest = written_bytes[0];
156 assert_eq!(lowest, 1); let second = written_bytes[1];
159 assert_eq!(second >> 2, 1); let highest = written_bytes[3];
162 assert_eq!(highest >> 2, 35);
163 }
164
165 #[test]
166 pub fn test_to_u32() {
167 let time = SilkroadTime::from(Utc.with_ymd_and_hms(2001, 10, 20, 14, 24, 40).unwrap());
168 let res = time.as_u32();
169 assert_eq!(res, 2709999169);
170 }
171
172 #[test]
173 pub fn test_convert_time_back() {
174 let time = SilkroadTime::from_u32(2709999169);
175 assert_eq!(time.year(), 2001);
176 assert_eq!(time.month(), 10);
177 assert_eq!(time.day(), 20);
178 assert_eq!(time.hour(), 14);
179 assert_eq!(time.minute(), 24);
180 assert_eq!(time.second(), 40);
181 }
182}