Skip to content
Closed
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
36 changes: 36 additions & 0 deletions sql/api/src/main/scala/org/apache/spark/sql/functions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8795,6 +8795,24 @@ object functions {
secs: Column): Column =
Column.fn("make_timestamp", years, months, days, hours, mins, secs)

/**
* Create a local date-time from date, time, and timezone fields.
*
* @group datetime_funcs
* @since 4.1.0
*/
def make_timestamp(date: Column, time: Column, timezone: Column): Column =
Column.fn("make_timestamp", date, time, timezone)

/**
* Create a local date-time from date and time fields.
*
* @group datetime_funcs
* @since 4.1.0
*/
def make_timestamp(date: Column, time: Column): Column =
Column.fn("make_timestamp", date, time)

/**
* Try to create a timestamp from years, months, days, hours, mins, secs and timezone fields.
* The result data type is consistent with the value of configuration `spark.sql.timestampType`.
Expand Down Expand Up @@ -8830,6 +8848,24 @@ object functions {
secs: Column): Column =
Column.fn("try_make_timestamp", years, months, days, hours, mins, secs)

/**
* Try to create a local date-time from date, time, and timezone fields.
*
* @group datetime_funcs
* @since 4.1.0
*/
def try_make_timestamp(date: Column, time: Column, timezone: Column): Column =
Column.fn("try_make_timestamp", date, time, timezone)

/**
* Try to create a local date-time from date and time fields.
*
* @group datetime_funcs
* @since 4.1.0
*/
def try_make_timestamp(date: Column, time: Column): Column =
Column.fn("try_make_timestamp", date, time)

/**
* Create the current timestamp with local time zone from years, months, days, hours, mins, secs
* and timezone fields. If the configuration `spark.sql.ansi.enabled` is false, the function
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,71 @@ abstract class TimeFunctionsSuiteBase extends QueryTest with SharedSparkSession
checkAnswer(result2, expected)
}

test("SPARK-53929: make_timestamp function") {
// Input data for the function.
val schema = StructType(Seq(
StructField("date", DateType, nullable = false),
StructField("time", TimeType(), nullable = false),
StructField("tz", StringType, nullable = false)
))
val data = Seq(
Row(LocalDate.parse("2020-01-01"), LocalTime.parse("00:00:00"), "America/Los_Angeles"),
Row(LocalDate.parse("2023-10-20"), LocalTime.parse("12:34:56"), "UTC"),
Row(LocalDate.parse("2023-12-31"), LocalTime.parse("23:59:59.999999"), "+01:00")
)
val df = spark.createDataFrame(spark.sparkContext.parallelize(data), schema)

// Test the function using both `selectExpr` and `select`, without Timezone.
val resultNoTz1 = df.selectExpr("make_timestamp(date, time)")
val resultNoTz2 = df.select(make_timestamp(col("date"), col("time")))
// Test the function using both `selectExpr` and `select`, with Timezone.
val resultWithTz1 = df.selectExpr("make_timestamp(date, time, tz)")
val resultWithTz2 = df.select(make_timestamp(col("date"), col("time"), col("tz")))
// Check that both methods produce the same result.
checkAnswer(resultNoTz1, resultNoTz2)
checkAnswer(resultWithTz1, resultWithTz2)

// Expected output of the function, without Timezone.
val expectedNoTz = Seq(
"2020-01-01 00:00:00",
"2023-10-20 12:34:56",
"2023-12-31 23:59:59.999999"
).toDF("timestamp").select(col("timestamp").cast("timestamp"))
// Check that the results match the expected output.
checkAnswer(resultNoTz1, expectedNoTz)
checkAnswer(resultNoTz2, expectedNoTz)
// Expected output of the function, with Timezone.
val expectedWithTz = Seq(
"2020-01-01 00:00:00",
"2023-10-20 05:34:56",
"2023-12-31 14:59:59.999999"
).toDF("timestamp").select(col("timestamp").cast("timestamp"))
// Check that the results match the expected output.
checkAnswer(resultWithTz1, expectedWithTz)
checkAnswer(resultWithTz2, expectedWithTz)

// NULL result is returned for any NULL input, without Timezone.
val nullInputNoTzDF = Seq(
(null, LocalTime.parse("00:00:00")),
(LocalDate.parse("2020-01-01"), null),
(null, null)
).toDF("date", "time")
val nullResultNoTz = Seq[Integer](null, null, null).toDF("ts").select(col("ts"))
checkAnswer(
nullInputNoTzDF.select(make_timestamp(col("date"), col("time"))),
nullResultNoTz
)
// NULL result is returned for any NULL input, with Timezone.
val nullInputWithTzDF = Seq(
(LocalDate.parse("2020-01-01"), LocalTime.parse("00:00:00"), null)
).toDF("date", "time", "timezone")
val nullResultWithTz = Seq[Integer](null).toDF("ts").select(col("ts"))
checkAnswer(
nullInputWithTzDF.select(make_timestamp(col("date"), col("time"), col("timezone"))),
nullResultWithTz
)
}

test("SPARK-53109: make_timestamp_ntz function") {
// Input data for the function.
val schema = StructType(Seq(
Expand Down Expand Up @@ -500,6 +565,71 @@ abstract class TimeFunctionsSuiteBase extends QueryTest with SharedSparkSession
)
}

test("SPARK-53929: try_make_timestamp function") {
// Input data for the function.
val schema = StructType(Seq(
StructField("date", DateType, nullable = false),
StructField("time", TimeType(), nullable = false),
StructField("tz", StringType, nullable = false)
))
val data = Seq(
Row(LocalDate.parse("2020-01-01"), LocalTime.parse("00:00:00"), "America/Los_Angeles"),
Row(LocalDate.parse("2023-10-20"), LocalTime.parse("12:34:56"), "UTC"),
Row(LocalDate.parse("2023-12-31"), LocalTime.parse("23:59:59.999999"), "+01:00")
)
val df = spark.createDataFrame(spark.sparkContext.parallelize(data), schema)

// Test the function using both `selectExpr` and `select`, without Timezone.
val resultNoTz1 = df.selectExpr("try_make_timestamp(date, time)")
val resultNoTz2 = df.select(try_make_timestamp(col("date"), col("time")))
// Test the function using both `selectExpr` and `select`, with Timezone.
val resultWithTz1 = df.selectExpr("try_make_timestamp(date, time, tz)")
val resultWithTz2 = df.select(try_make_timestamp(col("date"), col("time"), col("tz")))
// Check that both methods produce the same result.
checkAnswer(resultNoTz1, resultNoTz2)
checkAnswer(resultWithTz1, resultWithTz2)

// Expected output of the function, without Timezone.
val expectedNoTz = Seq(
"2020-01-01 00:00:00",
"2023-10-20 12:34:56",
"2023-12-31 23:59:59.999999"
).toDF("timestamp").select(col("timestamp").cast("timestamp"))
// Check that the results match the expected output.
checkAnswer(resultNoTz1, expectedNoTz)
checkAnswer(resultNoTz2, expectedNoTz)
// Expected output of the function, with Timezone.
val expectedWithTz = Seq(
"2020-01-01 00:00:00",
"2023-10-20 05:34:56",
"2023-12-31 14:59:59.999999"
).toDF("timestamp").select(col("timestamp").cast("timestamp"))
// Check that the results match the expected output.
checkAnswer(resultWithTz1, expectedWithTz)
checkAnswer(resultWithTz2, expectedWithTz)

// NULL result is returned for any NULL input, without Timezone.
val nullInputNoTzDF = Seq(
(null, LocalTime.parse("00:00:00")),
(LocalDate.parse("2020-01-01"), null),
(null, null)
).toDF("date", "time")
val nullResultNoTz = Seq[Integer](null, null, null).toDF("ts").select(col("ts"))
checkAnswer(
nullInputNoTzDF.select(try_make_timestamp(col("date"), col("time"))),
nullResultNoTz
)
// NULL result is returned for any NULL input, with Timezone.
val nullInputWithTzDF = Seq(
(LocalDate.parse("2020-01-01"), LocalTime.parse("00:00:00"), null)
).toDF("date", "time", "timezone")
val nullResultWithTz = Seq[Integer](null).toDF("ts").select(col("ts"))
checkAnswer(
nullInputWithTzDF.select(try_make_timestamp(col("date"), col("time"), col("timezone"))),
nullResultWithTz
)
}

test("SPARK-53109: try_make_timestamp_ntz function") {
// Input data for the function.
val schema = StructType(Seq(
Expand Down