baseunits_rs/time/
calendar_date.rs1use chrono::{Date, Datelike, DateTime, TimeZone, Utc};
2use num::FromPrimitive;
3use time::Duration as OldDuration;
4
5use crate::time::{CalendarYearMonth, DayOfMonth, DayOfWeek, TimePoint};
6use std::ops::{Sub, Add};
7
8#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Hash)]
9pub struct CalendarDate {
10 year_month: CalendarYearMonth,
11 day: DayOfMonth,
12}
13
14impl ToString for CalendarDate {
15 fn to_string(&self) -> String {
16 unimplemented!()
17 }
18}
19
20impl<T> From<Date<T>> for CalendarDate
21where
22 T: TimeZone,
23{
24 fn from(value: Date<T>) -> Self {
25 let dt: DateTime<T> = value.and_hms_milli(0, 0, 0, 0);
26 Self::from(dt)
27 }
28}
29
30impl<T> From<DateTime<T>> for CalendarDate
31where
32 T: TimeZone,
33{
34 fn from(value: DateTime<T>) -> Self {
35 let cym = CalendarYearMonth::from((value.year(), value.month()));
36 let dom = DayOfMonth::new(value.day());
37 CalendarDate::new(cym, dom)
38 }
39}
40
41impl From<TimePoint> for CalendarDate {
42 fn from(time_point: TimePoint) -> Self {
43 Self::from((time_point, Utc))
44 }
45}
46
47impl<T: TimeZone> From<(TimePoint, T)> for CalendarDate {
48 fn from((time_point, time_zone): (TimePoint, T)) -> Self {
49 let date_time = time_point.to_date_time(time_zone);
50 let cym = CalendarYearMonth::from((date_time.year(), date_time.month()));
51 let dom = DayOfMonth::new(date_time.day());
52 CalendarDate::new(cym, dom)
53 }
54}
55
56impl From<(CalendarYearMonth, DayOfMonth)> for CalendarDate {
57 fn from((year_month, day): (CalendarYearMonth, DayOfMonth)) -> Self {
58 Self::new(year_month, day)
59 }
60}
61
62impl From<(i32, u32, u32)> for CalendarDate {
63 fn from((year, month, day): (i32, u32, u32)) -> Self {
64 let cym = CalendarYearMonth::from((year, month));
65 let dom = DayOfMonth::new(day);
66 Self::new(cym, dom)
67 }
68}
69
70impl CalendarDate {
71 pub fn new(year_month: CalendarYearMonth, day: DayOfMonth) -> Self {
73 Self { year_month, day }
74 }
75
76 pub fn as_year_month(&self) -> &CalendarYearMonth {
77 &self.year_month
78 }
79
80 pub fn to_year_month(&self) -> CalendarYearMonth {
81 self.year_month.clone()
82 }
83
84 pub fn as_day(&self) -> &DayOfMonth {
85 &self.day
86 }
87
88 pub fn to_day(&self) -> DayOfMonth {
89 self.day.clone()
90 }
91
92 pub fn to_date_time_on_midnight_at_utc(&self) -> DateTime<Utc> {
93 self.to_date_time_on_midnight(Utc)
94 }
95
96 pub fn to_date_time_on_midnight<T: TimeZone>(&self, time_zone: T) -> DateTime<T> {
97 time_zone
98 .ymd(
99 self.year_month.to_year(),
100 self.year_month.to_month_u32(),
101 self.day.0,
102 )
103 .and_hms_milli(0, 0, 0, 0)
104 }
105
106 pub fn day_of_week_at_utc(&self) -> DayOfWeek {
107 self.day_of_week(Utc)
108 }
109
110 pub fn day_of_week<T: TimeZone>(&self, time_zone: T) -> DayOfWeek {
111 let no = self
112 .to_date_time_on_midnight(time_zone)
113 .date()
114 .weekday()
115 .number_from_monday();
116 DayOfWeek::from_u32(no).unwrap()
117 }
118
119 pub fn add_days<T>(&self, days: i64, time_zone: T) -> Self
120 where
121 T: TimeZone,
122 {
123 let date_time = self.to_date_time_on_midnight(time_zone);
124 let new_date_time = date_time.add(OldDuration::days(days));
125 Self::from(new_date_time)
126 }
127
128 pub fn subtract_days<T>(&self, days: i64, time_zone: T) -> Self
129 where
130 T: TimeZone,
131 {
132 let date_time = self.to_date_time_on_midnight(time_zone);
133 let new_date_time = date_time.sub(OldDuration::days(days));
134 Self::from(new_date_time)
135 }
136
137 pub fn subtract_months<T>(&self, months: i64, time_zone: T) -> Self
138 where
139 T: TimeZone,
140 {
141 let date_time = self.to_date_time_on_midnight(time_zone);
142 let new_date_time = date_time - OldDuration::days(30 * months);
143 Self::from(new_date_time)
144 }
145
146 pub fn add_months<T>(&self, months: i64, time_zone: T) -> Self
147 where
148 T: TimeZone,
149 {
150 let date_time = self.to_date_time_on_midnight(time_zone);
151 let new_date_time = date_time + OldDuration::days(30 * months);
152 Self::from(new_date_time)
153 }
154
155 pub fn is_after(&self, other: &Self) -> bool {
156 !self.is_before(other) && self != other
157 }
158
159 pub fn is_before(&self, other: &Self) -> bool {
160 if self.year_month.is_before(&other.year_month) {
161 true
162 } else if self.year_month.is_after(&other.year_month) {
163 false
164 } else {
165 self.day.is_before(&other.day)
166 }
167 }
168}