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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
use chrono::{DateTime, Datelike, Utc};
use diesel::{
backend::Backend,
deserialize::{self, FromSql, FromSqlRow},
expression::AsExpression,
serialize::{self, ToSql},
sql_types::Text,
sqlite::Sqlite,
};
use serde::{Deserialize, Serialize};
#[derive(
Eq,
PartialEq,
Ord,
PartialOrd,
Serialize,
Deserialize,
Copy,
Clone,
Debug,
AsExpression,
FromSqlRow,
)]
#[diesel(sql_type=Text)]
pub struct DateTimeUtc(DateTime<Utc>);
impl DateTimeUtc {
pub fn day_diff(&self, other: &DateTimeUtc) -> u32 {
self.0
.num_days_from_ce()
.abs_diff(other.0.num_days_from_ce())
}
pub fn to_day_str(&self) -> String {
self.0
.to_rfc3339()
.split_at_checked(10)
.map(|(day_str, _)| String::from(day_str))
.unwrap_or_else(|| String::from(""))
}
pub fn new(date_time_utc: DateTime<Utc>) -> Self {
Self(date_time_utc)
}
pub fn now() -> Self {
Self(Utc::now())
}
}
impl ToSql<Text, Sqlite> for DateTimeUtc {
fn to_sql<'b>(
&'b self,
out: &mut diesel::serialize::Output<'b, '_, Sqlite>,
) -> serialize::Result {
out.set_value(self.to_day_str());
Ok(diesel::serialize::IsNull::No)
}
}
impl FromSql<Text, Sqlite> for DateTimeUtc {
fn from_sql(bytes: <Sqlite as Backend>::RawValue<'_>) -> deserialize::Result<DateTimeUtc> {
let str: String = FromSql::<Text, Sqlite>::from_sql(bytes)?;
let date_time = str.as_str().parse::<DateTime<Utc>>()?;
Ok(DateTimeUtc(date_time))
}
}
#[cfg(test)]
mod test {
use chrono::TimeZone;
use super::*;
#[test]
fn given_midnight_when_day_diff_next_midnight_less_1s_then_return_0() {
let start = DateTimeUtc::new(Utc.with_ymd_and_hms(2000, 1, 1, 0, 0, 0).unwrap().to_utc());
let end = DateTimeUtc::new(
Utc.with_ymd_and_hms(2000, 1, 1, 23, 59, 59)
.unwrap()
.to_utc(),
);
let day_diff = start.day_diff(&end);
let neg_day_diff = end.day_diff(&start);
assert_eq!(day_diff, 0);
assert_eq!(day_diff, neg_day_diff);
}
#[test]
fn given_midnight_when_day_diff_next_midnight_then_return_1() {
let start = DateTimeUtc::new(Utc.with_ymd_and_hms(2000, 1, 1, 0, 0, 0).unwrap().to_utc());
let end = DateTimeUtc::new(Utc.with_ymd_and_hms(2000, 1, 2, 0, 0, 0).unwrap().to_utc());
let day_diff = start.day_diff(&end);
let neg_day_diff = end.day_diff(&start);
assert_eq!(day_diff, 1);
assert_eq!(day_diff, neg_day_diff);
}
#[test]
fn given_midnight_less_1s_when_day_diff_midnight_then_return_1() {
let start = DateTimeUtc::new(
Utc.with_ymd_and_hms(2000, 1, 1, 23, 59, 59)
.unwrap()
.to_utc(),
);
let end = DateTimeUtc::new(Utc.with_ymd_and_hms(2000, 1, 2, 0, 0, 0).unwrap().to_utc());
let day_diff = start.day_diff(&end);
let neg_day_diff = end.day_diff(&start);
assert_eq!(day_diff, 1);
assert_eq!(day_diff, neg_day_diff);
}
#[test]
fn given_23_nov_1970_when_to_day_str_then_return_iso_day_str() {
let date_time_utc = DateTimeUtc::new(
Utc.with_ymd_and_hms(1970, 11, 23, 0, 0, 0)
.unwrap()
.to_utc(),
);
let day_str = date_time_utc.to_day_str();
assert_eq!(day_str, "1970-11-23");
}
}
|