surrealdb_core/sql/
duration.rs1use crate::sql::datetime::Datetime;
2use crate::sql::strand::Strand;
3use crate::syn;
4use revision::revisioned;
5use serde::{Deserialize, Serialize};
6use std::fmt;
7use std::iter::Sum;
8use std::ops;
9use std::ops::Deref;
10use std::str::FromStr;
11use std::time;
12
13pub(crate) static SECONDS_PER_YEAR: u64 = 365 * SECONDS_PER_DAY;
14pub(crate) static SECONDS_PER_WEEK: u64 = 7 * SECONDS_PER_DAY;
15pub(crate) static SECONDS_PER_DAY: u64 = 24 * SECONDS_PER_HOUR;
16pub(crate) static SECONDS_PER_HOUR: u64 = 60 * SECONDS_PER_MINUTE;
17pub(crate) static SECONDS_PER_MINUTE: u64 = 60;
18pub(crate) static NANOSECONDS_PER_MILLISECOND: u32 = 1000000;
19pub(crate) static NANOSECONDS_PER_MICROSECOND: u32 = 1000;
20
21pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Duration";
22
23#[revisioned(revision = 1)]
24#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
25#[serde(rename = "$surrealdb::private::sql::Duration")]
26#[non_exhaustive]
27pub struct Duration(pub time::Duration);
28
29impl From<time::Duration> for Duration {
30 fn from(v: time::Duration) -> Self {
31 Self(v)
32 }
33}
34
35impl From<Duration> for time::Duration {
36 fn from(s: Duration) -> Self {
37 s.0
38 }
39}
40
41impl FromStr for Duration {
42 type Err = ();
43 fn from_str(s: &str) -> Result<Self, Self::Err> {
44 Self::try_from(s)
45 }
46}
47
48impl TryFrom<String> for Duration {
49 type Error = ();
50 fn try_from(v: String) -> Result<Self, Self::Error> {
51 Self::try_from(v.as_str())
52 }
53}
54
55impl TryFrom<Strand> for Duration {
56 type Error = ();
57 fn try_from(v: Strand) -> Result<Self, Self::Error> {
58 Self::try_from(v.as_str())
59 }
60}
61
62impl TryFrom<&str> for Duration {
63 type Error = ();
64 fn try_from(v: &str) -> Result<Self, Self::Error> {
65 match syn::duration(v) {
66 Ok(v) => Ok(v),
67 _ => Err(()),
68 }
69 }
70}
71
72impl Deref for Duration {
73 type Target = time::Duration;
74 fn deref(&self) -> &Self::Target {
75 &self.0
76 }
77}
78
79impl Duration {
80 pub fn new(secs: u64, nanos: u32) -> Duration {
82 time::Duration::new(secs, nanos).into()
83 }
84 pub fn to_raw(&self) -> String {
86 self.to_string()
87 }
88 pub fn nanos(&self) -> u128 {
90 self.0.as_nanos()
91 }
92 pub fn micros(&self) -> u128 {
94 self.0.as_micros()
95 }
96 pub fn millis(&self) -> u128 {
98 self.0.as_millis()
99 }
100 pub fn secs(&self) -> u64 {
102 self.0.as_secs()
103 }
104 pub fn mins(&self) -> u64 {
106 self.0.as_secs() / SECONDS_PER_MINUTE
107 }
108 pub fn hours(&self) -> u64 {
110 self.0.as_secs() / SECONDS_PER_HOUR
111 }
112 pub fn days(&self) -> u64 {
114 self.0.as_secs() / SECONDS_PER_DAY
115 }
116 pub fn weeks(&self) -> u64 {
118 self.0.as_secs() / SECONDS_PER_WEEK
119 }
120 pub fn years(&self) -> u64 {
122 self.0.as_secs() / SECONDS_PER_YEAR
123 }
124 pub fn from_nanos(nanos: u64) -> Duration {
126 time::Duration::from_nanos(nanos).into()
127 }
128 pub fn from_micros(micros: u64) -> Duration {
130 time::Duration::from_micros(micros).into()
131 }
132 pub fn from_millis(millis: u64) -> Duration {
134 time::Duration::from_millis(millis).into()
135 }
136 pub fn from_secs(secs: u64) -> Duration {
138 time::Duration::from_secs(secs).into()
139 }
140 pub fn from_mins(mins: u64) -> Duration {
142 time::Duration::from_secs(mins * SECONDS_PER_MINUTE).into()
143 }
144 pub fn from_hours(hours: u64) -> Duration {
146 time::Duration::from_secs(hours * SECONDS_PER_HOUR).into()
147 }
148 pub fn from_days(days: u64) -> Duration {
150 time::Duration::from_secs(days * SECONDS_PER_DAY).into()
151 }
152 pub fn from_weeks(days: u64) -> Duration {
154 time::Duration::from_secs(days * SECONDS_PER_WEEK).into()
155 }
156}
157
158impl fmt::Display for Duration {
159 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
160 let secs = self.0.as_secs();
162 let nano = self.0.subsec_nanos();
163 if secs == 0 && nano == 0 {
165 return write!(f, "0ns");
166 }
167 let year = secs / SECONDS_PER_YEAR;
169 let secs = secs % SECONDS_PER_YEAR;
170 let week = secs / SECONDS_PER_WEEK;
172 let secs = secs % SECONDS_PER_WEEK;
173 let days = secs / SECONDS_PER_DAY;
175 let secs = secs % SECONDS_PER_DAY;
176 let hour = secs / SECONDS_PER_HOUR;
178 let secs = secs % SECONDS_PER_HOUR;
179 let mins = secs / SECONDS_PER_MINUTE;
181 let secs = secs % SECONDS_PER_MINUTE;
182 let msec = nano / NANOSECONDS_PER_MILLISECOND;
184 let nano = nano % NANOSECONDS_PER_MILLISECOND;
185 let usec = nano / NANOSECONDS_PER_MICROSECOND;
187 let nano = nano % NANOSECONDS_PER_MICROSECOND;
188 if year > 0 {
190 write!(f, "{year}y")?;
191 }
192 if week > 0 {
193 write!(f, "{week}w")?;
194 }
195 if days > 0 {
196 write!(f, "{days}d")?;
197 }
198 if hour > 0 {
199 write!(f, "{hour}h")?;
200 }
201 if mins > 0 {
202 write!(f, "{mins}m")?;
203 }
204 if secs > 0 {
205 write!(f, "{secs}s")?;
206 }
207 if msec > 0 {
208 write!(f, "{msec}ms")?;
209 }
210 if usec > 0 {
211 write!(f, "{usec}µs")?;
212 }
213 if nano > 0 {
214 write!(f, "{nano}ns")?;
215 }
216 Ok(())
217 }
218}
219
220impl ops::Add for Duration {
221 type Output = Self;
222 fn add(self, other: Self) -> Self {
223 match self.0.checked_add(other.0) {
224 Some(v) => Duration::from(v),
225 None => Duration::from(time::Duration::MAX),
226 }
227 }
228}
229
230impl<'a, 'b> ops::Add<&'b Duration> for &'a Duration {
231 type Output = Duration;
232 fn add(self, other: &'b Duration) -> Duration {
233 match self.0.checked_add(other.0) {
234 Some(v) => Duration::from(v),
235 None => Duration::from(time::Duration::MAX),
236 }
237 }
238}
239
240impl ops::Sub for Duration {
241 type Output = Self;
242 fn sub(self, other: Self) -> Self {
243 match self.0.checked_sub(other.0) {
244 Some(v) => Duration::from(v),
245 None => Duration::default(),
246 }
247 }
248}
249
250impl<'a, 'b> ops::Sub<&'b Duration> for &'a Duration {
251 type Output = Duration;
252 fn sub(self, other: &'b Duration) -> Duration {
253 match self.0.checked_sub(other.0) {
254 Some(v) => Duration::from(v),
255 None => Duration::default(),
256 }
257 }
258}
259
260impl ops::Add<Datetime> for Duration {
261 type Output = Datetime;
262 fn add(self, other: Datetime) -> Datetime {
263 match chrono::Duration::from_std(self.0) {
264 Ok(d) => Datetime::from(other.0 + d),
265 Err(_) => Datetime::default(),
266 }
267 }
268}
269
270impl ops::Sub<Datetime> for Duration {
271 type Output = Datetime;
272 fn sub(self, other: Datetime) -> Datetime {
273 match chrono::Duration::from_std(self.0) {
274 Ok(d) => Datetime::from(other.0 - d),
275 Err(_) => Datetime::default(),
276 }
277 }
278}
279
280impl Sum<Self> for Duration {
281 fn sum<I>(iter: I) -> Duration
282 where
283 I: Iterator<Item = Self>,
284 {
285 iter.fold(Duration::default(), |a, b| a + b)
286 }
287}
288
289impl<'a> Sum<&'a Self> for Duration {
290 fn sum<I>(iter: I) -> Duration
291 where
292 I: Iterator<Item = &'a Self>,
293 {
294 iter.fold(Duration::default(), |a, b| &a + b)
295 }
296}