surrealdb/sql/
duration.rs

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