You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@arrow.apache.org by tu...@apache.org on 2023/06/26 11:16:06 UTC
[arrow-rs] branch master updated: Parse intervals like `.5` the same as `0.5` (#4425)
This is an automated email from the ASF dual-hosted git repository.
tustvold pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/arrow-rs.git
The following commit(s) were added to refs/heads/master by this push:
new 23465ec49 Parse intervals like `.5` the same as `0.5` (#4425)
23465ec49 is described below
commit 23465ec49962eba398394fdc2a2ee2baa11cc1e4
Author: Andrew Lamb <an...@nerdnetworks.org>
AuthorDate: Mon Jun 26 07:16:00 2023 -0400
Parse intervals like `.5` the same as `0.5` (#4425)
* Allow intervals like .5
* Support -.5 and -0.5 intervals as well
---
arrow-cast/src/parse.rs | 51 +++++++++++++++++++++++++++++++++++++------------
1 file changed, 39 insertions(+), 12 deletions(-)
diff --git a/arrow-cast/src/parse.rs b/arrow-cast/src/parse.rs
index accce99b4..67477c57d 100644
--- a/arrow-cast/src/parse.rs
+++ b/arrow-cast/src/parse.rs
@@ -830,15 +830,21 @@ impl FromStr for IntervalAmount {
match s.split_once('.') {
Some((integer, frac))
if frac.len() <= INTERVAL_PRECISION as usize
- && !integer.is_empty()
&& !frac.is_empty()
&& !frac.starts_with('-') =>
{
- let integer = integer.parse::<i64>().map_err(|_| {
- ArrowError::ParseError(format!(
- "Failed to parse {s} as interval amount"
- ))
- })?;
+ // integer will be "" for values like ".5"
+ // and "-" for values like "-.5"
+ let explicit_neg = integer.starts_with('-');
+ let integer = if integer.is_empty() || integer == "-" {
+ Ok(0)
+ } else {
+ integer.parse::<i64>().map_err(|_| {
+ ArrowError::ParseError(format!(
+ "Failed to parse {s} as interval amount"
+ ))
+ })
+ }?;
let frac_unscaled = frac.parse::<i64>().map_err(|_| {
ArrowError::ParseError(format!(
@@ -851,7 +857,11 @@ impl FromStr for IntervalAmount {
frac_unscaled * 10_i64.pow(INTERVAL_PRECISION - frac.len() as u32);
// propagate the sign of the integer part to the fractional part
- let frac = if integer < 0 { -frac } else { frac };
+ let frac = if integer < 0 || explicit_neg {
+ -frac
+ } else {
+ frac
+ };
let result = Self { integer, frac };
@@ -929,7 +939,8 @@ impl Interval {
(self.months, self.days, self.nanos)
}
- /// Parse string value in traditional Postgres format (e.g. 1 year 2 months 3 days 4 hours 5 minutes 6 seconds)
+ /// Parse string value in traditional Postgres format such as
+ /// `1 year 2 months 3 days 4 hours 5 minutes 6 seconds`
fn parse(value: &str, config: &IntervalParseConfig) -> Result<Self, ArrowError> {
let components = parse_interval_components(value, config)?;
@@ -1798,6 +1809,26 @@ mod tests {
Interval::parse("-1.5 months -3.2 days", &config).unwrap(),
);
+ assert_eq!(
+ Interval::new(0i32, 15i32, 0),
+ Interval::parse("0.5 months", &config).unwrap(),
+ );
+
+ assert_eq!(
+ Interval::new(0i32, 15i32, 0),
+ Interval::parse(".5 months", &config).unwrap(),
+ );
+
+ assert_eq!(
+ Interval::new(0i32, -15i32, 0),
+ Interval::parse("-0.5 months", &config).unwrap(),
+ );
+
+ assert_eq!(
+ Interval::new(0i32, -15i32, 0),
+ Interval::parse("-.5 months", &config).unwrap(),
+ );
+
assert_eq!(
Interval::new(2i32, 10i32, 9 * NANOS_PER_HOUR),
Interval::parse("2.1 months 7.25 days 3 hours", &config).unwrap(),
@@ -1944,10 +1975,6 @@ mod tests {
assert_eq!(result, expected);
- // invalid: missing integer
- let result = IntervalAmount::from_str(".5");
- assert!(result.is_err());
-
// invalid: missing fractional
let result = IntervalAmount::from_str("3.");
assert!(result.is_err());