linrrzqqq commented on code in PR #58592:
URL: https://github.com/apache/doris/pull/58592#discussion_r2661024723


##########
be/src/vec/runtime/vdatetime_value.cpp:
##########
@@ -2982,6 +2982,187 @@ bool 
DateV2Value<T>::to_format_string_conservative(const char* format, size_t le
     if (is_invalid(year(), month(), day(), hour(), minute(), second(), 
microsecond())) {
         return false;
     }
+
+    return DatetimeValueUtil::to_format_string_without_check<false>(
+            format, len, to, max_valid_length, this->year(), this->month(), 
this->day(),
+            this->hour(), this->minute(), this->second(), this->microsecond());
+}
+
+template <typename T>
+int64_t DateV2Value<T>::standardize_timevalue(int64_t value) {
+    if (value <= 0) {
+        return 0;
+    }
+    if (value >= 10000101000000L) {
+        // 9999-99-99 99:99:99
+        if (value > 99999999999999L) {
+            return 0;
+        }
+
+        // between 1000-01-01 00:00:00L and 9999-99-99 99:99:99
+        // all digits exist.
+        return value;
+    }
+    // 2000-01-01
+    if (value < 101) {
+        return 0;
+    }
+    // two digits  year. 2000 ~ 2069
+    if (value <= (YY_PART_YEAR - 1) * 10000L + 1231L) {
+        return (value + 20000000L) * 1000000L;
+    }
+    // two digits year, invalid date
+    if (value < YY_PART_YEAR * 10000L + 101) {
+        return 0;
+    }
+    // two digits year. 1970 ~ 1999
+    if (value <= 991231L) {
+        return (value + 19000000L) * 1000000L;
+    }
+    if (value < 10000101) {
+        return 0;
+    }
+    // four digits years without hour.
+    if (value <= 99991231L) {
+        return value * 1000000L;
+    }
+    // below 0000-01-01
+    if (value < 101000000) {
+        return 0;
+    }
+
+    // below is with datetime, must have hh:mm:ss
+    // 2000 ~ 2069
+    if (value <= (YY_PART_YEAR - 1) * 10000000000L + 1231235959L) {
+        return value + 20000000000000L;
+    }
+    if (value < YY_PART_YEAR * 10000000000L + 101000000L) {
+        return 0;
+    }
+    // 1970 ~ 1999
+    if (value <= 991231235959L) {
+        return value + 19000000000000L;
+    }
+    return value;
+}
+
+template <typename T>
+bool DateV2Value<T>::from_date_int64(int64_t value) {
+    value = standardize_timevalue(value);
+    if (value <= 0) {
+        return false;
+    }
+    uint64_t date = value / 1000000;
+
+    auto [year, month, day, hour, minute, second] = std::tuple {0, 0, 0, 0, 0, 
0};
+    year = date / 10000;
+    date %= 10000;
+    month = date / 100;
+    day = date % 100;
+
+    if constexpr (is_datetime) {
+        uint64_t time = value % 1000000;
+        hour = time / 10000;
+        time %= 10000;
+        minute = time / 100;
+        second = time % 100;
+        return check_range_and_set_time(year, month, day, hour, minute, 
second, 0);
+    } else {
+        return check_range_and_set_time(year, month, day, 0, 0, 0, 0);
+    }
+}
+
+// An ISO week-numbering year (also called ISO year informally) has 52 or 53 
full weeks. That is 364 or 371 days instead of the usual 365 or 366 days. These 
53-week years occur on all years that have Thursday as 1 January and on leap 
years that start on Wednesday. The extra week is sometimes referred to as a 
leap week, although ISO 8601 does not use this term. 
https://en.wikipedia.org/wiki/ISO_week_date
+template <typename T>
+uint16_t DateV2Value<T>::year_of_week() const {
+    constexpr uint8_t THURSDAY = 3;
+
+    if (date_v2_value_.month_ == 1) {
+        constexpr uint8_t MAX_DISTANCE_WITH_THURSDAY = 6 - THURSDAY;
+        if (date_v2_value_.day_ <= MAX_DISTANCE_WITH_THURSDAY) {
+            auto weekday = calc_weekday(daynr(), false);
+            // if the current day is after Thursday and Thursday is in the 
previous year, return the previous year
+            return date_v2_value_.year_ -
+                   (weekday > THURSDAY && weekday - THURSDAY > 
date_v2_value_.day_ - 1);
+        }
+    } else if (date_v2_value_.month_ == 12) {
+        constexpr uint8_t MAX_DISTANCE_WITH_THURSDAY = THURSDAY - 0;
+        if (S_DAYS_IN_MONTH[12] - date_v2_value_.day_ <= 
MAX_DISTANCE_WITH_THURSDAY) {
+            auto weekday = calc_weekday(daynr(), false);
+            // if the current day is before Thursday and Thursday is in the 
next year, return the next year
+            return date_v2_value_.year_ +
+                   (weekday < THURSDAY &&
+                    (THURSDAY - weekday) > S_DAYS_IN_MONTH[12] - 
date_v2_value_.day_);
+        }
+    }
+    return date_v2_value_.year_;
+}
+
+template <typename T>
+uint8_t DateV2Value<T>::calc_week(const uint32_t& day_nr, const uint16_t& year,
+                                  const uint8_t& month, const uint8_t& day, 
uint8_t mode,
+                                  uint16_t* to_year, bool disable_lut) {
+    if (year == 0) [[unlikely]] {
+        *to_year = 0;
+        return 0;
+    }
+    if (config::enable_time_lut && !disable_lut && mode == 3 && year >= 1950 
&& year < 2030) {
+        return doris::TimeLUT::GetImplement()
+                ->week_of_year_table[year - doris::LUT_START_YEAR][month - 
1][day - 1];
+    }
+    // mode=4 is used for week()
+    if (config::enable_time_lut && !disable_lut && mode == 4 && year >= 1950 
&& year < 2030) {
+        return doris::TimeLUT::GetImplement()
+                ->week_table[year - doris::LUT_START_YEAR][month - 1][day - 1];
+    }
+    bool monday_first = mode & WEEK_MONDAY_FIRST;
+    bool week_year = mode & WEEK_YEAR;
+    bool first_weekday = mode & WEEK_FIRST_WEEKDAY;
+    uint64_t daynr_first_day = doris::calc_daynr(year, 1, 1);
+    uint8_t weekday_first_day = doris::calc_weekday(daynr_first_day, 
!monday_first);
+
+    int days = 0;
+    *to_year = year;
+
+    // Check weather the first days of this year belongs to last year
+    if (month == 1 && day <= (7 - weekday_first_day)) {
+        if (!week_year && ((first_weekday && weekday_first_day != 0) ||
+                           (!first_weekday && weekday_first_day > 3))) {
+            return 0;
+        }
+        (*to_year)--;
+        week_year = true;
+        daynr_first_day -= (days = doris::calc_days_in_year(*to_year));
+        weekday_first_day = (weekday_first_day + 53 * 7 - days) % 7;
+    }
+
+    // How many days since first week
+    if ((first_weekday && weekday_first_day != 0) || (!first_weekday && 
weekday_first_day > 3)) {
+        // days in new year belongs to last year.
+        days = day_nr - (daynr_first_day + (7 - weekday_first_day));
+    } else {
+        // days in new year belongs to this year.
+        days = day_nr - (daynr_first_day - weekday_first_day);
+    }
+
+    if (week_year && days >= 52 * 7) {
+        weekday_first_day = (weekday_first_day + 
doris::calc_days_in_year(*to_year)) % 7;
+        if ((first_weekday && weekday_first_day == 0) ||
+            (!first_weekday && weekday_first_day <= 3)) {
+            // Belong to next year.
+            (*to_year)++;
+            return 1;
+        }
+    }
+
+    return days / 7 + 1;
+}
+
+template <bool only_time>
+bool DatetimeValueUtil::to_format_string_without_check(const char* format, 
size_t len, char* to,

Review Comment:
   Before:
   ```sql
   Doris> SELECT COUNT(*) FROM (
       ->     SELECT DATE_FORMAT(dttm, 
'%a%b%c%D%d%e%f%H%h%I%i%j%k%l%M%m%p%r%S%s%T%U%u%V%v%W%w%X%x%Y%y%%')
       -> FROM test_date_format
       -> ) t;
   +-----------+
   | COUNT(*)  |
   +-----------+
   | 100000000 |
   +-----------+
   1 row in set (22.46 sec)
   ```
   
   After:
   ```sql
   Doris> SELECT COUNT(*) FROM (
       ->     SELECT DATE_FORMAT(dttm, 
'%a%b%c%D%d%e%f%H%h%I%i%j%k%l%M%m%p%r%S%s%T%U%u%V%v%W%w%X%x%Y%y%%')
       -> FROM test_date_format
       -> ) t;
   +-----------+
   | COUNT(*)  |
   +-----------+
   | 100000000 |
   +-----------+
   1 row in set (22.58 sec)
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


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

Reply via email to