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 5630dc98f24 branch-4.0: [Feature](function) Support function 
TIME_FORMAT (#58592) (#59704)
5630dc98f24 is described below

commit 5630dc98f242c7638d5888be0fe0b069ea0be41b
Author: linrrarity <[email protected]>
AuthorDate: Mon Jan 12 10:14:21 2026 +0800

    branch-4.0: [Feature](function) Support function TIME_FORMAT (#58592) 
(#59704)
    
    pick: https://github.com/apache/doris/pull/58592
    
    doc: https://github.com/apache/doris-website/pull/3135
    
    The TIME_FORMAT function is used to convert a time value into a string
    according to the specified format string. It supports formatting for
    TIME and DATETIME types, and the output is a string that conforms to the
    format requirements.
    
    ```sql
    SELECT TIME_FORMAT('2025-11-25 15:30:45', '%Y-%m-%d %H:%i:%s') AS 
date_with_time;
    ```
    ```text
    +---------------------+
    | date_with_time      |
    +---------------------+
    | 0000-00-00 15:30:45 |
    +---------------------+
    ```
    
    ### What problem does this PR solve?
    
    Issue Number: close #xxx
    
    Related PR: #xxx
    
    Problem Summary:
    
    ### Release note
    
    None
    
    ### Check List (For Author)
    
    - Test <!-- At least one of them must be included. -->
        - [ ] Regression test
        - [ ] Unit Test
        - [ ] Manual test (add detailed scripts or steps below)
        - [ ] No need to test or manual test. Explain why:
    - [ ] This is a refactor/code format and no logic has been changed.
            - [ ] Previous test can cover this change.
            - [ ] No code files have been changed.
            - [ ] Other reason <!-- Add your reason?  -->
    
    - Behavior changed:
        - [ ] No.
        - [ ] Yes. <!-- Explain the behavior change -->
    
    - Does this need documentation?
        - [ ] No.
    - [ ] Yes. <!-- Add document PR link here. eg:
    https://github.com/apache/doris-website/pull/1214 -->
    
    ### Check List (For Reviewer who merge this PR)
    
    - [ ] Confirm the release note
    - [ ] Confirm test cases
    - [ ] Confirm document
    - [ ] Add branch pick label <!-- Add branch pick label that this PR
    should merge into -->
---
 be/src/vec/functions/date_time_transforms.h        |  71 +++
 .../function_datetime_string_to_string.cpp         |   6 +
 be/src/vec/runtime/time_value.h                    |  16 +
 be/src/vec/runtime/vdatetime_value.cpp             | 505 ++++++++++++---------
 be/src/vec/runtime/vdatetime_value.h               |  21 +
 .../doris/catalog/BuiltinScalarFunctions.java      |   2 +
 .../executable/DateTimeExtractAndTransform.java    |  33 +-
 .../expressions/functions/scalar/DateFormat.java   |   4 +-
 .../scalar/{DateFormat.java => TimeFormat.java}    |  33 +-
 .../trees/expressions/literal/TimeV2Literal.java   |   4 +
 .../expressions/visitor/ScalarFunctionVisitor.java |   5 +
 .../doris/nereids/util/DateTimeFormatterUtils.java | 425 +++++++++++++++++
 .../nereids/rules/expression/FoldConstantTest.java |  12 +-
 .../sql-functions/doc_date_functions_test.out      | 107 +++++
 .../test_function_signature_all_types.groovy       |   2 +-
 .../sql-functions/doc_date_functions_test.groovy   | 164 ++++++-
 16 files changed, 1146 insertions(+), 264 deletions(-)

diff --git a/be/src/vec/functions/date_time_transforms.h 
b/be/src/vec/functions/date_time_transforms.h
index f494750cf24..8954e664988 100644
--- a/be/src/vec/functions/date_time_transforms.h
+++ b/be/src/vec/functions/date_time_transforms.h
@@ -39,6 +39,7 @@
 #include "vec/data_types/data_type_decimal.h"
 #include "vec/data_types/data_type_string.h"
 #include "vec/functions/date_format_type.h"
+#include "vec/runtime/time_value.h"
 #include "vec/runtime/vdatetime_value.h"
 #include "vec/utils/util.hpp"
 
@@ -427,6 +428,76 @@ struct FromUnixTimeDecimalImpl {
     }
 };
 
+template <PrimitiveType ArgPType>
+class FunctionTimeFormat : public IFunction {
+public:
+    using ArgColType = typename PrimitiveTypeTraits<ArgPType>::ColumnType;
+    using ArgCppType = typename PrimitiveTypeTraits<ArgPType>::CppType;
+
+    static constexpr auto name = "time_format";
+    String get_name() const override { return name; }
+    static FunctionPtr create() { return 
std::make_shared<FunctionTimeFormat>(); }
+    DataTypes get_variadic_argument_types_impl() const override {
+        return {std::make_shared<typename 
PrimitiveTypeTraits<ArgPType>::DataType>(),
+                std::make_shared<vectorized::DataTypeString>()};
+    }
+    DataTypePtr get_return_type_impl(const ColumnsWithTypeAndName& arguments) 
const override {
+        return make_nullable(std::make_shared<DataTypeString>());
+    }
+    size_t get_number_of_arguments() const override { return 2; }
+
+    Status execute_impl(FunctionContext* context, Block& block, const 
ColumnNumbers& arguments,
+                        uint32_t result, size_t input_rows_count) const 
override {
+        auto res_col = ColumnString::create();
+        ColumnString::Chars& res_chars = res_col->get_chars();
+        ColumnString::Offsets& res_offsets = res_col->get_offsets();
+
+        auto null_map = ColumnUInt8::create();
+        auto& null_map_data = null_map->get_data();
+        null_map_data.resize_fill(input_rows_count, 0);
+
+        res_offsets.reserve(input_rows_count);
+
+        ColumnPtr arg_col[2];
+        bool is_const[2];
+        for (size_t i = 0; i < 2; ++i) {
+            const ColumnPtr& col = block.get_by_position(arguments[i]).column;
+            std::tie(arg_col[i], is_const[i]) = unpack_if_const(col);
+        }
+
+        const auto* datetime_col = assert_cast<const 
ArgColType*>(arg_col[0].get());
+        const auto* format_col = assert_cast<const 
ColumnString*>(arg_col[1].get());
+        for (size_t i = 0; i < input_rows_count; ++i) {
+            const auto& datetime_val = 
datetime_col->get_element(index_check_const(i, is_const[0]));
+            StringRef format = format_col->get_data_at(index_check_const(i, 
is_const[1]));
+            TimeValue::TimeType time = get_time_value(datetime_val);
+
+            char buf[100 + SAFE_FORMAT_STRING_MARGIN];
+            if (!TimeValue::to_format_string_conservative(format.data, 
format.size, buf,
+                                                          100 + 
SAFE_FORMAT_STRING_MARGIN, time)) {
+                null_map_data[i] = 1;
+                res_offsets.push_back(res_chars.size());
+                continue;
+            }
+            res_chars.insert(buf, buf + strlen(buf));
+            res_offsets.push_back(res_chars.size());
+        }
+        block.replace_by_position(result,
+                                  ColumnNullable::create(std::move(res_col), 
std::move(null_map)));
+        return Status::OK();
+    }
+
+private:
+    TimeValue::TimeType get_time_value(const ArgCppType& datetime_val) const {
+        if constexpr (ArgPType == PrimitiveType::TYPE_TIMEV2) {
+            return static_cast<TimeValue::TimeType>(datetime_val);
+        } else {
+            return TimeValue::make_time(datetime_val.hour(), 
datetime_val.minute(),
+                                        datetime_val.second(), 
datetime_val.microsecond());
+        }
+    }
+};
+
 #include "common/compile_check_end.h"
 } // namespace doris::vectorized
 
diff --git a/be/src/vec/functions/function_datetime_string_to_string.cpp 
b/be/src/vec/functions/function_datetime_string_to_string.cpp
index 53a472f3179..72fc5edd5a7 100644
--- a/be/src/vec/functions/function_datetime_string_to_string.cpp
+++ b/be/src/vec/functions/function_datetime_string_to_string.cpp
@@ -37,6 +37,9 @@ using FunctionFromUnixTimeNewDecimalOneArg =
         FunctionDateTimeStringToString<FromUnixTimeDecimalImpl<false>>;
 using FunctionFromUnixTimeNewDecimalTwoArg =
         FunctionDateTimeStringToString<FromUnixTimeDecimalImpl<true>>;
+using FunctionTimeFormatDate = FunctionTimeFormat<TYPE_DATEV2>;
+using FunctionTimeFormatDateTime = FunctionTimeFormat<TYPE_DATETIMEV2>;
+using FunctionTimeFormatTime = FunctionTimeFormat<TYPE_TIMEV2>;
 
 void register_function_date_time_string_to_string(SimpleFunctionFactory& 
factory) {
     factory.register_function<FunctionDateFormatV2>();
@@ -47,6 +50,9 @@ void 
register_function_date_time_string_to_string(SimpleFunctionFactory& factory
     factory.register_function<FunctionFromUnixTimeNewDecimalOneArg>();
     factory.register_function<FunctionFromUnixTimeNewDecimalTwoArg>();
     factory.register_function<FunctionDateTimeV2DateFormat>();
+    factory.register_function<FunctionTimeFormatDate>();
+    factory.register_function<FunctionTimeFormatDateTime>();
+    factory.register_function<FunctionTimeFormatTime>();
 }
 
 } // namespace doris::vectorized
diff --git a/be/src/vec/runtime/time_value.h b/be/src/vec/runtime/time_value.h
index 10c1a12bb03..340b4da42b3 100644
--- a/be/src/vec/runtime/time_value.h
+++ b/be/src/vec/runtime/time_value.h
@@ -28,6 +28,7 @@
 #include "runtime/define_primitive_type.h"
 #include "runtime/primitive_type.h"
 #include "util/date_func.h"
+#include "vec/runtime/vdatetime_value.h"
 
 namespace doris {
 #include "common/compile_check_begin.h"
@@ -150,6 +151,21 @@ public:
     }
 
     static bool valid(double time) { return time <= MAX_TIME && time >= 
-MAX_TIME; }
+
+    static bool to_format_string_conservative(const char* format, size_t len, 
char* to,
+                                              size_t max_valid_length, 
TimeType time) {
+        // If time is negative, we here only add a '-' to the begining of res
+        // This behavior is consistent with MySQL
+        if (time < 0) {
+            memcpy(to, "-", 1);
+            ++to;
+            time = -time;
+        }
+
+        return DatetimeValueUtil::to_format_string_without_check<true>(
+                format, len, to, max_valid_length, 0, 0, 0, 
TimeValue::hour(time),
+                TimeValue::minute(time), TimeValue::second(time), 
TimeValue::microsecond(time));
+    }
 };
 } // namespace doris
 #include "common/compile_check_end.h"
diff --git a/be/src/vec/runtime/vdatetime_value.cpp 
b/be/src/vec/runtime/vdatetime_value.cpp
index 3b77981e3ea..da3b2831289 100644
--- a/be/src/vec/runtime/vdatetime_value.cpp
+++ b/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,
+                                                       size_t 
max_valid_length, int16_t year,
+                                                       int8_t month, int8_t 
day, int hour,
+                                                       int minute, int second, 
int ms) {
     char* const begin = to; // to check written bytes
     char buf[64];
     char* pos = nullptr;
@@ -3003,79 +3184,85 @@ bool 
DateV2Value<T>::to_format_string_conservative(const char* format, size_t le
         switch (ch = *ptr++) {
         case 'y':
             // Year, numeric (two digits)
-            to = write_two_digits_to_string(this->year() % 100, to);
+            to = write_two_digits_to_string(year % 100, to);
             cursor += 2;
             pos = cursor;
             break;
         case 'Y':
             // Year, numeric, four digits
-            to = write_four_digits_to_string(this->year(), to);
+            to = write_four_digits_to_string(year, to);
             cursor += 4;
             pos = cursor;
             break;
         case 'd':
             // Day of month (00...31)
-            to = write_two_digits_to_string(this->day(), to);
+            to = write_two_digits_to_string(day, to);
             cursor += 2;
             pos = cursor;
             break;
         case 'H':
-            to = write_two_digits_to_string(this->hour(), to);
-            cursor += 2;
+            // Hour (00...838)
+            pos = int_to_str(hour, cursor);
+            to = append_with_prefix(cursor, static_cast<int>(pos - cursor), 
'0', 2, to);
+            cursor += (pos - cursor);
             pos = cursor;
             break;
         case 'i':
             // Minutes, numeric (00..59)
-            to = write_two_digits_to_string(this->minute(), to);
+            to = write_two_digits_to_string(minute, to);
             cursor += 2;
             pos = cursor;
             break;
         case 'm':
-            to = write_two_digits_to_string(this->month(), to);
+            to = write_two_digits_to_string(month, to);
             cursor += 2;
             pos = cursor;
             break;
         case 'h':
         case 'I':
             // Hour (01..12)
-            to = write_two_digits_to_string((this->hour() % 24 + 11) % 12 + 1, 
to);
+            to = write_two_digits_to_string((hour % 24 + 11) % 12 + 1, to);
             cursor += 2;
             pos = cursor;
             break;
         case 's':
         case 'S':
             // Seconds (00..59)
-            to = write_two_digits_to_string(this->second(), to);
+            to = write_two_digits_to_string(second, to);
             cursor += 2;
             pos = cursor;
             break;
         case 'a':
             // Abbreviated weekday name
-            if (this->year() == 0 && this->month() == 0) {
+            if constexpr (only_time) {
                 return false;
             }
-            to = append_string(s_ab_day_name[weekday()], to);
+            to = append_string(s_ab_day_name[calc_weekday(calc_daynr(year, 
month, day), false)],
+                               to);
             break;
         case 'b':
             // Abbreviated month name
-            if (this->month() == 0) {
+            if constexpr (only_time) {
                 return false;
             }
-            to = append_string(s_ab_month_name[this->month()], to);
+            to = append_string(s_ab_month_name[month], to);
             break;
         case 'c':
             // Month, numeric (0...12)
-            pos = int_to_str(this->month(), cursor);
+            pos = int_to_str(month, cursor);
             to = append_with_prefix(cursor, pos - cursor, '0', 1, to);
             break;
         case 'D':
             // Day of the month with English suffix (0th, 1st, ...)
-            pos = int_to_str(this->day(), cursor);
+            if constexpr (only_time) {
+                return false;
+            }
+            pos = int_to_str(day, cursor);
             to = append_with_prefix(cursor, pos - cursor, '0', 1, to);
-            if (this->day() >= 10 && this->day() <= 19) {
+            if (day >= 10 && day <= 19) {
                 to = append_string("th", to);
             } else {
-                switch (this->day() % 10) {
+                switch (day % 10) {
                 case 1:
                     to = append_string("st", to);
                     break;
@@ -3093,39 +3280,42 @@ bool 
DateV2Value<T>::to_format_string_conservative(const char* format, size_t le
             break;
         case 'e':
             // Day of the month, numeric (0..31)
-            pos = int_to_str(this->day(), cursor);
+            pos = int_to_str(day, cursor);
             to = append_with_prefix(cursor, pos - cursor, '0', 1, to);
             break;
         case 'f':
             // Microseconds (000000..999999)
-            pos = int_to_str(this->microsecond(), cursor);
+            pos = int_to_str(ms, cursor);
             to = append_with_prefix(cursor, pos - cursor, '0', 6, to);
             break;
         case 'j':
             // Day of year (001..366)
-            pos = int_to_str(daynr() - doris::calc_daynr(this->year(), 1, 1) + 
1, cursor);
+            if constexpr (only_time) {
+                return false;
+            }
+            pos = int_to_str(calc_daynr(year, month, day) - calc_daynr(year, 
1, 1) + 1, cursor);
             to = append_with_prefix(cursor, pos - cursor, '0', 3, to);
             break;
         case 'k':
-            // Hour (0..23)
-            pos = int_to_str(this->hour(), cursor);
+            // Hour (0..838)
+            pos = int_to_str(hour, cursor);
             to = append_with_prefix(cursor, pos - cursor, '0', 1, to);
             break;
         case 'l':
             // Hour (1..12)
-            pos = int_to_str((this->hour() % 24 + 11) % 12 + 1, cursor);
+            pos = int_to_str((hour % 24 + 11) % 12 + 1, cursor);
             to = append_with_prefix(cursor, pos - cursor, '0', 1, to);
             break;
         case 'M':
             // Month name (January..December)
-            if (this->month() == 0) {
+            if constexpr (only_time) {
                 return false;
             }
-            to = append_string(s_month_name[this->month()], to);
+            to = append_string(s_month_name[month], to);
             break;
         case 'p':
             // AM or PM
-            if ((this->hour() % 24) >= 12) {
+            if ((hour % 24) >= 12) {
                 to = append_string("PM", to);
             } else {
                 to = append_string("AM", to);
@@ -3133,17 +3323,17 @@ bool 
DateV2Value<T>::to_format_string_conservative(const char* format, size_t le
             break;
         case 'r': {
             // Time, 12-hour (hh:mm:ss followed by AM or PM)
-            *to++ = (char)('0' + (((this->hour() + 11) % 12 + 1) / 10));
-            *to++ = (char)('0' + (((this->hour() + 11) % 12 + 1) % 10));
+            *to++ = (char)('0' + (((hour + 11) % 12 + 1) / 10));
+            *to++ = (char)('0' + (((hour + 11) % 12 + 1) % 10));
             *to++ = ':';
             // Minute
-            *to++ = (char)('0' + (this->minute() / 10));
-            *to++ = (char)('0' + (this->minute() % 10));
+            *to++ = (char)('0' + (minute / 10));
+            *to++ = (char)('0' + (minute % 10));
             *to++ = ':';
             /* Second */
-            *to++ = (char)('0' + (this->second() / 10));
-            *to++ = (char)('0' + (this->second() % 10));
-            if ((this->hour() % 24) >= 12) {
+            *to++ = (char)('0' + (second / 10));
+            *to++ = (char)('0' + (second % 10));
+            if ((hour % 24) >= 12) {
                 to = append_string(" PM", to);
             } else {
                 to = append_string(" AM", to);
@@ -3151,66 +3341,89 @@ bool 
DateV2Value<T>::to_format_string_conservative(const char* format, size_t le
             break;
         }
         case 'T': {
-            // Time, 24-hour (hh:mm:ss)
-            *to++ = (char)('0' + ((this->hour() % 24) / 10));
-            *to++ = (char)('0' + ((this->hour() % 24) % 10));
+            // Time, 24-hour (hh:mm:ss or hhh:mm:ss for TIME type)
+            if (hour < 100) {
+                *to++ = (char)('0' + (hour / 10));
+                *to++ = (char)('0' + (hour % 10));
+            } else {
+                pos = int_to_str(hour, cursor);
+                to = append_with_prefix(cursor, static_cast<int>(pos - 
cursor), '0', 2, to);
+            }
             *to++ = ':';
             // Minute
-            *to++ = (char)('0' + (this->minute() / 10));
-            *to++ = (char)('0' + (this->minute() % 10));
+            *to++ = (char)('0' + (minute / 10));
+            *to++ = (char)('0' + (minute % 10));
             *to++ = ':';
             /* Second */
-            *to++ = (char)('0' + (this->second() / 10));
-            *to++ = (char)('0' + (this->second() % 10));
+            *to++ = (char)('0' + (second / 10));
+            *to++ = (char)('0' + (second % 10));
             break;
         }
         case 'u':
             // Week (00..53), where Monday is the first day of the week;
             // WEEK() mode 1
-            to = write_two_digits_to_string(week(mysql_week_mode(1)), to);
+            if constexpr (only_time) {
+                return false;
+            }
+            to = write_two_digits_to_string(week(year, month, day, 
mysql_week_mode(1)), to);
             cursor += 2;
             pos = cursor;
             break;
         case 'U':
             // Week (00..53), where Sunday is the first day of the week;
             // WEEK() mode 0
-            to = write_two_digits_to_string(week(mysql_week_mode(0)), to);
+            if constexpr (only_time) {
+                return false;
+            }
+            to = write_two_digits_to_string(week(year, month, day, 
mysql_week_mode(0)), to);
             cursor += 2;
             pos = cursor;
             break;
         case 'v':
             // Week (01..53), where Monday is the first day of the week;
             // WEEK() mode 3; used with %x
-            to = write_two_digits_to_string(week(mysql_week_mode(3)), to);
+            if constexpr (only_time) {
+                return false;
+            }
+            to = write_two_digits_to_string(week(year, month, day, 
mysql_week_mode(3)), to);
             cursor += 2;
             pos = cursor;
             break;
         case 'V':
             // Week (01..53), where Sunday is the first day of the week;
             // WEEK() mode 2; used with %X
-            to = write_two_digits_to_string(week(mysql_week_mode(2)), to);
+            if constexpr (only_time) {
+                return false;
+            }
+            to = write_two_digits_to_string(week(year, month, day, 
mysql_week_mode(2)), to);
             cursor += 2;
             pos = cursor;
             break;
         case 'w':
             // Day of the week (0=Sunday..6=Saturday)
-            if (this->month() == 0 && this->year() == 0) {
+            if constexpr (only_time) {
                 return false;
             }
-            pos = int_to_str(doris::calc_weekday(daynr(), true), cursor);
+            pos = int_to_str(calc_weekday(calc_daynr(year, month, day), true), 
cursor);
             to = append_with_prefix(cursor, pos - cursor, '0', 1, to);
             break;
         case 'W':
             // Weekday name (Sunday..Saturday)
-            to = append_string(s_day_name[weekday()], to);
+            if constexpr (only_time) {
+                return false;
+            }
+            to = append_string(s_day_name[calc_weekday(calc_daynr(year, month, 
day), false)], to);
             break;
         case 'x': {
             // Year for the week, where Monday is the first day of the week,
             // numeric, four digits; used with %v
-            uint16_t year = 0;
-            calc_week(this->daynr(), this->year(), this->month(), this->day(), 
mysql_week_mode(3),
-                      &year, true);
-            to = write_four_digits_to_string(year, to);
+            if constexpr (only_time) {
+                return false;
+            }
+            uint16_t year_to_write = 0;
+            calc_week(calc_daynr(year, month, day), year, month, day, 
mysql_week_mode(3),
+                      &year_to_write, true);
+            to = write_four_digits_to_string(year_to_write, to);
             cursor += 4;
             pos = cursor;
             break;
@@ -3218,10 +3431,13 @@ bool 
DateV2Value<T>::to_format_string_conservative(const char* format, size_t le
         case 'X': {
             // Year for the week where Sunday is the first day of the week,
             // numeric, four digits; used with %V
-            uint16_t year = 0;
-            calc_week(this->daynr(), this->year(), this->month(), this->day(), 
mysql_week_mode(2),
-                      &year);
-            to = write_four_digits_to_string(year, to);
+            if constexpr (only_time) {
+                return false;
+            }
+            uint16_t year_to_write = 0;
+            calc_week(calc_daynr(year, month, day), year, month, day, 
mysql_week_mode(2),
+                      &year_to_write);
+            to = write_four_digits_to_string(year_to_write, to);
             cursor += 4;
             pos = cursor;
             break;
@@ -3236,174 +3452,9 @@ bool 
DateV2Value<T>::to_format_string_conservative(const char* format, size_t le
     return true;
 }
 
-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;
+uint8_t DatetimeValueUtil::week(int16_t year, int8_t month, int8_t day, 
uint8_t mode) {
+    uint16_t year_to_write = 0;
+    return calc_week(calc_daynr(year, month, day), year, month, day, mode, 
&year_to_write);
 }
 
 template <typename T>
@@ -3668,5 +3719,13 @@ template bool 
DateV2Value<DateTimeV2ValueType>::datetime_trunc<TimeUnit::MONTH>(
 template bool 
DateV2Value<DateTimeV2ValueType>::datetime_trunc<TimeUnit::YEAR>();
 template bool 
DateV2Value<DateTimeV2ValueType>::datetime_trunc<TimeUnit::QUARTER>();
 template bool 
DateV2Value<DateTimeV2ValueType>::datetime_trunc<TimeUnit::WEEK>();
+
+template bool DatetimeValueUtil::to_format_string_without_check<false>(const 
char*, size_t, char*,
+                                                                       size_t, 
int16_t, int8_t,
+                                                                       int8_t, 
int, int, int, int);
+
+template bool DatetimeValueUtil::to_format_string_without_check<true>(const 
char*, size_t, char*,
+                                                                      size_t, 
int16_t, int8_t,
+                                                                      int8_t, 
int, int, int, int);
 #include "common/compile_check_avoid_end.h"
 } // namespace doris
diff --git a/be/src/vec/runtime/vdatetime_value.h 
b/be/src/vec/runtime/vdatetime_value.h
index ffb5da58408..b8fe4067fd3 100644
--- a/be/src/vec/runtime/vdatetime_value.h
+++ b/be/src/vec/runtime/vdatetime_value.h
@@ -817,6 +817,8 @@ inline const VecDateTimeValue 
VecDateTimeValue::DEFAULT_VALUE(false, TYPE_DATETI
 
 template <typename T>
 class DateV2Value {
+    friend class DatetimeValueUtil;
+
 public:
     static constexpr bool is_datetime = std::is_same_v<T, DateTimeV2ValueType>;
     using underlying_value = std::conditional_t<is_datetime, uint64_t, 
uint32_t>;
@@ -1751,6 +1753,25 @@ inline uint32_t calc_daynr(uint16_t year, uint8_t month, 
uint8_t day) {
     return delsum + y / 4 - y / 100 + y / 400;
 }
 
+class DatetimeValueUtil {
+public:
+    template <bool only_time>
+    static bool to_format_string_without_check(const char* format, size_t len, 
char* to,
+                                               size_t max_valid_length, 
int16_t year, int8_t month,
+                                               int8_t day, int hour, int 
minute, int second,
+                                               int ms);
+
+private:
+    static uint8_t week(int16_t year, int8_t month, int8_t day, uint8_t mode);
+
+    static uint8_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 = false) {
+        return DateV2Value<DateTimeV2ValueType>::calc_week(day_nr, year, 
month, day, mode, to_year,
+                                                           disable_lut);
+    }
+};
+
 template <typename T>
 struct DateTraits {};
 
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/catalog/BuiltinScalarFunctions.java 
b/fe/fe-core/src/main/java/org/apache/doris/catalog/BuiltinScalarFunctions.java
index f06ef3e7752..48bb1375e3c 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/catalog/BuiltinScalarFunctions.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/catalog/BuiltinScalarFunctions.java
@@ -485,6 +485,7 @@ import 
org.apache.doris.nereids.trees.expressions.functions.scalar.Tan;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.Tanh;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.Time;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.TimeDiff;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.TimeFormat;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.TimeToSec;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.Timestamp;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.ToBase64;
@@ -1038,6 +1039,7 @@ public class BuiltinScalarFunctions implements 
FunctionHelper {
             scalar(Tanh.class, "tanh"),
             scalar(Time.class, "time"),
             scalar(TimeDiff.class, "timediff"),
+            scalar(TimeFormat.class, "time_format"),
             scalar(TimeToSec.class, "time_to_sec"),
             scalar(Timestamp.class, "timestamp"),
             scalar(ToBase64.class, "to_base64"),
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeExtractAndTransform.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeExtractAndTransform.java
index ea6551687ba..2c005583c3c 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeExtractAndTransform.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeExtractAndTransform.java
@@ -44,6 +44,7 @@ import org.apache.doris.nereids.types.DateV2Type;
 import org.apache.doris.nereids.types.DecimalV3Type;
 import org.apache.doris.nereids.types.StringType;
 import org.apache.doris.nereids.types.TimeV2Type;
+import org.apache.doris.nereids.util.DateTimeFormatterUtils;
 import org.apache.doris.nereids.util.DateUtils;
 import org.apache.doris.qe.ConnectContext;
 
@@ -276,31 +277,37 @@ public class DateTimeExtractAndTransform {
      * datetime arithmetic function date-format
      */
     @ExecFunction(name = "date_format")
-    public static Expression dateFormat(DateV2Literal date, StringLikeLiteral 
format) {
+    public static Expression dateFormat(DateTimeV2Literal date, 
StringLikeLiteral format) {
         if (StringUtils.trim(format.getValue()).length() > 128) {
             throw new AnalysisException("The length of format string in 
date_format() function should not be greater"
                     + " than 128.");
         }
-        DateTimeV2Literal datetime = new DateTimeV2Literal(date.getYear(), 
date.getMonth(), date.getDay(), 0, 0, 0, 0);
         format = (StringLikeLiteral) 
SupportJavaDateFormatter.translateJavaFormatter(format);
-        return new 
VarcharLiteral(DateUtils.dateTimeFormatterChecklength(format.getValue(), 
datetime).format(
-                java.time.LocalDate.of(((int) date.getYear()), ((int) 
date.getMonth()), ((int) date.getDay()))));
+        return new 
VarcharLiteral(DateTimeFormatterUtils.toFormatStringConservative(date, format, 
false));
     }
 
     /**
-     * datetime arithmetic function date-format
+     * time_format constant folding for time literal.
      */
-    @ExecFunction(name = "date_format")
-    public static Expression dateFormat(DateTimeV2Literal date, 
StringLikeLiteral format) {
+    @ExecFunction(name = "time_format")
+    public static Expression timeFormat(TimeV2Literal time, StringLikeLiteral 
format) {
         if (StringUtils.trim(format.getValue()).length() > 128) {
-            throw new AnalysisException("The length of format string in 
date_format() function should not be greater"
+            throw new AnalysisException("The length of format string in 
time_format() function should not be greater"
                     + " than 128.");
         }
-        format = (StringLikeLiteral) 
SupportJavaDateFormatter.translateJavaFormatter(format);
-        return new 
VarcharLiteral(DateUtils.dateTimeFormatterChecklength(format.getValue(), 
date).format(
-                java.time.LocalDateTime.of(((int) date.getYear()), ((int) 
date.getMonth()), ((int) date.getDay()),
-                        ((int) date.getHour()), ((int) date.getMinute()), 
((int) date.getSecond()),
-                        ((int) date.getMicroSecond() * 1000))));
+        return new 
VarcharLiteral(DateTimeFormatterUtils.toFormatStringConservative(time, format));
+    }
+
+    /**
+     * time_format constant folding for datetimev2 literal.
+     */
+    @ExecFunction(name = "time_format")
+    public static Expression timeFormat(DateTimeV2Literal dateTime, 
StringLikeLiteral format) {
+        if (StringUtils.trim(format.getValue()).length() > 128) {
+            throw new AnalysisException("The length of format string in 
time_format() function should not be greater"
+                    + " than 128.");
+        }
+        return new 
VarcharLiteral(DateTimeFormatterUtils.toFormatStringConservative(dateTime, 
format, true));
     }
 
     /**
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/DateFormat.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/DateFormat.java
index 3da486abbed..6c26a94f635 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/DateFormat.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/DateFormat.java
@@ -28,7 +28,6 @@ import 
org.apache.doris.nereids.trees.expressions.literal.StringLikeLiteral;
 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.VarcharType;
 import org.apache.doris.nereids.util.DateUtils;
 
@@ -45,8 +44,7 @@ public class DateFormat extends ScalarFunction
 
     public static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
             
FunctionSignature.ret(VarcharType.SYSTEM_DEFAULT).args(DateTimeV2Type.WILDCARD,
-                    VarcharType.SYSTEM_DEFAULT),
-            
FunctionSignature.ret(VarcharType.SYSTEM_DEFAULT).args(DateV2Type.INSTANCE, 
VarcharType.SYSTEM_DEFAULT));
+                    VarcharType.SYSTEM_DEFAULT));
 
     /**
      * constructor with 2 arguments.
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/DateFormat.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/TimeFormat.java
similarity index 73%
copy from 
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/DateFormat.java
copy to 
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/TimeFormat.java
index 3da486abbed..6c96683e29d 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/DateFormat.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/TimeFormat.java
@@ -19,16 +19,15 @@ package 
org.apache.doris.nereids.trees.expressions.functions.scalar;
 
 import org.apache.doris.catalog.FunctionSignature;
 import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.expressions.functions.AlwaysNullable;
 import 
org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature;
 import org.apache.doris.nereids.trees.expressions.functions.Monotonic;
-import 
org.apache.doris.nereids.trees.expressions.functions.PropagateNullLiteral;
-import org.apache.doris.nereids.trees.expressions.functions.PropagateNullable;
 import org.apache.doris.nereids.trees.expressions.literal.Literal;
 import org.apache.doris.nereids.trees.expressions.literal.StringLikeLiteral;
 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.TimeV2Type;
 import org.apache.doris.nereids.types.VarcharType;
 import org.apache.doris.nereids.util.DateUtils;
 
@@ -38,25 +37,27 @@ import com.google.common.collect.ImmutableList;
 import java.util.List;
 
 /**
- * ScalarFunction 'date_format'. This class is generated by GenerateFunction.
+ * ScalarFunction 'time_format'.
  */
-public class DateFormat extends ScalarFunction
-        implements BinaryExpression, ExplicitlyCastableSignature, 
PropagateNullable, PropagateNullLiteral, Monotonic {
+public class TimeFormat extends ScalarFunction
+        implements BinaryExpression, ExplicitlyCastableSignature, 
AlwaysNullable, Monotonic {
 
     public static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
-            
FunctionSignature.ret(VarcharType.SYSTEM_DEFAULT).args(DateTimeV2Type.WILDCARD,
-                    VarcharType.SYSTEM_DEFAULT),
-            
FunctionSignature.ret(VarcharType.SYSTEM_DEFAULT).args(DateV2Type.INSTANCE, 
VarcharType.SYSTEM_DEFAULT));
+            FunctionSignature.ret(VarcharType.SYSTEM_DEFAULT)
+                .args(TimeV2Type.WILDCARD, VarcharType.SYSTEM_DEFAULT),
+            FunctionSignature.ret(VarcharType.SYSTEM_DEFAULT)
+                .args(DateTimeV2Type.WILDCARD, VarcharType.SYSTEM_DEFAULT)
+    );
 
     /**
      * constructor with 2 arguments.
      */
-    public DateFormat(Expression arg0, Expression arg1) {
-        super("date_format", arg0, arg1);
+    public TimeFormat(Expression arg0, Expression arg1) {
+        super("time_format", arg0, arg1);
     }
 
     /** constructor for withChildren and reuse signature */
-    private DateFormat(ScalarFunctionParams functionParams) {
+    private TimeFormat(ScalarFunctionParams functionParams) {
         super(functionParams);
     }
 
@@ -64,9 +65,9 @@ public class DateFormat extends ScalarFunction
      * withChildren.
      */
     @Override
-    public DateFormat withChildren(List<Expression> children) {
+    public TimeFormat withChildren(List<Expression> children) {
         Preconditions.checkArgument(children.size() == 2);
-        return new DateFormat(getFunctionParams(children));
+        return new TimeFormat(getFunctionParams(children));
     }
 
     @Override
@@ -76,7 +77,7 @@ public class DateFormat extends ScalarFunction
 
     @Override
     public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
-        return visitor.visitDateFormat(this, context);
+        return visitor.visitTimeFormat(this, context);
     }
 
     @Override
@@ -101,6 +102,6 @@ public class DateFormat extends ScalarFunction
 
     @Override
     public Expression withConstantArgs(Expression literal) {
-        return new DateFormat(literal, child(1));
+        return new TimeFormat(literal, child(1));
     }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/TimeV2Literal.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/TimeV2Literal.java
index 0d34d75344e..7a1201ccf5b 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/TimeV2Literal.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/TimeV2Literal.java
@@ -391,4 +391,8 @@ public class TimeV2Literal extends Literal {
     public String computeToSql() {
         return "'" + getStringValue() + "'";
     }
+
+    public boolean isNegative() {
+        return negative;
+    }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ScalarFunctionVisitor.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ScalarFunctionVisitor.java
index 7f70a6bf586..122450fe1b8 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ScalarFunctionVisitor.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ScalarFunctionVisitor.java
@@ -488,6 +488,7 @@ import 
org.apache.doris.nereids.trees.expressions.functions.scalar.Tan;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.Tanh;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.Time;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.TimeDiff;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.TimeFormat;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.Timestamp;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.ToBase64;
 import 
org.apache.doris.nereids.trees.expressions.functions.scalar.ToBase64Binary;
@@ -2315,6 +2316,10 @@ public interface ScalarFunctionVisitor<R, C> {
         return visitScalarFunction(timeDiff, context);
     }
 
+    default R visitTimeFormat(TimeFormat timeFormat, C context) {
+        return visitScalarFunction(timeFormat, context);
+    }
+
     default R visitTimestamp(Timestamp timestamp, C context) {
         return visitScalarFunction(timestamp, context);
     }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/DateTimeFormatterUtils.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/DateTimeFormatterUtils.java
index dd342820343..0e47a8f2915 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/DateTimeFormatterUtils.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/DateTimeFormatterUtils.java
@@ -17,6 +17,11 @@
 
 package org.apache.doris.nereids.util;
 
+import org.apache.doris.nereids.exceptions.AnalysisException;
+import org.apache.doris.nereids.trees.expressions.literal.DateTimeV2Literal;
+import org.apache.doris.nereids.trees.expressions.literal.StringLikeLiteral;
+import org.apache.doris.nereids.trees.expressions.literal.TimeV2Literal;
+
 import java.time.format.DateTimeFormatter;
 import java.time.format.DateTimeFormatterBuilder;
 import java.time.format.ResolverStyle;
@@ -106,4 +111,424 @@ public class DateTimeFormatterUtils {
             .append(TIME_FORMATTER)
             .append(ZONE_FORMATTER)
             .toFormatter().withResolverStyle(ResolverStyle.STRICT);
+
+    private static final int WEEK_MONDAY_FIRST = 1;
+    private static final int WEEK_YEAR = 2;
+    private static final int WEEK_FIRST_WEEKDAY = 4;
+
+    private static final int MAX_FORMAT_RESULT_LENGTH = 100;
+    private static final int SAFE_FORMAT_STRING_MARGIN = 12;
+    private static final int MAX_FORMAT_STRING_LENGTH = 128;
+
+    private static final String[] ABBR_MONTH_NAMES = {
+            "", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", 
"Oct", "Nov", "Dec"
+    };
+
+    private static final String[] MONTH_NAMES = {
+            "", "January", "February", "March", "April", "May", "June", 
"July", "August", "September",
+            "October", "November", "December"
+    };
+
+    private static final String[] ABBR_DAY_NAMES = {
+            "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"
+    };
+
+    private static final String[] DAY_NAMES = {
+            "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", 
"Saturday", "Sunday"
+    };
+
+    private static void appendTwoDigits(StringBuilder builder, int value) {
+        builder.append((char) ('0' + (value / 10) % 10));
+        builder.append((char) ('0' + (value % 10)));
+    }
+
+    /**
+     * Conservative implementation of DATE_FORMAT/TIME_FORMAT for datetime 
literals
+     * used in constant folding.
+     *
+     * @param datetime     datetime literal to format
+     * @param format       format pattern
+     * @param isTimeFormat true when invoked via time_format, false for 
date_format
+     * @return formatted string or null when pattern requires missing date 
fields
+     */
+    public static String toFormatStringConservative(DateTimeV2Literal 
datetime, StringLikeLiteral format,
+            boolean isTimeFormat) {
+        int year = isTimeFormat ? 0 : (int) datetime.getYear();
+        int month = isTimeFormat ? 0 : (int) datetime.getMonth();
+        int day = isTimeFormat ? 0 : (int) datetime.getDay();
+        int hour = (int) datetime.getHour();
+        int minute = (int) datetime.getMinute();
+        int second = (int) datetime.getSecond();
+        int microsecond = (int) datetime.getMicroSecond();
+
+        String pattern = trimFormat(format.getValue());
+        return formatTemporalLiteral(year, month, day, hour, minute, second, 
microsecond, pattern);
+    }
+
+    /**
+     * Conservative implementation of TIME_FORMAT for time literals used in 
constant
+     * folding.
+     *
+     * @param time   time literal to format
+     * @param format format pattern
+     * @return formatted string with sign preserved; null when pattern 
requires date
+     *         fields
+     */
+    public static String toFormatStringConservative(TimeV2Literal time, 
StringLikeLiteral format) {
+        String pattern = trimFormat(format.getValue());
+        String res = formatTemporalLiteral(0, 0, 0, time.getHour(), 
time.getMinute(),
+                time.getSecond(), time.getMicroSecond(), pattern);
+        if (time.isNegative()) {
+            res = "-" + res;
+        }
+        return res;
+    }
+
+    private static int calcWeekNumber(int year, int month, int day, int mode) {
+        int[] weekYear = new int[1];
+        return calcWeekNumberAndYear(year, month, day, mode, weekYear);
+    }
+
+    private static int calcWeekNumberAndYear(int year, int month, int day, int 
mode, int[] toYear) {
+        return calcWeekInternal(calcDayNr(year, month, day), year, month, day, 
mode, toYear);
+    }
+
+    private static int calcWeekInternal(long dayNr, int year, int month, int 
day, int mode, int[] toYear) {
+        if (year == 0) {
+            toYear[0] = 0;
+            return 0;
+        }
+        boolean mondayFirst = (mode & WEEK_MONDAY_FIRST) != 0;
+        boolean weekYear = (mode & WEEK_YEAR) != 0;
+        boolean firstWeekday = (mode & WEEK_FIRST_WEEKDAY) != 0;
+
+        long daynrFirstDay = calcDayNr(year, 1, 1);
+        int weekdayFirstDay = calcWeekday(daynrFirstDay, !mondayFirst);
+
+        toYear[0] = year;
+
+        if (month == 1 && day <= (7 - weekdayFirstDay)) {
+            if (!weekYear && ((firstWeekday && weekdayFirstDay != 0) || 
(!firstWeekday && weekdayFirstDay > 3))) {
+                return 0;
+            }
+            toYear[0]--;
+            weekYear = true;
+            int days = calcDaysInYear(toYear[0]);
+            daynrFirstDay -= days;
+            weekdayFirstDay = (weekdayFirstDay + 53 * 7 - days) % 7;
+        }
+
+        int days;
+        if ((firstWeekday && weekdayFirstDay != 0) || (!firstWeekday && 
weekdayFirstDay > 3)) {
+            days = (int) (dayNr - (daynrFirstDay + (7 - weekdayFirstDay)));
+        } else {
+            days = (int) (dayNr - (daynrFirstDay - weekdayFirstDay));
+        }
+
+        if (weekYear && days >= 52 * 7) {
+            weekdayFirstDay = (weekdayFirstDay + calcDaysInYear(toYear[0])) % 
7;
+            if ((firstWeekday && weekdayFirstDay == 0) || (!firstWeekday && 
weekdayFirstDay <= 3)) {
+                toYear[0]++;
+                return 1;
+            }
+        }
+
+        return days / 7 + 1;
+    }
+
+    private static int mysqlWeekMode(int mode) {
+        mode &= 7;
+        if ((mode & WEEK_MONDAY_FIRST) == 0) {
+            mode ^= WEEK_FIRST_WEEKDAY;
+        }
+        return mode;
+    }
+
+    private static int calcWeekday(long dayNr, boolean sundayFirst) {
+        return (int) ((dayNr + 5 + (sundayFirst ? 1 : 0)) % 7);
+    }
+
+    private static long calcDayNr(int year, int month, int day) {
+        // Align with BE/MySQL: Monday = 0 when sundayFirst=false in 
calcWeekday.
+        if (year == 0 && month == 0) {
+            return 0;
+        }
+        if (year == 0 && month == 1 && day == 1) {
+            return 1;
+        }
+
+        long y = year;
+        long delsum = 365 * y + 31L * (month - 1) + day;
+        if (month <= 2) {
+            y--;
+        } else {
+            delsum -= (month * 4 + 23) / 10;
+        }
+        return delsum + y / 4 - y / 100 + y / 400;
+    }
+
+    private static int calcDaysInYear(int year) {
+        return isLeap(year) ? 366 : 365;
+    }
+
+    private static boolean isLeap(int year) {
+        return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
+    }
+
+    private static void appendFourDigits(StringBuilder builder, int value) {
+        if (value >= 1000 && value <= 9999) {
+            builder.append(value);
+            return;
+        }
+        appendWithPad(builder, value, 4, '0');
+    }
+
+    private static void appendWithPad(StringBuilder builder, int value, int 
targetLength, char padChar) {
+        String str = Integer.toString(Math.abs(value));
+        for (int i = str.length(); i < targetLength; i++) {
+            builder.append(padChar);
+        }
+        builder.append(str);
+    }
+
+    // MySQL-compatible time_format for TIME/DATE/DATETIME literals.
+    private static String formatTemporalLiteral(int year, int month, int day, 
int hour, int minute,
+            int second, int microsecond, String pattern) {
+        StringBuilder builder = new StringBuilder(pattern.length() + 16);
+
+        for (int i = 0; i < pattern.length(); i++) {
+            char c = pattern.charAt(i);
+            if (c != '%' || i == pattern.length() - 1) {
+                builder.append(c);
+                continue;
+            }
+
+            char spec = pattern.charAt(++i);
+            switch (spec) {
+                case 'y':
+                    appendTwoDigits(builder, year % 100);
+                    break;
+                case 'Y':
+                    appendFourDigits(builder, year);
+                    break;
+                case 'd':
+                    appendTwoDigits(builder, day);
+                    break;
+                case 'H':
+                    if (hour < 100) {
+                        appendTwoDigits(builder, hour);
+                    } else {
+                        appendWithPad(builder, hour, 2, '0');
+                    }
+                    break;
+                case 'i':
+                    appendTwoDigits(builder, minute);
+                    break;
+                case 'm':
+                    appendTwoDigits(builder, month);
+                    break;
+                case 'h':
+                case 'I': {
+                    int hour12 = (hour % 24 + 11) % 12 + 1;
+                    appendTwoDigits(builder, hour12);
+                    break;
+                }
+                case 's':
+                case 'S':
+                    appendTwoDigits(builder, second);
+                    break;
+                case 'a':
+                    if (month == 0 || day == 0 || year == 0) {
+                        return null;
+                    }
+                    builder.append(ABBR_DAY_NAMES[calcWeekday(calcDayNr(year, 
month, day), false)]);
+                    break;
+                case 'b':
+                    if (month == 0) {
+                        return null;
+                    }
+                    builder.append(ABBR_MONTH_NAMES[month]);
+                    break;
+                case 'c': {
+                    String str = Integer.toString(month);
+                    if (str.length() < 1) {
+                        builder.append('0');
+                    }
+                    builder.append(str);
+                    break;
+                }
+                case 'D':
+                    if (month == 0) {
+                        return null;
+                    }
+                    builder.append(day);
+                    if (day >= 10 && day <= 19) {
+                        builder.append("th");
+                    } else {
+                        switch (day % 10) {
+                            case 1:
+                                builder.append("st");
+                                break;
+                            case 2:
+                                builder.append("nd");
+                                break;
+                            case 3:
+                                builder.append("rd");
+                                break;
+                            default:
+                                builder.append("th");
+                                break;
+                        }
+                    }
+                    break;
+                case 'e': {
+                    String str = Integer.toString(day);
+                    if (str.length() < 1) {
+                        builder.append('0');
+                    }
+                    builder.append(str);
+                    break;
+                }
+                case 'f':
+                    appendWithPad(builder, microsecond, 6, '0');
+                    break;
+                case 'j':
+                    if (month == 0 || day == 0) {
+                        return null;
+                    }
+                    int dayOfYear = (int) (calcDayNr(year, month, day) - 
calcDayNr(year, 1, 1) + 1);
+                    appendWithPad(builder, dayOfYear, 3, '0');
+                    break;
+                case 'k': {
+                    String str = Integer.toString(hour);
+                    if (str.length() < 1) {
+                        builder.append('0');
+                    }
+                    builder.append(str);
+                    break;
+                }
+                case 'l': {
+                    int hour12 = (hour % 24 + 11) % 12 + 1;
+                    String str = Integer.toString(hour12);
+                    if (str.length() < 1) {
+                        builder.append('0');
+                    }
+                    builder.append(str);
+                    break;
+                }
+                case 'M':
+                    if (month == 0) {
+                        return null;
+                    }
+                    builder.append(MONTH_NAMES[month]);
+                    break;
+                case 'p':
+                    builder.append((hour % 24) >= 12 ? "PM" : "AM");
+                    break;
+                case 'r': {
+                    int hour12 = (hour % 24 + 11) % 12 + 1;
+                    appendTwoDigits(builder, hour12);
+                    builder.append(':');
+                    appendTwoDigits(builder, minute);
+                    builder.append(':');
+                    appendTwoDigits(builder, second);
+                    builder.append(' ');
+                    builder.append((hour % 24) >= 12 ? "PM" : "AM");
+                    break;
+                }
+                case 'T':
+                    if (hour < 100) {
+                        appendTwoDigits(builder, hour);
+                    } else {
+                        appendWithPad(builder, hour, 2, '0');
+                    }
+                    builder.append(':');
+                    appendTwoDigits(builder, minute);
+                    builder.append(':');
+                    appendTwoDigits(builder, second);
+                    break;
+                case 'u':
+                    if (month == 0) {
+                        return null;
+                    }
+                    appendTwoDigits(builder, calcWeekNumber(year, month, day, 
mysqlWeekMode(1)));
+                    break;
+                case 'U':
+                    if (month == 0) {
+                        return null;
+                    }
+                    appendTwoDigits(builder, calcWeekNumber(year, month, day, 
mysqlWeekMode(0)));
+                    break;
+                case 'v':
+                    if (month == 0) {
+                        return null;
+                    }
+                    appendTwoDigits(builder, calcWeekNumber(year, month, day, 
mysqlWeekMode(3)));
+                    break;
+                case 'V':
+                    if (month == 0) {
+                        return null;
+                    }
+                    appendTwoDigits(builder, calcWeekNumber(year, month, day, 
mysqlWeekMode(2)));
+                    break;
+                case 'w':
+                    if (month == 0 && year == 0) {
+                        return null;
+                    }
+                    builder.append(calcWeekday(calcDayNr(year, month, day), 
true));
+                    break;
+                case 'W':
+                    if (year == 0 && month == 0) {
+                        return null;
+                    }
+                    builder.append(DAY_NAMES[calcWeekday(calcDayNr(year, 
month, day), false)]);
+                    break;
+                case 'x': {
+                    if (month == 0 || day == 0) {
+                        return null;
+                    }
+                    int[] weekYear = new int[1];
+                    calcWeekNumberAndYear(year, month, day, mysqlWeekMode(3), 
weekYear);
+                    appendFourDigits(builder, weekYear[0]);
+                    break;
+                }
+                case 'X': {
+                    if (month == 0 || day == 0) {
+                        return null;
+                    }
+                    int[] weekYear = new int[1];
+                    calcWeekNumberAndYear(year, month, day, mysqlWeekMode(2), 
weekYear);
+                    appendFourDigits(builder, weekYear[0]);
+                    break;
+                }
+                default:
+                    builder.append(spec);
+                    break;
+            }
+        }
+
+        if (builder.length() > MAX_FORMAT_RESULT_LENGTH) {
+            throw new AnalysisException("Formatted string length exceeds the 
maximum allowed length");
+        }
+        return builder.toString();
+    }
+
+    private static String trimFormat(String pattern) {
+        if (pattern == null) {
+            throw new AnalysisException("Format string is null");
+        }
+        int start = 0;
+        int end = pattern.length();
+        while (start < end && Character.isWhitespace(pattern.charAt(start))) {
+            start++;
+        }
+        while (end > start && Character.isWhitespace(pattern.charAt(end - 1))) 
{
+            end--;
+        }
+        String trimmed = pattern.substring(start, end);
+        if (trimmed.length() > MAX_FORMAT_STRING_LENGTH) {
+            throw new AnalysisException("Format string length exceeds the 
maximum allowed length");
+        }
+        return trimmed;
+    }
 }
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/FoldConstantTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/FoldConstantTest.java
index 50468baf16f..b0bc15aaa92 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/FoldConstantTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/FoldConstantTest.java
@@ -448,15 +448,16 @@ class FoldConstantTest extends 
ExpressionRewriteTestHelper {
                         StringLiteral.of("%y %m %d"));
         rewritten = executor.rewrite(d, context);
         Assertions.assertEquals(new VarcharLiteral("01 01 01"), rewritten);
-        d = new DateFormat(DateV2Literal.fromJavaDateType(LocalDateTime.of(1, 
1, 1, 1, 1, 1)),
+        d = new 
DateFormat(DateTimeV2Literal.fromJavaDateType(LocalDateTime.of(1, 1, 1, 1, 1, 
1)),
                         StringLiteral.of("%y %m %d"));
         rewritten = executor.rewrite(d, context);
         Assertions.assertEquals(new VarcharLiteral("01 01 01"), rewritten);
 
-        d = new DateFormat(DateV2Literal.fromJavaDateType(LocalDateTime.of(1, 
1, 1, 1, 1, 1)),
+        d = new 
DateFormat(DateTimeV2Literal.fromJavaDateType(LocalDateTime.of(1, 1, 1, 1, 1, 
1)),
                         StringLiteral.of(StringUtils.repeat("s", 128) + " "));
         rewritten = executor.rewrite(d, context);
-        Assertions.assertEquals(new VarcharLiteral(StringUtils.repeat("s", 
128) + " "), rewritten);
+        // Overlength output (>100 chars) is not folded
+        Assertions.assertEquals(d, rewritten);
 
         DateTrunc t = new 
DateTrunc(DateTimeV2Literal.fromJavaDateType(LocalDateTime.of(1, 1, 1, 1, 1, 
1)),
                 StringLiteral.of("week"));
@@ -1189,13 +1190,12 @@ class FoldConstantTest extends 
ExpressionRewriteTestHelper {
     void testDateV2TypeDateTimeArithmeticFunctions() {
         DateV2Literal dateLiteral = new DateV2Literal("1999-12-31");
         IntegerLiteral integerLiteral = new IntegerLiteral(30);
-        VarcharLiteral format = new VarcharLiteral("%Y-%m-%d");
 
         String[] answer = {
                 "'2000-01-30'", "'1999-12-01'", "'2029-12-31'", "'1969-12-31'",
                 "'2002-06-30'", "'1997-06-30'", "'2000-01-30'", "'1999-12-01'",
                 "1999", "4", "12", "6", "31", "365", "31",
-                "'1999-12-31'", "'1999-12-27'", "'1999-12-31'"
+                "'1999-12-27'", "'1999-12-31'"
         };
         int answerIdx = 0;
 
@@ -1216,8 +1216,6 @@ class FoldConstantTest extends 
ExpressionRewriteTestHelper {
         
Assertions.assertEquals(DateTimeExtractAndTransform.dayOfYear(dateLiteral).toSql(),
 answer[answerIdx++]);
         
Assertions.assertEquals(DateTimeExtractAndTransform.day(dateLiteral).toSql(), 
answer[answerIdx++]);
 
-        
Assertions.assertEquals(DateTimeExtractAndTransform.dateFormat(dateLiteral, 
format).toSql(),
-                answer[answerIdx++]);
         
Assertions.assertEquals(DateTimeExtractAndTransform.toMonday(dateLiteral).toSql(),
 answer[answerIdx++]);
         
Assertions.assertEquals(DateTimeExtractAndTransform.lastDay(dateLiteral).toSql(),
 answer[answerIdx]);
     }
diff --git 
a/regression-test/data/doc/sql-manual/sql-functions/doc_date_functions_test.out 
b/regression-test/data/doc/sql-manual/sql-functions/doc_date_functions_test.out
index 25c5b1672ab..a05c5e1a17b 100644
--- 
a/regression-test/data/doc/sql-manual/sql-functions/doc_date_functions_test.out
+++ 
b/regression-test/data/doc/sql-manual/sql-functions/doc_date_functions_test.out
@@ -128,6 +128,9 @@ Sun Oct 10
 -- !date_format_8 --
 \N
 
+-- !date_format_9 --
+Sunday October    2009
+
 -- !date_1 --
 2003-12-31
 
@@ -2029,6 +2032,110 @@ da fanadur
 \N
 07:23:25
 
+-- !time_format_1 --
+1      00:00:00        00      0       12      12      12      00      00      
00      000000  AM      12:00:00 AM     00:00:00        00:00:00.000000 0 00 12 
12 12   00 000000 00 AM 00:00:00 12:00:00 AM 12:12      12 0 12 00 12 AM        
000000 00 00 00:00:00 12:00:00 AM
+2      00:00:00.123456 00      0       12      12      12      00      00      
00      123456  AM      12:00:00 AM     00:00:00        00:00:00.123456 0 00 12 
12 12   00 123456 00 AM 00:00:00 12:00:00 AM 12:12      12 0 12 00 12 AM        
123456 00 00 00:00:00 12:00:00 AM
+3      12:34:56        12      12      12      12      12      34      56      
56      000000  PM      12:34:56 PM     12:34:56        12:34:56.000000 12 12 
12 12 12  56 000000 34 PM 12:34:56 12:34:56 PM 12:12      12 12 12 12 12 PM     
  000000 56 34 12:34:56 12:34:56 PM
+4      12:34:56.789012 12      12      12      12      12      34      56      
56      789012  PM      12:34:56 PM     12:34:56        12:34:56.789012 12 12 
12 12 12  56 789012 34 PM 12:34:56 12:34:56 PM 12:12      12 12 12 12 12 PM     
  789012 56 34 12:34:56 12:34:56 PM
+5      23:59:59        23      23      11      11      11      59      59      
59      000000  PM      11:59:59 PM     23:59:59        23:59:59.000000 23 23 
11 11 11  59 000000 59 PM 23:59:59 11:59:59 PM 11:11      11 23 11 23 11 PM     
  000000 59 59 23:59:59 11:59:59 PM
+6      23:59:59.999999 23      23      11      11      11      59      59      
59      999999  PM      11:59:59 PM     23:59:59        23:59:59.999999 23 23 
11 11 11  59 999999 59 PM 23:59:59 11:59:59 PM 11:11      11 23 11 23 11 PM     
  999999 59 59 23:59:59 11:59:59 PM
+7      08:00:00        08      8       08      08      8       00      00      
00      000000  AM      08:00:00 AM     08:00:00        08:00:00.000000 8 08 8 
08 08    00 000000 00 AM 08:00:00 08:00:00 AM 08:08      8 8 08 08 08 AM 000000 
00 00 08:00:00 08:00:00 AM
+8      15:00:00        15      15      03      03      3       00      00      
00      000000  PM      03:00:00 PM     15:00:00        15:00:00.000000 15 15 3 
03 03   00 000000 00 PM 15:00:00 03:00:00 PM 03:03      3 15 03 15 03 PM        
000000 00 00 15:00:00 03:00:00 PM
+9      100:00:00       100     100     04      04      4       00      00      
00      000000  AM      04:00:00 AM     100:00:00       100:00:00.000000        
100 100 4 04 04 00 000000 00 AM 100:00:00 04:00:00 AM 04:04     4 100 04 100 04 
AM      000000 00 00 100:00:00 04:00:00 AM
+10     123:45:56       123     123     03      03      3       45      56      
56      000000  AM      03:45:56 AM     123:45:56       123:45:56.000000        
123 123 3 03 03 56 000000 45 AM 123:45:56 03:45:56 AM 03:03     3 123 03 123 03 
AM      000000 56 45 123:45:56 03:45:56 AM
+11     838:59:59.999999        \N      \N      \N      \N      \N      \N      
\N      \N      \N      \N      \N      \N      \N      \N      \N      \N      
\N      \N
+12     -00:00:01       -00     -0      -12     -12     -12     -00     -01     
-01     -000000 -AM     -12:00:01 AM    -00:00:01       -00:00:01.000000        
-0 00 12 12 12  -01 000000 00 AM        -00:00:01 12:00:01 AM 12:12     -12 0 
12 00 12 AM       -000000 01 00 00:00:01 12:00:01 AM
+13     -12:34:56.000001        -12     -12     -12     -12     -12     -34     
-56     -56     -000001 -PM     -12:34:56 PM    -12:34:56       
-12:34:56.000001        -12 12 12 12 12 -56 000001 34 PM        -12:34:56 
12:34:56 PM 12:12     -12 12 12 12 12 PM      -000001 56 34 12:34:56 12:34:56 PM
+14     -838:59:59.999999       \N      \N      \N      \N      \N      \N      
\N      \N      \N      \N      \N      \N      \N      \N      \N      \N      
\N      \N
+15     \N      \N      \N      \N      \N      \N      \N      \N      \N      
\N      \N      \N      \N      \N      \N      \N      \N      \N      \N
+
+-- !time_format_2 --
+00 0 12 12 12 AM
+
+-- !time_format_3 --
+00 123456 00 00:00:00
+
+-- !time_format_4 --
+12:34:56 PM 12:34:56 12:12 12
+
+-- !time_format_5 --
+12 12 12 12 12 PM 56
+
+-- !time_format_6 --
+000000 59 59 PM 11:59:59 PM
+
+-- !time_format_7 --
+23:59:59 11:59:59 PM 23:59:59.999999
+
+-- !time_format_8 --
+8 8 08 08 08 AM 000000
+
+-- !time_format_9 --
+00 00 000000 15:00:00 03:00:00 PM PM
+
+-- !time_format_10 --
+\N
+
+-- !time_format_11 --
+\N
+
+-- !time_format_12 --
+\N
+
+-- !time_format_13 --
+00:00:01 00 12:00:01 AM 01 000000 12:12
+
+-- !time_format_14 --
+PM 12 12 12 12 12:34:56 000001
+
+-- !time_format_15 --
+\N
+
+-- !time_format_16 --
+0000-00-00 12:34:56
+
+-- !time_format_17 --
+00-00-00
+
+-- !time_format_18 --
+0000 00 00
+
+-- !time_format_19 --
+0-0
+
+-- !time_format_20 --
+0000/00/00 15:45:30.123456
+
+-- !time_format_21 --
+\N
+
+-- !time_format_22 --
+\N
+
+-- !time_format_23 --
+\N
+
+-- !time_format_24 --
+\N
+
+-- !time_format_25 --
+\N
+
+-- !time_format_26 --
+\N
+
+-- !time_format_27 --
+\N
+
+-- !time_format_28 --
+\N
+
+-- !time_format_29 --
+\N
+
+-- !time_format_30 --
+\N
+
 -- !to_seconds_1 --
 63358934400
 
diff --git 
a/regression-test/suites/correctness_p0/test_function_signature_all_types.groovy
 
b/regression-test/suites/correctness_p0/test_function_signature_all_types.groovy
index 0e5f49433d7..31ea693bb3c 100644
--- 
a/regression-test/suites/correctness_p0/test_function_signature_all_types.groovy
+++ 
b/regression-test/suites/correctness_p0/test_function_signature_all_types.groovy
@@ -461,7 +461,7 @@ suite("test_function_signature_all_types", 'nonConcurrent') 
{
     
     explain {
         sql("SELECT date_format(k14, '%Y-%m-%d') FROM test_sig_all_types")
-        notContains("CAST")
+        contains("CAST")
     }
     qt_dateformat_datev2 "SELECT date_format(k14, '%Y-%m-%d') FROM 
test_sig_all_types ORDER BY k1"
     
diff --git 
a/regression-test/suites/doc/sql-manual/sql-functions/doc_date_functions_test.groovy
 
b/regression-test/suites/doc/sql-manual/sql-functions/doc_date_functions_test.groovy
index 41930efff3b..f64e6391bd3 100644
--- 
a/regression-test/suites/doc/sql-manual/sql-functions/doc_date_functions_test.groovy
+++ 
b/regression-test/suites/doc/sql-manual/sql-functions/doc_date_functions_test.groovy
@@ -194,6 +194,7 @@ suite("doc_date_functions_test") {
     // Any parameter is NULL
     qt_date_format_7 """SELECT DATE_FORMAT(NULL, '%Y-%m-%d')"""
     qt_date_format_8 """SELECT DATE_FORMAT('2009-10-04', NULL)"""
+    qt_date_format_9 """SELECT DATE_FORMAT('2009-10-04 22:23:00', '   %W %M    
%Y')"""
 
     // 10. DATE function tests
     // Extract date part from datetime
@@ -1405,6 +1406,87 @@ suite("doc_date_functions_test") {
     testFoldConst("SELECT YEARWEEK('2023-01-02', 5) AS yearweek_mode5")
     testFoldConst("SELECT YEARWEEK('2023-12-25', 1) AS date_type_mode1")
 
+    //101. TIME_FORMAT function tests
+    sql """ DROP TABLE IF EXISTS test_time_format; """
+    sql """CREATE TABLE test_time_format (
+        id  INT,
+        tm VARCHAR(32)
+    ) DUPLICATE KEY(id)
+    PROPERTIES ( 'replication_num' = '1' );
+        """
+    sql """ INSERT INTO test_time_format VALUES
+            ( 1, '00:00:00'),
+            ( 2, '00:00:00.123456'),
+            ( 3, '12:34:56'),
+            ( 4, '12:34:56.789012'),
+            ( 5, '23:59:59'),
+            ( 6, '23:59:59.999999'),
+            ( 7, '08:00:00'),
+            ( 8, '15:00:00'),
+            ( 9, '100:00:00'),
+            (10, '123:45:56'),
+            (11, '838:59:59.999999'),
+            (12, '-00:00:01'),
+            (13, '-12:34:56.000001'),
+            (14, '-838:59:59.999999'),
+            (15, NULL);
+        """
+    qt_time_format_1 """SELECT
+                            id,
+                            tm,
+                            TIME_FORMAT(tm, '%H'),
+                            TIME_FORMAT(tm, '%k'),
+                            TIME_FORMAT(tm, '%h'),
+                            TIME_FORMAT(tm, '%I'),
+                            TIME_FORMAT(tm, '%l'),
+                            TIME_FORMAT(tm, '%i'),
+                            TIME_FORMAT(tm, '%s'),
+                            TIME_FORMAT(tm, '%S'),
+                            TIME_FORMAT(tm, '%f'),
+                            TIME_FORMAT(tm, '%p'),
+                            TIME_FORMAT(tm, '%r'),
+                            TIME_FORMAT(tm, '%T'),
+                            TIME_FORMAT(tm, '%H:%i:%s.%f'),
+                            TIME_FORMAT(tm, '%k %H %l %I %h'),
+                            TIME_FORMAT(tm, '%s %f %i %p'),
+                            TIME_FORMAT(tm, '%T %r %h:%I'),
+                            TIME_FORMAT(tm, '%l %k %I %H %h %p'),
+                            TIME_FORMAT(tm, '%f %s %i %T %r')
+                        FROM test_time_format
+                        ORDER BY id;
+                        """
+    qt_time_format_2 """SELECT TIME_FORMAT('2023-01-01 00:00:00', '%H %k %l %I 
%h %p')"""
+    qt_time_format_3 """SELECT TIME_FORMAT('2023-01-01 00:00:00.123456', '%s 
%f %i %T')"""
+    qt_time_format_4 """SELECT TIME_FORMAT('2023-01-01 12:34:56', '%r %T %h:%I 
%l')"""
+    qt_time_format_5 """SELECT TIME_FORMAT('2023-01-01 12:34:56.789012', '%k 
%H %I %l %h %p %s')"""
+    qt_time_format_6 """SELECT TIME_FORMAT('2023-01-01 23:59:59', '%f %s %i %p 
%r')"""
+    qt_time_format_7 """SELECT TIME_FORMAT('2023-01-01 23:59:59.999999', '%T 
%r %H:%i:%s.%f')"""
+    qt_time_format_8 """SELECT TIME_FORMAT('2023-01-01 08:00:00', '%l %k %h %I 
%H %p %f')"""
+    qt_time_format_9 """SELECT TIME_FORMAT('2023-01-01 15:00:00', '%s %i %f %T 
%r %p')"""
+    qt_time_format_10 """SELECT TIME_FORMAT('2023-01-01 100:00:00', '%H %l %I 
%k %h %s %f')"""
+    qt_time_format_11 """SELECT TIME_FORMAT('2023-01-01 123:45:56', '%p %r %T 
%i %s %f %H')"""
+    qt_time_format_12 """SELECT TIME_FORMAT('2023-01-01 838:59:59.999999', '%k 
%f %s %I %l %H %p')"""
+    qt_time_format_13 """SELECT TIME_FORMAT('2023-01-01 00:00:01', '%T %i %r 
%s %f %h:%I')"""
+    qt_time_format_14 """SELECT TIME_FORMAT('2023-01-01 12:34:56.000001', '%p 
%H %k %l %I %T %f')"""
+    qt_time_format_15 """SELECT TIME_FORMAT('2023-01-01 838:59:59.999999', '%s 
%i %f %r %p %H:%i:%s')"""
+
+    // Time format with date placeholders (Year, Month, Day return zeros or 
NULL)
+    qt_time_format_16 """SELECT TIME_FORMAT('2023-01-01 12:34:56.789012', 
'%Y-%m-%d %H:%i:%s')"""
+    qt_time_format_17 """SELECT TIME_FORMAT('2023-01-01 01:02:03.456789', 
'%y-%m-%d')"""
+    qt_time_format_18 """SELECT TIME_FORMAT('2023-01-01 23:59:59.999999', '%Y 
%m %d')"""
+    qt_time_format_19 """SELECT TIME_FORMAT('2023-01-01 00:00:00', '%c-%e')"""
+    qt_time_format_20 """SELECT TIME_FORMAT('2023-01-01 15:45:30.123456', 
'%Y/%m/%d %H:%i:%s.%f')"""
+    qt_time_format_21 """SELECT TIME_FORMAT('2023-01-01 12:34:56', '%M')"""
+    qt_time_format_22 """SELECT TIME_FORMAT('2023-01-01 12:34:56', '%W')"""
+    qt_time_format_23 """SELECT TIME_FORMAT('2023-01-01 12:34:56', '%j')"""
+    qt_time_format_24 """SELECT TIME_FORMAT('2023-01-01 12:34:56', '%D')"""
+    qt_time_format_25 """SELECT TIME_FORMAT('2023-01-01 12:34:56', '%U')"""
+    qt_time_format_26 """SELECT TIME_FORMAT('2023-01-01 12:34:56', '%u')"""
+    qt_time_format_27 """SELECT TIME_FORMAT('2023-01-01 12:34:56', '%V')"""
+    qt_time_format_28 """SELECT TIME_FORMAT('2023-01-01 12:34:56', '%v')"""
+    qt_time_format_29 """SELECT TIME_FORMAT('2023-01-01 12:34:56', '%x')"""
+    qt_time_format_30 """SELECT TIME_FORMAT('2023-01-01 12:34:56', '%X %w')"""
+
     // TO_SECONDS function tests
     qt_to_seconds_1 """select to_seconds('2007-10-07')"""
     qt_to_seconds_2 """select to_seconds('2007-10-07 10:03:09')"""
@@ -1431,7 +1513,7 @@ suite("doc_date_functions_test") {
     testFoldConst("SELECT to_seconds(20250101)")
     testFoldConst("SELECT to_seconds(20250101123045)")
 
-    // Test constant folding for Group 1 functions (基础日期函数)
+    // Test constant folding for Group 1 functions
     
     // 1. CONVERT_TZ function constant folding tests
     testFoldConst("SELECT CONVERT_TZ(CAST('2019-08-01 13:21:03' AS DATETIME), 
'Asia/Shanghai', 'America/Los_Angeles')")
@@ -1489,6 +1571,7 @@ suite("doc_date_functions_test") {
     testFoldConst("SELECT DATE_FORMAT('2009-10-04', '%D %e %f')")
     testFoldConst("SELECT DATE_FORMAT(NULL, '%Y-%m-%d')")
     testFoldConst("SELECT DATE_FORMAT('2009-10-04', NULL)")
+    testFoldConst("SELECT DATE_FORMAT('2009-10-04 22:23:00', '   %W %M    
%Y')")
 
     // 7. DATE function constant folding tests
     testFoldConst("SELECT DATE('2003-12-31 01:02:03')")
@@ -2058,6 +2141,85 @@ suite("doc_date_functions_test") {
     testFoldConst("SELECT MAKETIME(123, -4, 40)")
     testFoldConst("SELECT MAKETIME(7, 8, -23)")
 
+    // 100. TIME_FORMAT function constant folding tests
+    testFoldConst("SELECT TIME_FORMAT('00:00:00', '%H') AS zero_24hour")
+    testFoldConst("SELECT TIME_FORMAT('00:00:00', '%k') AS zero_24hour_no_pad")
+    testFoldConst("SELECT TIME_FORMAT('00:00:00', '%h') AS zero_12hour")
+    testFoldConst("SELECT TIME_FORMAT('00:00:00', '%I') AS zero_12hour_alt")
+    testFoldConst("SELECT TIME_FORMAT('00:00:00', '%l') AS zero_12hour_no_pad")
+    testFoldConst("SELECT TIME_FORMAT('838:59:59', '%k:%i:%S') AS 
max_k_format")
+    testFoldConst("SELECT TIME_FORMAT('838:59:59', '%H.%i.%s.%f') AS 
max_with_micro_sep")
+    testFoldConst("SELECT TIME_FORMAT('838:59:59', '%T') AS max_time_T")
+    testFoldConst("SELECT TIME_FORMAT('838:59:59', '%r') AS max_time_r")
+    testFoldConst("SELECT TIME_FORMAT('-838:59:59', '%k %i %S') AS 
min_k_format")
+    testFoldConst("SELECT TIME_FORMAT('-838:59:59', '%H%i%S%f') AS 
min_compact")
+    testFoldConst("SELECT TIME_FORMAT('839:00:00', '%T') AS beyond_max_T")
+    testFoldConst("SELECT TIME_FORMAT('-839:00:00', '%r') AS beyond_min_r")
+    testFoldConst("SELECT TIME_FORMAT('12:34:56.123456', '%f') AS 
only_microseconds")
+    testFoldConst("SELECT TIME_FORMAT('12:34:56.789012', '%k.%f') AS 
hour_microsec")
+    testFoldConst("SELECT TIME_FORMAT('23:59:59.999999', '%T.%f') AS 
T_format_micro")
+    testFoldConst("SELECT TIME_FORMAT('00:00:00.000001', '%f only') AS 
micro_with_text")
+    testFoldConst("SELECT TIME_FORMAT('13:45:30', '%H vs %k vs %h vs %I vs 
%l') AS all_hour_formats")
+    testFoldConst("SELECT TIME_FORMAT('03:07:09', '%H-%k-%h-%I-%l') AS 
morning_all_formats")
+    testFoldConst("SELECT TIME_FORMAT('00:30:45', '%H|%k|%h|%I|%l') AS 
midnight_all_formats")
+    testFoldConst("SELECT TIME_FORMAT('12:00:00', '%H/%k/%h/%I/%l') AS 
noon_all_formats")
+    testFoldConst("SELECT TIME_FORMAT('23:59:59', '%k,%h,%l,%p') AS 
late_night_formats")
+    testFoldConst("SELECT TIME_FORMAT('12:34:56', '%S') AS uppercase_S")
+    testFoldConst("SELECT TIME_FORMAT('12:34:09', '%S vs %s') AS both_seconds")
+    testFoldConst("SELECT TIME_FORMAT('12:34:05', '%k:%i:%S') AS k_i_S")
+    testFoldConst("SELECT TIME_FORMAT('15:30:45', '%T') AS T_afternoon")
+    testFoldConst("SELECT TIME_FORMAT('03:07:22', '%T') AS T_morning")
+    testFoldConst("SELECT TIME_FORMAT('15:30:45', '%r') AS r_afternoon")
+    testFoldConst("SELECT TIME_FORMAT('03:07:22', '%r') AS r_morning")
+    testFoldConst("SELECT TIME_FORMAT('00:00:00', '%T vs %r') AS 
T_vs_r_midnight")
+    testFoldConst("SELECT TIME_FORMAT('12:00:00', '%T vs %r') AS T_vs_r_noon")
+    testFoldConst("SELECT TIME_FORMAT('13:45:30', '%p') AS only_pm")
+    testFoldConst("SELECT TIME_FORMAT('09:15:20', '%p') AS only_am")
+    testFoldConst("SELECT TIME_FORMAT('23:59:59', '%p at %l:%i') AS 
pm_natural")
+    testFoldConst("SELECT TIME_FORMAT('00:30:45', '%p-%l-%i-%S') AS am_dashes")
+    testFoldConst("SELECT TIME_FORMAT('15:07:22', '%p%p%p') AS triple_pm")
+    testFoldConst("SELECT TIME_FORMAT('12:34:56', '%i') AS only_minutes")
+    testFoldConst("SELECT TIME_FORMAT('12:05:56', '%i') AS 
minutes_leading_zero")
+    testFoldConst("SELECT TIME_FORMAT('12:00:00', '%i:%S') AS min_sec_only")
+    testFoldConst("SELECT TIME_FORMAT('23:59:59', '%i%S') AS min_sec_compact")
+    testFoldConst("SELECT TIME_FORMAT('500:30:45', '%k:%i:%S') AS large_k")
+    testFoldConst("SELECT TIME_FORMAT('700:00:00', '%H-%k') AS large_H_k")
+    testFoldConst("SELECT TIME_FORMAT('100:15:30', '%T') AS large_T")
+    testFoldConst("SELECT TIME_FORMAT('838:00:00', '%k only') AS max_hour_k")
+    testFoldConst("SELECT TIME_FORMAT('-12:34:56', '%k:%i:%S') AS negative_k")
+    testFoldConst("SELECT TIME_FORMAT('-100:30:45', '%T') AS negative_T")
+    testFoldConst("SELECT TIME_FORMAT('-05:07:09', '%r') AS negative_r")
+    testFoldConst("SELECT TIME_FORMAT('-838:59:59', '%H%k%h%I%l') AS 
negative_max_all")
+    testFoldConst("SELECT TIME_FORMAT('12:34:56', '%%H=%%k') AS 
percent_escaped")
+    testFoldConst("SELECT TIME_FORMAT('12:34:56', '%% %T %%') AS 
percent_around_T")
+    testFoldConst("SELECT TIME_FORMAT('12:34:56', '%H\\:%i\\:%s') AS 
backslash_colon")
+    testFoldConst("SELECT TIME_FORMAT('12:34:56', '%k-%i-%S-%f') AS 
all_with_dashes")
+    testFoldConst("SELECT TIME_FORMAT('12:34:56', '') AS empty_format")
+    testFoldConst("SELECT TIME_FORMAT('12:34:56', 'no specifiers at all') AS 
literal_only")
+    testFoldConst("SELECT TIME_FORMAT('15:45:30', '%k%i%S%f%p%T%r') AS 
everything_combined")
+    testFoldConst("SELECT TIME_FORMAT('03:07:09', '%l o clock %i minutes %S 
seconds %p') AS natural_lang")
+    testFoldConst("SELECT TIME_FORMAT('23:59:59', '%H=%k, %h=%I=%l, %p') AS 
hour_comparisons")
+    testFoldConst("SELECT TIME_FORMAT('12:00:00', 'Noon: %T or %r?') AS 
noon_question")
+    testFoldConst("SELECT TIME_FORMAT('00:00:00', 'Midnight: %k|%h|%l %p') AS 
midnight_formats")
+    testFoldConst("SELECT TIME_FORMAT('2023-12-25 15:30:45', '%k:%i:%S') AS 
datetime_k")
+    testFoldConst("SELECT TIME_FORMAT('2023-12-25 03:07:22', '%l:%i %p') AS 
datetime_12h")
+    testFoldConst("SELECT TIME_FORMAT(NULL, '%T') AS null_time_T")
+    testFoldConst("SELECT TIME_FORMAT('12:34:56', NULL) AS null_format")
+    testFoldConst("SELECT TIME_FORMAT(NULL, NULL) AS both_null")
+
+    // TIME_FORMAT with date placeholders constant folding tests
+    testFoldConst("SELECT TIME_FORMAT('2023-12-25 15:30:45', '%Y-%m-%d 
%H:%i:%s') AS date_with_time")
+    testFoldConst("SELECT TIME_FORMAT('2023-12-25 08:15:30.123456', '%y/%m/%d 
%T.%f') AS short_date_format")
+    testFoldConst("SELECT TIME_FORMAT('2023-12-25 23:59:59', '%Y %m %d') AS 
year_month_day")
+    testFoldConst("SELECT TIME_FORMAT('2023-12-25 12:34:56', '%c-%e') AS 
month_day_no_pad")
+    testFoldConst("SELECT TIME_FORMAT('2023-12-25 10:20:30.987654', '%Y/%m/%d 
%H:%i:%s.%f') AS full_datetime")
+    testFoldConst("SELECT TIME_FORMAT('2023-12-25 15:30:45', '%M') AS 
month_name")
+    testFoldConst("SELECT TIME_FORMAT('2023-12-25 15:30:45', '%W') AS 
weekday_name")
+    testFoldConst("SELECT TIME_FORMAT('2023-12-25 15:30:45', '%j') AS 
day_of_year")
+    testFoldConst("SELECT TIME_FORMAT('2023-12-25 15:30:45', '%D') AS 
day_with_suffix")
+    testFoldConst("SELECT TIME_FORMAT('2023-12-25 15:30:45', '%U %u') AS 
week_numbers")
+    testFoldConst("SELECT TIME_FORMAT('2023-12-25 15:30:45', '%V %v %w') AS 
week_variants")
+
     // Additional NULL parameter tests for comprehensive coverage
     
     // MINUTE functions NULL tests


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


Reply via email to