2024-10-27 18:04:55 +00:00

216 lines
5.2 KiB
Rust

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
}
}