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
use super::Object;
#[cfg(feature = "chrono_time")]
use chrono::prelude::*;
#[cfg(not(feature = "chrono_time"))]
use time::strptime;
use time::{strftime, Tm};
const TIME_FMT_DECODE_STR: &str = "%Y%m%d%H%M%S%z";
#[cfg(feature = "chrono_time")]
impl From<DateTime<Local>> for Object {
fn from(date: DateTime<Local>) -> Self {
let mut timezone_str = date.format("D:%Y%m%d%H%M%S%:z'").to_string().into_bytes();
convert_utc_offset(&mut timezone_str);
Object::string_literal(timezone_str)
}
}
fn convert_utc_offset(bytes: &mut [u8]) {
let mut index = bytes.len();
while let Some(last) = bytes[..index].last_mut() {
if *last == b':' {
*last = b'\'';
break;
}
index -= 1;
}
}
#[cfg(feature = "chrono_time")]
impl From<DateTime<UTC>> for Object {
fn from(date: DateTime<UTC>) -> Self {
Object::string_literal(date.format("D:%Y%m%d%H%M%SZ").to_string())
}
}
impl From<Tm> for Object {
fn from(date: Tm) -> Self {
Object::string_literal(if date.tm_utcoff != 0 {
let timezone = strftime("%z", &date).unwrap();
let timezone_str_start = strftime("%Y%m%d%H%M%S", &date).unwrap();
let mut timezone_str = format!("D:{}{}:{}'", timezone_str_start, &timezone[..3], &timezone[3..]).into_bytes();
convert_utc_offset(&mut timezone_str);
timezone_str
} else {
format!("D:{}", strftime("%Y%m%d%H%M%SZ", &date).unwrap()).into_bytes()
})
}
}
impl Object {
fn datetime_string(&self) -> Option<String> {
if let Object::String(ref bytes, _) = self {
String::from_utf8(bytes.iter().filter(|b| ![b'D', b':', b'\''].contains(b)).cloned().collect()).ok()
} else {
None
}
}
#[cfg(feature = "chrono_time")]
pub fn as_datetime(&self) -> Option<DateTime<Local>> {
let text = self.datetime_string()?;
Local.datetime_from_str(&text, TIME_FMT_DECODE_STR).ok()
}
#[cfg(not(feature = "chrono_time"))]
pub fn as_datetime(&self) -> Option<Tm> {
let text = self.datetime_string()?;
strptime(&text, TIME_FMT_DECODE_STR).ok()
}
}
#[cfg(feature = "chrono_time")]
#[test]
fn parse_datetime() {
let time = Local::now().with_nanosecond(0).unwrap();
let text: Object = time.into();
let time2 = text.as_datetime();
assert_eq!(time2, Some(time));
}
#[cfg(not(feature = "chrono_time"))]
#[test]
fn parse_datetime() {
let time = Tm {
tm_wday: 0,
tm_yday: 0,
tm_isdst: 0,
tm_nsec: 0,
..::time::now()
};
let text: Object = time.into();
let time2 = text.as_datetime();
assert_eq!(time2, Some(time));
}