1use crate::{ATTOS_PER_SEC_I128, Dt, Scale};
2
3mod to_str;
4
5#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
34#[cfg_attr(feature = "js", derive(tsify::Tsify))]
35#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
36pub struct YmdHms {
37 pub(crate) yr: i64,
38 pub(crate) mo: u8,
39 pub(crate) day: u8,
40 pub(crate) hr: u8,
41 pub(crate) min: u8,
42 pub(crate) sec: u8, pub(crate) attos: u64, pub(crate) scale: Scale,
45}
46
47impl YmdHms {
48 #[inline]
50 pub fn to_dt(&self) -> Dt {
51 Dt::from_ymd(
52 self.yr, self.mo, self.day, self.hr, self.min, self.sec, self.attos, self.scale,
53 )
54 }
55
56 #[inline(always)]
57 fn reconstruct(
58 yr: i64,
59 mo: u8,
60 day: u8,
61 hr: u8,
62 min: u8,
63 sec: u8,
64 attos: u64,
65 scale: Scale,
66 ) -> Self {
67 Dt::from_ymd(yr, mo, day, hr, min, sec, attos, scale).to_ymd()
68 }
69
70 pub fn add_yr(&self, years: i64) -> Self {
73 if years == 0 {
74 return *self;
75 }
76 let new_yr = self.yr.saturating_add(years);
77 let max_day = Dt::days_in_month(new_yr, self.mo);
78 let new_day = Dt::clamp_u8(self.day, 1, max_day);
79 Self::reconstruct(
80 new_yr, self.mo, new_day, self.hr, self.min, self.sec, self.attos, self.scale,
81 )
82 }
83
84 pub fn add_mo(&self, months: i64) -> Self {
87 if months == 0 {
88 return *self;
89 }
90 let yr = self.yr as i128;
91 let mo = self.mo as i128;
92 let delta = months as i128;
93
94 let total_months = yr * 12 + (mo - 1) + delta;
95
96 let new_yr = Dt::i128_to_i64(total_months.div_euclid(12));
97 let new_mo = Dt::clamp_u8((total_months.rem_euclid(12) + 1) as u8, 1, 12);
98
99 let max_day = Dt::days_in_month(new_yr, new_mo);
100 let new_day = Dt::clamp_u8(self.day, 1, max_day);
101
102 Self::reconstruct(
103 new_yr, new_mo, new_day, self.hr, self.min, self.sec, self.attos, self.scale,
104 )
105 }
106
107 pub fn add_days(&self, days: i64) -> Self {
110 if days == 0 {
111 return *self;
112 }
113 let jd = Dt::ymd_to_jd(self.yr, self.mo, self.day);
114 let new_jd = jd.saturating_add(days);
115 let (new_yr, new_mo, new_day) = Dt::jd_to_ymd(new_jd);
116 Self::reconstruct(
117 new_yr, new_mo, new_day, self.hr, self.min, self.sec, self.attos, self.scale,
118 )
119 }
120
121 #[inline]
122 pub fn add_wk(&self, weeks: i64) -> Self {
123 self.add_days(weeks.saturating_mul(7))
124 }
125
126 #[inline(never)]
127 fn _add_attos(&self, attos_delta: i128) -> Self {
128 let tai = Dt::from_ymd(
129 self.yr, self.mo, self.day, self.hr, self.min, self.sec, self.attos, self.scale,
130 );
131 let new_tai = tai.add(Dt::span(attos_delta));
132 new_tai.to_ymd()
133 }
134
135 #[inline]
136 pub fn add_attos(&self, n: i128) -> Self {
137 self._add_attos(n)
138 }
139
140 #[inline]
141 pub fn add_sec(&self, n: i64) -> Self {
142 self._add_attos((n as i128).saturating_mul(ATTOS_PER_SEC_I128))
143 }
144
145 #[inline]
146 pub fn add_min(&self, n: i64) -> Self {
147 let delta = (n as i128)
148 .saturating_mul(60)
149 .saturating_mul(ATTOS_PER_SEC_I128);
150 self._add_attos(delta)
151 }
152
153 #[inline]
154 pub fn add_hr(&self, n: i64) -> Self {
155 let delta = (n as i128)
156 .saturating_mul(3600)
157 .saturating_mul(ATTOS_PER_SEC_I128);
158 self._add_attos(delta)
159 }
160
161 #[inline]
162 pub fn yr(&self) -> i64 {
163 self.yr
164 }
165
166 #[inline]
167 pub fn mo(&self) -> u8 {
168 self.mo
169 }
170
171 #[inline]
172 pub fn day(&self) -> u8 {
173 self.day
174 }
175
176 #[inline]
177 pub fn hr(&self) -> u8 {
178 self.hr
179 }
180
181 #[inline]
182 pub fn min(&self) -> u8 {
183 self.min
184 }
185
186 #[inline]
187 pub fn sec(&self) -> u8 {
188 self.sec
189 }
190
191 #[inline]
192 pub fn attos(&self) -> u64 {
193 self.attos
194 }
195
196 #[inline]
198 pub fn scale(&self) -> Scale {
199 self.scale
200 }
201
202 #[inline]
203 pub fn iso_yr(&self) -> i64 {
204 let (iso_yr, _, _) = Dt::_to_iso_wk_date(self.yr, self.mo, self.day);
205 iso_yr
206 }
207
208 #[inline]
209 pub fn iso_wk(&self) -> u8 {
210 let (_, iso_wk, _) = Dt::_to_iso_wk_date(self.yr, self.mo, self.day);
211 iso_wk
212 }
213
214 #[inline]
215 pub fn day_of_yr(&self) -> u16 {
216 Dt::_day_of_yr(self.yr, self.mo, self.day)
217 }
218
219 #[inline]
220 pub fn wkday(&self) -> u8 {
221 let jd = Dt::ymd_to_jd(self.yr, self.mo, self.day);
222 Dt::jd_to_wkday(jd)
223 }
224
225 #[inline]
226 pub fn wk_of_yr_sun(&self) -> u8 {
227 Dt::_wk_sun(self.yr, self.day_of_yr())
228 }
229
230 #[inline]
231 pub fn wk_of_yr_mon(&self) -> u8 {
232 Dt::_wk_mon(self.yr, self.day_of_yr())
233 }
234}