You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@doris.apache.org by yi...@apache.org on 2022/10/28 00:41:22 UTC

[doris] branch master updated: [function](date function) add new date function 'to_monday' #13707

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

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


The following commit(s) were added to refs/heads/master by this push:
     new c108554f14 [function](date function) add new date function 'to_monday' #13707
c108554f14 is described below

commit c108554f14ee9be0cdf73cd69f8698e42874dd91
Author: lsy3993 <11...@users.noreply.github.com>
AuthorDate: Fri Oct 28 08:41:16 2022 +0800

    [function](date function) add new date function 'to_monday' #13707
---
 be/src/vec/functions/function_timestamp.cpp        | 122 +++++++++++++++++++++
 .../sql-functions/date-time-functions/to_monday.md |  46 ++++++++
 docs/sidebars.json                                 |   1 +
 .../sql-functions/date-time-functions/to_monday.md |  45 ++++++++
 gensrc/script/doris_builtins_functions.py          |   8 ++
 .../datetime_functions/test_date_function.out      |   7 ++
 .../datetime_functions/test_date_function.groovy   |  27 +++++
 7 files changed, 256 insertions(+)

diff --git a/be/src/vec/functions/function_timestamp.cpp b/be/src/vec/functions/function_timestamp.cpp
index 63fb1d900c..f941408dc8 100644
--- a/be/src/vec/functions/function_timestamp.cpp
+++ b/be/src/vec/functions/function_timestamp.cpp
@@ -717,6 +717,124 @@ struct LastDayImpl {
     }
 };
 
+template <typename DateType>
+struct MondayImpl {
+    static constexpr auto name = "to_monday";
+
+    static Status execute_impl(FunctionContext* context, Block& block,
+                               const ColumnNumbers& arguments, size_t result,
+                               size_t input_rows_count) {
+        auto null_map = ColumnUInt8::create(input_rows_count, 0);
+        ColumnPtr res_column;
+        ColumnPtr argument_column =
+                block.get_by_position(arguments[0]).column->convert_to_full_column_if_const();
+        if constexpr (std::is_same_v<DateType, DataTypeDateTime> ||
+                      std::is_same_v<DateType, DataTypeDate>) {
+            auto data_col = assert_cast<const ColumnVector<Int64>*>(argument_column.get());
+            res_column = ColumnInt64::create(input_rows_count);
+            execute_straight<VecDateTimeValue, Int64, Int64>(
+                    input_rows_count, null_map->get_data(), data_col->get_data(),
+                    static_cast<ColumnVector<Int64>*>(res_column->assume_mutable().get())
+                            ->get_data());
+
+        } else if constexpr (std::is_same_v<DateType, DataTypeDateV2>) {
+            auto data_col = assert_cast<const ColumnVector<UInt32>*>(argument_column.get());
+            res_column = ColumnVector<UInt32>::create(input_rows_count);
+            execute_straight<DateV2Value<DateV2ValueType>, UInt32, UInt32>(
+                    input_rows_count, null_map->get_data(), data_col->get_data(),
+                    static_cast<ColumnVector<UInt32>*>(res_column->assume_mutable().get())
+                            ->get_data());
+
+        } else if constexpr (std::is_same_v<DateType, DataTypeDateTimeV2>) {
+            auto data_col = assert_cast<const ColumnVector<UInt64>*>(argument_column.get());
+            res_column = ColumnVector<UInt32>::create(input_rows_count);
+            execute_straight<DateV2Value<DateTimeV2ValueType>, UInt32, UInt64>(
+                    input_rows_count, null_map->get_data(), data_col->get_data(),
+                    static_cast<ColumnVector<UInt32>*>(res_column->assume_mutable().get())
+                            ->get_data());
+        }
+        block.replace_by_position(
+                result, ColumnNullable::create(std::move(res_column), std::move(null_map)));
+        return Status::OK();
+    }
+
+    template <typename DateValueType, typename ReturnType, typename InputDateType>
+    static void execute_straight(size_t input_rows_count, NullMap& null_map,
+                                 const PaddedPODArray<InputDateType>& data_col,
+                                 PaddedPODArray<ReturnType>& res_data) {
+        for (int i = 0; i < input_rows_count; i++) {
+            if constexpr (std::is_same_v<DateValueType, VecDateTimeValue>) {
+                const auto& cur_data = data_col[i];
+                auto ts_value = binary_cast<Int64, VecDateTimeValue>(cur_data);
+                if (!ts_value.is_valid_date()) {
+                    null_map[i] = 1;
+                    continue;
+                }
+                if (is_special_day(ts_value.year(), ts_value.month(), ts_value.day())) {
+                    ts_value.set_time(ts_value.year(), ts_value.month(), 1, 0, 0, 0);
+                    ts_value.set_type(TIME_DATE);
+                    res_data[i] = binary_cast<VecDateTimeValue, Int64>(ts_value);
+                    continue;
+                }
+
+                // day_of_week, from 1(Mon) to 7(Sun)
+                int day_of_week = ts_value.weekday() + 1;
+                int gap_of_monday = day_of_week - 1;
+                TimeInterval interval(DAY, gap_of_monday, true);
+                ts_value.template date_add_interval<DAY>(interval);
+                ts_value.set_type(TIME_DATE);
+                res_data[i] = binary_cast<VecDateTimeValue, Int64>(ts_value);
+
+            } else if constexpr (std::is_same_v<DateValueType, DateV2Value<DateV2ValueType>>) {
+                const auto& cur_data = data_col[i];
+                auto ts_value = binary_cast<UInt32, DateValueType>(cur_data);
+                if (!ts_value.is_valid_date()) {
+                    null_map[i] = 1;
+                    continue;
+                }
+                if (is_special_day(ts_value.year(), ts_value.month(), ts_value.day())) {
+                    ts_value.template set_time_unit<TimeUnit::DAY>(1);
+                    res_data[i] = binary_cast<DateValueType, UInt32>(ts_value);
+                    continue;
+                }
+
+                // day_of_week, from 1(Mon) to 7(Sun)
+                int day_of_week = ts_value.weekday() + 1;
+                int gap_of_monday = day_of_week - 1;
+                TimeInterval interval(DAY, gap_of_monday, true);
+                ts_value.template date_add_interval<DAY>(interval);
+                res_data[i] = binary_cast<DateValueType, UInt32>(ts_value);
+            } else {
+                const auto& cur_data = data_col[i];
+                auto ts_value = binary_cast<UInt64, DateValueType>(cur_data);
+                if (!ts_value.is_valid_date()) {
+                    null_map[i] = 1;
+                    continue;
+                }
+                if (is_special_day(ts_value.year(), ts_value.month(), ts_value.day())) {
+                    ts_value.set_time(ts_value.year(), ts_value.month(), 1, 0, 0, 0, 0);
+                    UInt64 cast_value = binary_cast<DateValueType, UInt64>(ts_value);
+                    DataTypeDateTimeV2::cast_to_date_v2(cast_value, res_data[i]);
+                    continue;
+                }
+                // day_of_week, from 1(Mon) to 7(Sun)
+                int day_of_week = ts_value.weekday() + 1;
+                int gap_of_monday = day_of_week - 1;
+                TimeInterval interval(DAY, gap_of_monday, true);
+                ts_value.template date_add_interval<DAY>(interval);
+                ts_value.set_time(ts_value.year(), ts_value.month(), ts_value.day(), 0, 0, 0, 0);
+                UInt64 cast_value = binary_cast<DateValueType, UInt64>(ts_value);
+                DataTypeDateTimeV2::cast_to_date_v2(cast_value, res_data[i]);
+            }
+        }
+    }
+
+    // specially, 1970-01-01, 1970-01-02, 1970-01-03 and 1970-01-04 return 1970-01-01
+    static bool is_special_day(int year, int month, int day) {
+        return year == 1970 && month == 1 && day > 0 && day < 5;
+    }
+};
+
 template <typename Impl>
 class FunctionOtherTypesToDateType : public IFunction {
 public:
@@ -771,6 +889,10 @@ void register_function_timestamp(SimpleFunctionFactory& factory) {
     factory.register_function<FunctionDateOrDateTimeToDate<LastDayImpl, DataTypeDate>>();
     factory.register_function<FunctionDateOrDateTimeToDate<LastDayImpl, DataTypeDateV2>>();
     factory.register_function<FunctionDateOrDateTimeToDate<LastDayImpl, DataTypeDateTimeV2>>();
+    factory.register_function<FunctionDateOrDateTimeToDate<MondayImpl, DataTypeDateV2>>();
+    factory.register_function<FunctionDateOrDateTimeToDate<MondayImpl, DataTypeDateTimeV2>>();
+    factory.register_function<FunctionDateOrDateTimeToDate<MondayImpl, DataTypeDate>>();
+    factory.register_function<FunctionDateOrDateTimeToDate<MondayImpl, DataTypeDateTime>>();
 }
 
 } // namespace doris::vectorized
diff --git a/docs/en/docs/sql-manual/sql-functions/date-time-functions/to_monday.md b/docs/en/docs/sql-manual/sql-functions/date-time-functions/to_monday.md
new file mode 100644
index 0000000000..dde3f877aa
--- /dev/null
+++ b/docs/en/docs/sql-manual/sql-functions/date-time-functions/to_monday.md
@@ -0,0 +1,46 @@
+---
+{
+    "title": "to_monday",
+    "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.
+-->
+
+## to_monday
+### Description
+#### Syntax
+
+`DATE to_monday(DATETIME date)`
+
+Round a date or datetime down to the nearest Monday, return type is Date or DateV2.
+Specially, input 1970-01-01, 1970-01-02, 1970-01-03 and 1970-01-04 will return '1970-01-01'
+
+### example
+
+```
+MySQL [(none)]> select to_monday('2022-09-10');
++----------------------------------+
+| to_monday('2022-09-10 00:00:00') |
++----------------------------------+
+| 2022-09-05                       |
++----------------------------------+
+```
+
+### keywords
+    MONDAY
diff --git a/docs/sidebars.json b/docs/sidebars.json
index 4cf82d482b..6d515f636d 100644
--- a/docs/sidebars.json
+++ b/docs/sidebars.json
@@ -294,6 +294,7 @@
                                 "sql-manual/sql-functions/date-time-functions/second",
                                 "sql-manual/sql-functions/date-time-functions/from_days",
                                 "sql-manual/sql-functions/date-time-functions/last_day",
+                                "sql-manual/sql-functions/date-time-functions/to_monday",
                                 "sql-manual/sql-functions/date-time-functions/from_unixtime",
                                 "sql-manual/sql-functions/date-time-functions/unix_timestamp",
                                 "sql-manual/sql-functions/date-time-functions/utc_timestamp",
diff --git a/docs/zh-CN/docs/sql-manual/sql-functions/date-time-functions/to_monday.md b/docs/zh-CN/docs/sql-manual/sql-functions/date-time-functions/to_monday.md
new file mode 100644
index 0000000000..55f6e46b05
--- /dev/null
+++ b/docs/zh-CN/docs/sql-manual/sql-functions/date-time-functions/to_monday.md
@@ -0,0 +1,45 @@
+---
+{
+    "title": "to_monday",
+    "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.
+-->
+
+## to_monday
+### Description
+#### Syntax
+
+`DATE to_monday(DATETIME date)`
+
+将日期或带时间的日期向下舍入到最近的星期一。作为一种特殊情况,日期参数 1970-01-01、1970-01-02、1970-01-03 和 1970-01-04 返回日期 1970-01-01
+
+### example
+
+```
+MySQL [(none)]> select to_monday('2022-09-10');
++----------------------------------+
+| to_monday('2022-09-10 00:00:00') |
++----------------------------------+
+| 2022-09-05                       |
++----------------------------------+
+```
+
+### keywords
+    MONDAY
diff --git a/gensrc/script/doris_builtins_functions.py b/gensrc/script/doris_builtins_functions.py
index 8e9b447cde..444cf48716 100755
--- a/gensrc/script/doris_builtins_functions.py
+++ b/gensrc/script/doris_builtins_functions.py
@@ -532,6 +532,14 @@ visible_functions = [
     [['last_day'], 'DATEV2', ['DATEV2'],
         '_ZN5doris18TimestampFunctions8last_dayEPN9doris_udf15FunctionContextERKNS1_11DateTimeValE',
         '', '', 'vec', 'ALWAYS_NULLABLE'],
+    [['to_monday'], 'DATEV2', ['DATETIMEV2'],
+        '', '', '', 'vec', 'ALWAYS_NULLABLE'],
+    [['to_monday'], 'DATEV2', ['DATEV2'],
+        '','', '', 'vec', 'ALWAYS_NULLABLE'],
+    [['to_monday'], 'DATE', ['DATETIME'],
+        '', '', '', 'vec', 'ALWAYS_NULLABLE'],
+    [['to_monday'], 'DATE', ['DATE'],
+        '','', '', 'vec', 'ALWAYS_NULLABLE'],
     [['to_days'], 'INT', ['DATE'],
         '_ZN5doris18TimestampFunctions7to_daysEPN9doris_udf15FunctionContextERKNS1_11DateTimeValE',
         '', '', 'vec', 'ALWAYS_NULLABLE'],
diff --git a/regression-test/data/query_p0/sql_functions/datetime_functions/test_date_function.out b/regression-test/data/query_p0/sql_functions/datetime_functions/test_date_function.out
index b465af0658..847060d35b 100644
--- a/regression-test/data/query_p0/sql_functions/datetime_functions/test_date_function.out
+++ b/regression-test/data/query_p0/sql_functions/datetime_functions/test_date_function.out
@@ -541,3 +541,10 @@ true
 2022-01-31	2022-01-31
 2022-02-28	2022-02-28
 
+-- !sql --
+\N	\N	\N	\N
+1970-01-01	1970-01-01	1970-01-01	1970-01-01
+2000-01-31	2000-01-31	2000-01-31	2000-01-31
+2021-12-27	2021-12-27	2021-12-27	2021-12-27
+2022-02-28	2022-02-28	2022-02-28	2022-02-28
+
diff --git a/regression-test/suites/query_p0/sql_functions/datetime_functions/test_date_function.groovy b/regression-test/suites/query_p0/sql_functions/datetime_functions/test_date_function.groovy
index 7ff926157f..b63de704e1 100644
--- a/regression-test/suites/query_p0/sql_functions/datetime_functions/test_date_function.groovy
+++ b/regression-test/suites/query_p0/sql_functions/datetime_functions/test_date_function.groovy
@@ -477,4 +477,31 @@ suite("test_date_function") {
         select last_day(birth), last_day(birth1) from ${tableName};
     """
     sql """ DROP TABLE IF EXISTS ${tableName}; """
+
+    // test to_monday
+    sql """ SET enable_vectorized_engine = TRUE; """
+    sql """ DROP TABLE IF EXISTS ${tableName}; """
+    sql """
+            CREATE TABLE IF NOT EXISTS ${tableName} (
+                birth date,    
+                birth1 datev2, 
+                birth2 datetime, 
+                birth3 datetimev2)
+            UNIQUE KEY(birth, birth1, birth2, birth3)
+            DISTRIBUTED BY HASH (birth) BUCKETS 1 
+            PROPERTIES( "replication_allocation" = "tag.location.default: 1");
+        """
+    sql """
+        insert into ${tableName} values 
+        ('2022-01-01', '2022-01-01', '2022-01-01 00:00:00', '2022-01-01 00:00:00'), 
+        ('2000-02-01', '2000-02-01', '2000-02-01 00:00:00', '2000-02-01 00:00:00.123'), 
+        ('2022-02-29', '2022-02-29', '2022-02-29 00:00:00', '2022-02-29 00:00:00'),
+        ('2022-02-28', '2022-02-28', '2022-02-28 23:59:59', '2022-02-28 23:59:59'),
+        ('1970-01-02', '1970-01-02', '1970-01-02 01:02:03', '1970-01-02 02:03:04');"""
+    qt_sql """
+        select to_monday(birth), to_monday(birth1), 
+                to_monday(birth2), to_monday(birth3) 
+                from ${tableName};
+    """
+    sql """ DROP TABLE IF EXISTS ${tableName}; """
 }


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