Add string to datetime to str plugin (#1381)

* Add string to datetime to str plugin

* Test string to date/time conversion
This commit is contained in:
Corvus Corax 2020-02-13 09:47:04 -06:00 committed by GitHub
parent 84927d52b5
commit 0961da406d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 70 additions and 20 deletions

1
Cargo.lock generated
View file

@ -2555,6 +2555,7 @@ dependencies = [
name = "nu_plugin_str" name = "nu_plugin_str"
version = "0.9.0" version = "0.9.0"
dependencies = [ dependencies = [
"chrono",
"nu-build", "nu-build",
"nu-errors", "nu-errors",
"nu-plugin", "nu-plugin",

View file

@ -15,6 +15,7 @@ use crate::value::primitive::Primitive;
use crate::value::range::{Range, RangeInclusion}; use crate::value::range::{Range, RangeInclusion};
use crate::{ColumnPath, PathMember}; use crate::{ColumnPath, PathMember};
use bigdecimal::BigDecimal; use bigdecimal::BigDecimal;
use chrono::{DateTime, Utc};
use indexmap::IndexMap; use indexmap::IndexMap;
use nu_errors::ShellError; use nu_errors::ShellError;
use nu_source::{AnchorLocation, HasSpan, Span, Spanned, Tag}; use nu_source::{AnchorLocation, HasSpan, Span, Spanned, Tag};
@ -201,6 +202,10 @@ impl UntaggedValue {
UntaggedValue::Primitive(Primitive::Date(s.into())) UntaggedValue::Primitive(Primitive::Date(s.into()))
} }
pub fn date(d: impl Into<DateTime<Utc>>) -> UntaggedValue {
UntaggedValue::Primitive(Primitive::Date(d.into()))
}
/// Helper for creating the Nothing value /// Helper for creating the Nothing value
pub fn nothing() -> UntaggedValue { pub fn nothing() -> UntaggedValue {
UntaggedValue::Primitive(Primitive::Nothing) UntaggedValue::Primitive(Primitive::Nothing)

View file

@ -15,6 +15,7 @@ nu-protocol = { path = "../nu-protocol", version = "0.9.0" }
nu-source = { path = "../nu-source", version = "0.9.0" } nu-source = { path = "../nu-source", version = "0.9.0" }
nu-errors = { path = "../nu-errors", version = "0.9.0" } nu-errors = { path = "../nu-errors", version = "0.9.0" }
nu-value-ext = { path = "../nu-value-ext", version = "0.9.0" } nu-value-ext = { path = "../nu-value-ext", version = "0.9.0" }
chrono = { version = "0.4.10", features = ["serde"] }
regex = "1" regex = "1"
num-bigint = "0.2.3" num-bigint = "0.2.3"

View file

@ -36,6 +36,12 @@ impl Plugin for Str {
"convert string to portion of original, requires \"start,end\"", "convert string to portion of original, requires \"start,end\"",
Some('s'), Some('s'),
) )
.named(
"to-date-time",
SyntaxShape::String,
"Convert string to Date/Time",
Some('D'),
)
.rest(SyntaxShape::ColumnPath, "the column(s) to convert") .rest(SyntaxShape::ColumnPath, "the column(s) to convert")
.filter()) .filter())
} }
@ -117,6 +123,11 @@ impl Plugin for Str {
self.for_field(possible_field); self.for_field(possible_field);
} }
if let Some(dt) = args.get("to-date-time") {
let dt = dt.as_string()?;
self.for_date_time(dt);
}
match &self.error { match &self.error {
Some(reason) => Err(ShellError::untagged_runtime_error(format!( Some(reason) => Err(ShellError::untagged_runtime_error(format!(
"{}: {}", "{}: {}",

View file

@ -7,7 +7,37 @@ mod integration {
unstructured_sample_record, unstructured_sample_record,
}; };
use nu_plugin::test_helpers::{expect_return_value_at, plugin, CallStub}; use nu_plugin::test_helpers::{expect_return_value_at, plugin, CallStub};
use nu_protocol::UntaggedValue; use nu_protocol::{Primitive, UntaggedValue};
#[test]
fn picks_up_date_time() {
let run = plugin(&mut Str::new())
.args(
CallStub::new()
.with_named_parameter("to-date-time", string("%d.%m.%Y %H:%M %P %z"))
.create(),
)
.input(string("5.8.1994 8:00 am +0000"))
.input(string("6.9.1995 10:00 am +0000"))
.input(string("5.8.1994 20:00 pm +0000"))
.input(string("20.4.2020 8:00 am +0000"))
.setup(|_, _| {})
.test();
let ret_vals = run.unwrap();
for r in ret_vals {
let r = r
.as_ref()
.unwrap()
.raw_value()
.unwrap()
.as_primitive()
.unwrap();
match r {
Primitive::Date(_) => (),
_ => assert!(false, "failed to convert string to date"),
}
}
}
#[test] #[test]
fn picks_up_one_action_flag_only() { fn picks_up_one_action_flag_only() {

View file

@ -1,3 +1,6 @@
extern crate chrono;
use chrono::DateTime;
use nu_errors::ShellError; use nu_errors::ShellError;
use nu_protocol::{did_you_mean, ColumnPath, Primitive, ShellTypeName, UntaggedValue, Value}; use nu_protocol::{did_you_mean, ColumnPath, Primitive, ShellTypeName, UntaggedValue, Value};
use nu_source::{span_for_spanned_list, Tagged}; use nu_source::{span_for_spanned_list, Tagged};
@ -12,6 +15,7 @@ pub enum Action {
ToInteger, ToInteger,
Substring(usize, usize), Substring(usize, usize),
Replace(ReplaceAction), Replace(ReplaceAction),
ToDateTime(String),
} }
#[derive(Debug, Eq, PartialEq)] #[derive(Debug, Eq, PartialEq)]
@ -70,6 +74,10 @@ impl Str {
Err(_) => UntaggedValue::string(input), Err(_) => UntaggedValue::string(input),
}, },
}, },
Some(Action::ToDateTime(dt)) => match DateTime::parse_from_str(input, dt) {
Ok(d) => UntaggedValue::date(d),
Err(_) => UntaggedValue::string(input),
},
None => UntaggedValue::string(input), None => UntaggedValue::string(input),
}; };
@ -89,27 +97,15 @@ impl Str {
} }
pub fn for_to_int(&mut self) { pub fn for_to_int(&mut self) {
if self.permit() { self.add_action(Action::ToInteger);
self.action = Some(Action::ToInteger);
} else {
self.log_error("can only apply one");
}
} }
pub fn for_downcase(&mut self) { pub fn for_downcase(&mut self) {
if self.permit() { self.add_action(Action::Downcase);
self.action = Some(Action::Downcase);
} else {
self.log_error("can only apply one");
}
} }
pub fn for_upcase(&mut self) { pub fn for_upcase(&mut self) {
if self.permit() { self.add_action(Action::Upcase);
self.action = Some(Action::Upcase);
} else {
self.log_error("can only apply one");
}
} }
pub fn for_substring(&mut self, s: String) -> Result<(), ShellError> { pub fn for_substring(&mut self, s: String) -> Result<(), ShellError> {
@ -130,18 +126,24 @@ impl Str {
}; };
if start > end { if start > end {
self.log_error("End must be greater than or equal to Start"); self.log_error("End must be greater than or equal to Start");
} else if self.permit() {
self.action = Some(Action::Substring(start, end));
} else { } else {
self.log_error("can only apply one"); self.add_action(Action::Substring(start, end));
} }
Ok(()) Ok(())
} }
pub fn for_replace(&mut self, mode: ReplaceAction) { pub fn for_replace(&mut self, mode: ReplaceAction) {
self.add_action(Action::Replace(mode));
}
pub fn for_date_time(&mut self, dt: String) {
self.add_action(Action::ToDateTime(dt));
}
fn add_action(&mut self, act: Action) {
if self.permit() { if self.permit() {
self.action = Some(Action::Replace(mode)); self.action = Some(act);
} else { } else {
self.log_error("can only apply one"); self.log_error("can only apply one");
} }