deep_time/gregorian_time/
mod.rs1use crate::{AsciiStr, Dt, Weekday};
2
3mod to_str;
4
5#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
7pub struct YmdHms {
8 pub yr: i64,
9 pub mo: u8,
10 pub day: u8,
11 pub hr: u8,
12 pub min: u8,
13 pub sec: u8, pub attos: u64, pub unix_attosec: i128,
16}
17
18#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
20#[cfg_attr(feature = "js", derive(tsify::Tsify))]
21#[derive(Clone, Copy, Debug, PartialEq, Eq)]
22pub struct GregorianTime {
23 pub(crate) unix_attosec: i128,
25 pub(crate) yr: i64,
27 pub(crate) mo: u8,
29 pub(crate) day: u8,
31 pub(crate) hr: u8,
33 pub(crate) min: u8,
35 pub(crate) sec: u8,
37 pub(crate) attos: u64,
39 pub(crate) iso_yr: i64,
41 pub(crate) iso_wk: u8,
43 pub(crate) iso_wkday: Weekday,
45 pub(crate) day_of_yr: u16,
47 pub(crate) wkday: u8,
49 pub(crate) wk_of_yr_sun: u8,
51 pub(crate) wk_of_yr_mon: u8,
53 pub(crate) offset_sec: Option<i32>,
56 pub(crate) tz: Option<AsciiStr<49>>,
58 pub(crate) tz_abbrev: Option<AsciiStr<49>>,
60}
61
62impl GregorianTime {
63 #[inline]
67 pub const fn new(
68 unix_attosec: i128,
69 yr: i64,
70 mo: u8,
71 day: u8,
72 hr: u8,
73 min: u8,
74 sec: u8,
75 attos: u64,
76 iso_yr: i64,
77 iso_wk: u8,
78 iso_wkday: Weekday,
79 day_of_yr: u16,
80 wkday: u8,
81 wk_of_yr_sun: u8,
82 wk_of_yr_mon: u8,
83 ) -> Self {
84 Self {
85 unix_attosec,
86 yr,
87 mo,
88 day,
89 hr,
90 min,
91 sec,
92 attos,
93 iso_yr,
94 iso_wk,
95 iso_wkday,
96 day_of_yr,
97 wkday,
98 wk_of_yr_sun,
99 wk_of_yr_mon,
100 offset_sec: None,
101 tz: None,
102 tz_abbrev: None,
103 }
104 }
105
106 #[inline]
108 pub const fn unix_attosec(&self) -> i128 {
109 self.unix_attosec
110 }
111
112 #[inline]
118 pub const fn unix_timestamp(&self) -> (i64, u64) {
119 const ATTOS_PER_SEC_I128: i128 = 1_000_000_000_000_000_000;
120 let total = self.unix_attosec;
121 let secs = (total / ATTOS_PER_SEC_I128) as i64;
122 let frac = (total % ATTOS_PER_SEC_I128).unsigned_abs() as u64;
123 (secs, frac)
124 }
125
126 #[inline]
128 pub const fn yr(&self) -> i64 {
129 self.yr
130 }
131
132 #[inline]
134 pub const fn mo(&self) -> u8 {
135 self.mo
136 }
137
138 #[inline]
140 pub const fn day(&self) -> u8 {
141 self.day
142 }
143
144 #[inline]
146 pub const fn hr(&self) -> u8 {
147 self.hr
148 }
149
150 #[inline]
152 pub const fn min(&self) -> u8 {
153 self.min
154 }
155
156 #[inline]
158 pub const fn sec(&self) -> u8 {
159 self.sec
160 }
161
162 #[inline]
164 pub const fn attos(&self) -> u64 {
165 self.attos
166 }
167
168 #[inline]
170 pub const fn iso_yr(&self) -> i64 {
171 self.iso_yr
172 }
173
174 #[inline]
176 pub const fn iso_wk(&self) -> u8 {
177 self.iso_wk
178 }
179
180 #[inline]
182 pub const fn iso_wkday(&self) -> Weekday {
183 self.iso_wkday
184 }
185
186 #[inline]
188 pub const fn day_of_yr(&self) -> u16 {
189 self.day_of_yr
190 }
191
192 #[inline]
194 pub const fn wkday_sun(&self) -> u8 {
195 self.wkday
196 }
197
198 #[inline]
200 pub const fn wkday_mon(&self) -> u8 {
201 self.iso_wkday.wk_mon()
202 }
203
204 #[inline]
206 pub const fn wk_of_yr_sun(&self) -> u8 {
207 self.wk_of_yr_sun
208 }
209
210 #[inline]
212 pub const fn wk_of_yr_mon(&self) -> u8 {
213 self.wk_of_yr_mon
214 }
215
216 #[inline]
217 pub const fn offset_sec(&self) -> Option<i32> {
218 self.offset_sec
219 }
220
221 #[inline]
222 pub const fn tz(&self) -> Option<&AsciiStr<49>> {
223 self.tz.as_ref()
224 }
225
226 #[inline]
227 pub const fn tz_abbrev(&self) -> Option<&AsciiStr<49>> {
228 self.tz_abbrev.as_ref()
229 }
230
231 #[inline]
232 pub(crate) fn set_offset(&mut self, offset_sec: Option<i32>) -> &mut Self {
233 self.offset_sec = offset_sec;
234 self
235 }
236
237 #[inline]
238 pub(crate) fn set_tz(&mut self, tz: Option<&str>) -> &mut Self {
239 self.tz = tz.and_then(|s| AsciiStr::try_from_str(s).ok());
240 self
241 }
242
243 #[inline]
244 pub(crate) fn set_tz_abbrev(&mut self, tz_abbrev: Option<&str>) -> &mut Self {
245 self.tz_abbrev = tz_abbrev.and_then(|s| AsciiStr::try_from_str(s).ok());
246 self
247 }
248
249 #[inline]
253 pub const fn to_dt(&self) -> Dt {
254 Dt::from_ymdhms(self.yr, self.mo, self.day, self.hr, self.min, self.sec, 0)
255 }
256}
257
258#[cfg(feature = "wire")]
259impl GregorianTime {
260 pub const WIRE_VERSION: u8 = 1;
262
263 pub const WIRE_SIZE: usize = 158;
265
266 pub fn to_wire_bytes(&self) -> [u8; Self::WIRE_SIZE] {
284 let mut buf = [0u8; Self::WIRE_SIZE];
285 buf[0] = Self::WIRE_VERSION;
286 let mut offset = 1usize;
287
288 buf[offset..offset + 16].copy_from_slice(&self.unix_attosec.to_le_bytes());
290 offset += 16;
291
292 buf[offset..offset + 8].copy_from_slice(&self.yr.to_le_bytes());
294 offset += 8;
295
296 buf[offset] = self.mo;
298 offset += 1;
299 buf[offset] = self.day;
300 offset += 1;
301 buf[offset] = self.hr;
302 offset += 1;
303 buf[offset] = self.min;
304 offset += 1;
305 buf[offset] = self.sec;
306 offset += 1;
307
308 buf[offset..offset + 8].copy_from_slice(&self.attos.to_le_bytes());
310 offset += 8;
311
312 buf[offset..offset + 8].copy_from_slice(&self.iso_yr.to_le_bytes());
314 offset += 8;
315
316 buf[offset] = self.iso_wk;
318 offset += 1;
319 buf[offset] = self.iso_wkday.to_wire_byte();
320 offset += 1;
321
322 buf[offset..offset + 2].copy_from_slice(&self.day_of_yr.to_le_bytes());
324 offset += 2;
325
326 buf[offset] = self.wkday;
328 offset += 1;
329
330 buf[offset] = self.wk_of_yr_sun;
332 offset += 1;
333 buf[offset] = self.wk_of_yr_mon;
334 offset += 1;
335
336 if let Some(val) = self.offset_sec {
338 buf[offset] = 1;
339 buf[offset + 1..offset + 5].copy_from_slice(&val.to_le_bytes());
340 } else {
341 buf[offset] = 0;
342 }
343 offset += 5;
344
345 if let Some(tz) = &self.tz {
347 buf[offset] = 1;
348 let tz_bytes = tz.to_wire_bytes();
349 buf[offset + 1..offset + 1 + AsciiStr::<49>::WIRE_SIZE].copy_from_slice(&tz_bytes);
350 } else {
351 buf[offset] = 0;
352 }
353 offset += 1 + AsciiStr::<49>::WIRE_SIZE;
354
355 if let Some(abbrev) = &self.tz_abbrev {
357 buf[offset] = 1;
358 let abbrev_bytes = abbrev.to_wire_bytes();
359 buf[offset + 1..offset + 1 + AsciiStr::<49>::WIRE_SIZE].copy_from_slice(&abbrev_bytes);
360 } else {
361 buf[offset] = 0;
362 }
363
364 buf
365 }
366
367 pub fn from_wire_bytes(bytes: &[u8]) -> Option<Self> {
376 if bytes.len() != Self::WIRE_SIZE {
377 return None;
378 }
379 if bytes[0] != Self::WIRE_VERSION {
380 return None;
381 }
382
383 let mut offset = 1usize;
384
385 let unix_attosec = i128::from_le_bytes(bytes[offset..offset + 16].try_into().ok()?);
387 offset += 16;
388
389 let yr = i64::from_le_bytes(bytes[offset..offset + 8].try_into().ok()?);
391 offset += 8;
392
393 let mo = bytes[offset];
395 offset += 1;
396 let day = bytes[offset];
397 offset += 1;
398 let hr = bytes[offset];
399 offset += 1;
400 let min = bytes[offset];
401 offset += 1;
402 let sec = bytes[offset];
403 offset += 1;
404
405 let attos = u64::from_le_bytes(bytes[offset..offset + 8].try_into().ok()?);
407 offset += 8;
408
409 let iso_yr = i64::from_le_bytes(bytes[offset..offset + 8].try_into().ok()?);
411 offset += 8;
412
413 let iso_wk = bytes[offset];
415 offset += 1;
416 let iso_wkday = Weekday::from_wire_byte(bytes[offset])?;
417 offset += 1;
418
419 let day_of_yr = u16::from_le_bytes(bytes[offset..offset + 2].try_into().ok()?);
421 offset += 2;
422
423 let wkday = bytes[offset];
425 offset += 1;
426
427 let wk_of_yr_sun = bytes[offset];
429 offset += 1;
430 let wk_of_yr_mon = bytes[offset];
431 offset += 1;
432
433 let offset_sec = if bytes[offset] == 1 {
435 Some(i32::from_le_bytes(
436 bytes[offset + 1..offset + 5].try_into().ok()?,
437 ))
438 } else {
439 None
440 };
441 offset += 5;
442
443 let tz = if bytes[offset] == 1 {
445 AsciiStr::<49>::from_wire_bytes(
446 &bytes[offset + 1..offset + 1 + AsciiStr::<49>::WIRE_SIZE],
447 )
448 } else {
449 None
450 };
451 offset += 1 + AsciiStr::<49>::WIRE_SIZE;
452
453 let tz_abbrev = if bytes[offset] == 1 {
455 AsciiStr::<49>::from_wire_bytes(
456 &bytes[offset + 1..offset + 1 + AsciiStr::<49>::WIRE_SIZE],
457 )
458 } else {
459 None
460 };
461
462 Some(Self {
463 unix_attosec,
464 yr,
465 mo,
466 day,
467 hr,
468 min,
469 sec,
470 attos,
471 iso_yr,
472 iso_wk,
473 iso_wkday,
474 day_of_yr,
475 wkday,
476 wk_of_yr_sun,
477 wk_of_yr_mon,
478 offset_sec,
479 tz,
480 tz_abbrev,
481 })
482 }
483}