1use chrono::{NaiveTime, Timelike};
2use tea_error::{TError, TResult};
3
4use crate::convert::*;
5#[repr(transparent)]
11#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
12#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
13pub struct Time(pub i64);
14
15impl Time {
16 #[inline]
18 pub const fn from_i64(nanos: i64) -> Self {
19 Self(nanos)
20 }
21
22 #[inline]
26 pub const fn is_nat(&self) -> bool {
27 self.0 == i64::MIN
28 }
29
30 #[inline]
34 pub const fn is_not_nat(&self) -> bool {
35 self.0 != i64::MIN
36 }
37
38 #[inline]
40 pub const fn nat() -> Self {
41 Self(i64::MIN)
42 }
43
44 #[inline]
46 pub const fn into_i64(self) -> i64 {
47 self.0
48 }
49
50 #[inline]
52 pub fn from_cr(cr: &NaiveTime) -> Self {
53 Self(cr.num_seconds_from_midnight() as i64 * NANOS_PER_SEC + cr.nanosecond() as i64)
54 }
55
56 #[inline]
58 pub const fn as_cr(&self) -> Option<NaiveTime> {
59 use NANOS_PER_SEC;
60 let secs = self.0 / NANOS_PER_SEC;
61 let nanos = self.0 % NANOS_PER_SEC;
62 NaiveTime::from_num_seconds_from_midnight_opt(secs as u32, nanos as u32)
63 }
64
65 #[inline]
67 pub const fn from_hms(hour: i64, min: i64, sec: i64) -> Self {
68 let secs = hour * SECS_PER_HOUR + min * SECS_PER_MINUTE + sec;
69 let nanos = secs * NANOS_PER_SEC;
70 Self(nanos)
71 }
72
73 #[inline]
75 pub const fn from_hms_milli(hour: i64, min: i64, sec: i64, milli: i64) -> Self {
76 let mut time = Self::from_hms(hour, min, sec);
77 let nanos = milli * NANOS_PER_MILLI;
78 time.0 += nanos;
79 time
80 }
81
82 #[inline]
84 pub const fn from_hms_micro(hour: i64, min: i64, sec: i64, micro: i64) -> Self {
85 let mut time = Self::from_hms(hour, min, sec);
86 let nanos = micro * NANOS_PER_MICRO;
87 time.0 += nanos;
88 time
89 }
90
91 #[inline]
93 pub const fn from_hms_nano(hour: i64, min: i64, sec: i64, nano: i64) -> Self {
94 let mut time = Self::from_hms(hour, min, sec);
95 time.0 += nano;
96 time
97 }
98
99 #[inline]
101 pub const fn from_num_seconds_from_midnight(secs: i64, nano: i64) -> Self {
102 let nanos = secs * NANOS_PER_SEC + nano;
103 Self(nanos)
104 }
105
106 #[inline]
110 pub fn parse(s: &str, fmt: Option<&str>) -> TResult<Self> {
111 let naive_time = if let Some(fmt) = fmt {
112 NaiveTime::parse_from_str(s, fmt)
113 } else {
114 s.parse()
115 }
116 .map_err(|e| TError::ParseError(e.to_string().into()))?;
117 Ok(Time(
118 naive_time.num_seconds_from_midnight() as i64 * NANOS_PER_SEC
119 + naive_time.nanosecond() as i64,
120 ))
121 }
122}
123
124#[cfg(test)]
125mod tests {
126 use super::*;
127
128 #[test]
129 fn test_from_hms() {
130 let time = Time::from_hms(12, 34, 56);
131 assert_eq!(time.0, (12 * 3600 + 34 * 60 + 56) * NANOS_PER_SEC);
132 }
133
134 #[test]
135 fn test_from_hms_milli() {
136 let time = Time::from_hms_milli(12, 34, 56, 789);
137 assert_eq!(
138 time.0,
139 (12 * 3600 + 34 * 60 + 56) * NANOS_PER_SEC + 789 * NANOS_PER_MILLI
140 );
141 }
142
143 #[test]
144 fn test_from_hms_micro() {
145 let time = Time::from_hms_micro(12, 34, 56, 789);
146 assert_eq!(
147 time.0,
148 (12 * 3600 + 34 * 60 + 56) * NANOS_PER_SEC + 789 * NANOS_PER_MICRO
149 );
150 }
151
152 #[test]
153 fn test_from_hms_nano() {
154 let time = Time::from_hms_nano(12, 34, 56, 789);
155 assert_eq!(time.0, (12 * 3600 + 34 * 60 + 56) * NANOS_PER_SEC + 789);
156 }
157
158 #[test]
159 fn test_from_num_seconds_from_midnight() {
160 let time = Time::from_num_seconds_from_midnight(45296, 789);
161 assert_eq!(time.0, 45296 * NANOS_PER_SEC + 789);
162 }
163
164 #[test]
165 fn test_parse() {
166 let time = Time::parse("12:34:56", None).unwrap();
167 assert_eq!(time.0, (12 * 3600 + 34 * 60 + 56) * NANOS_PER_SEC);
168
169 let time = Time::parse("12:34:56.789", Some("%H:%M:%S%.3f")).unwrap();
170 assert_eq!(
171 time.0,
172 (12 * 3600 + 34 * 60 + 56) * NANOS_PER_SEC + 789 * NANOS_PER_MILLI
173 );
174
175 assert!(Time::parse("invalid", None).is_err());
176 }
177}