This is an automated email from the ASF dual-hosted git repository.
wenchen pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/spark.git
The following commit(s) were added to refs/heads/master by this push:
new 4a62f7509c50 [SPARK-53319][SQL] Support the time type by
try_make_timestamp_ltz()
4a62f7509c50 is described below
commit 4a62f7509c50018bd5928b0af9c5cb8ef739f29e
Author: Uros Bojanic <[email protected]>
AuthorDate: Thu Oct 23 01:01:12 2025 +0800
[SPARK-53319][SQL] Support the time type by try_make_timestamp_ltz()
### What changes were proposed in this pull request?
In the PR, I propose to extend the `try_make_timestamp_ltz` function, and
accept a date and time fields.
**Syntax**
```
try_make_timestamp_ltz(date[, time])
```
**Arguments**
- `date`: A date expression.
- `time`: A time expression.
**Returns**
A `TIMESTAMP_LTZ`.
Examples
```
> SELECT try_make_timestamp_ltz(DATE'2014-12-28', TIME'6:30:45.887');
2014-12-28 06:30:45.887
```
### Why are the changes needed?
Users will be able to create a timestamp with local time zone by combining
a time and a date.
### Does this PR introduce _any_ user-facing change?
Yes, this extends `try_make_timestamp_ltz` to accept additional kinds of
inputs.
### How was this patch tested?
Added new e2e SQL tests in corresponding golden files.
### Was this patch authored or co-authored using generative AI tooling?
No.
Closes #52063 from uros-db/try_make_timestamp_ltz.
Lead-authored-by: Uros Bojanic <[email protected]>
Co-authored-by: Wenchen Fan <[email protected]>
Signed-off-by: Wenchen Fan <[email protected]>
---
.../catalyst/expressions/datetimeExpressions.scala | 21 ++++-
.../analyzer-results/timestamp-ltz.sql.out | 81 +++++++++++++++++++
.../resources/sql-tests/inputs/timestamp-ltz.sql | 12 +++
.../sql-tests/results/timestamp-ltz.sql.out | 92 ++++++++++++++++++++++
4 files changed, 204 insertions(+), 2 deletions(-)
diff --git
a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/datetimeExpressions.scala
b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/datetimeExpressions.scala
index 3948f8bd0dd6..226e098165b8 100644
---
a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/datetimeExpressions.scala
+++
b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/datetimeExpressions.scala
@@ -2806,7 +2806,11 @@ object MakeTimestampLTZExpressionBuilder extends
ExpressionBuilder {
// scalastyle:off line.size.limit
@ExpressionDescription(
- usage = "_FUNC_(year, month, day, hour, min, sec[, timezone]) - Try to
create the current timestamp with local time zone from year, month, day, hour,
min, sec and timezone fields. The function returns NULL on invalid inputs.",
+ usage = """
+ _FUNC_(year, month, day, hour, min, sec[, timezone]) - Try to create the
current timestamp with local time zone from year, month, day, hour, min, sec
and (optional) timezone fields. The function returns NULL on invalid inputs.
+
+ _FUNC_(date, time[, timezone]) - Try to create the current timestamp with
local time zone from date, time and (optional) timezone fields.
+ """,
arguments = """
Arguments:
* year - the year to represent, from 1 to 9999
@@ -2818,6 +2822,8 @@ object MakeTimestampLTZExpressionBuilder extends
ExpressionBuilder {
0 to 60. If the sec argument equals to 60, the seconds field is
set
to 0 and 1 minute is added to the final timestamp.
* timezone - the time zone identifier. For example, CET, UTC and etc.
+ * date - a date to represent, from 0001-01-01 to 9999-12-31
+ * time - a local time to represent, from 00:00:00 to 23:59:59.999999
""",
examples = """
Examples:
@@ -2831,6 +2837,10 @@ object MakeTimestampLTZExpressionBuilder extends
ExpressionBuilder {
NULL
> SELECT _FUNC_(2024, 13, 22, 15, 30, 0);
NULL
+ > SELECT _FUNC_(DATE'2014-12-28', TIME'6:30:45.887');
+ 2014-12-28 06:30:45.887
+ > SELECT _FUNC_(DATE'2014-12-28', TIME'6:30:45.887', 'CET');
+ 2014-12-27 21:30:45.887
""",
group = "datetime_funcs",
since = "4.0.0")
@@ -2838,7 +2848,14 @@ object MakeTimestampLTZExpressionBuilder extends
ExpressionBuilder {
object TryMakeTimestampLTZExpressionBuilder extends ExpressionBuilder {
override def build(funcName: String, expressions: Seq[Expression]):
Expression = {
val numArgs = expressions.length
- if (numArgs == 6 || numArgs == 7) {
+ if (numArgs == 2 || numArgs == 3) {
+ // Overload for: date, time[, timezone].
+ MakeTimestampFromDateTime(
+ expressions(0),
+ Some(expressions(1)),
+ expressions.drop(2).lastOption
+ )
+ } else if (numArgs == 6 || numArgs == 7) {
MakeTimestamp(
expressions(0),
expressions(1),
diff --git
a/sql/core/src/test/resources/sql-tests/analyzer-results/timestamp-ltz.sql.out
b/sql/core/src/test/resources/sql-tests/analyzer-results/timestamp-ltz.sql.out
index 73fbade579c5..cc6ff0da5f79 100644
---
a/sql/core/src/test/resources/sql-tests/analyzer-results/timestamp-ltz.sql.out
+++
b/sql/core/src/test/resources/sql-tests/analyzer-results/timestamp-ltz.sql.out
@@ -132,3 +132,84 @@ Project [make_timestamp(make_date(2021, 7, 11, true),
Some(make_time(6, 30, cast
SELECT convert_timezone('Europe/Brussels', timestamp_ltz'2022-03-23 00:00:00
America/Los_Angeles')
-- !query analysis
[Analyzer test output redacted due to nondeterminism]
+
+
+-- !query
+SELECT try_make_timestamp_ltz(make_date(2021, 07, 11), make_time(6, 30,
45.678))
+-- !query analysis
+Project [make_timestamp(make_date(2021, 7, 11, true), Some(make_time(6, 30,
cast(45.678 as decimal(16,6)))), None, Some(America/Los_Angeles)) AS
make_timestamp(make_date(2021, 7, 11), make_time(6, 30, 45.678))#x]
++- OneRowRelation
+
+
+-- !query
+SELECT try_make_timestamp_ltz(NULL, TIME'00:00:00')
+-- !query analysis
+[Analyzer test output redacted due to nondeterminism]
+
+
+-- !query
+SELECT try_make_timestamp_ltz(DATE'1970-01-01', NULL)
+-- !query analysis
+[Analyzer test output redacted due to nondeterminism]
+
+
+-- !query
+SELECT try_make_timestamp_ltz(timestamp_ntz'2018-11-17 13:33:33', TIME'0:0:0')
+-- !query analysis
+org.apache.spark.sql.catalyst.ExtendedAnalysisException
+{
+ "errorClass" : "DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE",
+ "sqlState" : "42K09",
+ "messageParameters" : {
+ "inputSql" : "\"TIMESTAMP_NTZ '2018-11-17 13:33:33'\"",
+ "inputType" : "\"TIMESTAMP_NTZ\"",
+ "paramIndex" : "first",
+ "requiredType" : "\"DATE\"",
+ "sqlExpr" : "\"make_timestamp(TIMESTAMP_NTZ '2018-11-17 13:33:33', TIME
'00:00:00')\""
+ },
+ "queryContext" : [ {
+ "objectType" : "",
+ "objectName" : "",
+ "startIndex" : 8,
+ "stopIndex" : 78,
+ "fragment" : "try_make_timestamp_ltz(timestamp_ntz'2018-11-17 13:33:33',
TIME'0:0:0')"
+ } ]
+}
+
+
+-- !query
+SELECT try_make_timestamp_ltz(DATE'2025-06-20', timestamp_ntz'2018-11-17
13:33:33')
+-- !query analysis
+org.apache.spark.sql.catalyst.ExtendedAnalysisException
+{
+ "errorClass" : "DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE",
+ "sqlState" : "42K09",
+ "messageParameters" : {
+ "inputSql" : "\"TIMESTAMP_NTZ '2018-11-17 13:33:33'\"",
+ "inputType" : "\"TIMESTAMP_NTZ\"",
+ "paramIndex" : "second",
+ "requiredType" : "\"TIME\"",
+ "sqlExpr" : "\"make_timestamp(DATE '2025-06-20', TIMESTAMP_NTZ '2018-11-17
13:33:33')\""
+ },
+ "queryContext" : [ {
+ "objectType" : "",
+ "objectName" : "",
+ "startIndex" : 8,
+ "stopIndex" : 83,
+ "fragment" : "try_make_timestamp_ltz(DATE'2025-06-20',
timestamp_ntz'2018-11-17 13:33:33')"
+ } ]
+}
+
+
+-- !query
+SELECT try_make_timestamp_ltz(make_date(2021, 07, 11), make_time(6, 30,
45.678), 'PST')
+-- !query analysis
+Project [make_timestamp(make_date(2021, 7, 11, true), Some(make_time(6, 30,
cast(45.678 as decimal(16,6)))), Some(PST), Some(America/Los_Angeles)) AS
make_timestamp(make_date(2021, 7, 11), make_time(6, 30, 45.678), PST)#x]
++- OneRowRelation
+
+
+-- !query
+SELECT try_make_timestamp_ltz(make_date(2021, 07, 11), make_time(6, 30,
45.678), 'CET')
+-- !query analysis
+Project [make_timestamp(make_date(2021, 7, 11, true), Some(make_time(6, 30,
cast(45.678 as decimal(16,6)))), Some(CET), Some(America/Los_Angeles)) AS
make_timestamp(make_date(2021, 7, 11), make_time(6, 30, 45.678), CET)#x]
++- OneRowRelation
diff --git a/sql/core/src/test/resources/sql-tests/inputs/timestamp-ltz.sql
b/sql/core/src/test/resources/sql-tests/inputs/timestamp-ltz.sql
index c068e35dbd92..6484383eabc0 100644
--- a/sql/core/src/test/resources/sql-tests/inputs/timestamp-ltz.sql
+++ b/sql/core/src/test/resources/sql-tests/inputs/timestamp-ltz.sql
@@ -28,3 +28,15 @@ SELECT make_timestamp_ltz(make_date(2021, 07, 11),
make_time(6, 30, 45.678), 'PS
SELECT make_timestamp_ltz(make_date(2021, 07, 11), make_time(6, 30, 45.678),
'CET');
SELECT convert_timezone('Europe/Brussels', timestamp_ltz'2022-03-23 00:00:00
America/Los_Angeles');
+
+-- Try TimestampLTZ date/time fields constructor
+SELECT try_make_timestamp_ltz(make_date(2021, 07, 11), make_time(6, 30,
45.678));
+-- Handling NULL input.
+SELECT try_make_timestamp_ltz(NULL, TIME'00:00:00');
+SELECT try_make_timestamp_ltz(DATE'1970-01-01', NULL);
+-- Handling invalid input.
+SELECT try_make_timestamp_ltz(timestamp_ntz'2018-11-17 13:33:33', TIME'0:0:0');
+SELECT try_make_timestamp_ltz(DATE'2025-06-20', timestamp_ntz'2018-11-17
13:33:33');
+-- Optional timezone is ignored.
+SELECT try_make_timestamp_ltz(make_date(2021, 07, 11), make_time(6, 30,
45.678), 'PST');
+SELECT try_make_timestamp_ltz(make_date(2021, 07, 11), make_time(6, 30,
45.678), 'CET');
diff --git
a/sql/core/src/test/resources/sql-tests/results/timestamp-ltz.sql.out
b/sql/core/src/test/resources/sql-tests/results/timestamp-ltz.sql.out
index 69f9213cfc23..6ec411a790eb 100644
--- a/sql/core/src/test/resources/sql-tests/results/timestamp-ltz.sql.out
+++ b/sql/core/src/test/resources/sql-tests/results/timestamp-ltz.sql.out
@@ -160,3 +160,95 @@ SELECT convert_timezone('Europe/Brussels',
timestamp_ltz'2022-03-23 00:00:00 Ame
struct<convert_timezone(current_timezone(), Europe/Brussels, TIMESTAMP
'2022-03-23 00:00:00'):timestamp_ntz>
-- !query output
2022-03-23 08:00:00
+
+
+-- !query
+SELECT try_make_timestamp_ltz(make_date(2021, 07, 11), make_time(6, 30,
45.678))
+-- !query schema
+struct<make_timestamp(make_date(2021, 7, 11), make_time(6, 30,
45.678)):timestamp>
+-- !query output
+2021-07-11 06:30:45.678
+
+
+-- !query
+SELECT try_make_timestamp_ltz(NULL, TIME'00:00:00')
+-- !query schema
+struct<make_timestamp(NULL, TIME '00:00:00'):timestamp>
+-- !query output
+NULL
+
+
+-- !query
+SELECT try_make_timestamp_ltz(DATE'1970-01-01', NULL)
+-- !query schema
+struct<make_timestamp(DATE '1970-01-01', NULL):timestamp>
+-- !query output
+NULL
+
+
+-- !query
+SELECT try_make_timestamp_ltz(timestamp_ntz'2018-11-17 13:33:33', TIME'0:0:0')
+-- !query schema
+struct<>
+-- !query output
+org.apache.spark.sql.catalyst.ExtendedAnalysisException
+{
+ "errorClass" : "DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE",
+ "sqlState" : "42K09",
+ "messageParameters" : {
+ "inputSql" : "\"TIMESTAMP_NTZ '2018-11-17 13:33:33'\"",
+ "inputType" : "\"TIMESTAMP_NTZ\"",
+ "paramIndex" : "first",
+ "requiredType" : "\"DATE\"",
+ "sqlExpr" : "\"make_timestamp(TIMESTAMP_NTZ '2018-11-17 13:33:33', TIME
'00:00:00')\""
+ },
+ "queryContext" : [ {
+ "objectType" : "",
+ "objectName" : "",
+ "startIndex" : 8,
+ "stopIndex" : 78,
+ "fragment" : "try_make_timestamp_ltz(timestamp_ntz'2018-11-17 13:33:33',
TIME'0:0:0')"
+ } ]
+}
+
+
+-- !query
+SELECT try_make_timestamp_ltz(DATE'2025-06-20', timestamp_ntz'2018-11-17
13:33:33')
+-- !query schema
+struct<>
+-- !query output
+org.apache.spark.sql.catalyst.ExtendedAnalysisException
+{
+ "errorClass" : "DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE",
+ "sqlState" : "42K09",
+ "messageParameters" : {
+ "inputSql" : "\"TIMESTAMP_NTZ '2018-11-17 13:33:33'\"",
+ "inputType" : "\"TIMESTAMP_NTZ\"",
+ "paramIndex" : "second",
+ "requiredType" : "\"TIME\"",
+ "sqlExpr" : "\"make_timestamp(DATE '2025-06-20', TIMESTAMP_NTZ '2018-11-17
13:33:33')\""
+ },
+ "queryContext" : [ {
+ "objectType" : "",
+ "objectName" : "",
+ "startIndex" : 8,
+ "stopIndex" : 83,
+ "fragment" : "try_make_timestamp_ltz(DATE'2025-06-20',
timestamp_ntz'2018-11-17 13:33:33')"
+ } ]
+}
+
+
+-- !query
+SELECT try_make_timestamp_ltz(make_date(2021, 07, 11), make_time(6, 30,
45.678), 'PST')
+-- !query schema
+struct<make_timestamp(make_date(2021, 7, 11), make_time(6, 30, 45.678),
PST):timestamp>
+-- !query output
+2021-07-11 06:30:45.678
+
+
+-- !query
+SELECT try_make_timestamp_ltz(make_date(2021, 07, 11), make_time(6, 30,
45.678), 'CET')
+-- !query schema
+struct<make_timestamp(make_date(2021, 7, 11), make_time(6, 30, 45.678),
CET):timestamp>
+-- !query output
+2021-07-10 21:30:45.678
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]