parse timestamp

main
Ziyang Hu 2 years ago
parent 12d8af24d6
commit 115873e61a

@ -627,7 +627,7 @@ Empty matches::
-------------------- --------------------
Misc functions Timestamp functions
-------------------- --------------------
.. function:: now() .. function:: now()
@ -639,3 +639,7 @@ Misc functions
Interpret ``ts`` as seconds since the epoch and format as a string according to `RFC3339 <https://www.rfc-editor.org/rfc/rfc3339>`_. Interpret ``ts`` as seconds since the epoch and format as a string according to `RFC3339 <https://www.rfc-editor.org/rfc/rfc3339>`_.
If a second string argument is provided, it is interpreted as a `timezone <https://en.wikipedia.org/wiki/Tz_database>`_ and used to format the timestamp. If a second string argument is provided, it is interpreted as a `timezone <https://en.wikipedia.org/wiki/Tz_database>`_ and used to format the timestamp.
.. function:: parse_timestamp(str)
Parse ``str`` into seconds since the epoch according to RFC3339.

@ -336,7 +336,7 @@ impl Expr {
if target == symb { if target == symb {
let tar_val = match val.get_int() { let tar_val = match val.get_int() {
Some(i) => DataValue::from(i), Some(i) => DataValue::from(i),
None => val.clone() None => val.clone(),
}; };
return Ok(ValueRange::lower_bound(tar_val)); return Ok(ValueRange::lower_bound(tar_val));
} }
@ -347,7 +347,7 @@ impl Expr {
if target == symb { if target == symb {
let tar_val = match val.get_float() { let tar_val = match val.get_float() {
Some(i) => DataValue::from(i), Some(i) => DataValue::from(i),
None => val.clone() None => val.clone(),
}; };
return Ok(ValueRange::upper_bound(tar_val)); return Ok(ValueRange::upper_bound(tar_val));
} }
@ -361,7 +361,7 @@ impl Expr {
if target == symb { if target == symb {
let tar_val = match val.get_float() { let tar_val = match val.get_float() {
Some(i) => DataValue::from(i), Some(i) => DataValue::from(i),
None => val.clone() None => val.clone(),
}; };
return Ok(ValueRange::upper_bound(tar_val)); return Ok(ValueRange::upper_bound(tar_val));
@ -373,7 +373,7 @@ impl Expr {
if target == symb { if target == symb {
let tar_val = match val.get_int() { let tar_val = match val.get_int() {
Some(i) => DataValue::from(i), Some(i) => DataValue::from(i),
None => val.clone() None => val.clone(),
}; };
return Ok(ValueRange::lower_bound(tar_val)); return Ok(ValueRange::lower_bound(tar_val));
@ -653,6 +653,7 @@ pub(crate) fn get_op(name: &str) -> Option<&'static Op> {
"uuid_timestamp" => &OP_UUID_TIMESTAMP, "uuid_timestamp" => &OP_UUID_TIMESTAMP,
"now" => &OP_NOW, "now" => &OP_NOW,
"format_timestamp" => &OP_FORMAT_TIMESTAMP, "format_timestamp" => &OP_FORMAT_TIMESTAMP,
"parse_timestamp" => &OP_PARSE_TIMESTAMP,
_ => return None, _ => return None,
}) })
} }

@ -3,7 +3,7 @@ use std::ops::{Div, Rem};
use std::str::FromStr; use std::str::FromStr;
use std::time::{SystemTime, UNIX_EPOCH}; use std::time::{SystemTime, UNIX_EPOCH};
use chrono::{TimeZone, Utc}; use chrono::{DateTime, TimeZone, Utc};
use itertools::Itertools; use itertools::Itertools;
use miette::{bail, ensure, miette, Result}; use miette::{bail, ensure, miette, Result};
use num_traits::FloatConst; use num_traits::FloatConst;
@ -1417,7 +1417,8 @@ pub(crate) fn op_format_timestamp(args: &[DataValue]) -> Result<DataValue> {
let tz_s = tz_v.get_string().ok_or_else(|| { let tz_s = tz_v.get_string().ok_or_else(|| {
miette!("'format_timestamp' timezone specification requires a string") miette!("'format_timestamp' timezone specification requires a string")
})?; })?;
let tz = chrono_tz::Tz::from_str(tz_s).map_err(|_| miette!("bad timezone specification: {}", tz_s))?; let tz = chrono_tz::Tz::from_str(tz_s)
.map_err(|_| miette!("bad timezone specification: {}", tz_s))?;
let dt_tz = dt.with_timezone(&tz); let dt_tz = dt.with_timezone(&tz);
let s = SmartString::from(dt_tz.to_rfc3339()); let s = SmartString::from(dt_tz.to_rfc3339());
Ok(DataValue::Str(s)) Ok(DataValue::Str(s))
@ -1429,6 +1430,18 @@ pub(crate) fn op_format_timestamp(args: &[DataValue]) -> Result<DataValue> {
} }
} }
define_op!(OP_PARSE_TIMESTAMP, 1, false);
pub(crate) fn op_parse_timestamp(args: &[DataValue]) -> Result<DataValue> {
let s = args[0]
.get_string()
.ok_or_else(|| miette!("'parse_timestamp' expects a string"))?;
let dt = DateTime::parse_from_rfc3339(s).map_err(|_| miette!("bad datetime: {}", s))?;
let st: SystemTime = dt.into();
Ok(DataValue::from(
st.duration_since(UNIX_EPOCH).unwrap().as_secs_f64(),
))
}
define_op!(OP_RAND_UUID_V1, 0, false); define_op!(OP_RAND_UUID_V1, 0, false);
pub(crate) fn op_rand_uuid_v1(_args: &[DataValue]) -> Result<DataValue> { pub(crate) fn op_rand_uuid_v1(_args: &[DataValue]) -> Result<DataValue> {
let mut rng = rand::thread_rng(); let mut rng = rand::thread_rng();

@ -1328,5 +1328,6 @@ fn test_uuid() {
fn test_now() { fn test_now() {
let now = op_now(&[]).unwrap(); let now = op_now(&[]).unwrap();
assert!(matches!(now, DataValue::Num(_))); assert!(matches!(now, DataValue::Num(_)));
op_format_timestamp(&[now]).unwrap(); let s = op_format_timestamp(&[now]).unwrap();
let _dt = op_parse_timestamp(&[s]).unwrap();
} }

@ -756,6 +756,7 @@ impl RelationRA {
left_to_prefix_indices.push(left_join_indices[*idx]); left_to_prefix_indices.push(left_join_indices[*idx]);
} }
// TODO don't build the whole thing is prefix scan suffices
let mut right_join_vals = BTreeSet::new(); let mut right_join_vals = BTreeSet::new();
for tuple in self.storage.scan_all(tx) { for tuple in self.storage.scan_all(tx) {
let tuple = tuple?; let tuple = tuple?;

Loading…
Cancel
Save