This is an automated email from the ASF dual-hosted git repository.

comphead pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion-comet.git


The following commit(s) were added to refs/heads/main by this push:
     new 2e8cc34fc feat: Support Spark expression: convert_timezone (#4369)
2e8cc34fc is described below

commit 2e8cc34fcae12650ecfa455a5b25caf37731977b
Author: Bolin Lin <[email protected]>
AuthorDate: Wed May 20 13:26:03 2026 -0400

    feat: Support Spark expression: convert_timezone (#4369)
---
 .../contributor-guide/spark_expressions_support.md |  2 +-
 docs/source/user-guide/latest/expressions.md       |  1 +
 .../org/apache/comet/serde/QueryPlanSerde.scala    |  1 +
 .../scala/org/apache/comet/serde/datetime.scala    | 23 +++++++++-
 .../expressions/datetime/convert_timezone.sql      | 49 ++++++++++++++++++++++
 5 files changed, 74 insertions(+), 2 deletions(-)

diff --git a/docs/source/contributor-guide/spark_expressions_support.md 
b/docs/source/contributor-guide/spark_expressions_support.md
index 3594881fe..24422b7a6 100644
--- a/docs/source/contributor-guide/spark_expressions_support.md
+++ b/docs/source/contributor-guide/spark_expressions_support.md
@@ -215,7 +215,7 @@
 ### datetime_funcs
 
 - [ ] add_months
-- [ ] convert_timezone
+- [x] convert_timezone
 - [ ] curdate
 - [ ] current_date
 - [ ] current_time
diff --git a/docs/source/user-guide/latest/expressions.md 
b/docs/source/user-guide/latest/expressions.md
index 513110b5f..ef74836d8 100644
--- a/docs/source/user-guide/latest/expressions.md
+++ b/docs/source/user-guide/latest/expressions.md
@@ -101,6 +101,7 @@ of expressions that be disabled.
 
 | Expression       | SQL                          |
 | ---------------- | ---------------------------- |
+| ConvertTimezone  | `convert_timezone`           |
 | CurrentTimeZone  | `current_timezone`           |
 | DateAdd          | `date_add`                   |
 | DateDiff         | `datediff`                   |
diff --git a/spark/src/main/scala/org/apache/comet/serde/QueryPlanSerde.scala 
b/spark/src/main/scala/org/apache/comet/serde/QueryPlanSerde.scala
index 6ce22968d..bfdc78226 100644
--- a/spark/src/main/scala/org/apache/comet/serde/QueryPlanSerde.scala
+++ b/spark/src/main/scala/org/apache/comet/serde/QueryPlanSerde.scala
@@ -217,6 +217,7 @@ object QueryPlanSerde extends Logging with CometExprShim 
with CometTypeShim {
 
   private[comet] val temporalExpressions: Map[Class[_ <: Expression], 
CometExpressionSerde[_]] =
     Map(
+      classOf[ConvertTimezone] -> CometConvertTimezone,
       classOf[DateAdd] -> CometDateAdd,
       classOf[DateDiff] -> CometDateDiff,
       classOf[DateFormatClass] -> CometDateFormat,
diff --git a/spark/src/main/scala/org/apache/comet/serde/datetime.scala 
b/spark/src/main/scala/org/apache/comet/serde/datetime.scala
index 3192697b2..b57b1e4e5 100644
--- a/spark/src/main/scala/org/apache/comet/serde/datetime.scala
+++ b/spark/src/main/scala/org/apache/comet/serde/datetime.scala
@@ -21,7 +21,7 @@ package org.apache.comet.serde
 
 import java.util.Locale
 
-import org.apache.spark.sql.catalyst.expressions.{Attribute, DateAdd, 
DateDiff, DateFormatClass, DateFromUnixDate, DateSub, DayOfMonth, DayOfWeek, 
DayOfYear, Days, FromUTCTimestamp, GetDateField, Hour, Hours, LastDay, Literal, 
MakeDate, Minute, Month, NextDay, Quarter, Second, SecondsToTimestamp, 
ToUTCTimestamp, TruncDate, TruncTimestamp, UnixDate, UnixTimestamp, WeekDay, 
WeekOfYear, Year}
+import org.apache.spark.sql.catalyst.expressions.{Attribute, ConvertTimezone, 
DateAdd, DateDiff, DateFormatClass, DateFromUnixDate, DateSub, DayOfMonth, 
DayOfWeek, DayOfYear, Days, FromUTCTimestamp, GetDateField, Hour, Hours, 
LastDay, Literal, MakeDate, Minute, Month, NextDay, Quarter, Second, 
SecondsToTimestamp, ToUTCTimestamp, TruncDate, TruncTimestamp, UnixDate, 
UnixTimestamp, WeekDay, WeekOfYear, Year}
 import org.apache.spark.sql.internal.SQLConf
 import org.apache.spark.sql.types.{DateType, DoubleType, FloatType, 
IntegerType, LongType, StringType, TimestampNTZType, TimestampType}
 import org.apache.spark.unsafe.types.UTF8String
@@ -409,6 +409,27 @@ object CometToUTCTimestamp extends 
CometExpressionSerde[ToUTCTimestamp] {
   }
 }
 
+object CometConvertTimezone extends CometExpressionSerde[ConvertTimezone] {
+
+  override def getSupportLevel(expr: ConvertTimezone): SupportLevel =
+    Incompatible(Some(UTCTimestampSerde.tzParseIncompatReason))
+
+  override def getIncompatibleReasons(): Seq[String] =
+    Seq(UTCTimestampSerde.tzParseIncompatReason)
+
+  override def convert(
+      expr: ConvertTimezone,
+      inputs: Seq[Attribute],
+      binding: Boolean): Option[ExprOuterClass.Expr] = {
+    val srcTz = exprToProtoInternal(expr.sourceTz, inputs, binding)
+    val tgtTz = exprToProtoInternal(expr.targetTz, inputs, binding)
+    val ts = exprToProtoInternal(expr.sourceTs, inputs, binding)
+    val toUtc = scalarFunctionExprToProto("to_utc_timestamp", ts, srcTz)
+    val fromUtc = scalarFunctionExprToProto("from_utc_timestamp", toUtc, tgtTz)
+    optExprWithInfo(fromUtc, expr, expr.children: _*)
+  }
+}
+
 object CometNextDay extends CometScalarFunction[NextDay]("next_day")
 
 object CometMakeDate extends CometScalarFunction[MakeDate]("make_date")
diff --git 
a/spark/src/test/resources/sql-tests/expressions/datetime/convert_timezone.sql 
b/spark/src/test/resources/sql-tests/expressions/datetime/convert_timezone.sql
new file mode 100644
index 000000000..6c9a8947b
--- /dev/null
+++ 
b/spark/src/test/resources/sql-tests/expressions/datetime/convert_timezone.sql
@@ -0,0 +1,49 @@
+-- Licensed to the Apache Software Foundation (ASF) under one
+-- or more contributor license agreements.  See the NOTICE file
+-- distributed with this work for additional information
+-- regarding copyright ownership.  The ASF licenses this file
+-- to you under the Apache License, Version 2.0 (the
+-- "License"); you may not use this file except in compliance
+-- with the License.  You may obtain a copy of the License at
+--
+--   http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing,
+-- software distributed under the License is distributed on an
+-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+-- KIND, either express or implied.  See the License for the
+-- specific language governing permissions and limitations
+-- under the License.
+
+-- Config: spark.comet.expression.ConvertTimezone.allowIncompatible=true
+-- ConfigMatrix: spark.sql.session.timeZone=UTC,America/Los_Angeles
+
+statement
+CREATE TABLE test_convert_timezone(ts timestamp_ntz, src string, tgt string) 
USING parquet
+
+statement
+INSERT INTO test_convert_timezone VALUES
+  (timestamp_ntz'2021-12-06 08:00:00', 'UTC', 'America/Los_Angeles'),
+  (timestamp_ntz'2021-07-01 12:00:00', 'America/New_York', 'Asia/Tokyo'),
+  (timestamp_ntz'2023-01-15 09:30:00', 'America/Los_Angeles', 'UTC'),
+  (NULL, 'UTC', 'Asia/Tokyo'),
+  (timestamp_ntz'2021-12-06 08:00:00', NULL, 'Asia/Tokyo'),
+  (timestamp_ntz'2021-12-06 08:00:00', 'UTC', NULL)
+
+query
+SELECT convert_timezone('UTC', 'America/Los_Angeles', timestamp_ntz'2021-12-06 
08:00:00')
+
+query
+SELECT convert_timezone('Asia/Tokyo', 'Europe/Berlin', 
timestamp_ntz'2021-12-06 12:00:00')
+
+query
+SELECT convert_timezone('America/Los_Angeles', 'Asia/Tokyo', 
timestamp_ntz'2023-01-15 20:00:00')
+
+query
+SELECT convert_timezone(CAST(NULL AS STRING), 'Asia/Tokyo', 
timestamp_ntz'2021-12-06 08:00:00')
+
+query
+SELECT convert_timezone('UTC', CAST(NULL AS STRING), timestamp_ntz'2021-12-06 
08:00:00')
+
+query
+SELECT convert_timezone(src, tgt, ts) FROM test_convert_timezone


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to