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

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

commit af556cff3cbe348843bb14c7f917e55fddcfd925
Author: zclllyybb <zhaochan...@selectdb.com>
AuthorDate: Fri Apr 12 23:22:44 2024 +0800

    [Fix](timezone) fix miss of expected rounding of Date type with timezone 
#33553
---
 be/src/http/action/stream_load.cpp                 |  3 +++
 be/src/http/http_common.h                          |  1 +
 be/src/vec/runtime/vdatetime_value.cpp             | 20 ++++++++++++++++++
 be/src/vec/runtime/vdatetime_value.h               | 13 ++++++++++++
 .../data/datatype_p0/datetimev2/only_date.csv      |  2 ++
 .../datatype_p0/datetimev2/test_tz_streamload.out  |  4 ++++
 .../datetimev2/test_tz_streamload.groovy           | 24 ++++++++++++++++++++++
 7 files changed, 67 insertions(+)

diff --git a/be/src/http/action/stream_load.cpp 
b/be/src/http/action/stream_load.cpp
index a3c7554ea1f..995d08b0af9 100644
--- a/be/src/http/action/stream_load.cpp
+++ b/be/src/http/action/stream_load.cpp
@@ -474,8 +474,11 @@ Status StreamLoadAction::_process_put(HttpRequest* 
http_req,
             return Status::InvalidArgument("Invalid strict mode format. Must 
be bool type");
         }
     }
+    // timezone first. if not, try time_zone
     if (!http_req->header(HTTP_TIMEZONE).empty()) {
         request.__set_timezone(http_req->header(HTTP_TIMEZONE));
+    } else if (!http_req->header(HTTP_TIME_ZONE).empty()) {
+        request.__set_timezone(http_req->header(HTTP_TIME_ZONE));
     }
     if (!http_req->header(HTTP_EXEC_MEM_LIMIT).empty()) {
         try {
diff --git a/be/src/http/http_common.h b/be/src/http/http_common.h
index 5a1550f48fc..175b7290378 100644
--- a/be/src/http/http_common.h
+++ b/be/src/http/http_common.h
@@ -38,6 +38,7 @@ static const std::string HTTP_TEMP_PARTITIONS = 
"temporary_partitions";
 static const std::string HTTP_NEGATIVE = "negative";
 static const std::string HTTP_STRICT_MODE = "strict_mode";
 static const std::string HTTP_TIMEZONE = "timezone";
+static const std::string HTTP_TIME_ZONE = "time_zone";
 static const std::string HTTP_EXEC_MEM_LIMIT = "exec_mem_limit";
 static const std::string HTTP_JSONPATHS = "jsonpaths";
 static const std::string HTTP_JSONROOT = "json_root";
diff --git a/be/src/vec/runtime/vdatetime_value.cpp 
b/be/src/vec/runtime/vdatetime_value.cpp
index ee384286455..6b769c68f9d 100644
--- a/be/src/vec/runtime/vdatetime_value.cpp
+++ b/be/src/vec/runtime/vdatetime_value.cpp
@@ -2192,6 +2192,26 @@ bool DateV2Value<T>::from_date_str_base(const char* 
date_str, int len, int scale
         return false;
     }
 
+    // In check_range_and_set_time, for Date type the time part will be 
truncated. So if the timezone offset should make
+    // rounding to date part, it would be lost. To avoid this, we use a 
Datetime type to do these calc. It will save the
+    // time part and apply the offset. Then convert to Date type back.
+    // see https://github.com/apache/doris/pull/33553 for more details.
+    if constexpr (!is_datetime) {
+        if (sec_offset) {
+            DateV2Value<DateTimeV2ValueType> tmp;
+            if (!tmp.check_range_and_set_time(date_val[0], date_val[1], 
date_val[2], date_val[3],
+                                              date_val[4], date_val[5], 
date_val[6])) {
+                return false;
+            }
+            if (!tmp.date_add_interval<TimeUnit::SECOND>(
+                        TimeInterval {TimeUnit::SECOND, sec_offset, false})) {
+                return false;
+            }
+            this->assign_from(tmp);
+            return true;
+        }
+    }
+
     if (!check_range_and_set_time(date_val[0], date_val[1], date_val[2], 
date_val[3], date_val[4],
                                   date_val[5], date_val[6])) {
         return false;
diff --git a/be/src/vec/runtime/vdatetime_value.h 
b/be/src/vec/runtime/vdatetime_value.h
index 54dc368f620..2031c782267 100644
--- a/be/src/vec/runtime/vdatetime_value.h
+++ b/be/src/vec/runtime/vdatetime_value.h
@@ -824,6 +824,19 @@ public:
         return from_date_format_str(format, format_len, value, value_len, 
nullptr);
     }
 
+    template <typename U>
+    void assign_from(DateV2Value<U> src) {
+        date_v2_value_.year_ = src.year();
+        date_v2_value_.month_ = src.month();
+        date_v2_value_.day_ = src.day();
+        if constexpr (is_datetime && std::is_same_v<U, DateTimeV2ValueType>) {
+            date_v2_value_.hour_ = src.hour();
+            date_v2_value_.minute_ = src.minute();
+            date_v2_value_.second_ = src.second();
+            date_v2_value_.microsecond_ = src.microsecond();
+        }
+    }
+
     // Construct Date/Datetime type value from string.
     // At least the following formats are recognised (based on number of 
digits)
     // 'YYMMDD', 'YYYYMMDD', 'YYMMDDHHMMSS', 'YYYYMMDDHHMMSS'
diff --git a/regression-test/data/datatype_p0/datetimev2/only_date.csv 
b/regression-test/data/datatype_p0/datetimev2/only_date.csv
new file mode 100644
index 00000000000..63b49fef9d9
--- /dev/null
+++ b/regression-test/data/datatype_p0/datetimev2/only_date.csv
@@ -0,0 +1,2 @@
+1,2024-04-11T16:00:13+08:00,2024-04-11T16:00:13+08:00
+1,2024-04-11T06:00:13+08:00,2024-04-11T06:00:13+08:00
diff --git a/regression-test/data/datatype_p0/datetimev2/test_tz_streamload.out 
b/regression-test/data/datatype_p0/datetimev2/test_tz_streamload.out
index c7fd50e3bb4..ab103c3a306 100644
--- a/regression-test/data/datatype_p0/datetimev2/test_tz_streamload.out
+++ b/regression-test/data/datatype_p0/datetimev2/test_tz_streamload.out
@@ -19,3 +19,7 @@
 7      2023-08-17T17:41:18
 8      2023-08-17T19:41:18
 
+-- !table1 --
+1      2024-04-10      2024-04-10T22:00:13
+1      2024-04-11      2024-04-11T08:00:13
+
diff --git 
a/regression-test/suites/datatype_p0/datetimev2/test_tz_streamload.groovy 
b/regression-test/suites/datatype_p0/datetimev2/test_tz_streamload.groovy
index 6e32facc83e..9ccd48477e1 100644
--- a/regression-test/suites/datatype_p0/datetimev2/test_tz_streamload.groovy
+++ b/regression-test/suites/datatype_p0/datetimev2/test_tz_streamload.groovy
@@ -68,4 +68,28 @@ suite("test_tz_streamload") {
     }
     sql "sync"
     qt_table2 "select * from ${table2} order by id"
+
+    // test rounding for date type. from hour to date.
+    sql "drop table if exists d"
+    sql """
+        CREATE TABLE d (
+            `k1` int,
+            `k2` date,
+            `k3` datetime
+        )
+        DISTRIBUTED BY HASH(k1) BUCKETS 3
+        PROPERTIES (
+            "replication_num" = "1"
+        );
+    """
+
+    streamLoad {
+        table "d"
+        set 'column_separator', ','
+        set 'timezone', 'UTC'
+        file "only_date.csv"
+        time 20000
+    }
+    sql "sync"
+    qt_table1 "select * from d order by k1, k2, k3"
 }


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

Reply via email to