From e1733ca31e6a15deaf893917d10cbcbebf0721ee Mon Sep 17 00:00:00 2001 From: pedrocarlo Date: Fri, 31 Jan 2025 22:44:00 -0300 Subject: [PATCH] all functions implemented --- extensions/time/src/lib.rs | 192 +++++++++++++++++++++++++++++++----- extensions/time/src/time.rs | 48 +++++++++ 2 files changed, 215 insertions(+), 25 deletions(-) diff --git a/extensions/time/src/lib.rs b/extensions/time/src/lib.rs index 5971cb215..d776eb0bf 100644 --- a/extensions/time/src/lib.rs +++ b/extensions/time/src/lib.rs @@ -14,7 +14,6 @@ use time::*; register_extension! { scalars: { time_now, - time_fmt_iso, time_date, make_date, make_timestamp, @@ -43,6 +42,7 @@ register_extension! { time_before, time_compare, time_equal, + dur_ns, dur_us, dur_ms, dur_s, @@ -53,7 +53,13 @@ register_extension! { time_sub, time_since, time_until, - time_trunc + time_trunc, + time_round, + time_fmt_iso, + time_fmt_datetime, + time_fmt_date, + time_fmt_time, + time_parse, }, } @@ -121,29 +127,6 @@ fn time_now(args: &[Value]) -> Value { t.into_blob() } -#[scalar(name = "time_fmt_iso")] -fn time_fmt_iso(args: &[Value]) -> Value { - if args.len() != 1 && args.len() != 2 { - return Value::error(ResultCode::InvalidArgs); - } - let blob = ok_tri!(args[0].to_blob()); - - let t = tri!(Time::try_from(blob)); - - let offset_sec = { - if args.len() == 2 { - value_tri!(args[1].value_type(), ValueType::Integer); - ok_tri!(args[1].to_integer()) as i32 - } else { - 0 - } - }; - - let fmt_str = tri!(t.fmt_iso(offset_sec)); - - Value::from_text(fmt_str) -} - /// ```text /// time_date(year, month, day[, hour, min, sec[, nsec[, offset_sec]]]) /// ``` @@ -614,6 +597,16 @@ fn time_equal(args: &[Value]) -> Value { // Duration Constants +/// 1 nanosecond +#[scalar(name = "dur_ns")] +fn dur_ns(args: &[Value]) -> Value { + if args.len() != 0 { + return Value::error(ResultCode::InvalidArgs); + } + + Value::from_integer(ok_tri!(chrono::Duration::nanoseconds(1).num_nanoseconds())) +} + /// 1 microsecond #[scalar(name = "dur_us")] fn dur_us(args: &[Value]) -> Value { @@ -810,3 +803,152 @@ fn time_trunc(args: &[Value]) -> Value { _ => Value::error(ResultCode::Error), } } + +#[scalar(name = "time_round")] +fn time_round(args: &[Value]) -> Value { + if args.len() != 2 { + return Value::error(ResultCode::InvalidArgs); + } + + let blob = ok_tri!(args[0].to_blob()); + + let t = tri!(Time::try_from(blob)); + + value_tri!(args[1].value_type(), ValueType::Integer); + + let duration = ok_tri!(args[1].to_integer()); + let duration = Duration::from(duration); + + tri!(t.round_duration(duration)).into_blob() +} + +// Formatting + +#[scalar(name = "time_fmt_iso")] +fn time_fmt_iso(args: &[Value]) -> Value { + if args.len() != 1 && args.len() != 2 { + return Value::error(ResultCode::InvalidArgs); + } + let blob = ok_tri!(args[0].to_blob()); + + let t = tri!(Time::try_from(blob)); + + let offset_sec = { + if args.len() == 2 { + value_tri!(args[1].value_type(), ValueType::Integer); + ok_tri!(args[1].to_integer()) as i32 + } else { + 0 + } + }; + + let fmt_str = tri!(t.fmt_iso(offset_sec)); + + Value::from_text(fmt_str) +} + +#[scalar(name = "time_fmt_datetime")] +fn time_fmt_datetime(args: &[Value]) -> Value { + if args.len() != 1 && args.len() != 2 { + return Value::error(ResultCode::InvalidArgs); + } + let blob = ok_tri!(args[0].to_blob()); + + let t = tri!(Time::try_from(blob)); + + let offset_sec = { + if args.len() == 2 { + value_tri!(args[1].value_type(), ValueType::Integer); + ok_tri!(args[1].to_integer()) as i32 + } else { + 0 + } + }; + + let fmt_str = tri!(t.fmt_datetime(offset_sec)); + + Value::from_text(fmt_str) +} + +#[scalar(name = "time_fmt_date")] +fn time_fmt_date(args: &[Value]) -> Value { + if args.len() != 1 && args.len() != 2 { + return Value::error(ResultCode::InvalidArgs); + } + let blob = ok_tri!(args[0].to_blob()); + + let t = tri!(Time::try_from(blob)); + + let offset_sec = { + if args.len() == 2 { + value_tri!(args[1].value_type(), ValueType::Integer); + ok_tri!(args[1].to_integer()) as i32 + } else { + 0 + } + }; + + let fmt_str = tri!(t.fmt_date(offset_sec)); + + Value::from_text(fmt_str) +} + +#[scalar(name = "time_fmt_time")] +fn time_fmt_time(args: &[Value]) -> Value { + if args.len() != 1 && args.len() != 2 { + return Value::error(ResultCode::InvalidArgs); + } + let blob = ok_tri!(args[0].to_blob()); + + let t = tri!(Time::try_from(blob)); + + let offset_sec = { + if args.len() == 2 { + value_tri!(args[1].value_type(), ValueType::Integer); + ok_tri!(args[1].to_integer()) as i32 + } else { + 0 + } + }; + + let fmt_str = tri!(t.fmt_time(offset_sec)); + + Value::from_text(fmt_str) +} + +#[scalar(name = "time_parse")] +fn time_parse(args: &[Value]) -> Value { + if args.len() != 1 { + return Value::error(ResultCode::InvalidArgs); + } + + let dt_str = ok_tri!(args[0].to_text()); + + if let Ok(dt) = chrono::DateTime::parse_from_rfc3339(&dt_str) { + return Time::from_datetime(dt.to_utc()).into_blob(); + } + + if let Ok(mut dt) = chrono::NaiveDateTime::parse_from_str(&dt_str, "%Y-%m-%d %H:%M:%S") { + // Unwrap is safe here + dt = dt.with_nanosecond(0).unwrap(); + return Time::from_datetime(dt.and_utc()).into_blob(); + } + + if let Ok(date) = chrono::NaiveDate::parse_from_str(&dt_str, "%Y-%m-%d") { + // Unwrap is safe here + + let dt = date + .and_hms_opt(0, 0, 0) + .unwrap() + .with_nanosecond(0) + .unwrap(); + return Time::from_datetime(dt.and_utc()).into_blob(); + } + + let time = tri!(chrono::NaiveTime::parse_from_str(&dt_str, "%H:%M:%S")); + let dt = NaiveDateTime::new(NaiveDate::from_ymd_opt(1, 1, 1).unwrap(), time) + .with_nanosecond(0) + .unwrap(); + + Time::from_datetime(dt.and_utc()).into_blob() +} diff --git a/extensions/time/src/time.rs b/extensions/time/src/time.rs index 87d214cad..05536c1bc 100644 --- a/extensions/time/src/time.rs +++ b/extensions/time/src/time.rs @@ -134,6 +134,48 @@ impl Time { } } + pub fn fmt_datetime(&self, offset_sec: i32) -> Result { + let fmt = "%F %T"; + + if offset_sec == 0 { + return Ok(self.inner.format(fmt).to_string()); + } + // I do not see how this can error + let offset = &FixedOffset::east_opt(offset_sec).ok_or(TimeError::InvalidFormat)?; + + let timezone_date = self.inner.with_timezone(offset); + + return Ok(timezone_date.format(fmt).to_string()); + } + + pub fn fmt_date(&self, offset_sec: i32) -> Result { + let fmt = "%F"; + + if offset_sec == 0 { + return Ok(self.inner.format(fmt).to_string()); + } + // I do not see how this can error + let offset = &FixedOffset::east_opt(offset_sec).ok_or(TimeError::InvalidFormat)?; + + let timezone_date = self.inner.with_timezone(offset); + + return Ok(timezone_date.format(fmt).to_string()); + } + + pub fn fmt_time(&self, offset_sec: i32) -> Result { + let fmt = "%T"; + + if offset_sec == 0 { + return Ok(self.inner.format(fmt).to_string()); + } + // I do not see how this can error + let offset = &FixedOffset::east_opt(offset_sec).ok_or(TimeError::InvalidFormat)?; + + let timezone_date = self.inner.with_timezone(offset); + + return Ok(timezone_date.format(fmt).to_string()); + } + /// Adjust the datetime to the offset pub fn from_datetime(dt: DateTime) -> Self { Self { inner: dt } @@ -361,6 +403,12 @@ impl Time { Ok(ret) } + pub fn round_duration(&self, d: Duration) -> Result { + Ok(Self { + inner: self.inner.duration_round(d.inner)?, + }) + } + pub fn time_get(&self, field: TimeField) -> Value { use TimeField::*;