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

yiguolei pushed a commit to branch branch-4.0
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/branch-4.0 by this push:
     new 7a4edb0c158 branch-4.0: [Fix](ttz) Fix TIMESTAMPTZ elapsed-time 
semantics to use UTC (#63161) (#63251)
7a4edb0c158 is described below

commit 7a4edb0c158b86e01923ff2838433a5a78b4e5ec
Author: linrrarity <[email protected]>
AuthorDate: Wed May 27 12:24:28 2026 +0800

    branch-4.0: [Fix](ttz) Fix TIMESTAMPTZ elapsed-time semantics to use UTC 
(#63161) (#63251)
    
    pick: https://github.com/apache/doris/pull/63161
---
 .../aggregate_function_sequence_match.cpp          |   3 +
 .../aggregate_function_sequence_match.h            |   7 +-
 .../aggregate_function_window_funnel.cpp           |   7 +-
 .../aggregate_function_window_funnel.h             |  36 +++--
 .../function_date_or_datetime_computation.cpp      |   6 +-
 .../function_date_or_datetime_computation.h        |  16 +-
 be/src/vec/runtime/timestamptz_value.h             |   6 +
 .../expressions/functions/agg/SequenceCount.java   |   3 +
 .../functions/agg/SequenceFunction.java            |   2 +-
 .../expressions/functions/agg/SequenceMatch.java   |   3 +
 .../expressions/functions/agg/TopNWeighted.java    |   8 +
 .../expressions/functions/agg/WindowFunnel.java    |  15 +-
 .../expressions/functions/scalar/DateDiff.java     |   3 +
 .../expressions/functions/scalar/DaysDiff.java     |   2 +
 .../expressions/functions/scalar/HoursDiff.java    |   3 +
 .../functions/scalar/MicroSecondsDiff.java         |   3 +
 .../functions/scalar/MilliSecondsDiff.java         |   3 +
 .../expressions/functions/scalar/MinutesDiff.java  |   3 +
 .../expressions/functions/scalar/MonthsDiff.java   |   7 +-
 .../expressions/functions/scalar/QuartersDiff.java |   7 +-
 .../expressions/functions/scalar/SecondsDiff.java  |   3 +
 .../expressions/functions/scalar/TimeDiff.java     |  11 ++
 .../expressions/functions/scalar/WeeksDiff.java    |   7 +-
 .../expressions/functions/scalar/YearsDiff.java    |   7 +-
 .../timestamptz/test_timestamptz_utc_functions.out |  33 ++++
 .../test_timestamptz_utc_functions.groovy          | 180 +++++++++++++++++++++
 26 files changed, 345 insertions(+), 39 deletions(-)

diff --git 
a/be/src/vec/aggregate_functions/aggregate_function_sequence_match.cpp 
b/be/src/vec/aggregate_functions/aggregate_function_sequence_match.cpp
index fd975bb5e34..a607b1440eb 100644
--- a/be/src/vec/aggregate_functions/aggregate_function_sequence_match.cpp
+++ b/be/src/vec/aggregate_functions/aggregate_function_sequence_match.cpp
@@ -52,6 +52,9 @@ AggregateFunctionPtr 
create_aggregate_function_sequence_base(const std::string&
     case TYPE_DATEV2:
         return creator_without_type::create<AggregateFunction<TYPE_DATEV2>>(
                 argument_types, result_is_nullable, attr);
+    case TYPE_TIMESTAMPTZ:
+        return 
creator_without_type::create<AggregateFunction<TYPE_TIMESTAMPTZ>>(
+                argument_types, result_is_nullable, attr);
     default:
         return nullptr;
     }
diff --git a/be/src/vec/aggregate_functions/aggregate_function_sequence_match.h 
b/be/src/vec/aggregate_functions/aggregate_function_sequence_match.h
index ba0c2259327..0b2c327062b 100644
--- a/be/src/vec/aggregate_functions/aggregate_function_sequence_match.h
+++ b/be/src/vec/aggregate_functions/aggregate_function_sequence_match.h
@@ -75,10 +75,6 @@ constexpr auto sequence_match_max_iterations = 1000000l;
 template <PrimitiveType T, typename Derived>
 struct AggregateFunctionSequenceMatchData final {
     using Timestamp = typename PrimitiveTypeTraits<T>::CppType;
-    using NativeType =
-            std::conditional_t<T == TYPE_DATEV2, uint32_t,
-                               std::conditional_t<T == TYPE_DATETIMEV2, 
uint64_t,
-                                                  typename 
PrimitiveTypeTraits<T>::CppType>>;
     using Events = std::bitset<MAX_EVENTS>;
     using TimestampEvents = std::pair<Timestamp, Events>;
     using Comparator = ComparePairFirst<std::less>;
@@ -256,7 +252,7 @@ private:
                         return;
                     }
 
-                    NativeType duration = 0;
+                    uint64_t duration = 0;
                     const auto* prev_pos = pos;
                     pos = try_read_first_int_text(duration, pos, end);
                     if (pos == prev_pos) {
@@ -595,7 +591,6 @@ class AggregateFunctionSequenceBase
         : public 
IAggregateFunctionDataHelper<AggregateFunctionSequenceMatchData<T, Derived>,
                                               Derived> {
 public:
-    using NativeType = typename PrimitiveTypeTraits<T>::CppType;
     AggregateFunctionSequenceBase(const DataTypes& arguments)
             : 
IAggregateFunctionDataHelper<AggregateFunctionSequenceMatchData<T, Derived>, 
Derived>(
                       arguments) {
diff --git 
a/be/src/vec/aggregate_functions/aggregate_function_window_funnel.cpp 
b/be/src/vec/aggregate_functions/aggregate_function_window_funnel.cpp
index dca650724f9..094f1b54625 100644
--- a/be/src/vec/aggregate_functions/aggregate_function_window_funnel.cpp
+++ b/be/src/vec/aggregate_functions/aggregate_function_window_funnel.cpp
@@ -38,10 +38,13 @@ AggregateFunctionPtr 
create_aggregate_function_window_funnel(const std::string&
         return nullptr;
     }
     if (argument_types[2]->get_primitive_type() == TYPE_DATETIMEV2) {
-        return creator_without_type::create<AggregateFunctionWindowFunnel>(
+        return 
creator_without_type::create<AggregateFunctionWindowFunnel<TYPE_DATETIMEV2>>(
+                argument_types, result_is_nullable, attr);
+    } else if (argument_types[2]->get_primitive_type() == TYPE_TIMESTAMPTZ) {
+        return 
creator_without_type::create<AggregateFunctionWindowFunnel<TYPE_TIMESTAMPTZ>>(
                 argument_types, result_is_nullable, attr);
     } else {
-        LOG(WARNING) << "Only support DateTime type as window argument!";
+        LOG(WARNING) << "Only support DateTime or TimeStampTz type as window 
argument!";
         return nullptr;
     }
 }
diff --git a/be/src/vec/aggregate_functions/aggregate_function_window_funnel.h 
b/be/src/vec/aggregate_functions/aggregate_function_window_funnel.h
index ad0cf057e62..4ebfdc9f77e 100644
--- a/be/src/vec/aggregate_functions/aggregate_function_window_funnel.h
+++ b/be/src/vec/aggregate_functions/aggregate_function_window_funnel.h
@@ -72,9 +72,11 @@ WindowFunnelMode string_to_window_funnel_mode(const String& 
string) {
     }
 }
 
+template <PrimitiveType T>
 struct DataValue {
     using TimestampEvent = std::vector<ColumnUInt8::Container>;
-    std::vector<DateV2Value<DateTimeV2ValueType>> dt;
+    using DateValueType = typename PrimitiveTypeTraits<T>::CppType;
+    std::vector<DateValueType> dt;
     TimestampEvent event_columns_data;
     bool operator<(const DataValue& other) const { return dt < other.dt; }
     void clear() {
@@ -99,15 +101,16 @@ struct DataValue {
     }
 };
 
+template <PrimitiveType T>
 struct WindowFunnelState {
-    static constexpr PrimitiveType PType = PrimitiveType::TYPE_DATETIMEV2;
-    using NativeType = UInt64;
-    using DateValueType = DateV2Value<DateTimeV2ValueType>;
+    static constexpr PrimitiveType PType = T;
+    using NativeType = typename PrimitiveTypeTraits<T>::StorageFieldType;
+    using DateValueType = typename PrimitiveTypeTraits<T>::CppType;
     int event_count = 0;
     int64_t window;
     bool enable_mode;
     WindowFunnelMode window_funnel_mode;
-    DataValue events_list;
+    DataValue<T> events_list;
 
     WindowFunnelState() {
         event_count = 0;
@@ -125,7 +128,8 @@ struct WindowFunnelState {
         window = win;
         window_funnel_mode = enable_mode ? mode : WindowFunnelMode::DEFAULT;
         events_list.dt.emplace_back(
-                assert_cast<const 
ColumnVector<PType>&>(*arg_columns[2]).get_data()[row_num]);
+                assert_cast<const typename 
PrimitiveTypeTraits<PType>::ColumnType&>(*arg_columns[2])
+                        .get_data()[row_num]);
         for (int i = 0; i < event_count; i++) {
             events_list.event_columns_data[i].emplace_back(
                     assert_cast<const ColumnUInt8&>(*arg_columns[3 + 
i]).get_data()[row_num]);
@@ -270,7 +274,7 @@ struct WindowFunnelState {
         }
     }
 
-    void merge(const WindowFunnelState& other) {
+    void merge(const WindowFunnelState<T>& other) {
         if (other.events_list.empty()) {
             return;
         }
@@ -329,7 +333,9 @@ struct WindowFunnelState {
         events_list.clear();
         events_list.dt.resize(size);
         for (auto i = 0; i < size; i++) {
-            read_var_int(*reinterpret_cast<Int64*>(&events_list.dt[i]), in);
+            Int64 timestamp = 0;
+            read_var_int(timestamp, in);
+            events_list.dt[i] = DateValueType(static_cast<UInt64>(timestamp));
         }
         events_list.event_columns_data.resize(event_count);
         for (int64_t i = 0; i < event_count; i++) {
@@ -344,17 +350,19 @@ struct WindowFunnelState {
     }
 };
 
-class AggregateFunctionWindowFunnel
-        : public IAggregateFunctionDataHelper<WindowFunnelState, 
AggregateFunctionWindowFunnel>,
+template <PrimitiveType T>
+class AggregateFunctionWindowFunnel final
+        : public IAggregateFunctionDataHelper<WindowFunnelState<T>,
+                                              
AggregateFunctionWindowFunnel<T>>,
           MultiExpression,
           NullableAggregateFunction {
 public:
     AggregateFunctionWindowFunnel(const DataTypes& argument_types_)
-            : IAggregateFunctionDataHelper<WindowFunnelState, 
AggregateFunctionWindowFunnel>(
+            : IAggregateFunctionDataHelper<WindowFunnelState<T>, 
AggregateFunctionWindowFunnel<T>>(
                       argument_types_) {}
 
     void create(AggregateDataPtr __restrict place) const override {
-        auto data = new (place) WindowFunnelState(
+        auto data = new (place) WindowFunnelState<T>(
                 cast_set<int>(IAggregateFunction::get_argument_types().size() 
- 3));
         /// support window funnel mode from 2.0. See 
`BeExecVersionManager::max_be_exec_version`
         data->enable_mode = IAggregateFunction::version >= 3;
@@ -392,8 +400,8 @@ public:
         // place is essentially an AggregateDataPtr, passed as a 
ConstAggregateDataPtr.
         this->data(const_cast<AggregateDataPtr>(place)).sort();
         assert_cast<ColumnInt32&>(to).get_data().push_back(
-                IAggregateFunctionDataHelper<WindowFunnelState,
-                                             
AggregateFunctionWindowFunnel>::data(place)
+                IAggregateFunctionDataHelper<WindowFunnelState<T>,
+                                             
AggregateFunctionWindowFunnel<T>>::data(place)
                         .get());
     }
 
diff --git a/be/src/vec/functions/function_date_or_datetime_computation.cpp 
b/be/src/vec/functions/function_date_or_datetime_computation.cpp
index e236e56bbcc..0fc89dc533f 100644
--- a/be/src/vec/functions/function_date_or_datetime_computation.cpp
+++ b/be/src/vec/functions/function_date_or_datetime_computation.cpp
@@ -186,7 +186,8 @@ using FunctionSubTimeTimestampTz =
 
 #define ALL_FUNCTION_TIME_DIFF(NAME, IMPL)          \
     FUNCTION_TIME_DIFF(NAME, IMPL, TYPE_DATETIMEV2) \
-    FUNCTION_TIME_DIFF(NAME, IMPL, TYPE_DATEV2)
+    FUNCTION_TIME_DIFF(NAME, IMPL, TYPE_DATEV2)     \
+    FUNCTION_TIME_DIFF(NAME, IMPL, TYPE_TIMESTAMPTZ)
 // these diff functions accept all v2 types. but for v1 only datetime.
 ALL_FUNCTION_TIME_DIFF(FunctionDatetimeDateDiff, DateDiffImpl)
 ALL_FUNCTION_TIME_DIFF(FunctionDatetimeTimeDiff, TimeDiffImpl)
@@ -324,7 +325,8 @@ void 
register_function_date_time_computation(SimpleFunctionFactory& factory) {
 
 #define REGISTER_ALL_DATEV2_FUNCTIONS_DIFF(NAME)          \
     REGISTER_DATEV2_FUNCTIONS_DIFF(NAME, TYPE_DATETIMEV2) \
-    REGISTER_DATEV2_FUNCTIONS_DIFF(NAME, TYPE_DATEV2)
+    REGISTER_DATEV2_FUNCTIONS_DIFF(NAME, TYPE_DATEV2)     \
+    REGISTER_DATEV2_FUNCTIONS_DIFF(NAME, TYPE_TIMESTAMPTZ)
 
     REGISTER_ALL_DATEV2_FUNCTIONS_DIFF(FunctionDatetimeDateDiff)
     REGISTER_ALL_DATEV2_FUNCTIONS_DIFF(FunctionDatetimeTimeDiff)
diff --git a/be/src/vec/functions/function_date_or_datetime_computation.h 
b/be/src/vec/functions/function_date_or_datetime_computation.h
index b8a1a4f1eef..06f7514ce73 100644
--- a/be/src/vec/functions/function_date_or_datetime_computation.h
+++ b/be/src/vec/functions/function_date_or_datetime_computation.h
@@ -573,7 +573,8 @@ struct TimeDiffImpl {
     using ValueType = typename PrimitiveTypeTraits<DateType>::CppType;
     using ArgType = typename 
PrimitiveTypeTraits<DateType>::DataType::FieldType;
     //TODO: remove V1 since FE already removed it.
-    static constexpr bool UsingTimev2 = is_date_v2_or_datetime_v2(DateType);
+    static constexpr bool UsingTimev2 =
+            is_date_v2_or_datetime_v2(DateType) || DateType == 
TYPE_TIMESTAMPTZ;
     static constexpr PrimitiveType ReturnType = TYPE_TIMEV2;
 
     static constexpr auto name = "timediff";
@@ -601,8 +602,19 @@ struct TimeDiffImpl {
         return 
std::make_shared<DataTypeTimeV2>(arguments[0].type->get_scale());
     }
 };
+
+template <TimeUnit UNIT, typename T0, typename T1>
+int64_t diff_on_utc_datetime(const T0& ts1, const T1& ts0) {
+    return datetime_diff<UNIT>(ts1, ts0);
+}
+
+template <TimeUnit UNIT>
+int64_t diff_on_utc_datetime(const TimestampTzValue& ts1, const 
TimestampTzValue& ts0) {
+    return datetime_diff<UNIT>(ts1.utc_dt(), ts0.utc_dt());
+}
+
 #define TIME_DIFF_FUNCTION_IMPL(CLASS, NAME, UNIT) \
-    DECLARE_DATE_FUNCTIONS(CLASS, NAME, TYPE_BIGINT, 
datetime_diff<TimeUnit::UNIT>(ts1, ts0))
+    DECLARE_DATE_FUNCTIONS(CLASS, NAME, TYPE_BIGINT, 
diff_on_utc_datetime<TimeUnit::UNIT>(ts1, ts0))
 
 // all these functions implemented by datediff
 TIME_DIFF_FUNCTION_IMPL(YearsDiffImpl, years_diff, YEAR);
diff --git a/be/src/vec/runtime/timestamptz_value.h 
b/be/src/vec/runtime/timestamptz_value.h
index 3dad4a693da..3a5ce2c5887 100644
--- a/be/src/vec/runtime/timestamptz_value.h
+++ b/be/src/vec/runtime/timestamptz_value.h
@@ -96,6 +96,10 @@ public:
         return _utc_dt.datetime_diff_in_seconds(other._utc_dt);
     }
 
+    int64_t datetime_diff_in_microseconds(const TimestampTzValue& other) const 
{
+        return _utc_dt.datetime_diff_in_microseconds(other._utc_dt);
+    }
+
     template <TimeUnit unit>
     bool date_set_interval(const TimeInterval& interval) {
         return _utc_dt.date_set_interval<unit>(interval);
@@ -143,6 +147,8 @@ public:
         _utc_dt.unix_timestamp(timestamp, ctz);
     }
 
+    std::string debug_string() const { return _utc_dt.debug_string(); }
+
     // Convert UTC time to local time based on the given timezone
     void convert_utc_to_local(const cctz::time_zone& local_time_zone,
                               DateV2Value<DateTimeV2ValueType>& dt) const;
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/SequenceCount.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/SequenceCount.java
index 5cbc0903979..e4ad5956c1c 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/SequenceCount.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/SequenceCount.java
@@ -27,6 +27,7 @@ import org.apache.doris.nereids.types.BooleanType;
 import org.apache.doris.nereids.types.DateTimeV2Type;
 import org.apache.doris.nereids.types.DateV2Type;
 import org.apache.doris.nereids.types.StringType;
+import org.apache.doris.nereids.types.TimeStampTzType;
 import org.apache.doris.nereids.util.ExpressionUtils;
 
 import com.google.common.base.Preconditions;
@@ -43,6 +44,8 @@ public class SequenceCount extends 
NotNullableAggregateFunction
     public static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
             FunctionSignature.ret(BigIntType.INSTANCE)
                     .varArgs(StringType.INSTANCE, DateV2Type.INSTANCE, 
BooleanType.INSTANCE),
+            FunctionSignature.ret(BigIntType.INSTANCE)
+                    .varArgs(StringType.INSTANCE, TimeStampTzType.WILDCARD, 
BooleanType.INSTANCE),
             FunctionSignature.ret(BigIntType.INSTANCE)
                     .varArgs(StringType.INSTANCE, DateTimeV2Type.WILDCARD, 
BooleanType.INSTANCE)
     );
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/SequenceFunction.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/SequenceFunction.java
index 673c91479a4..6bbf4e6e992 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/SequenceFunction.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/SequenceFunction.java
@@ -36,7 +36,7 @@ public interface SequenceFunction extends FunctionTrait {
         }
         if (!getArgumentType(1).isDateLikeType()) {
             throw new AnalysisException("The timestamp params of " + 
functionName
-                    + " function must be DATE or DATETIME, but it is " + 
getArgumentType(1));
+                    + " function must be DATE, DATETIME or TIMESTAMPTZ, but it 
is " + getArgumentType(1));
         }
         String pattern = ((StringLikeLiteral) firstArg).getStringValue();
         if (!FunctionCallExpr.parsePattern(pattern)) {
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/SequenceMatch.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/SequenceMatch.java
index c6cf9e436a4..c9f15731a19 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/SequenceMatch.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/SequenceMatch.java
@@ -25,6 +25,7 @@ import org.apache.doris.nereids.types.BooleanType;
 import org.apache.doris.nereids.types.DateTimeV2Type;
 import org.apache.doris.nereids.types.DateV2Type;
 import org.apache.doris.nereids.types.StringType;
+import org.apache.doris.nereids.types.TimeStampTzType;
 import org.apache.doris.nereids.util.ExpressionUtils;
 
 import com.google.common.base.Preconditions;
@@ -41,6 +42,8 @@ public class SequenceMatch extends NullableAggregateFunction
     public static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
             FunctionSignature.ret(BooleanType.INSTANCE)
                     .varArgs(StringType.INSTANCE, DateV2Type.INSTANCE, 
BooleanType.INSTANCE),
+            FunctionSignature.ret(BooleanType.INSTANCE)
+                    .varArgs(StringType.INSTANCE, TimeStampTzType.WILDCARD, 
BooleanType.INSTANCE),
             FunctionSignature.ret(BooleanType.INSTANCE)
                     .varArgs(StringType.INSTANCE, DateTimeV2Type.WILDCARD, 
BooleanType.INSTANCE)
     );
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/TopNWeighted.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/TopNWeighted.java
index 79db1318c62..1ed1586f99f 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/TopNWeighted.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/TopNWeighted.java
@@ -35,6 +35,7 @@ import org.apache.doris.nereids.types.IntegerType;
 import org.apache.doris.nereids.types.LargeIntType;
 import org.apache.doris.nereids.types.SmallIntType;
 import org.apache.doris.nereids.types.StringType;
+import org.apache.doris.nereids.types.TimeStampTzType;
 import org.apache.doris.nereids.types.TinyIntType;
 import org.apache.doris.nereids.types.VarcharType;
 
@@ -71,6 +72,8 @@ public class TopNWeighted extends NullableAggregateFunction
                                     .args(FloatType.INSTANCE, 
BigIntType.INSTANCE, IntegerType.INSTANCE),
                             
FunctionSignature.ret(ArrayType.of(DateV2Type.INSTANCE))
                     .args(DateV2Type.INSTANCE, BigIntType.INSTANCE, 
IntegerType.INSTANCE),
+            FunctionSignature.ret(ArrayType.of(TimeStampTzType.WILDCARD))
+                    .args(TimeStampTzType.WILDCARD, BigIntType.INSTANCE, 
IntegerType.INSTANCE),
             FunctionSignature.ret(ArrayType.of(DateTimeV2Type.WILDCARD))
                     .args(DateTimeV2Type.WILDCARD, BigIntType.INSTANCE, 
IntegerType.INSTANCE),
             FunctionSignature.ret(ArrayType.of(StringType.INSTANCE))
@@ -105,6 +108,11 @@ public class TopNWeighted extends NullableAggregateFunction
                                                     IntegerType.INSTANCE),
                             
FunctionSignature.ret(ArrayType.of(DateV2Type.INSTANCE))
                     .args(DateV2Type.INSTANCE, BigIntType.INSTANCE, 
IntegerType.INSTANCE, IntegerType.INSTANCE),
+            FunctionSignature.ret(ArrayType.of(TimeStampTzType.WILDCARD))
+                    .args(TimeStampTzType.WILDCARD,
+                            BigIntType.INSTANCE,
+                            IntegerType.INSTANCE,
+                            IntegerType.INSTANCE),
             FunctionSignature.ret(VarcharType.SYSTEM_DEFAULT)
                     .args(DateTimeV2Type.WILDCARD,
                             BigIntType.INSTANCE,
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/WindowFunnel.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/WindowFunnel.java
index fe68663ff5f..ccf9773a961 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/WindowFunnel.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/WindowFunnel.java
@@ -24,14 +24,17 @@ import 
org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSi
 import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
 import org.apache.doris.nereids.types.BigIntType;
 import org.apache.doris.nereids.types.BooleanType;
+import org.apache.doris.nereids.types.DataType;
 import org.apache.doris.nereids.types.DateTimeV2Type;
 import org.apache.doris.nereids.types.DateV2Type;
 import org.apache.doris.nereids.types.IntegerType;
 import org.apache.doris.nereids.types.StringType;
+import org.apache.doris.nereids.types.TimeStampTzType;
 import org.apache.doris.nereids.util.ExpressionUtils;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
 
 import java.util.List;
 
@@ -42,6 +45,9 @@ public class WindowFunnel extends NullableAggregateFunction
         implements ExplicitlyCastableSignature {
 
     public static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
+            FunctionSignature.ret(IntegerType.INSTANCE)
+                    .varArgs(BigIntType.INSTANCE, StringType.INSTANCE, 
TimeStampTzType.WILDCARD,
+                            BooleanType.INSTANCE),
             FunctionSignature.ret(IntegerType.INSTANCE)
                     .varArgs(BigIntType.INSTANCE, StringType.INSTANCE, 
DateTimeV2Type.WILDCARD,
                             BooleanType.INSTANCE)
@@ -84,7 +90,8 @@ public class WindowFunnel extends NullableAggregateFunction
             throw new AnalysisException("The mode params of " + functionName + 
" function must be string");
         }
         if (!getArgumentType(2).isDateLikeType()) {
-            throw new AnalysisException("The 3rd param of " + functionName + " 
function must be DATE or DATETIME");
+            throw new AnalysisException("The 3rd param of " + functionName
+                    + " function must be DATE, DATETIME or TIMESTAMPTZ");
         }
         for (int i = 3; i < arity(); i++) {
             if (!getArgumentType(i).isBooleanType()) {
@@ -98,9 +105,9 @@ public class WindowFunnel extends NullableAggregateFunction
     public FunctionSignature computeSignature(FunctionSignature signature) {
         FunctionSignature functionSignature = 
super.computeSignature(signature);
         if (functionSignature.getArgType(2) instanceof DateV2Type) {
-            return functionSignature.withArgumentTypes(getArguments(), (index, 
originType, arg) ->
-                    (index == 2) ? DateTimeV2Type.SYSTEM_DEFAULT : originType
-            );
+            List<DataType> newTypes = 
Lists.newArrayList(functionSignature.argumentsTypes);
+            newTypes.set(2, DateTimeV2Type.SYSTEM_DEFAULT);
+            return 
functionSignature.withArgumentTypes(functionSignature.hasVarArgs, newTypes);
         }
         return functionSignature;
     }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/DateDiff.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/DateDiff.java
index 16a2e1cf325..2d766295f64 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/DateDiff.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/DateDiff.java
@@ -26,6 +26,7 @@ import 
org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
 import org.apache.doris.nereids.types.DateTimeV2Type;
 import org.apache.doris.nereids.types.DateV2Type;
 import org.apache.doris.nereids.types.IntegerType;
+import org.apache.doris.nereids.types.TimeStampTzType;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
@@ -39,6 +40,8 @@ public class DateDiff extends ScalarFunction
         implements BinaryExpression, ExplicitlyCastableSignature, 
PropagateNullable {
 
     public static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
+            FunctionSignature.ret(IntegerType.INSTANCE)
+                    .args(TimeStampTzType.WILDCARD, TimeStampTzType.WILDCARD),
             FunctionSignature.ret(IntegerType.INSTANCE)
                     .args(DateTimeV2Type.WILDCARD, DateTimeV2Type.WILDCARD),
             
FunctionSignature.ret(IntegerType.INSTANCE).args(DateV2Type.INSTANCE, 
DateV2Type.INSTANCE));
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/DaysDiff.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/DaysDiff.java
index f894c9f09a6..012ad7c6399 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/DaysDiff.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/DaysDiff.java
@@ -28,6 +28,7 @@ import 
org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
 import org.apache.doris.nereids.types.BigIntType;
 import org.apache.doris.nereids.types.DateTimeV2Type;
 import org.apache.doris.nereids.types.DateV2Type;
+import org.apache.doris.nereids.types.TimeStampTzType;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
@@ -41,6 +42,7 @@ public class DaysDiff extends ScalarFunction implements 
BinaryExpression, Explic
         PropagateNullable, DateDiffMonotonic {
 
     private static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
+            
FunctionSignature.ret(BigIntType.INSTANCE).args(TimeStampTzType.WILDCARD, 
TimeStampTzType.WILDCARD),
             
FunctionSignature.ret(BigIntType.INSTANCE).args(DateTimeV2Type.WILDCARD, 
DateTimeV2Type.WILDCARD),
             
FunctionSignature.ret(BigIntType.INSTANCE).args(DateV2Type.INSTANCE, 
DateV2Type.INSTANCE));
 
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/HoursDiff.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/HoursDiff.java
index b4d8f4ce181..c601497c45d 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/HoursDiff.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/HoursDiff.java
@@ -28,6 +28,7 @@ import 
org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
 import org.apache.doris.nereids.types.BigIntType;
 import org.apache.doris.nereids.types.DateTimeV2Type;
 import org.apache.doris.nereids.types.DateV2Type;
+import org.apache.doris.nereids.types.TimeStampTzType;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
@@ -41,6 +42,8 @@ public class HoursDiff extends ScalarFunction implements 
BinaryExpression, Expli
         PropagateNullable, DateDiffMonotonic {
 
     public static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
+            FunctionSignature.ret(BigIntType.INSTANCE)
+                    .args(TimeStampTzType.WILDCARD, TimeStampTzType.WILDCARD),
             FunctionSignature.ret(BigIntType.INSTANCE)
                     .args(DateTimeV2Type.WILDCARD, DateTimeV2Type.WILDCARD),
             
FunctionSignature.ret(BigIntType.INSTANCE).args(DateV2Type.INSTANCE, 
DateV2Type.INSTANCE));
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/MicroSecondsDiff.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/MicroSecondsDiff.java
index 434043119a0..26081a347a0 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/MicroSecondsDiff.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/MicroSecondsDiff.java
@@ -27,6 +27,7 @@ import 
org.apache.doris.nereids.trees.expressions.shape.BinaryExpression;
 import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
 import org.apache.doris.nereids.types.BigIntType;
 import org.apache.doris.nereids.types.DateTimeV2Type;
+import org.apache.doris.nereids.types.TimeStampTzType;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
@@ -40,6 +41,8 @@ public class MicroSecondsDiff extends ScalarFunction 
implements BinaryExpression
         PropagateNullable, DateDiffMonotonic {
 
     private static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
+            FunctionSignature.ret(BigIntType.INSTANCE)
+                    .args(TimeStampTzType.WILDCARD, TimeStampTzType.WILDCARD),
             FunctionSignature.ret(BigIntType.INSTANCE)
                     .args(DateTimeV2Type.WILDCARD, DateTimeV2Type.WILDCARD)
             );
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/MilliSecondsDiff.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/MilliSecondsDiff.java
index 3f07927f920..9cda6cb8e4a 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/MilliSecondsDiff.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/MilliSecondsDiff.java
@@ -27,6 +27,7 @@ import 
org.apache.doris.nereids.trees.expressions.shape.BinaryExpression;
 import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
 import org.apache.doris.nereids.types.BigIntType;
 import org.apache.doris.nereids.types.DateTimeV2Type;
+import org.apache.doris.nereids.types.TimeStampTzType;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
@@ -40,6 +41,8 @@ public class MilliSecondsDiff extends ScalarFunction 
implements BinaryExpression
         PropagateNullable, DateDiffMonotonic {
 
     private static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
+            FunctionSignature.ret(BigIntType.INSTANCE)
+                    .args(TimeStampTzType.WILDCARD, TimeStampTzType.WILDCARD),
             FunctionSignature.ret(BigIntType.INSTANCE)
                     .args(DateTimeV2Type.WILDCARD, DateTimeV2Type.WILDCARD)
             );
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/MinutesDiff.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/MinutesDiff.java
index a66b5beb53f..f1a320932f0 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/MinutesDiff.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/MinutesDiff.java
@@ -28,6 +28,7 @@ import 
org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
 import org.apache.doris.nereids.types.BigIntType;
 import org.apache.doris.nereids.types.DateTimeV2Type;
 import org.apache.doris.nereids.types.DateV2Type;
+import org.apache.doris.nereids.types.TimeStampTzType;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
@@ -41,6 +42,8 @@ public class MinutesDiff extends ScalarFunction implements 
BinaryExpression, Exp
         PropagateNullable, DateDiffMonotonic {
 
     private static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
+            FunctionSignature.ret(BigIntType.INSTANCE)
+                    .args(TimeStampTzType.WILDCARD, TimeStampTzType.WILDCARD),
             FunctionSignature.ret(BigIntType.INSTANCE)
                     .args(DateTimeV2Type.WILDCARD, DateTimeV2Type.WILDCARD),
             
FunctionSignature.ret(BigIntType.INSTANCE).args(DateV2Type.INSTANCE, 
DateV2Type.INSTANCE));
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/MonthsDiff.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/MonthsDiff.java
index 32735b3931e..7c11156861b 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/MonthsDiff.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/MonthsDiff.java
@@ -28,6 +28,7 @@ import 
org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
 import org.apache.doris.nereids.types.BigIntType;
 import org.apache.doris.nereids.types.DateTimeV2Type;
 import org.apache.doris.nereids.types.DateV2Type;
+import org.apache.doris.nereids.types.TimeStampTzType;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
@@ -41,9 +42,11 @@ public class MonthsDiff extends ScalarFunction implements 
BinaryExpression, Expl
         PropagateNullable, DateDiffMonotonic {
 
     private static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
-            
FunctionSignature.ret(BigIntType.INSTANCE).args(DateV2Type.INSTANCE, 
DateV2Type.INSTANCE),
             FunctionSignature.ret(BigIntType.INSTANCE)
-                    .args(DateTimeV2Type.WILDCARD, DateTimeV2Type.WILDCARD));
+                    .args(TimeStampTzType.WILDCARD, TimeStampTzType.WILDCARD),
+            FunctionSignature.ret(BigIntType.INSTANCE)
+                    .args(DateTimeV2Type.WILDCARD, DateTimeV2Type.WILDCARD),
+            
FunctionSignature.ret(BigIntType.INSTANCE).args(DateV2Type.INSTANCE, 
DateV2Type.INSTANCE));
 
     /**
      * constructor with 2 arguments.
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/QuartersDiff.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/QuartersDiff.java
index d13b49db683..ec8f889baa5 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/QuartersDiff.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/QuartersDiff.java
@@ -28,6 +28,7 @@ import 
org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
 import org.apache.doris.nereids.types.BigIntType;
 import org.apache.doris.nereids.types.DateTimeV2Type;
 import org.apache.doris.nereids.types.DateV2Type;
+import org.apache.doris.nereids.types.TimeStampTzType;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
@@ -41,9 +42,11 @@ public class QuartersDiff extends ScalarFunction implements 
BinaryExpression, Ex
         PropagateNullable, DateDiffMonotonic {
 
     private static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
-            
FunctionSignature.ret(BigIntType.INSTANCE).args(DateV2Type.INSTANCE, 
DateV2Type.INSTANCE),
             FunctionSignature.ret(BigIntType.INSTANCE)
-                    .args(DateTimeV2Type.WILDCARD, DateTimeV2Type.WILDCARD)
+                    .args(TimeStampTzType.WILDCARD, TimeStampTzType.WILDCARD),
+            FunctionSignature.ret(BigIntType.INSTANCE)
+                    .args(DateTimeV2Type.WILDCARD, DateTimeV2Type.WILDCARD),
+            
FunctionSignature.ret(BigIntType.INSTANCE).args(DateV2Type.INSTANCE, 
DateV2Type.INSTANCE)
     );
 
     /**
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/SecondsDiff.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/SecondsDiff.java
index aab4fb18054..bb7df199d28 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/SecondsDiff.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/SecondsDiff.java
@@ -28,6 +28,7 @@ import 
org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
 import org.apache.doris.nereids.types.BigIntType;
 import org.apache.doris.nereids.types.DateTimeV2Type;
 import org.apache.doris.nereids.types.DateV2Type;
+import org.apache.doris.nereids.types.TimeStampTzType;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
@@ -41,6 +42,8 @@ public class SecondsDiff extends ScalarFunction implements 
BinaryExpression, Exp
         PropagateNullable, DateDiffMonotonic {
 
     private static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
+            FunctionSignature.ret(BigIntType.INSTANCE)
+                    .args(TimeStampTzType.WILDCARD, TimeStampTzType.WILDCARD),
             FunctionSignature.ret(BigIntType.INSTANCE)
                     .args(DateTimeV2Type.WILDCARD, DateTimeV2Type.WILDCARD),
             
FunctionSignature.ret(BigIntType.INSTANCE).args(DateV2Type.INSTANCE, 
DateV2Type.INSTANCE));
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/TimeDiff.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/TimeDiff.java
index 7602743ec5c..a25ce2d45f8 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/TimeDiff.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/TimeDiff.java
@@ -25,6 +25,7 @@ import 
org.apache.doris.nereids.trees.expressions.shape.BinaryExpression;
 import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
 import org.apache.doris.nereids.types.DateTimeV2Type;
 import org.apache.doris.nereids.types.DateV2Type;
+import org.apache.doris.nereids.types.TimeStampTzType;
 import org.apache.doris.nereids.types.TimeV2Type;
 
 import com.google.common.base.Preconditions;
@@ -39,6 +40,8 @@ public class TimeDiff extends ScalarFunction
         implements BinaryExpression, ExplicitlyCastableSignature, 
PropagateNullable {
 
     private static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
+            FunctionSignature.ret(TimeV2Type.WILDCARD)
+                    .args(TimeStampTzType.WILDCARD, TimeStampTzType.WILDCARD),
             FunctionSignature.ret(TimeV2Type.WILDCARD)
                     .args(DateTimeV2Type.WILDCARD, DateTimeV2Type.WILDCARD),
             
FunctionSignature.ret(TimeV2Type.SYSTEM_DEFAULT).args(DateV2Type.INSTANCE, 
DateV2Type.INSTANCE));
@@ -83,11 +86,19 @@ public class TimeDiff extends ScalarFunction
             DateTimeV2Type left = (DateTimeV2Type) 
getArgument(0).getDataType();
             scale = Math.max(scale, left.getScale());
             useTimev2 = true;
+        } else if (getArgument(0).getDataType() instanceof TimeStampTzType) {
+            TimeStampTzType left = (TimeStampTzType) 
getArgument(0).getDataType();
+            scale = Math.max(scale, left.getScale());
+            useTimev2 = true;
         }
         if (getArgument(1).getDataType() instanceof DateTimeV2Type) {
             DateTimeV2Type right = (DateTimeV2Type) 
getArgument(1).getDataType();
             scale = Math.max(scale, right.getScale());
             useTimev2 = true;
+        } else if (getArgument(1).getDataType() instanceof TimeStampTzType) {
+            TimeStampTzType right = (TimeStampTzType) 
getArgument(1).getDataType();
+            scale = Math.max(scale, right.getScale());
+            useTimev2 = true;
         }
         if (useTimev2) {
             signature = signature.withReturnType(TimeV2Type.of(scale));
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/WeeksDiff.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/WeeksDiff.java
index cc884d44911..771d43d2cb3 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/WeeksDiff.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/WeeksDiff.java
@@ -28,6 +28,7 @@ import 
org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
 import org.apache.doris.nereids.types.BigIntType;
 import org.apache.doris.nereids.types.DateTimeV2Type;
 import org.apache.doris.nereids.types.DateV2Type;
+import org.apache.doris.nereids.types.TimeStampTzType;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
@@ -41,9 +42,11 @@ public class WeeksDiff extends ScalarFunction implements 
BinaryExpression, Expli
         PropagateNullable, DateDiffMonotonic {
 
     private static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
-            
FunctionSignature.ret(BigIntType.INSTANCE).args(DateV2Type.INSTANCE, 
DateV2Type.INSTANCE),
             FunctionSignature.ret(BigIntType.INSTANCE)
-                    .args(DateTimeV2Type.WILDCARD, DateTimeV2Type.WILDCARD));
+                    .args(TimeStampTzType.WILDCARD, TimeStampTzType.WILDCARD),
+            FunctionSignature.ret(BigIntType.INSTANCE)
+                    .args(DateTimeV2Type.WILDCARD, DateTimeV2Type.WILDCARD),
+            
FunctionSignature.ret(BigIntType.INSTANCE).args(DateV2Type.INSTANCE, 
DateV2Type.INSTANCE));
 
     /**
      * constructor with 2 arguments.
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/YearsDiff.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/YearsDiff.java
index 060daf4fc57..da227338e0a 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/YearsDiff.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/YearsDiff.java
@@ -28,6 +28,7 @@ import 
org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
 import org.apache.doris.nereids.types.BigIntType;
 import org.apache.doris.nereids.types.DateTimeV2Type;
 import org.apache.doris.nereids.types.DateV2Type;
+import org.apache.doris.nereids.types.TimeStampTzType;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
@@ -41,9 +42,11 @@ public class YearsDiff extends ScalarFunction implements 
BinaryExpression, Expli
         PropagateNullable, DateDiffMonotonic {
 
     private static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
-            
FunctionSignature.ret(BigIntType.INSTANCE).args(DateV2Type.INSTANCE, 
DateV2Type.INSTANCE),
             FunctionSignature.ret(BigIntType.INSTANCE)
-                    .args(DateTimeV2Type.WILDCARD, DateTimeV2Type.WILDCARD));
+                    .args(TimeStampTzType.WILDCARD, TimeStampTzType.WILDCARD),
+            FunctionSignature.ret(BigIntType.INSTANCE)
+                    .args(DateTimeV2Type.WILDCARD, DateTimeV2Type.WILDCARD),
+            
FunctionSignature.ret(BigIntType.INSTANCE).args(DateV2Type.INSTANCE, 
DateV2Type.INSTANCE));
 
     /**
      * constructor with 2 arguments.
diff --git 
a/regression-test/data/datatype_p0/timestamptz/test_timestamptz_utc_functions.out
 
b/regression-test/data/datatype_p0/timestamptz/test_timestamptz_utc_functions.out
new file mode 100644
index 00000000000..cb3842c0bc5
--- /dev/null
+++ 
b/regression-test/data/datatype_p0/timestamptz/test_timestamptz_utc_functions.out
@@ -0,0 +1,33 @@
+-- This file is automatically generated. You should know what you did if you 
want to edit this
+-- !timestamptz_diff_utc --
+600000 600000000       600     10      0       0       0       0       0       
0       0       00:10:00.000000
+
+-- !timestamptz_diff_ny --
+600000 600000000       600     10      0       0       0       0       0       
0       0       00:10:00.000000
+
+-- !timestamptz_diff_spring_forward_ny --
+600000 600     10      0       00:10:00.000000
+
+-- !timestamptz_diff_mixed_scale_ny --
+600123 600123000       600     00:10:00.123
+
+-- !timestamptz_agg_utc --
+true   1       2
+
+-- !timestamptz_agg_ny --
+true   1       2
+
+-- !timestamptz_agg_by_group_ny --
+1      true    1       2
+3      true    1       2
+
+-- !timestamptz_column_diff_ny --
+600000 600     00:10:00.000000
+
+-- !timestamptz_topn_weighted --
+1      2024-11-03 06:30:00.000000+00:00        2024-11-03 06:30:00.000000+00:00
+3      2024-03-10 07:30:00.000000+00:00        2024-03-10 07:30:00.000000+00:00
+
+-- !timestamptz_null --
+\N     0
+
diff --git 
a/regression-test/suites/datatype_p0/timestamptz/test_timestamptz_utc_functions.groovy
 
b/regression-test/suites/datatype_p0/timestamptz/test_timestamptz_utc_functions.groovy
new file mode 100644
index 00000000000..60099ca09be
--- /dev/null
+++ 
b/regression-test/suites/datatype_p0/timestamptz/test_timestamptz_utc_functions.groovy
@@ -0,0 +1,180 @@
+// 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.
+
+suite("test_timestamptz_utc_functions") {
+    sql "SET enable_nereids_planner = true;"
+    sql "SET enable_fallback_to_original_planner = false;"
+
+    // Fall-back DST fold: 
+    // lhs UTC=2024-11-03 06:05:00, NY local=2024-11-03 01:05:00;
+    // rhs UTC=2024-11-03 05:55:00, NY local=2024-11-03 01:55:00.
+    // Expected: TIMESTAMPTZ functions use UTC instants, so lhs - rhs = +10 
minutes, not local -50 minutes.
+    def lhs = "CAST('2024-11-03 01:05:00 -05:00' AS TIMESTAMPTZ(6))"
+    def rhs = "CAST('2024-11-03 01:55:00 -04:00' AS TIMESTAMPTZ(6))"
+
+    // Spring-forward DST gap: 
+    // lhs UTC=2024-03-10 07:05:00, NY local=2024-03-10 03:05:00;
+    // rhs UTC=2024-03-10 06:55:00, NY local=2024-03-10 01:55:00.
+    // Expected: TIMESTAMPTZ functions use UTC instants, so lhs - rhs = +10 
minutes, not local +70 minutes.
+    def springLhs = "CAST('2024-03-10 03:05:00 -04:00' AS TIMESTAMPTZ(6))"
+    def springRhs = "CAST('2024-03-10 01:55:00 -05:00' AS TIMESTAMPTZ(6))"
+
+    // Mixed scale: lhs UTC=2024-11-03 06:05:00.123, rhs UTC=2024-11-03 
05:55:00.
+    // Expected: lhs - rhs = +600123 ms, and non-default TIMESTAMPTZ scales 
bind directly.
+    def scale3Lhs = "CAST('2024-11-03 01:05:00.123 -05:00' AS TIMESTAMPTZ(3))"
+    def scale0Rhs = "CAST('2024-11-03 01:55:00 -04:00' AS TIMESTAMPTZ(0))"
+
+    // Scalar diff results should be identical in UTC and America/New_York 
sessions.
+    sql "SET time_zone = '+00:00';"
+    qt_timestamptz_diff_utc """
+        SELECT milliseconds_diff(${lhs}, ${rhs}) AS ms_diff,
+               microseconds_diff(${lhs}, ${rhs}) AS us_diff,
+               seconds_diff(${lhs}, ${rhs}) AS sec_diff,
+               minutes_diff(${lhs}, ${rhs}) AS min_diff,
+               hours_diff(${lhs}, ${rhs}) AS hour_diff,
+               days_diff(${lhs}, ${rhs}) AS day_diff,
+               weeks_diff(${lhs}, ${rhs}) AS week_diff,
+               months_diff(${lhs}, ${rhs}) AS month_diff,
+               quarters_diff(${lhs}, ${rhs}) AS quarter_diff,
+               years_diff(${lhs}, ${rhs}) AS year_diff,
+               datediff(${lhs}, ${rhs}) AS date_diff,
+               timediff(${lhs}, ${rhs}) AS time_diff;
+    """
+
+    sql "SET time_zone = 'America/New_York';"
+    qt_timestamptz_diff_ny """
+        SELECT milliseconds_diff(${lhs}, ${rhs}) AS ms_diff,
+               microseconds_diff(${lhs}, ${rhs}) AS us_diff,
+               seconds_diff(${lhs}, ${rhs}) AS sec_diff,
+               minutes_diff(${lhs}, ${rhs}) AS min_diff,
+               hours_diff(${lhs}, ${rhs}) AS hour_diff,
+               days_diff(${lhs}, ${rhs}) AS day_diff,
+               weeks_diff(${lhs}, ${rhs}) AS week_diff,
+               months_diff(${lhs}, ${rhs}) AS month_diff,
+               quarters_diff(${lhs}, ${rhs}) AS quarter_diff,
+               years_diff(${lhs}, ${rhs}) AS year_diff,
+               datediff(${lhs}, ${rhs}) AS date_diff,
+               timediff(${lhs}, ${rhs}) AS time_diff;
+    """
+
+    qt_timestamptz_diff_spring_forward_ny """
+        SELECT milliseconds_diff(${springLhs}, ${springRhs}) AS ms_diff,
+               seconds_diff(${springLhs}, ${springRhs}) AS sec_diff,
+               minutes_diff(${springLhs}, ${springRhs}) AS min_diff,
+               hours_diff(${springLhs}, ${springRhs}) AS hour_diff,
+               timediff(${springLhs}, ${springRhs}) AS time_diff;
+    """
+
+    qt_timestamptz_diff_mixed_scale_ny """
+        SELECT milliseconds_diff(${scale3Lhs}, ${scale0Rhs}) AS ms_diff,
+               microseconds_diff(${scale3Lhs}, ${scale0Rhs}) AS us_diff,
+               seconds_diff(${scale3Lhs}, ${scale0Rhs}) AS sec_diff,
+               timediff(${scale3Lhs}, ${scale0Rhs}) AS time_diff;
+    """
+
+    testFoldConst("""
+        SELECT milliseconds_diff(${lhs}, ${rhs}),
+               seconds_diff(${lhs}, ${rhs}),
+               timediff(${lhs}, ${rhs});
+    """)
+
+    sql "DROP TABLE IF EXISTS tz_utc_function_events;"
+    sql """
+        CREATE TABLE tz_utc_function_events (
+            id INT,
+            grp INT,
+            weight BIGINT,
+            ts TIMESTAMPTZ(6),
+            e1 BOOLEAN,
+            e2 BOOLEAN
+        )
+        DUPLICATE KEY(id)
+        DISTRIBUTED BY HASH(id) BUCKETS 1
+        PROPERTIES('replication_num' = '1');
+    """
+    sql """
+        INSERT INTO tz_utc_function_events VALUES
+        (1, 1, 10, CAST('2024-11-03 01:55:00 -04:00' AS TIMESTAMPTZ(6)), true, 
false),
+        (2, 1, 20, CAST('2024-11-03 01:05:00 -05:00' AS TIMESTAMPTZ(6)), 
false, true),
+        (3, 1, 30, CAST('2024-11-03 01:30:00 -05:00' AS TIMESTAMPTZ(6)), 
false, false),
+        (4, 2, 40, NULL, true, false),
+        (5, 3, 50, CAST('2024-03-10 01:55:00 -05:00' AS TIMESTAMPTZ(6)), true, 
false),
+        (6, 3, 60, CAST('2024-03-10 03:05:00 -04:00' AS TIMESTAMPTZ(6)), 
false, true),
+        (7, 3, 70, CAST('2024-03-10 03:30:00 -04:00' AS TIMESTAMPTZ(6)), 
false, false);
+    """
+
+    // Aggregates should also compare TIMESTAMPTZ values by UTC instant.
+    sql "SET time_zone = '+00:00';"
+    qt_timestamptz_agg_utc """
+        SELECT sequence_match('(?1)(?t<=600)(?2)', ts, e1, e2) AS seq_match,
+               sequence_count('(?1)(?t<=600)(?2)', ts, e1, e2) AS seq_count,
+               window_funnel(600, 'default', ts, e1, e2) AS funnel_v1
+        FROM tz_utc_function_events
+        WHERE grp = 1;
+    """
+
+    sql "SET time_zone = 'America/New_York';"
+    qt_timestamptz_agg_ny """
+        SELECT sequence_match('(?1)(?t<=600)(?2)', ts, e1, e2) AS seq_match,
+               sequence_count('(?1)(?t<=600)(?2)', ts, e1, e2) AS seq_count,
+               window_funnel(600, 'default', ts, e1, e2) AS funnel_v1
+        FROM tz_utc_function_events
+        WHERE grp = 1;
+    """
+
+    // Grouped aggregation verifies both DST shapes.
+    order_qt_timestamptz_agg_by_group_ny """
+        SELECT grp,
+               sequence_match('(?1)(?t<=600)(?2)', ts, e1, e2) AS seq_match,
+               sequence_count('(?1)(?t<=600)(?2)', ts, e1, e2) AS seq_count,
+               window_funnel(600, 'default', ts, e1, e2) AS funnel_v1
+        FROM tz_utc_function_events
+        WHERE grp IN (1, 3)
+        GROUP BY grp
+        ORDER BY grp;
+    """
+
+    // Column inputs should also use UTC instant semantics.
+    qt_timestamptz_column_diff_ny """
+        SELECT milliseconds_diff(t2.ts, t1.ts) AS ms_diff,
+               seconds_diff(t2.ts, t1.ts) AS sec_diff,
+               timediff(t2.ts, t1.ts) AS time_diff
+        FROM tz_utc_function_events t1, tz_utc_function_events t2
+        WHERE t1.id = 1 AND t2.id = 2;
+    """
+
+    // topn_weighted should preserve TIMESTAMPTZ as the result array item type.
+    sql "SET time_zone = '+00:00';"
+    order_qt_timestamptz_topn_weighted """
+        SELECT grp,
+               CAST(topn_weighted(ts, weight, 2)[1] AS VARCHAR(64)) AS top_ts,
+               CAST(topn_weighted(ts, weight, 2, 100)[1] AS VARCHAR(64)) AS 
top_ts_with_default
+        FROM tz_utc_function_events
+        WHERE grp IN (1, 3)
+        GROUP BY grp
+        ORDER BY grp;
+    """
+
+    // NULL input remains NULL, and sequence_count ignores the NULL timestamp 
row.
+    qt_timestamptz_null """
+        SELECT milliseconds_diff(MAX(ts), NULL), sequence_count('(?1)(?2)', 
ts, e1, e2)
+        FROM tz_utc_function_events
+        WHERE grp = 2;
+    """
+
+    sql "SET time_zone = default;"
+}


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

Reply via email to