1use core::fmt;
2
3use chrono::*;
4use num::ToPrimitive;
5
6use crate::time::{CalendarDate, CalendarYearMonth, DayOfMonth, TimeOfDay};
7use crate::time::duration::Duration;
8
9#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Hash)]
11pub struct TimePoint(i64);
12
13impl From<i64> for TimePoint {
14 fn from(milliseconds: i64) -> Self {
15 TimePoint::new(milliseconds)
16 }
17}
18
19impl ToString for TimePoint {
20 fn to_string(&self) -> String {
21 Self::to_fmt_string_utc(self, "%Y/%m/%d %H:%M:%S")
22 }
23}
24
25impl<T> From<DateTime<T>> for TimePoint
26where
27 T: TimeZone,
28{
29 fn from(date_time: DateTime<T>) -> Self {
30 TimePoint::new(date_time.timestamp_millis())
31 }
32}
33
34impl<T> From<Date<T>> for TimePoint
35where
36 T: TimeZone,
37{
38 fn from(date: Date<T>) -> Self {
39 TimePoint::new(date.and_hms_milli(0, 0, 0, 0).timestamp_millis())
40 }
41}
42
43impl TimePoint {
44 pub fn new(milliseconds_from_epoc: i64) -> Self {
45 Self(milliseconds_from_epoc)
46 }
47
48 pub fn at_ymd_hms_milli_utc(
49 year: i32,
50 month: u32,
51 day: u32,
52 hour: u32,
53 minute: u32,
54 second: u32,
55 millisecond: u32,
56 ) -> Self {
57 Self::at_ymd_hms_milli_tz(year, month, day, hour, minute, second, millisecond, Utc)
58 }
59
60 pub fn at_ymd_hms_milli_tz<T>(
61 year: i32,
62 month: u32,
63 day: u32,
64 hour: u32,
65 minute: u32,
66 second: u32,
67 millisecond: u32,
68 time_zone: T,
69 ) -> Self
70 where
71 T: TimeZone,
72 {
73 let milliseconds_from_epoc = time_zone
74 .ymd(year, month, day)
75 .and_hms_milli(hour, minute, second, millisecond)
76 .timestamp_millis();
77 Self::new(milliseconds_from_epoc)
78 }
79
80 pub fn at_cym_dom_hms_milli_tz<T>(
81 year_month: CalendarYearMonth,
82 date: DayOfMonth,
83 hour: u32,
84 minute: u32,
85 second: u32,
86 millisecond: u32,
87 time_zone: T,
88 ) -> Self
89 where
90 T: TimeZone,
91 {
92 Self::at_ymd_hms_milli_tz(
93 year_month.to_year(),
94 year_month.to_month_u32(),
95 date.0.to_u32().unwrap(),
96 hour,
97 minute,
98 second,
99 millisecond,
100 time_zone,
101 )
102 }
103
104 pub fn at_midnight_cd_utc(calendar_date: CalendarDate) -> Self {
105 Self::at_midnight_cd_tz(calendar_date, Utc)
106 }
107
108 pub fn at_midnight_cd_tz<T>(calendar_date: CalendarDate, time_zone: T) -> Self
109 where
110 T: TimeZone,
111 {
112 Self::at_cym_dom_hms_milli_tz(
113 calendar_date.as_year_month().clone(),
114 calendar_date.as_day().clone(),
115 0,
116 0,
117 0,
118 0,
119 time_zone,
120 )
121 }
122
123 pub fn parse_utc(date_time_str: &str, pattern: &str) -> Result<TimePoint, ParseError> {
124 Self::parse_tz(date_time_str, pattern, Utc)
125 }
126
127 pub fn parse_tz<T>(date_time_str: &str, pattern: &str, time_zone: T) -> Result<Self, ParseError>
128 where
129 T: TimeZone,
130 {
131 let date_time = DateTime::parse_from_str(date_time_str, pattern)?.with_timezone(&time_zone);
132 Ok(TimePoint::from(date_time))
133 }
134
135 pub fn milliseconds_from_epoc(&self) -> i64 {
138 self.0
139 }
140
141 pub fn to_date_time_utc(&self) -> DateTime<Utc> {
142 self.to_date_time(Utc)
143 }
144
145 pub fn to_date_time<T>(&self, time_zone: T) -> DateTime<T>
146 where
147 T: TimeZone,
148 {
149 time_zone.timestamp_millis(self.0)
150 }
151
152 pub fn to_date_utc(&self) -> Date<Utc> {
153 self.to_date(Utc)
154 }
155
156 pub fn to_date<T>(&self, time_zone: T) -> Date<T>
157 where
158 T: TimeZone,
159 {
160 self.to_date_time(time_zone).date()
161 }
162
163 pub fn to_naive_date_time_utc(&self) -> NaiveDateTime {
164 self.to_naive_date_time(Utc)
165 }
166
167 pub fn to_naive_date_time<T>(&self, time_zone: T) -> NaiveDateTime
168 where
169 T: TimeZone,
170 {
171 let dt = self.to_naive_date(time_zone.clone());
172 let nt = self.to_naive_time(time_zone);
173 NaiveDateTime::new(dt, nt)
174 }
175
176 pub fn to_naive_time_utc(&self) -> NaiveTime {
177 self.to_naive_time(Utc)
178 }
179
180 pub fn to_naive_time<T>(&self, time_zone: T) -> NaiveTime
181 where
182 T: TimeZone,
183 {
184 let dt = self.to_date_time(time_zone);
185 NaiveTime::from_hms_milli(
186 dt.hour(),
187 dt.minute(),
188 dt.second(),
189 dt.nanosecond() * 1000000,
190 )
191 }
192
193 pub fn to_naive_date_utc(&self) -> NaiveDate {
194 self.to_naive_date(Utc)
195 }
196
197 pub fn to_naive_date<T>(&self, time_zone: T) -> NaiveDate
198 where
199 T: TimeZone,
200 {
201 let date = self.to_date(time_zone);
202 NaiveDate::from_ymd(date.year(), date.month(), date.day())
203 }
204
205 pub fn into_calendar_date_utc(self) -> CalendarDate {
206 self.into_calendar_date(Utc)
207 }
208
209 pub fn into_calendar_date<T>(self, time_zone: T) -> CalendarDate
210 where
211 T: TimeZone,
212 {
213 CalendarDate::from((self, time_zone))
214 }
215
216 pub fn to_time_of_day_utc(&self) -> TimeOfDay {
217 self.to_time_of_day(Utc)
218 }
219
220 pub fn to_time_of_day<T>(&self, time_zone: T) -> TimeOfDay
221 where
222 T: TimeZone,
223 {
224 let dt = self.to_date_time(time_zone);
225 TimeOfDay::from((dt.hour(), dt.minute()))
226 }
227
228 pub fn add(self, duration: Duration) -> Self {
229 duration.added_to(self)
230 }
231
232 pub fn subtract(self, duration: Duration) -> Self {
233 duration.subtracted_from(self)
234 }
235
236 pub fn next_day(self) -> Self {
237 self.add(Duration::days(1))
238 }
239
240 pub fn is_after(&self, other: &Self) -> bool {
241 !self.is_before(other) && self != other
242 }
243
244 pub fn is_before(&self, other: &Self) -> bool {
245 self.0 < other.0
246 }
247
248 pub fn is_same_day_as_utc(&self, other: &Self) -> bool {
249 self.is_same_day_as(other, Utc)
250 }
251
252 pub fn is_same_day_as<T>(&self, other: &Self, time_zone: T) -> bool
253 where
254 T: TimeZone,
255 {
256 self.clone().into_calendar_date(time_zone.clone())
257 == other.clone().into_calendar_date(time_zone)
258 }
259
260 fn to_fmt_string_utc(&self, fmt: &str) -> String {
261 self.to_fmt_string(fmt, Utc)
262 }
263
264 fn to_fmt_string<Tz: TimeZone>(&self, fmt: &str, time_zone: Tz) -> String
265 where
266 Tz::Offset: fmt::Display,
267 {
268 self.to_date_time(time_zone).format(fmt).to_string()
269 }
270}
271
272#[cfg(test)]
273mod tests {
274 use chrono::Utc;
275
276 use crate::time::{TimeOfDay, TimePoint};
277
278 #[test]
279 fn from_from_date_time() {
280 let date_time = Utc::now();
281 let tp = TimePoint::from(date_time);
282 assert_eq!(
283 tp.to_date_time_utc().timestamp_millis(),
284 date_time.timestamp_millis()
285 )
286 }
287
288 #[test]
289 fn _at_ymd_milli() {
290 let tp1 = TimePoint::new(1262304000000);
291 let tp2 = TimePoint::at_ymd_hms_milli_utc(2010, 1, 1, 0, 0, 0, 0);
292 assert_eq!(tp2, tp1)
293 }
294
295 #[test]
296 fn to_time_of_day() {
297 let tp1 = TimePoint::at_ymd_hms_milli_utc(2010, 1, 1, 0, 0, 0, 0);
298 let tod = TimeOfDay::from((0, 0));
299 assert_eq!(tp1.to_time_of_day_utc(), tod)
300 }
301
302 #[test]
303 fn is_same_day_as() {
304 let tp1 = TimePoint::at_ymd_hms_milli_utc(2010, 1, 1, 0, 0, 0, 0);
305 let tp2 = TimePoint::at_ymd_hms_milli_utc(2010, 1, 1, 23, 59, 59, 0);
306 assert!(tp1.is_same_day_as_utc(&tp2))
307 }
308
309 #[test]
310 fn to_string() {
311 let tp1 = TimePoint::at_ymd_hms_milli_utc(2010, 1, 1, 23, 59, 59, 0);
312 println!("{}", ToString::to_string(&tp1));
313 }
314}