diff options
Diffstat (limited to 'crates/typst-library/src/foundations/duration.rs')
| -rw-r--r-- | crates/typst-library/src/foundations/duration.rs | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/crates/typst-library/src/foundations/duration.rs b/crates/typst-library/src/foundations/duration.rs new file mode 100644 index 00000000..94d44fb2 --- /dev/null +++ b/crates/typst-library/src/foundations/duration.rs @@ -0,0 +1,215 @@ +use std::fmt::{self, Debug, Formatter}; +use std::ops::{Add, Div, Mul, Neg, Sub}; + +use ecow::{eco_format, EcoString}; +use time::ext::NumericalDuration; + +use crate::foundations::{func, repr, scope, ty, Repr}; + +/// Represents a positive or negative span of time. +#[ty(scope, cast)] +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub struct Duration(time::Duration); + +impl Duration { + /// Whether the duration is empty / zero. + pub fn is_zero(&self) -> bool { + self.0.is_zero() + } +} + +#[scope] +impl Duration { + /// Creates a new duration. + /// + /// You can specify the [duration] using weeks, days, hours, minutes and + /// seconds. You can also get a duration by subtracting two + /// [datetimes]($datetime). + /// + /// ```example + /// #duration( + /// days: 3, + /// hours: 12, + /// ).hours() + /// ``` + #[func(constructor)] + pub fn construct( + /// The number of seconds. + #[named] + #[default(0)] + seconds: i64, + /// The number of minutes. + #[named] + #[default(0)] + minutes: i64, + /// The number of hours. + #[named] + #[default(0)] + hours: i64, + /// The number of days. + #[named] + #[default(0)] + days: i64, + /// The number of weeks. + #[named] + #[default(0)] + weeks: i64, + ) -> Duration { + Duration::from( + time::Duration::seconds(seconds) + + time::Duration::minutes(minutes) + + time::Duration::hours(hours) + + time::Duration::days(days) + + time::Duration::weeks(weeks), + ) + } + + /// The duration expressed in seconds. + /// + /// This function returns the total duration represented in seconds as a + /// floating-point number rather than the second component of the duration. + #[func] + pub fn seconds(&self) -> f64 { + self.0.as_seconds_f64() + } + + /// The duration expressed in minutes. + /// + /// This function returns the total duration represented in minutes as a + /// floating-point number rather than the second component of the duration. + #[func] + pub fn minutes(&self) -> f64 { + self.seconds() / 60.0 + } + + /// The duration expressed in hours. + /// + /// This function returns the total duration represented in hours as a + /// floating-point number rather than the second component of the duration. + #[func] + pub fn hours(&self) -> f64 { + self.seconds() / 3_600.0 + } + + /// The duration expressed in days. + /// + /// This function returns the total duration represented in days as a + /// floating-point number rather than the second component of the duration. + #[func] + pub fn days(&self) -> f64 { + self.seconds() / 86_400.0 + } + + /// The duration expressed in weeks. + /// + /// This function returns the total duration represented in weeks as a + /// floating-point number rather than the second component of the duration. + #[func] + pub fn weeks(&self) -> f64 { + self.seconds() / 604_800.0 + } +} + +impl Debug for Duration { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + self.0.fmt(f) + } +} + +impl Repr for Duration { + fn repr(&self) -> EcoString { + let mut tmp = self.0; + let mut vec = Vec::with_capacity(5); + + let weeks = tmp.whole_seconds() / 604_800.0 as i64; + if weeks != 0 { + vec.push(eco_format!("weeks: {}", weeks.repr())); + } + tmp -= weeks.weeks(); + + let days = tmp.whole_days(); + if days != 0 { + vec.push(eco_format!("days: {}", days.repr())); + } + tmp -= days.days(); + + let hours = tmp.whole_hours(); + if hours != 0 { + vec.push(eco_format!("hours: {}", hours.repr())); + } + tmp -= hours.hours(); + + let minutes = tmp.whole_minutes(); + if minutes != 0 { + vec.push(eco_format!("minutes: {}", minutes.repr())); + } + tmp -= minutes.minutes(); + + let seconds = tmp.whole_seconds(); + if seconds != 0 { + vec.push(eco_format!("seconds: {}", seconds.repr())); + } + + eco_format!("duration{}", &repr::pretty_array_like(&vec, false)) + } +} + +impl From<time::Duration> for Duration { + fn from(value: time::Duration) -> Self { + Self(value) + } +} + +impl From<Duration> for time::Duration { + fn from(value: Duration) -> Self { + value.0 + } +} + +impl Add for Duration { + type Output = Duration; + + fn add(self, rhs: Self) -> Self::Output { + Duration(self.0 + rhs.0) + } +} + +impl Sub for Duration { + type Output = Duration; + + fn sub(self, rhs: Self) -> Self::Output { + Duration(self.0 - rhs.0) + } +} + +impl Neg for Duration { + type Output = Duration; + + fn neg(self) -> Self::Output { + Duration(-self.0) + } +} + +impl Mul<f64> for Duration { + type Output = Duration; + + fn mul(self, rhs: f64) -> Self::Output { + Duration(self.0 * rhs) + } +} + +impl Div<f64> for Duration { + type Output = Duration; + + fn div(self, rhs: f64) -> Self::Output { + Duration(self.0 / rhs) + } +} + +impl Div for Duration { + type Output = f64; + + fn div(self, rhs: Self) -> Self::Output { + self.0 / rhs.0 + } +} |
