Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 139 additions & 0 deletions datafusion/core/tests/sql/timestamp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

use super::*;
use datafusion::from_slice::FromSlice;
use std::ops::Add;

#[tokio::test]
async fn query_cast_timestamp_millis() -> Result<()> {
Expand Down Expand Up @@ -1256,3 +1257,141 @@ async fn date_bin() {
"Arrow error: External error: This feature is not implemented: DATE_BIN only supports literal values for the origin argument, not arrays"
);
}

#[tokio::test]
async fn timestamp_add_interval_second() -> Result<()> {
let ctx = SessionContext::new();

let sql = "SELECT NOW(), NOW() + INTERVAL '1' SECOND;";
let results = execute_to_batches(&ctx, sql).await;
let actual = result_vec(&results);

let res1 = actual[0][0].as_str();
let res2 = actual[0][1].as_str();

let format = "%Y-%m-%d %H:%M:%S%.6f";
let t1_naive = chrono::NaiveDateTime::parse_from_str(res1, format).unwrap();
let t2_naive = chrono::NaiveDateTime::parse_from_str(res2, format).unwrap();

assert_eq!(t1_naive.add(Duration::seconds(1)), t2_naive);
Ok(())
}

#[tokio::test]
async fn timestamp_sub_interval_days() -> Result<()> {
let ctx = SessionContext::new();

let sql = "SELECT NOW(), NOW() - INTERVAL '8' DAY;";
let results = execute_to_batches(&ctx, sql).await;
let actual = result_vec(&results);

let res1 = actual[0][0].as_str();
let res2 = actual[0][1].as_str();

let format = "%Y-%m-%d %H:%M:%S%.6f";
let t1_naive = chrono::NaiveDateTime::parse_from_str(res1, format).unwrap();
let t2_naive = chrono::NaiveDateTime::parse_from_str(res2, format).unwrap();

assert_eq!(t1_naive.sub(Duration::days(8)), t2_naive);
Ok(())
}

#[tokio::test]
async fn timestamp_add_interval_months() -> Result<()> {
let ctx = SessionContext::new();

let sql = "SELECT NOW(), NOW() + INTERVAL '4' MONTH;";
let results = execute_to_batches(&ctx, sql).await;
let actual = result_vec(&results);

let res1 = actual[0][0].as_str();
let res2 = actual[0][1].as_str();

let format = "%Y-%m-%d %H:%M:%S%.6f";
let t1_naive = chrono::NaiveDateTime::parse_from_str(res1, format).unwrap();
let t2_naive = chrono::NaiveDateTime::parse_from_str(res2, format).unwrap();

assert_eq!(t1_naive.with_month(t1_naive.month() + 4).unwrap(), t2_naive);
Ok(())
}

#[tokio::test]
async fn timestamp_sub_interval_years() -> Result<()> {
let ctx = SessionContext::new();

let sql = "SELECT NOW(), NOW() - INTERVAL '16' YEAR;";
let results = execute_to_batches(&ctx, sql).await;
let actual = result_vec(&results);

let res1 = actual[0][0].as_str();
let res2 = actual[0][1].as_str();

let format = "%Y-%m-%d %H:%M:%S%.6f";
let t1_naive = chrono::NaiveDateTime::parse_from_str(res1, format).unwrap();
let t2_naive = chrono::NaiveDateTime::parse_from_str(res2, format).unwrap();

assert_eq!(t1_naive.with_year(t1_naive.year() - 16).unwrap(), t2_naive);
Ok(())
}

#[tokio::test]
async fn timestamp_array_add_interval() -> Result<()> {
let ctx = SessionContext::new();
let table_a = make_timestamp_table::<TimestampNanosecondType>()?;
let table_b = make_timestamp_table::<TimestampMicrosecondType>()?;
ctx.register_table("table_a", table_a)?;
ctx.register_table("table_b", table_b)?;

let sql = "SELECT ts, ts - INTERVAL '8' MILLISECONDS FROM table_a";
let actual = execute_to_batches(&ctx, sql).await;
let expected = vec![
"+----------------------------+---------------------------------------+",
"| ts | table_a.ts Minus IntervalDayTime(\"8\") |",
"+----------------------------+---------------------------------------+",
"| 2020-09-08 13:42:29.190855 | 2020-09-08 13:42:29.182855 |",
"| 2020-09-08 12:42:29.190855 | 2020-09-08 12:42:29.182855 |",
"| 2020-09-08 11:42:29.190855 | 2020-09-08 11:42:29.182855 |",
"+----------------------------+---------------------------------------+",
];
assert_batches_eq!(expected, &actual);

let sql = "SELECT ts, ts + INTERVAL '1' SECOND FROM table_b";
let actual = execute_to_batches(&ctx, sql).await;
let expected = vec![
"+----------------------------+-----------------------------------------+",
"| ts | table_b.ts Plus IntervalDayTime(\"1000\") |",
"+----------------------------+-----------------------------------------+",
"| 2020-09-08 13:42:29.190855 | 2020-09-08 13:42:30.190855 |",
"| 2020-09-08 12:42:29.190855 | 2020-09-08 12:42:30.190855 |",
"| 2020-09-08 11:42:29.190855 | 2020-09-08 11:42:30.190855 |",
"+----------------------------+-----------------------------------------+",
];
assert_batches_eq!(expected, &actual);

let sql = "SELECT ts, ts + INTERVAL '2' MONTH FROM table_b";
let actual = execute_to_batches(&ctx, sql).await;
let expected = vec![
"+----------------------------+----------------------------------------+",
"| ts | table_b.ts Plus IntervalYearMonth(\"2\") |",
"+----------------------------+----------------------------------------+",
"| 2020-09-08 13:42:29.190855 | 2020-11-08 13:42:29.190855 |",
"| 2020-09-08 12:42:29.190855 | 2020-11-08 12:42:29.190855 |",
"| 2020-09-08 11:42:29.190855 | 2020-11-08 11:42:29.190855 |",
"+----------------------------+----------------------------------------+",
];
assert_batches_eq!(expected, &actual);

let sql = "SELECT ts, ts - INTERVAL '16' YEAR FROM table_b";
let actual = execute_to_batches(&ctx, sql).await;
let expected = vec![
"+----------------------------+-------------------------------------------+",
"| ts | table_b.ts Minus IntervalYearMonth(\"192\") |",
"+----------------------------+-------------------------------------------+",
"| 2020-09-08 13:42:29.190855 | 2004-09-08 13:42:29.190855 |",
"| 2020-09-08 12:42:29.190855 | 2004-09-08 12:42:29.190855 |",
"| 2020-09-08 11:42:29.190855 | 2004-09-08 11:42:29.190855 |",
"+----------------------------+-------------------------------------------+",
];
assert_batches_eq!(expected, &actual);
Ok(())
}
4 changes: 3 additions & 1 deletion datafusion/expr/src/binary_rule.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,9 @@ pub fn coerce_types(
Operator::Like | Operator::NotLike => like_coercion(lhs_type, rhs_type),
// date +/- interval returns date
Operator::Plus | Operator::Minus
if (*lhs_type == DataType::Date32 || *lhs_type == DataType::Date64) =>
if (*lhs_type == DataType::Date32
|| *lhs_type == DataType::Date64
|| matches!(lhs_type, DataType::Timestamp(_, _))) =>
{
match rhs_type {
DataType::Interval(_) => Some(lhs_type.clone()),
Expand Down
Loading