tustvold commented on code in PR #3762: URL: https://github.com/apache/arrow-rs/pull/3762#discussion_r1126185850
########## arrow-cast/src/parse.rs: ########## @@ -445,6 +446,231 @@ impl Parser for Date64Type { } } +pub(crate) fn parse_interval_year_month( + value: &str, +) -> Result<<IntervalYearMonthType as ArrowPrimitiveType>::Native, ArrowError> { + let (result_months, result_days, result_nanos) = parse_interval("years", value)?; + if result_days != 0 || result_nanos != 0 { + return Err(ArrowError::CastError(format!( + "Cannot cast {value} to IntervalYearMonth because the value isn't multiple of months" + ))); + } + Ok(IntervalYearMonthType::make_value(0, result_months)) +} + +pub(crate) fn parse_interval_day_time( + value: &str, +) -> Result<<IntervalDayTimeType as ArrowPrimitiveType>::Native, ArrowError> { + let (result_months, mut result_days, result_nanos) = parse_interval("days", value)?; + if result_nanos % 1_000_000 != 0 { + return Err(ArrowError::CastError(format!( + "Cannot cast {value} to IntervalDayTime because the nanos part isn't multiple of milliseconds" + ))); + } + result_days += result_months * 30; + Ok(IntervalDayTimeType::make_value( + result_days, + (result_nanos / 1_000_000) as i32, + )) +} + +pub(crate) fn parse_interval_month_day_nano( + value: &str, +) -> Result<<IntervalMonthDayNanoType as ArrowPrimitiveType>::Native, ArrowError> { + let (result_months, result_days, result_nanos) = parse_interval("months", value)?; + Ok(IntervalMonthDayNanoType::make_value( + result_months, + result_days, + result_nanos, + )) +} + +const SECONDS_PER_HOUR: f64 = 3_600_f64; +const NANOS_PER_MILLIS: f64 = 1_000_000_f64; +const NANOS_PER_SECOND: f64 = 1_000_f64 * NANOS_PER_MILLIS; +const NANOS_PER_MINUTE: f64 = 60_f64 * NANOS_PER_SECOND; +const NANOS_PER_HOUR: f64 = 60_f64 * NANOS_PER_MINUTE; +const NANOS_PER_DAY: f64 = 24_f64 * NANOS_PER_HOUR; + +#[derive(Clone, Copy)] +#[repr(u16)] +enum IntervalType { + Century = 0b_00_0000_0001, + Decade = 0b_00_0000_0010, + Year = 0b_00_0000_0100, + Month = 0b_00_0000_1000, + Week = 0b_00_0001_0000, + Day = 0b_00_0010_0000, + Hour = 0b_00_0100_0000, + Minute = 0b_00_1000_0000, + Second = 0b_01_0000_0000, + Millisecond = 0b_10_0000_0000, +} + +impl FromStr for IntervalType { + type Err = ArrowError; + + fn from_str(s: &str) -> Result<Self, ArrowError> { + match s.to_lowercase().as_str() { + "century" | "centuries" => Ok(Self::Century), + "decade" | "decades" => Ok(Self::Decade), + "year" | "years" => Ok(Self::Year), + "month" | "months" => Ok(Self::Month), + "week" | "weeks" => Ok(Self::Week), + "day" | "days" => Ok(Self::Day), + "hour" | "hours" => Ok(Self::Hour), + "minute" | "minutes" => Ok(Self::Minute), + "second" | "seconds" => Ok(Self::Second), + "millisecond" | "milliseconds" => Ok(Self::Millisecond), + _ => Err(ArrowError::NotYetImplemented(format!( + "Unknown interval type: {s}" + ))), + } + } +} + +pub type MonthDayNano = (i32, i32, i64); + +/// parse string value to a triple of aligned months, days, nanos +pub fn parse_interval( Review Comment: Could we document this method better, it isn't clear to me how it is meant to be used. In particular `leading_field` is never documented AFAICT -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: github-unsubscr...@arrow.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org