baseunits_rs/time/
time_point.rs

1use core::fmt;
2
3use chrono::*;
4use num::ToPrimitive;
5
6use crate::time::{CalendarDate, CalendarYearMonth, DayOfMonth, TimeOfDay};
7use crate::time::duration::Duration;
8
9/// TimePoint
10#[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  // ---
136
137  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}