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 -- !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 +-- !query output +2021-07-11 06:30:45.678 + + +-- !query +SELECT try_make_timestamp_ltz(NULL, TIME'00:00:00') +-- !query schema +struct +-- !query output +NULL + + +-- !query +SELECT try_make_timestamp_ltz(DATE'1970-01-01', NULL) +-- !query schema +struct +-- !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 +-- !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 +-- !query output +2021-07-10 21:30:45.678