Skip to content
Open
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
15 changes: 12 additions & 3 deletions datafusion/sql/src/planner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -806,11 +806,20 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> {
))
}
SQLDataType::Date => Ok(DataType::Date32),
SQLDataType::Time(None, tz_info) => {
SQLDataType::Time(precision, tz_info)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The precision guard and the precision-to-TimeUnit match, including _ => unreachable!(), are copied from the TIMESTAMP arm instead of shared.

if precision.is_none() || [0, 3, 6, 9].contains(&precision.unwrap()) =>
{
if *tz_info == TimezoneInfo::None
|| *tz_info == TimezoneInfo::WithoutTimeZone
{
Ok(DataType::Time64(TimeUnit::Nanosecond))
let data_type = match precision {
Some(0) => DataType::Time32(TimeUnit::Second),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct me if I am wrong but TIME(0), TIME(3) and TIME(6) now give Time32(s), Time32(ms) and Time64(us), but DataFusion has no rule to compare two time values with different units, so these columns cannot be compared, joined or IN-listed against plain TIME values?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe that would be a good follow on to track in a separate ticket

Some(3) => DataType::Time32(TimeUnit::Millisecond),
Some(6) => DataType::Time64(TimeUnit::Microsecond),
None | Some(9) => DataType::Time64(TimeUnit::Nanosecond),
_ => unreachable!(),
};
Ok(data_type)
} else {
// We don't support TIMETZ and TIME WITH TIME ZONE for now
not_impl_err!("Unsupported SQL type {sql_type}")
Expand Down Expand Up @@ -880,7 +889,7 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> {
| SQLDataType::CharacterLargeObject(_)
| SQLDataType::CharLargeObject(_)
| SQLDataType::Timestamp(_, _)
| SQLDataType::Time(Some(_), _)
| SQLDataType::Time(_, _)
| SQLDataType::Dec(_)
| SQLDataType::BigNumeric(_)
| SQLDataType::BigDecimal(_)
Expand Down
79 changes: 79 additions & 0 deletions datafusion/sqllogictest/test_files/datetime/timestamps.slt
Original file line number Diff line number Diff line change
Expand Up @@ -749,6 +749,85 @@ select date '1994-01-01' - interval '1' day as date;
----
1993-12-31

# TIME precision selects the Arrow unit; the default remains nanoseconds.
query TTTTT
SELECT arrow_typeof(CAST(NULL AS TIME)) AS t,
arrow_typeof(CAST(NULL AS TIME(0))) AS s,
arrow_typeof(CAST(NULL AS TIME(3))) AS ms,
arrow_typeof(CAST(NULL AS TIME(6))) AS us,
arrow_typeof(CAST(NULL AS TIME(9))) AS ns;
----
Time64(ns) Time32(s) Time32(ms) Time64(µs) Time64(ns)

# String casts truncate fractional seconds to the requested precision.
query DDDD
SELECT CAST('12:34:56.123456789' AS TIME(0)) AS s,
CAST('12:34:56.123456789' AS TIME(3)) AS ms,
CAST('12:34:56.123456789' AS TIME(6)) AS us,
CAST('12:34:56.123456789' AS TIME(9)) AS ns;
----
12:34:56 12:34:56.123 12:34:56.123456 12:34:56.123456789

# Column declarations use the same mapping, including WITHOUT TIME ZONE.
statement ok
CREATE TABLE times (

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new times table is created but never dropped, so it stays in the session for the rest of this long test file.**

t TIME WITHOUT TIME ZONE,
s TIME(0) WITHOUT TIME ZONE,
ms TIME(3) WITHOUT TIME ZONE,
us TIME(6) WITHOUT TIME ZONE,
ns TIME(9) WITHOUT TIME ZONE
);

statement ok
INSERT INTO times VALUES (
'12:34:56.123456789', '12:34:56.123456789', '12:34:56.123456789',
'12:34:56.123456789', '12:34:56.123456789'
), (NULL, NULL, NULL, NULL, NULL);

query DDDDD rowsort
SELECT * FROM times;
----
12:34:56.123456789 12:34:56 12:34:56.123 12:34:56.123456 12:34:56.123456789
NULL NULL NULL NULL NULL

query TTTTT
SELECT arrow_typeof(t), arrow_typeof(s), arrow_typeof(ms), arrow_typeof(us), arrow_typeof(ns)
FROM times LIMIT 1;
----
Time64(ns) Time32(s) Time32(ms) Time64(µs) Time64(ns)

# Unsupported precisions, including values beyond nanoseconds, remain errors.
statement error
SELECT CAST('12:34:56' AS TIME(1));
----
DataFusion error: This feature is not implemented: Unsupported SQL type TIME(1)


statement error
CREATE TABLE invalid_time (t TIME(12));
----
DataFusion error: This feature is not implemented: Unsupported SQL type TIME(12)


# Arrow time types have no time zone.
statement error
SELECT CAST('12:34:56' AS TIME WITH TIME ZONE);
----
DataFusion error: This feature is not implemented: Unsupported SQL type TIME WITH TIME ZONE


statement error
SELECT CAST('12:34:56' AS TIME(6) WITH TIME ZONE);
----
DataFusion error: This feature is not implemented: Unsupported SQL type TIME(6) WITH TIME ZONE


statement error
SELECT CAST('12:34:56' AS TIMETZ(6));
----
DataFusion error: This feature is not implemented: Unsupported SQL type TIMETZ(6)


# cast_string_to_time()
query DDDD
select
Expand Down
9 changes: 7 additions & 2 deletions docs/source/user-guide/sql/data_types.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,10 @@ The maximum supported precision for `DECIMAL` types is 76.
| SQL DataType | Arrow DataType |
| ------------------------------------------------------------- | :--------------------------------------------------------- |
| `DATE` | `Date32` |
| `TIME` | `Time64(Nanosecond)` |
| `TIME`, `TIME(9)` | `Time64(Nanosecond)` |
| `TIME(0)` | `Time32(Second)` |
| `TIME(3)` | `Time32(Millisecond)` |
| `TIME(6)` | `Time64(Microsecond)` |
| `TIMESTAMP`, `TIMESTAMP(p)`, `TIMESTAMP(p) WITHOUT TIME ZONE` | `Timestamp(unit, None)` |
| `DATETIME`, `DATETIME(p)` | `Timestamp(unit, None)` |
| `TIMESTAMPTZ(p)`, `TIMESTAMP(p) WITH TIME ZONE` | `Timestamp(unit, None)` by default — see the warning below |
Expand Down Expand Up @@ -126,7 +129,9 @@ rows. Use
DataFusion rejects each other value of `p`. If you omit `p`, the unit is
`Nanosecond`. The precision goes after `TIMESTAMPTZ`, but before
`WITH TIME ZONE`: use `TIMESTAMPTZ(3)` or `TIMESTAMP(3) WITH TIME ZONE`.
`DATE`, `TIME` and `INTERVAL` do not accept a precision.
`TIME` accepts the same precisions and an optional `WITHOUT TIME ZONE` clause.
`TIME WITH TIME ZONE` and `TIMETZ` are unsupported.
`DATE` and `INTERVAL` do not accept a precision.

[`datafusion.execution.time_zone`]: ../configs.md
[issue #25166]: https://github.com/apache/datafusion/issues/25166
Expand Down
Loading