1use crate::{ATTOS_PER_SEC, Dt, GregorianTime, Scale};
2
3mod arithmetic;
4mod constructors;
5mod formatting;
6mod from_str;
7mod ops;
8pub mod time_units;
9
10#[cfg(feature = "alloc")]
11mod to_str;
12
13#[cfg(feature = "hifitime")]
14mod from_hifitime;
15#[cfg(feature = "hifitime")]
16mod to_hifitime;
17
18#[cfg(feature = "chrono")]
19mod from_chrono;
20#[cfg(feature = "chrono")]
21mod to_chrono;
22
23#[cfg(feature = "jiff")]
24mod from_jiff;
25#[cfg(feature = "jiff")]
26mod to_jiff;
27
28#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
36#[cfg_attr(feature = "js", derive(tsify::Tsify))]
37#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
38pub struct TSpan {
39 pub sec: i64,
41 pub attos: u64,
43}
44
45impl TSpan {
46 #[inline]
48 pub const fn sec(&self) -> i64 {
49 self.sec
50 }
51
52 #[inline]
54 pub const fn attos(&self) -> u64 {
55 self.attos
56 }
57
58 #[inline]
60 pub const fn carry_over(&mut self) -> &mut Self {
61 if self.attos >= ATTOS_PER_SEC {
62 self.sec += (self.attos / ATTOS_PER_SEC) as i64;
63 self.attos %= ATTOS_PER_SEC;
64 }
65 self
66 }
67
68 #[inline]
69 pub const fn to_tai(&self, current: Scale) -> Dt {
70 Dt::from(self.sec, self.attos, current)
71 }
72
73 #[inline]
74 pub const fn to(&self, current: Scale, target: Scale) -> TSpan {
75 Dt::from(self.sec, self.attos, current).to(target)
76 }
77
78 #[inline]
79 pub const fn to_gregorian_time(&self, current: Scale) -> GregorianTime {
80 Dt::from(self.sec, self.attos, current).to_gregorian_time()
81 }
82
83 #[inline]
84 pub const fn to_epoch(&self, epoch: Dt, current: Scale) -> Self {
85 Dt::from(self.sec, self.attos, current).to_epoch(epoch, current)
86 }
87}
88
89impl Default for TSpan {
90 fn default() -> Self {
91 Self::ZERO
92 }
93}
94
95#[cfg(feature = "wire")]
96impl TSpan {
97 pub const WIRE_VERSION: u8 = 1;
99
100 pub const WIRE_SIZE: usize = 17;
102
103 pub fn to_wire_bytes(&self) -> [u8; Self::WIRE_SIZE] {
111 let mut buf = [0u8; Self::WIRE_SIZE];
112 buf[0] = Self::WIRE_VERSION;
113 buf[1..9].copy_from_slice(&self.sec.to_le_bytes());
114 buf[9..17].copy_from_slice(&self.attos.to_le_bytes());
115 buf
116 }
117
118 pub fn from_wire_bytes(bytes: &[u8]) -> Option<Self> {
130 if bytes.len() != Self::WIRE_SIZE {
131 return None;
132 }
133
134 if bytes[0] != Self::WIRE_VERSION {
136 return None;
137 }
138
139 let sec = i64::from_le_bytes([
140 bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7], bytes[8],
141 ]);
142 let attos = u64::from_le_bytes([
143 bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15], bytes[16],
144 ]);
145
146 Some(Self::new(sec, attos))
147 }
148}