You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@doris.apache.org by mo...@apache.org on 2020/10/09 08:06:00 UTC

[incubator-doris] branch master updated: [Feature] Add time_round builtin functions (#4640)

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

morningman pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-doris.git


The following commit(s) were added to refs/heads/master by this push:
     new f3cdf16  [Feature] Add time_round builtin functions (#4640)
f3cdf16 is described below

commit f3cdf167d12d4fd0a466e6a9f2f8b22cf97afe07
Author: ccoffline <45...@users.noreply.github.com>
AuthorDate: Fri Oct 9 16:05:51 2020 +0800

    [Feature] Add time_round builtin functions (#4640)
    
    #4619
    Add time_round functions that provides `time_floor` & `time_ceil` at each time unit.
    
    Fix two related bugs.
    - #4618
    - Fix `struct TimeInterval` to use `int64_t` instead of `int32_t`, in case when the second diff overflow
---
 be/src/exprs/timestamp_functions.cpp               | 129 ++++++++++++++-
 be/src/exprs/timestamp_functions.h                 | 174 +++++++++++++++++++++
 be/src/runtime/datetime_value.h                    |  16 +-
 be/test/exprs/timestamp_functions_test.cpp         | 117 +++++++++-----
 docs/.vuepress/sidebar/en.js                       |   1 +
 docs/.vuepress/sidebar/zh-CN.js                    |   1 +
 .../date-time-functions/time_round.md              |  86 ++++++++++
 .../date-time-functions/time_round.md              |  86 ++++++++++
 gensrc/script/doris_builtins_functions.py          | 113 +++++++++++++
 9 files changed, 669 insertions(+), 54 deletions(-)

diff --git a/be/src/exprs/timestamp_functions.cpp b/be/src/exprs/timestamp_functions.cpp
index ea12b52..79faee0 100644
--- a/be/src/exprs/timestamp_functions.cpp
+++ b/be/src/exprs/timestamp_functions.cpp
@@ -398,36 +398,36 @@ BigIntVal TimestampFunctions::timestamp_diff(FunctionContext* ctx, const DateTim
     switch (unit) {
         case YEAR: {
             int year = (ts_value2.year() - ts_value1.year());
-            if (year >= 0) {
+            if (year > 0) {
                 year -= (ts_value2.to_int64() % 10000000000 - ts_value1.to_int64() % 10000000000) < 0;
-            } else {
+            } else if (year < 0) {
                 year += (ts_value2.to_int64() % 10000000000 - ts_value1.to_int64() % 10000000000) > 0;
             }
             return year;
         }
         case MONTH: {
             int month = (ts_value2.year() - ts_value1.year()) * 12 + (ts_value2.month() - ts_value1.month());
-            if (month >= 0) {
+            if (month > 0) {
                 month -= (ts_value2.to_int64() % 100000000 - ts_value1.to_int64() % 100000000) < 0;
-            } else {
+            } else if (month < 0) {
                 month += (ts_value2.to_int64() % 100000000 - ts_value1.to_int64() % 100000000) > 0;
             }
             return month;
         }
         case WEEK: {
             int day = ts_value2.daynr() - ts_value1.daynr();
-            if (day >= 0) {
+            if (day > 0) {
                 day -= ts_value2.time_part_diff(ts_value1) < 0;
-            } else {
+            } else if (day < 0) {
                 day += ts_value2.time_part_diff(ts_value1) > 0;
             }
             return day / 7;
         }
         case DAY: {
             int day = ts_value2.daynr() - ts_value1.daynr();
-            if (day >= 0) {
+            if (day > 0) {
                 day -= ts_value2.time_part_diff(ts_value1) < 0;
-            } else {
+            } else if (day < 0) {
                 day += ts_value2.time_part_diff(ts_value1) > 0;
             }
             return day;
@@ -496,6 +496,119 @@ void TimestampFunctions::format_close(
     }
 }
 
+DateTimeVal from_olap_datetime(uint64_t datetime) {
+    DateTimeValue ts_value;
+    if (!ts_value.from_olap_datetime(datetime)) {
+        return DateTimeVal::null();
+    }
+
+    DateTimeVal ts_val;
+    ts_value.to_datetime_val(&ts_val);
+    return ts_val;
+}
+
+#define _TR_4(TYPE, type, UNIT, unit) \
+    DateTimeVal TimestampFunctions::unit##_##type( \
+            FunctionContext* ctx, const DateTimeVal& ts_val, \
+            const IntVal& period, const DateTimeVal& origin) { \
+        return time_round<UNIT, TYPE>(ctx, ts_val, period, origin); \
+    } \
+    DateTimeVal TimestampFunctions::unit##_##type( \
+            FunctionContext* ctx, const DateTimeVal& ts_val, const DateTimeVal& origin) { \
+        return time_round<UNIT, TYPE>(ctx, ts_val, IntVal(1), origin); \
+    }
+
+#define _TR_5(TYPE, type, UNIT, unit, ORIGIN) \
+    DateTimeVal TimestampFunctions::unit##_##type( \
+            FunctionContext* ctx, const DateTimeVal& ts_val) { \
+        return time_round<UNIT, TYPE>(ctx, ts_val, IntVal(1), ORIGIN); \
+    } \
+    DateTimeVal TimestampFunctions::unit##_##type( \
+            FunctionContext* ctx, const DateTimeVal& ts_val, const IntVal& period) { \
+        return time_round<UNIT, TYPE>(ctx, ts_val, period, ORIGIN); \
+    }
+
+#define FLOOR 0
+#define CEIL  1
+
+static const DateTimeVal FIRST_DAY    = from_olap_datetime(19700101000000);
+static const DateTimeVal FIRST_SUNDAY = from_olap_datetime(19700104000000);
+
+#define TIME_ROUND(UNIT, unit, ORIGIN) \
+    _TR_4(FLOOR, floor, UNIT, unit)         _TR_4(CEIL, ceil, UNIT, unit) \
+    _TR_5(FLOOR, floor, UNIT, unit, ORIGIN) _TR_5(CEIL, ceil, UNIT, unit, ORIGIN)
+
+TIME_ROUND(YEAR, year, FIRST_DAY)
+TIME_ROUND(MONTH, month, FIRST_DAY)
+TIME_ROUND(WEEK, week, FIRST_SUNDAY)
+TIME_ROUND(DAY, day, FIRST_DAY)
+TIME_ROUND(HOUR, hour, FIRST_DAY)
+TIME_ROUND(MINUTE, minute, FIRST_DAY)
+TIME_ROUND(SECOND, second, FIRST_DAY)
+
+template <TimeUnit unit, bool type>
+DateTimeVal TimestampFunctions::time_round(
+        FunctionContext* ctx, const DateTimeVal& ts_val,
+        const IntVal& period, const DateTimeVal& origin) {
+    if (ts_val.is_null || period.is_null || period.val < 1 || origin.is_null) {
+        return DateTimeVal::null();
+    }
+
+    DateTimeValue ts1 = DateTimeValue::from_datetime_val(origin);
+    DateTimeValue ts2 = DateTimeValue::from_datetime_val(ts_val);
+    int64_t diff;
+    switch (unit) {
+        case YEAR: {
+            int year = (ts2.year() - ts1.year());
+            diff = year - (ts2.to_int64() % 10000000000 < ts1.to_int64() % 10000000000);
+            break;
+        }
+        case MONTH: {
+            int month = (ts2.year() - ts1.year()) * 12 + (ts2.month() - ts1.month());
+            diff =  month - (ts2.to_int64() % 100000000 < ts1.to_int64() % 100000000);
+            break;
+        }
+        case WEEK: {
+            int week = ts2.daynr() / 7 - ts1.daynr() / 7;
+            diff = week - (ts2.daynr() % 7 < ts1.daynr() % 7 + (ts2.time_part_diff(ts1) < 0));
+            break;
+        }
+        case DAY: {
+            int day = ts2.daynr() - ts1.daynr();
+            diff = day - (ts2.time_part_diff(ts1) < 0);
+            break;
+        }
+        case HOUR: {
+            int hour = (ts2.daynr() - ts1.daynr()) * 24 + (ts2.hour() - ts1.hour());
+            diff = hour - ((ts2.minute() * 60 + ts2.second()) < (ts1.minute() * 60 - ts1.second()));
+            break;
+        }
+        case MINUTE: {
+            int minute = (ts2.daynr() - ts1.daynr()) * 24 * 60 +
+                         (ts2.hour() - ts1.hour()) * 60 + (ts2.minute() - ts1.minute());
+            diff = minute - (ts2.second() < ts1.second());
+            break;
+        }
+        case SECOND: {
+            diff = ts2.second_diff(ts1);
+            break;
+        }
+        default:
+            return DateTimeVal::null();
+    }
+    int64_t count = period.val;
+    int64_t step = diff - (diff % count + count) % count + (type == FLOOR ? 0 : count);
+    bool is_neg = step < 0;
+
+    TimeInterval interval(unit, is_neg ? -step : step, is_neg);
+    if (!ts1.date_add_interval(interval, unit)) {
+        return DateTimeVal::null();
+    }
+    DateTimeVal new_ts_val;
+    ts1.to_datetime_val(&new_ts_val);
+    return new_ts_val;
+}
+
 StringVal TimestampFunctions::date_format(
         FunctionContext* ctx, const DateTimeVal& ts_val, const StringVal& format) {
     if (ts_val.is_null || format.is_null) {
diff --git a/be/src/exprs/timestamp_functions.h b/be/src/exprs/timestamp_functions.h
index 502436b..5aeafee 100644
--- a/be/src/exprs/timestamp_functions.h
+++ b/be/src/exprs/timestamp_functions.h
@@ -166,6 +166,180 @@ public:
     static doris_udf::BigIntVal seconds_diff(
             doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val1, const doris_udf::DateTimeVal& ts_val2);
 
+    // Period functions.
+    template <TimeUnit unit, bool type>
+    static doris_udf::DateTimeVal time_round(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val,
+            const doris_udf::IntVal& period, const doris_udf::DateTimeVal& origin);
+
+    static doris_udf::DateTimeVal year_floor(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val);
+    static doris_udf::DateTimeVal year_floor(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val,
+            const doris_udf::IntVal& period);
+    static doris_udf::DateTimeVal year_floor(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val,
+            const doris_udf::DateTimeVal& origin);
+    static doris_udf::DateTimeVal year_floor(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val,
+            const doris_udf::IntVal& period, const doris_udf::DateTimeVal& origin);
+
+    static doris_udf::DateTimeVal year_ceil(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val);
+    static doris_udf::DateTimeVal year_ceil(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val,
+            const doris_udf::IntVal& period);
+    static doris_udf::DateTimeVal year_ceil(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val,
+            const doris_udf::DateTimeVal& origin);
+    static doris_udf::DateTimeVal year_ceil(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val,
+            const doris_udf::IntVal& period, const doris_udf::DateTimeVal& origin);
+
+    static doris_udf::DateTimeVal month_floor(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val);
+    static doris_udf::DateTimeVal month_floor(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val,
+            const doris_udf::IntVal& period);
+    static doris_udf::DateTimeVal month_floor(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val,
+            const doris_udf::DateTimeVal& origin);
+    static doris_udf::DateTimeVal month_floor(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val,
+            const doris_udf::IntVal& period, const doris_udf::DateTimeVal& origin);
+
+    static doris_udf::DateTimeVal month_ceil(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val);
+    static doris_udf::DateTimeVal month_ceil(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val,
+            const doris_udf::IntVal& period);
+    static doris_udf::DateTimeVal month_ceil(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val,
+            const doris_udf::DateTimeVal& origin);
+    static doris_udf::DateTimeVal month_ceil(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val,
+            const doris_udf::IntVal& period, const doris_udf::DateTimeVal& origin);
+
+    static doris_udf::DateTimeVal week_floor(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val);
+    static doris_udf::DateTimeVal week_floor(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val,
+            const doris_udf::IntVal& period);
+    static doris_udf::DateTimeVal week_floor(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val,
+            const doris_udf::DateTimeVal& origin);
+    static doris_udf::DateTimeVal week_floor(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val,
+            const doris_udf::IntVal& period, const doris_udf::DateTimeVal& origin);
+
+    static doris_udf::DateTimeVal week_ceil(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val);
+    static doris_udf::DateTimeVal week_ceil(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val,
+            const doris_udf::IntVal& period);
+    static doris_udf::DateTimeVal week_ceil(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val,
+            const doris_udf::DateTimeVal& origin);
+    static doris_udf::DateTimeVal week_ceil(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val,
+            const doris_udf::IntVal& period, const doris_udf::DateTimeVal& origin);
+
+    static doris_udf::DateTimeVal day_floor(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val);
+    static doris_udf::DateTimeVal day_floor(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val,
+            const doris_udf::IntVal& period);
+    static doris_udf::DateTimeVal day_floor(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val,
+            const doris_udf::DateTimeVal& origin);
+    static doris_udf::DateTimeVal day_floor(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val,
+            const doris_udf::IntVal& period, const doris_udf::DateTimeVal& origin);
+
+    static doris_udf::DateTimeVal day_ceil(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val);
+    static doris_udf::DateTimeVal day_ceil(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val,
+            const doris_udf::IntVal& period);
+    static doris_udf::DateTimeVal day_ceil(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val,
+            const doris_udf::DateTimeVal& origin);
+    static doris_udf::DateTimeVal day_ceil(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val,
+            const doris_udf::IntVal& period, const doris_udf::DateTimeVal& origin);
+
+    static doris_udf::DateTimeVal hour_floor(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val);
+    static doris_udf::DateTimeVal hour_floor(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val,
+            const doris_udf::IntVal& period);
+    static doris_udf::DateTimeVal hour_floor(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val,
+            const doris_udf::DateTimeVal& origin);
+    static doris_udf::DateTimeVal hour_floor(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val,
+            const doris_udf::IntVal& period, const doris_udf::DateTimeVal& origin);
+
+    static doris_udf::DateTimeVal hour_ceil(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val);
+    static doris_udf::DateTimeVal hour_ceil(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val,
+            const doris_udf::IntVal& period);
+    static doris_udf::DateTimeVal hour_ceil(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val,
+            const doris_udf::DateTimeVal& origin);
+    static doris_udf::DateTimeVal hour_ceil(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val,
+            const doris_udf::IntVal& period, const doris_udf::DateTimeVal& origin);
+
+    static doris_udf::DateTimeVal minute_floor(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val);
+    static doris_udf::DateTimeVal minute_floor(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val,
+            const doris_udf::IntVal& period);
+    static doris_udf::DateTimeVal minute_floor(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val,
+            const doris_udf::DateTimeVal& origin);
+    static doris_udf::DateTimeVal minute_floor(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val,
+            const doris_udf::IntVal& period, const doris_udf::DateTimeVal& origin);
+
+    static doris_udf::DateTimeVal minute_ceil(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val);
+    static doris_udf::DateTimeVal minute_ceil(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val,
+            const doris_udf::IntVal& period);
+    static doris_udf::DateTimeVal minute_ceil(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val,
+            const doris_udf::DateTimeVal& origin);
+    static doris_udf::DateTimeVal minute_ceil(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val,
+            const doris_udf::IntVal& period, const doris_udf::DateTimeVal& origin);
+
+    static doris_udf::DateTimeVal second_floor(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val);
+    static doris_udf::DateTimeVal second_floor(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val,
+            const doris_udf::IntVal& period);
+    static doris_udf::DateTimeVal second_floor(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val,
+            const doris_udf::DateTimeVal& origin);
+    static doris_udf::DateTimeVal second_floor(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val,
+            const doris_udf::IntVal& period, const doris_udf::DateTimeVal& origin);
+
+    static doris_udf::DateTimeVal second_ceil(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val);
+    static doris_udf::DateTimeVal second_ceil(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val,
+            const doris_udf::IntVal& period);
+    static doris_udf::DateTimeVal second_ceil(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val,
+            const doris_udf::DateTimeVal& origin);
+    static doris_udf::DateTimeVal second_ceil(
+            doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val,
+            const doris_udf::IntVal& period, const doris_udf::DateTimeVal& origin);
+    
     // TimeZone correlation functions.
     static doris_udf::DateTimeVal timestamp(
         doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& val);
diff --git a/be/src/runtime/datetime_value.h b/be/src/runtime/datetime_value.h
index 3310eca..9471ee0 100644
--- a/be/src/runtime/datetime_value.h
+++ b/be/src/runtime/datetime_value.h
@@ -57,13 +57,13 @@ enum TimeUnit {
 };
 
 struct TimeInterval {
-    int32_t year;
-    int32_t month;
-    int32_t day;
-    int32_t hour;
-    int32_t minute;
-    int32_t second;
-    int32_t microsecond;
+    int64_t year;
+    int64_t month;
+    int64_t day;
+    int64_t hour;
+    int64_t minute;
+    int64_t second;
+    int64_t microsecond;
     bool is_neg;
 
     TimeInterval() :
@@ -71,7 +71,7 @@ struct TimeInterval {
             hour(0), minute(0), second(0), microsecond(0), is_neg(false) {
     }
 
-    TimeInterval(TimeUnit unit, int count, bool is_neg_param) :
+    TimeInterval(TimeUnit unit, int64_t count, bool is_neg_param) :
             year(0), month(0), day(0), 
             hour(0), minute(0), second(0), microsecond(0), is_neg(is_neg_param) {
         switch (unit) {
diff --git a/be/test/exprs/timestamp_functions_test.cpp b/be/test/exprs/timestamp_functions_test.cpp
index cc343ac..09e7637 100644
--- a/be/test/exprs/timestamp_functions_test.cpp
+++ b/be/test/exprs/timestamp_functions_test.cpp
@@ -31,6 +31,13 @@
 namespace doris {
 class FunctionContextImpl;
 
+doris_udf::DateTimeVal datetime_val(int64_t value) {
+    DateTimeValue dt(value);
+    doris_udf::DateTimeVal tv;
+    dt.to_datetime_val(&tv);
+    return tv;
+}
+
 class TimestampFunctionsTest : public testing::Test {
 public:
     TimestampFunctionsTest() { }
@@ -136,55 +143,89 @@ TEST_F(TimestampFunctionsTest, convert_tz_test) {
     delete context;
 }
 
+#define ASSERT_DIFF(unit, diff, tv1, tv2) \
+    ASSERT_EQ(diff, TimestampFunctions::unit##s_diff(context, datetime_val(tv1), datetime_val(tv2)).val); \
+    ASSERT_EQ(-(diff), TimestampFunctions::unit##s_diff(context, datetime_val(tv2), datetime_val(tv1)).val);
 TEST_F(TimestampFunctionsTest, timestampdiff_test) {
     doris_udf::FunctionContext *context = new doris_udf::FunctionContext();
-    DateTimeValue dt1(20120824000001);
-    doris_udf::DateTimeVal tv1;
-    dt1.to_datetime_val(&tv1);
-    DateTimeValue dt2(20120830000000);
-    doris_udf::DateTimeVal tv2;
-    dt2.to_datetime_val(&tv2);
+    int64_t tv1 = 20120824000001;
+    int64_t tv2 = 20120830000000;
+
+    //YEAR
+    ASSERT_DIFF(year, 0, tv2, tv1);
+    ASSERT_DIFF(year, 1, tv1, 20100930000000);
+    //MONTH
+    ASSERT_DIFF(month, 0, tv2, tv1);
+    ASSERT_DIFF(month, 0, tv2, tv1);
+    ASSERT_DIFF(month, 0, 20120924000000, tv1);
+    ASSERT_DIFF(month, 1, tv1, 20120631000000);
+    //WEEK
+    ASSERT_DIFF(week, 0, tv2, tv1);
+    //DAY
+    ASSERT_DIFF(day, 5, tv2, tv1);
+    ASSERT_DIFF(day, 6, 20120830000001, tv1);
+    ASSERT_DIFF(day, 8, 20120901000001, tv1);
+    ASSERT_DIFF(day, 0, 20120823000005, tv1);
+    ASSERT_DIFF(day, 0, 20120824000001, tv1);
+
+    //HOUR
+    ASSERT_DIFF(hour, 143, tv2, tv1);
+    //MINUTE
+    ASSERT_DIFF(minute, 8639, tv2, tv1);
+    //SECOND
+    ASSERT_DIFF(second, 518399, tv2, tv1);
+
+    delete context;
+}
+
+#define ASSERT_ROUND(unit, floor, ceil, ...) \
+    ASSERT_EQ(datetime_val(floor).packed_time, TimestampFunctions::unit##_floor(context, __VA_ARGS__).packed_time); \
+    ASSERT_EQ(datetime_val(ceil).packed_time, TimestampFunctions::unit##_ceil(context, __VA_ARGS__).packed_time);
+TEST_F(TimestampFunctionsTest, time_round_test) {
+    doris_udf::FunctionContext *context = new doris_udf::FunctionContext();
+    doris_udf::DateTimeVal tv = datetime_val(20120824132901);
 
+    doris_udf::IntVal three(3);
+    doris_udf::DateTimeVal wednesday = datetime_val(20200916000000);
     //YEAR
-    ASSERT_EQ(0, TimestampFunctions::years_diff(context, tv2, tv1).val);
-    DateTimeValue dt_year(20100930000000);
-    doris_udf::DateTimeVal tv_year;
-    dt_year.to_datetime_val(&tv_year);
-    ASSERT_EQ(-1, TimestampFunctions::years_diff(context, tv_year, tv1).val);
+    ASSERT_ROUND(year, 20120101000000, 20130101000000, tv);
+    ASSERT_ROUND(year, 20110916000000, 20120916000000, tv, wednesday);
+    ASSERT_ROUND(year, 20110916000000, 20140916000000, tv, three, wednesday);
+
     //MONTH
-    ASSERT_EQ(0, TimestampFunctions::months_diff(context, tv2, tv1).val);
-    DateTimeValue dt3(20120924000000);
-    doris_udf::DateTimeVal tv3;
-    dt3.to_datetime_val(&tv3);
-    ASSERT_EQ(0, TimestampFunctions::months_diff(context, tv3, tv1).val);
-    DateTimeValue dt_month(20120631000000);
-    doris_udf::DateTimeVal tv_month;
-    dt_month.to_datetime_val(&tv_month);
-    ASSERT_EQ(-1, TimestampFunctions::months_diff(context, tv_month, tv1).val);
+    ASSERT_ROUND(month, 20120801000000, 20120901000000, tv);
+    ASSERT_ROUND(month, 20120701000000, 20121001000000, tv, three);
+
     //WEEK
-    ASSERT_EQ(0, TimestampFunctions::weeks_diff(context, tv2, tv1).val);
+    ASSERT_ROUND(week, 20120819000000, 20120826000000, tv);
+    ASSERT_ROUND(week, 20120822000000, 20120829000000, tv, wednesday);
+    ASSERT_ROUND(week, 20120808000000, 20120829000000, tv, three, wednesday);
+
+    doris_udf::DateTimeVal tv1 = datetime_val(20200202130920);
+    doris_udf::DateTimeVal monday = datetime_val(20200106000000);
+    ASSERT_ROUND(week, 20200202000000, 20200209000000, tv1);
+    ASSERT_ROUND(week, 20200127000000, 20200203000000, tv1, monday);
+
     //DAY
-    ASSERT_EQ(5, TimestampFunctions::days_diff(context, tv2, tv1).val);
-    DateTimeValue dt4(20120830000001);
-    doris_udf::DateTimeVal tv4;
-    dt4.to_datetime_val(&tv4);
-    ASSERT_EQ(6, TimestampFunctions::days_diff(context, tv4, tv1).val);
-    DateTimeValue dt5(20120901000001);
-    doris_udf::DateTimeVal tv5;
-    dt5.to_datetime_val(&tv5);
-    ASSERT_EQ(8, TimestampFunctions::days_diff(context, tv5, tv1).val);
-
-    DateTimeValue dt_day(20120823000005);
-    doris_udf::DateTimeVal tv_day;
-    dt_day.to_datetime_val(&tv_day);
-    ASSERT_EQ(0, TimestampFunctions::days_diff(context, tv_day, tv1).val);
+    doris_udf::DateTimeVal noon = datetime_val(19700101120000);
+    ASSERT_ROUND(day, 20120824000000, 20120825000000, tv);
+    ASSERT_ROUND(day, 20120824120000, 20120825120000, tv, noon);
 
     //HOUR
-    ASSERT_EQ(143, TimestampFunctions::hours_diff(context, tv2, tv1).val);
+    doris_udf::DateTimeVal random = datetime_val(29380329113953);
+    ASSERT_ROUND(hour, 20120824120000, 20120824150000, tv, three);
+    ASSERT_ROUND(hour, 20120824113953, 20120824143953, tv, three, random);
+
     //MINUTE
-    ASSERT_EQ(8639, TimestampFunctions::minutes_diff(context, tv2, tv1).val);
+    doris_udf::IntVal val90(90);
+    ASSERT_ROUND(minute, 20120824132900, 20120824133000, tv);
+    ASSERT_ROUND(minute, 20120824120000, 20120824133000, tv, val90);
+    ASSERT_ROUND(minute, 20120824130953, 20120824143953, tv, val90, random);
+
     //SECOND
-    ASSERT_EQ(518399, TimestampFunctions::seconds_diff(context, tv2, tv1).val);
+    ASSERT_ROUND(second, 20120824132900, 20120824132903, tv, three);
+    ASSERT_ROUND(second, 20120824132830, 20120824133000, tv, val90);
+
     delete context;
 }
 
diff --git a/docs/.vuepress/sidebar/en.js b/docs/.vuepress/sidebar/en.js
index 0d07657..c51ce50 100644
--- a/docs/.vuepress/sidebar/en.js
+++ b/docs/.vuepress/sidebar/en.js
@@ -241,6 +241,7 @@ module.exports = [
               "now",
               "second",
               "str_to_date",
+              "time_round",
               "timediff",
               "timestampadd",
               "timestampdiff",
diff --git a/docs/.vuepress/sidebar/zh-CN.js b/docs/.vuepress/sidebar/zh-CN.js
index 2d694e7..76038b2 100644
--- a/docs/.vuepress/sidebar/zh-CN.js
+++ b/docs/.vuepress/sidebar/zh-CN.js
@@ -248,6 +248,7 @@ module.exports = [
               "now",
               "second",
               "str_to_date",
+              "time_round",
               "timediff",
               "timestampadd",
               "timestampdiff",
diff --git a/docs/en/sql-reference/sql-functions/date-time-functions/time_round.md b/docs/en/sql-reference/sql-functions/date-time-functions/time_round.md
new file mode 100644
index 0000000..9fb70f8
--- /dev/null
+++ b/docs/en/sql-reference/sql-functions/date-time-functions/time_round.md
@@ -0,0 +1,86 @@
+---
+{
+    "title": "time_round",
+    "language": "en"
+}
+---
+
+<!-- 
+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.
+-->
+
+# time_round
+## description
+### Syntax
+
+`DATETIME TIME_ROUND(DATETIME expr)`
+
+`DATETIME TIME_ROUND(DATETIME expr, INT period)`
+
+`DATETIME TIME_ROUND(DATETIME expr, DATETIME origin)`
+
+`DATETIME TIME_ROUND(DATETIME expr, INT period, DATETIME origin)`
+
+The function name `TIME_ROUND` consists of two parts,Each part consists of the following optional values.
+- `TIME`: `SECOND`, `MINUTE`, `HOUR`, `DAY`, `WEEK`, `MONTH`, `YEAR`
+- `ROUND`: `FLOOR`, `CEIL`
+
+Returns the upper/lower bound of `expr`.
+
+- `period` specifies how many `TIME` units, the default is `1`.
+- `origin` specifies the start time of the period, the default is `1970-01-01T00:00:00`, the start time of `WEEK` is Sunday, which is `1970-01-04T00:00:00`. Could be larger than `expr`.
+- Please try to choose common `period`, such as 3 `MONTH`, 90 `MINUTE`. If you set a uncommon `period`, please also specify `origin`.
+
+## example
+
+```
+
+MySQL> SELECT YEAR_FLOOR('20200202000000');
++------------------------------+
+| year_floor('20200202000000') |
++------------------------------+
+| 2020-01-01 00:00:00          |
++------------------------------+
+
+
+MySQL> SELECT MONTH_CEIL(CAST('2020-02-02 13:09:20' AS DATETIME), 3); --quarter
++--------------------------------------------------------+
+| month_ceil(CAST('2020-02-02 13:09:20' AS DATETIME), 3) |
++--------------------------------------------------------+
+| 2020-04-01 00:00:00                                    |
++--------------------------------------------------------+
+
+
+MySQL> SELECT WEEK_CEIL('2020-02-02 13:09:20', '2020-01-06'); --monday
++---------------------------------------------------------+
+| week_ceil('2020-02-02 13:09:20', '2020-01-06 00:00:00') |
++---------------------------------------------------------+
+| 2020-02-03 00:00:00                                     |
++---------------------------------------------------------+
+
+
+MySQL> SELECT MONTH_CEIL(CAST('2020-02-02 13:09:20' AS DATETIME), 3, CAST('1970-01-09 00:00:00' AS DATETIME)); --next rent day
++-------------------------------------------------------------------------------------------------+
+| month_ceil(CAST('2020-02-02 13:09:20' AS DATETIME), 3, CAST('1970-01-09 00:00:00' AS DATETIME)) |
++-------------------------------------------------------------------------------------------------+
+| 2020-04-09 00:00:00                                                                             |
++-------------------------------------------------------------------------------------------------+
+
+```
+## keyword
+TIME_ROUND
diff --git a/docs/zh-CN/sql-reference/sql-functions/date-time-functions/time_round.md b/docs/zh-CN/sql-reference/sql-functions/date-time-functions/time_round.md
new file mode 100644
index 0000000..2e8d142
--- /dev/null
+++ b/docs/zh-CN/sql-reference/sql-functions/date-time-functions/time_round.md
@@ -0,0 +1,86 @@
+---
+{
+    "title": "time_round",
+    "language": "zh-CN"
+}
+---
+
+<!-- 
+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.
+-->
+
+# time_round
+## description
+### Syntax
+
+`DATETIME TIME_ROUND(DATETIME expr)`
+
+`DATETIME TIME_ROUND(DATETIME expr, INT period)`
+
+`DATETIME TIME_ROUND(DATETIME expr, DATETIME origin)`
+
+`DATETIME TIME_ROUND(DATETIME expr, INT period, DATETIME origin)`
+
+函数名 `TIME_ROUND` 由两部分组成,每部分由以下可选值组成
+- `TIME`: `SECOND`, `MINUTE`, `HOUR`, `DAY`, `WEEK`, `MONTH`, `YEAR`
+- `ROUND`: `FLOOR`, `CEIL`
+
+返回 `expr` 的上/下界。
+
+- `period` 指定每个周期有多少个 `TIME` 单位组成,默认为 `1`。
+- `origin` 指定周期的开始时间,默认为 `1970-01-01T00:00:00`,`WEEK` 的默认开始时间为 `1970-01-04T00:00:00`,即周日。可以比 `expr` 大。
+- 请尽量选择常见 `period`,如 3 `MONTH`,90 `MINUTE` 等,如设置了非常用 `period`,请同时指定 `origin`。
+
+## example
+
+```
+
+MySQL> SELECT YEAR_FLOOR('20200202000000');
++------------------------------+
+| year_floor('20200202000000') |
++------------------------------+
+| 2020-01-01 00:00:00          |
++------------------------------+
+
+
+MySQL> SELECT MONTH_CEIL(CAST('2020-02-02 13:09:20' AS DATETIME), 3); --quarter
++--------------------------------------------------------+
+| month_ceil(CAST('2020-02-02 13:09:20' AS DATETIME), 3) |
++--------------------------------------------------------+
+| 2020-04-01 00:00:00                                    |
++--------------------------------------------------------+
+
+
+MySQL> SELECT WEEK_CEIL('2020-02-02 13:09:20', '2020-01-06'); --monday
++---------------------------------------------------------+
+| week_ceil('2020-02-02 13:09:20', '2020-01-06 00:00:00') |
++---------------------------------------------------------+
+| 2020-02-03 00:00:00                                     |
++---------------------------------------------------------+
+
+
+MySQL> SELECT MONTH_CEIL(CAST('2020-02-02 13:09:20' AS DATETIME), 3, CAST('1970-01-09 00:00:00' AS DATETIME)); --next rent day
++-------------------------------------------------------------------------------------------------+
+| month_ceil(CAST('2020-02-02 13:09:20' AS DATETIME), 3, CAST('1970-01-09 00:00:00' AS DATETIME)) |
++-------------------------------------------------------------------------------------------------+
+| 2020-04-09 00:00:00                                                                             |
++-------------------------------------------------------------------------------------------------+
+
+```
+## keyword
+TIME_ROUND
diff --git a/gensrc/script/doris_builtins_functions.py b/gensrc/script/doris_builtins_functions.py
index bd44884..c281cfe 100755
--- a/gensrc/script/doris_builtins_functions.py
+++ b/gensrc/script/doris_builtins_functions.py
@@ -260,6 +260,119 @@ visible_functions = [
     [['seconds_diff'], 'BIGINT', ['DATETIME', 'DATETIME'],
             '_ZN5doris18TimestampFunctions12seconds_diffEPN9doris_udf15FunctionContextERKNS1_11DateTimeValES6_'],
 
+    [['year_floor'], 'DATETIME', ['DATETIME'],
+            '_ZN5doris18TimestampFunctions10year_floorEPN9doris_udf15FunctionContextERKNS1_11DateTimeValE'],
+    [['year_floor'], 'DATETIME', ['DATETIME', 'DATETIME'],
+            '_ZN5doris18TimestampFunctions10year_floorEPN9doris_udf15FunctionContextERKNS1_11DateTimeValES6_'],
+    [['year_floor'], 'DATETIME', ['DATETIME', 'INT'],
+            '_ZN5doris18TimestampFunctions10year_floorEPN9doris_udf15FunctionContextERKNS1_11DateTimeValERKNS1_6IntValE'],
+    [['year_floor'], 'DATETIME', ['DATETIME', 'INT', 'DATETIME'],
+            '_ZN5doris18TimestampFunctions10year_floorEPN9doris_udf15FunctionContextERKNS1_11DateTimeValERKNS1_6IntValES6_'],
+    [['year_ceil'], 'DATETIME', ['DATETIME'],
+            '_ZN5doris18TimestampFunctions9year_ceilEPN9doris_udf15FunctionContextERKNS1_11DateTimeValE'],
+    [['year_ceil'], 'DATETIME', ['DATETIME', 'DATETIME'],
+            '_ZN5doris18TimestampFunctions9year_ceilEPN9doris_udf15FunctionContextERKNS1_11DateTimeValES6_'],
+    [['year_ceil'], 'DATETIME', ['DATETIME', 'INT'],
+            '_ZN5doris18TimestampFunctions9year_ceilEPN9doris_udf15FunctionContextERKNS1_11DateTimeValERKNS1_6IntValE'],
+    [['year_ceil'], 'DATETIME', ['DATETIME', 'INT', 'DATETIME'],
+            '_ZN5doris18TimestampFunctions9year_ceilEPN9doris_udf15FunctionContextERKNS1_11DateTimeValERKNS1_6IntValES6_'],
+    [['month_floor'], 'DATETIME', ['DATETIME'],
+            '_ZN5doris18TimestampFunctions11month_floorEPN9doris_udf15FunctionContextERKNS1_11DateTimeValE'],
+    [['month_floor'], 'DATETIME', ['DATETIME', 'DATETIME'],
+            '_ZN5doris18TimestampFunctions11month_floorEPN9doris_udf15FunctionContextERKNS1_11DateTimeValES6_'],
+    [['month_floor'], 'DATETIME', ['DATETIME', 'INT'],
+            '_ZN5doris18TimestampFunctions11month_floorEPN9doris_udf15FunctionContextERKNS1_11DateTimeValERKNS1_6IntValE'],
+    [['month_floor'], 'DATETIME', ['DATETIME', 'INT', 'DATETIME'],
+            '_ZN5doris18TimestampFunctions11month_floorEPN9doris_udf15FunctionContextERKNS1_11DateTimeValERKNS1_6IntValES6_'],
+    [['month_ceil'], 'DATETIME', ['DATETIME'],
+            '_ZN5doris18TimestampFunctions10month_ceilEPN9doris_udf15FunctionContextERKNS1_11DateTimeValE'],
+    [['month_ceil'], 'DATETIME', ['DATETIME', 'DATETIME'],
+            '_ZN5doris18TimestampFunctions10month_ceilEPN9doris_udf15FunctionContextERKNS1_11DateTimeValES6_'],
+    [['month_ceil'], 'DATETIME', ['DATETIME', 'INT'],
+            '_ZN5doris18TimestampFunctions10month_ceilEPN9doris_udf15FunctionContextERKNS1_11DateTimeValERKNS1_6IntValE'],
+    [['month_ceil'], 'DATETIME', ['DATETIME', 'INT', 'DATETIME'],
+            '_ZN5doris18TimestampFunctions10month_ceilEPN9doris_udf15FunctionContextERKNS1_11DateTimeValERKNS1_6IntValES6_'],
+    [['week_floor'], 'DATETIME', ['DATETIME'],
+            '_ZN5doris18TimestampFunctions10week_floorEPN9doris_udf15FunctionContextERKNS1_11DateTimeValE'],
+    [['week_floor'], 'DATETIME', ['DATETIME', 'DATETIME'],
+            '_ZN5doris18TimestampFunctions10week_floorEPN9doris_udf15FunctionContextERKNS1_11DateTimeValES6_'],
+    [['week_floor'], 'DATETIME', ['DATETIME', 'INT'],
+            '_ZN5doris18TimestampFunctions10week_floorEPN9doris_udf15FunctionContextERKNS1_11DateTimeValERKNS1_6IntValE'],
+    [['week_floor'], 'DATETIME', ['DATETIME', 'INT', 'DATETIME'],
+            '_ZN5doris18TimestampFunctions10week_floorEPN9doris_udf15FunctionContextERKNS1_11DateTimeValERKNS1_6IntValES6_'],
+    [['week_ceil'], 'DATETIME', ['DATETIME'],
+            '_ZN5doris18TimestampFunctions9week_ceilEPN9doris_udf15FunctionContextERKNS1_11DateTimeValE'],
+    [['week_ceil'], 'DATETIME', ['DATETIME', 'DATETIME'],
+            '_ZN5doris18TimestampFunctions9week_ceilEPN9doris_udf15FunctionContextERKNS1_11DateTimeValES6_'],
+    [['week_ceil'], 'DATETIME', ['DATETIME', 'INT'],
+            '_ZN5doris18TimestampFunctions9week_ceilEPN9doris_udf15FunctionContextERKNS1_11DateTimeValERKNS1_6IntValE'],
+    [['week_ceil'], 'DATETIME', ['DATETIME', 'INT', 'DATETIME'],
+            '_ZN5doris18TimestampFunctions9week_ceilEPN9doris_udf15FunctionContextERKNS1_11DateTimeValERKNS1_6IntValES6_'],
+    [['day_floor'], 'DATETIME', ['DATETIME'],
+            '_ZN5doris18TimestampFunctions9day_floorEPN9doris_udf15FunctionContextERKNS1_11DateTimeValE'],
+    [['day_floor'], 'DATETIME', ['DATETIME', 'DATETIME'],
+            '_ZN5doris18TimestampFunctions9day_floorEPN9doris_udf15FunctionContextERKNS1_11DateTimeValES6_'],
+    [['day_floor'], 'DATETIME', ['DATETIME', 'INT'],
+            '_ZN5doris18TimestampFunctions9day_floorEPN9doris_udf15FunctionContextERKNS1_11DateTimeValERKNS1_6IntValE'],
+    [['day_floor'], 'DATETIME', ['DATETIME', 'INT', 'DATETIME'],
+            '_ZN5doris18TimestampFunctions9day_floorEPN9doris_udf15FunctionContextERKNS1_11DateTimeValERKNS1_6IntValES6_'],
+    [['day_ceil'], 'DATETIME', ['DATETIME'],
+            '_ZN5doris18TimestampFunctions8day_ceilEPN9doris_udf15FunctionContextERKNS1_11DateTimeValE'],
+    [['day_ceil'], 'DATETIME', ['DATETIME', 'DATETIME'],
+            '_ZN5doris18TimestampFunctions8day_ceilEPN9doris_udf15FunctionContextERKNS1_11DateTimeValES6_'],
+    [['day_ceil'], 'DATETIME', ['DATETIME', 'INT'],
+            '_ZN5doris18TimestampFunctions8day_ceilEPN9doris_udf15FunctionContextERKNS1_11DateTimeValERKNS1_6IntValE'],
+    [['day_ceil'], 'DATETIME', ['DATETIME', 'INT', 'DATETIME'],
+            '_ZN5doris18TimestampFunctions8day_ceilEPN9doris_udf15FunctionContextERKNS1_11DateTimeValERKNS1_6IntValES6_'],
+    [['hour_floor'], 'DATETIME', ['DATETIME'],
+            '_ZN5doris18TimestampFunctions10hour_floorEPN9doris_udf15FunctionContextERKNS1_11DateTimeValE'],
+    [['hour_floor'], 'DATETIME', ['DATETIME', 'DATETIME'],
+            '_ZN5doris18TimestampFunctions10hour_floorEPN9doris_udf15FunctionContextERKNS1_11DateTimeValES6_'],
+    [['hour_floor'], 'DATETIME', ['DATETIME', 'INT'],
+            '_ZN5doris18TimestampFunctions10hour_floorEPN9doris_udf15FunctionContextERKNS1_11DateTimeValERKNS1_6IntValE'],
+    [['hour_floor'], 'DATETIME', ['DATETIME', 'INT', 'DATETIME'],
+            '_ZN5doris18TimestampFunctions10hour_floorEPN9doris_udf15FunctionContextERKNS1_11DateTimeValERKNS1_6IntValES6_'],
+    [['hour_ceil'], 'DATETIME', ['DATETIME'],
+            '_ZN5doris18TimestampFunctions9hour_ceilEPN9doris_udf15FunctionContextERKNS1_11DateTimeValE'],
+    [['hour_ceil'], 'DATETIME', ['DATETIME', 'DATETIME'],
+            '_ZN5doris18TimestampFunctions9hour_ceilEPN9doris_udf15FunctionContextERKNS1_11DateTimeValES6_'],
+    [['hour_ceil'], 'DATETIME', ['DATETIME', 'INT'],
+            '_ZN5doris18TimestampFunctions9hour_ceilEPN9doris_udf15FunctionContextERKNS1_11DateTimeValERKNS1_6IntValE'],
+    [['hour_ceil'], 'DATETIME', ['DATETIME', 'INT', 'DATETIME'],
+            '_ZN5doris18TimestampFunctions9hour_ceilEPN9doris_udf15FunctionContextERKNS1_11DateTimeValERKNS1_6IntValES6_'],
+    [['minute_floor'], 'DATETIME', ['DATETIME'],
+            '_ZN5doris18TimestampFunctions12minute_floorEPN9doris_udf15FunctionContextERKNS1_11DateTimeValE'],
+    [['minute_floor'], 'DATETIME', ['DATETIME', 'DATETIME'],
+            '_ZN5doris18TimestampFunctions12minute_floorEPN9doris_udf15FunctionContextERKNS1_11DateTimeValES6_'],
+    [['minute_floor'], 'DATETIME', ['DATETIME', 'INT'],
+            '_ZN5doris18TimestampFunctions12minute_floorEPN9doris_udf15FunctionContextERKNS1_11DateTimeValERKNS1_6IntValE'],
+    [['minute_floor'], 'DATETIME', ['DATETIME', 'INT', 'DATETIME'],
+            '_ZN5doris18TimestampFunctions12minute_floorEPN9doris_udf15FunctionContextERKNS1_11DateTimeValERKNS1_6IntValES6_'],
+    [['minute_ceil'], 'DATETIME', ['DATETIME'],
+            '_ZN5doris18TimestampFunctions11minute_ceilEPN9doris_udf15FunctionContextERKNS1_11DateTimeValE'],
+    [['minute_ceil'], 'DATETIME', ['DATETIME', 'DATETIME'],
+            '_ZN5doris18TimestampFunctions11minute_ceilEPN9doris_udf15FunctionContextERKNS1_11DateTimeValES6_'],
+    [['minute_ceil'], 'DATETIME', ['DATETIME', 'INT'],
+            '_ZN5doris18TimestampFunctions11minute_ceilEPN9doris_udf15FunctionContextERKNS1_11DateTimeValERKNS1_6IntValE'],
+    [['minute_ceil'], 'DATETIME', ['DATETIME', 'INT', 'DATETIME'],
+            '_ZN5doris18TimestampFunctions11minute_ceilEPN9doris_udf15FunctionContextERKNS1_11DateTimeValERKNS1_6IntValES6_'],
+    [['second_floor'], 'DATETIME', ['DATETIME'],
+            '_ZN5doris18TimestampFunctions12second_floorEPN9doris_udf15FunctionContextERKNS1_11DateTimeValE'],
+    [['second_floor'], 'DATETIME', ['DATETIME', 'DATETIME'],
+            '_ZN5doris18TimestampFunctions12second_floorEPN9doris_udf15FunctionContextERKNS1_11DateTimeValES6_'],
+    [['second_floor'], 'DATETIME', ['DATETIME', 'INT'],
+            '_ZN5doris18TimestampFunctions12second_floorEPN9doris_udf15FunctionContextERKNS1_11DateTimeValERKNS1_6IntValE'],
+    [['second_floor'], 'DATETIME', ['DATETIME', 'INT', 'DATETIME'],
+            '_ZN5doris18TimestampFunctions12second_floorEPN9doris_udf15FunctionContextERKNS1_11DateTimeValERKNS1_6IntValES6_'],
+    [['second_ceil'], 'DATETIME', ['DATETIME'],
+            '_ZN5doris18TimestampFunctions11second_ceilEPN9doris_udf15FunctionContextERKNS1_11DateTimeValE'],
+    [['second_ceil'], 'DATETIME', ['DATETIME', 'DATETIME'],
+            '_ZN5doris18TimestampFunctions11second_ceilEPN9doris_udf15FunctionContextERKNS1_11DateTimeValES6_'],
+    [['second_ceil'], 'DATETIME', ['DATETIME', 'INT'],
+            '_ZN5doris18TimestampFunctions11second_ceilEPN9doris_udf15FunctionContextERKNS1_11DateTimeValERKNS1_6IntValE'],
+    [['second_ceil'], 'DATETIME', ['DATETIME', 'INT', 'DATETIME'],
+            '_ZN5doris18TimestampFunctions11second_ceilEPN9doris_udf15FunctionContextERKNS1_11DateTimeValERKNS1_6IntValES6_'],
+
     # Math builtin functions
     [['pi'], 'DOUBLE', [],
         '_ZN5doris13MathFunctions2piEPN9doris_udf15FunctionContextE'],


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org