[branch-2.1](function) fix wrong floor of function date_diff when unit less than day (#49429) (#50606)
pick https://github.com/apache/doris/pull/49429
This commit is contained in:
@ -160,7 +160,7 @@ bool PipelineFragmentContext::is_timeout(const VecDateTimeValue& now) const {
|
||||
if (_timeout <= 0) {
|
||||
return false;
|
||||
}
|
||||
if (now.second_diff(_start_time) > _timeout) {
|
||||
if (now.datetime_diff_in_seconds(_start_time) > _timeout) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@ -1535,7 +1535,7 @@ void FragmentMgr::debug(std::stringstream& ss) {
|
||||
-> Status {
|
||||
for (auto& it : map) {
|
||||
ss << it.first << "\t" << it.second->start_time().debug_string() << "\t"
|
||||
<< now.second_diff(it.second->start_time()) << "\n";
|
||||
<< now.datetime_diff_in_seconds(it.second->start_time()) << "\n";
|
||||
}
|
||||
return Status::OK();
|
||||
});
|
||||
|
||||
@ -419,7 +419,7 @@ bool PlanFragmentExecutor::is_timeout(const VecDateTimeValue& now) const {
|
||||
if (_timeout_second <= 0) {
|
||||
return false;
|
||||
}
|
||||
if (now.second_diff(_start_time) > _timeout_second) {
|
||||
if (now.datetime_diff_in_seconds(_start_time) > _timeout_second) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@ -98,13 +98,13 @@ public:
|
||||
if (timeout_second <= 0) {
|
||||
return false;
|
||||
}
|
||||
if (now.second_diff(_start_time) > timeout_second) {
|
||||
if (now.datetime_diff_in_seconds(_start_time) > timeout_second) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int64_t query_time(VecDateTimeValue& now) { return now.second_diff(_start_time); }
|
||||
int64_t query_time(VecDateTimeValue& now) { return now.datetime_diff_in_seconds(_start_time); }
|
||||
|
||||
void set_thread_token(int concurrency, bool is_serial) {
|
||||
_thread_token = _exec_env->scanner_scheduler()->new_limited_scan_pool_token(
|
||||
|
||||
@ -29,8 +29,12 @@
|
||||
/*
|
||||
* We use these function family to clarify our types of datelike type. for example:
|
||||
* DataTypeDate -------------------> ColumnDate -----------------------> Int64
|
||||
* | TypeToColumn ValueTypeOfColumn
|
||||
* | TypeToValueType
|
||||
* | | TypeToColumn ValueTypeOfColumn |
|
||||
* | ↘--------------------------------------------------------------↗
|
||||
* | | ::FieldType |
|
||||
* | ↖--------------------------------------------------------------↙
|
||||
* | DateTraits<T>::DateType
|
||||
* ↓ TypeToValueType
|
||||
* VecDateTimeValue
|
||||
*/
|
||||
namespace doris::date_cast {
|
||||
|
||||
@ -413,7 +413,7 @@ public:
|
||||
base_it = events_it;
|
||||
++action_it;
|
||||
} else if (action_it->type == PatternActionType::TimeLessOrEqual) {
|
||||
if (events_it->first.second_diff(base_it->first) <= action_it->extra) {
|
||||
if (events_it->first.datetime_diff_in_seconds(base_it->first) <= action_it->extra) {
|
||||
/// condition satisfied, move onto next action
|
||||
back_stack.emplace(action_it, events_it, base_it);
|
||||
base_it = events_it;
|
||||
@ -421,28 +421,28 @@ public:
|
||||
} else if (!do_backtrack())
|
||||
break;
|
||||
} else if (action_it->type == PatternActionType::TimeLess) {
|
||||
if (events_it->first.second_diff(base_it->first) < action_it->extra) {
|
||||
if (events_it->first.datetime_diff_in_seconds(base_it->first) < action_it->extra) {
|
||||
back_stack.emplace(action_it, events_it, base_it);
|
||||
base_it = events_it;
|
||||
++action_it;
|
||||
} else if (!do_backtrack())
|
||||
break;
|
||||
} else if (action_it->type == PatternActionType::TimeGreaterOrEqual) {
|
||||
if (events_it->first.second_diff(base_it->first) >= action_it->extra) {
|
||||
if (events_it->first.datetime_diff_in_seconds(base_it->first) >= action_it->extra) {
|
||||
back_stack.emplace(action_it, events_it, base_it);
|
||||
base_it = events_it;
|
||||
++action_it;
|
||||
} else if (++events_it == events_end && !do_backtrack())
|
||||
break;
|
||||
} else if (action_it->type == PatternActionType::TimeGreater) {
|
||||
if (events_it->first.second_diff(base_it->first) > action_it->extra) {
|
||||
if (events_it->first.datetime_diff_in_seconds(base_it->first) > action_it->extra) {
|
||||
back_stack.emplace(action_it, events_it, base_it);
|
||||
base_it = events_it;
|
||||
++action_it;
|
||||
} else if (++events_it == events_end && !do_backtrack())
|
||||
break;
|
||||
} else if (action_it->type == PatternActionType::TimeEqual) {
|
||||
if (events_it->first.second_diff(base_it->first) == action_it->extra) {
|
||||
if (events_it->first.datetime_diff_in_seconds(base_it->first) == action_it->extra) {
|
||||
back_stack.emplace(action_it, events_it, base_it);
|
||||
base_it = events_it;
|
||||
++action_it;
|
||||
|
||||
@ -136,9 +136,8 @@ struct RangeImplUtil {
|
||||
auto dest_array_column_ptr = ColumnArray::create(return_nested_type->create_column(),
|
||||
ColumnArray::ColumnOffsets::create());
|
||||
IColumn* dest_nested_column = &dest_array_column_ptr->get_data();
|
||||
ColumnNullable* dest_nested_nullable_col =
|
||||
reinterpret_cast<ColumnNullable*>(dest_nested_column);
|
||||
dest_nested_column = dest_nested_nullable_col->get_nested_column_ptr();
|
||||
auto* dest_nested_nullable_col = assert_cast<ColumnNullable*>(dest_nested_column);
|
||||
dest_nested_column = dest_nested_nullable_col->get_nested_column_ptr().get();
|
||||
auto& dest_nested_null_map = dest_nested_nullable_col->get_null_map_column().get_data();
|
||||
|
||||
auto args_null_map = ColumnUInt8::create(input_rows_count, 0);
|
||||
@ -159,7 +158,8 @@ struct RangeImplUtil {
|
||||
assert_cast<const ColumnVector<SourceDataType>*>(argument_columns[0].get());
|
||||
auto end_column =
|
||||
assert_cast<const ColumnVector<SourceDataType>*>(argument_columns[1].get());
|
||||
auto step_column = assert_cast<const ColumnVector<Int32>*>(argument_columns[2].get());
|
||||
const auto* step_column =
|
||||
assert_cast<const ColumnVector<Int32>*>(argument_columns[2].get());
|
||||
|
||||
DCHECK(dest_nested_column != nullptr);
|
||||
auto& dest_offsets = dest_array_column_ptr->get_offsets();
|
||||
|
||||
@ -38,20 +38,20 @@
|
||||
|
||||
namespace doris::vectorized {
|
||||
|
||||
#define TIME_FUNCTION_IMPL(CLASS, UNIT, FUNCTION) \
|
||||
template <typename ArgType> \
|
||||
struct CLASS { \
|
||||
using OpArgType = ArgType; \
|
||||
static constexpr auto name = #UNIT; \
|
||||
\
|
||||
static inline auto execute(const ArgType& t) { \
|
||||
const auto& date_time_value = (typename DateTraits<ArgType>::T&)(t); \
|
||||
return date_time_value.FUNCTION; \
|
||||
} \
|
||||
\
|
||||
static DataTypes get_variadic_argument_types() { \
|
||||
return {std::make_shared<typename DateTraits<ArgType>::DateType>()}; \
|
||||
} \
|
||||
#define TIME_FUNCTION_IMPL(CLASS, UNIT, FUNCTION) \
|
||||
template <typename NativeType> \
|
||||
struct CLASS { \
|
||||
using OpArgType = NativeType; \
|
||||
static constexpr auto name = #UNIT; \
|
||||
\
|
||||
static inline auto execute(const NativeType& t) { \
|
||||
const auto& date_time_value = (typename DateTraits<NativeType>::T&)(t); \
|
||||
return date_time_value.FUNCTION; \
|
||||
} \
|
||||
\
|
||||
static DataTypes get_variadic_argument_types() { \
|
||||
return {std::make_shared<typename DateTraits<NativeType>::DateType>()}; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define TO_TIME_FUNCTION(CLASS, UNIT) TIME_FUNCTION_IMPL(CLASS, UNIT, UNIT())
|
||||
|
||||
@ -274,8 +274,8 @@ struct SubtractYearsImpl : SubtractIntervalImpl<AddYearsImpl<DateType>, DateType
|
||||
} \
|
||||
};
|
||||
DECLARE_DATE_FUNCTIONS(DateDiffImpl, datediff, DataTypeInt32, (ts0.daynr() - ts1.daynr()));
|
||||
// DECLARE_DATE_FUNCTIONS(TimeDiffImpl, timediff, DataTypeTime, ts0.second_diff(ts1));
|
||||
// Expands to
|
||||
// DECLARE_DATE_FUNCTIONS(TimeDiffImpl, timediff, DataTypeTime, ts0.datetime_diff_in_seconds(ts1));
|
||||
// Expands to below here because it use Time type which need some special deal.
|
||||
template <typename DateType1, typename DateType2>
|
||||
struct TimeDiffImpl {
|
||||
using DateValueType1 = date_cast::TypeToValueTypeV<DateType1>;
|
||||
@ -297,7 +297,7 @@ struct TimeDiffImpl {
|
||||
if constexpr (UsingTimev2) {
|
||||
// refer to https://dev.mysql.com/doc/refman/5.7/en/time.html
|
||||
// the time type value between '-838:59:59' and '838:59:59', so the return value should limited
|
||||
int64_t diff_m = ts0.microsecond_diff(ts1);
|
||||
int64_t diff_m = ts0.datetime_diff_in_microseconds(ts1);
|
||||
if (diff_m > limit_value) {
|
||||
return (double)limit_value;
|
||||
} else if (diff_m < -1 * limit_value) {
|
||||
@ -306,7 +306,7 @@ struct TimeDiffImpl {
|
||||
return (double)diff_m;
|
||||
}
|
||||
} else {
|
||||
return (double)((1000 * 1000) * ts0.second_diff(ts1));
|
||||
return (double)((1000 * 1000) * ts0.datetime_diff_in_seconds(ts1));
|
||||
}
|
||||
}
|
||||
static DataTypes get_variadic_argument_types() {
|
||||
|
||||
@ -713,7 +713,7 @@ struct TimeRound {
|
||||
trivial_part_ts1 = ts1.second();
|
||||
}
|
||||
if constexpr (Impl::Unit == SECOND) {
|
||||
diff = ts2.second_diff(ts1);
|
||||
diff = ts2.datetime_diff_in_seconds(ts1);
|
||||
trivial_part_ts1 = 0;
|
||||
trivial_part_ts2 = 0;
|
||||
}
|
||||
@ -752,7 +752,7 @@ struct TimeRound {
|
||||
trivial_part_ts1 = ts1.second();
|
||||
}
|
||||
if constexpr (Impl::Unit == SECOND) {
|
||||
diff = ts2.second_diff(ts1);
|
||||
diff = ts2.datetime_diff_in_seconds(ts1);
|
||||
trivial_part_ts1 = 0;
|
||||
trivial_part_ts2 = 0;
|
||||
}
|
||||
@ -793,7 +793,7 @@ struct TimeRound {
|
||||
ts1.to_date_int_val() & MASK_YEAR_MONTH_DAY_HOUR_MINUTE_FOR_DATETIMEV2;
|
||||
}
|
||||
if constexpr (Impl::Unit == SECOND) {
|
||||
diff = ts2.second_diff(ts1);
|
||||
diff = ts2.datetime_diff_in_seconds(ts1);
|
||||
trivial_part_ts2 = ts2.microsecond();
|
||||
trivial_part_ts1 = ts1.microsecond();
|
||||
}
|
||||
|
||||
@ -3942,9 +3942,9 @@ template void VecDateTimeValue::create_from_date_v2<DateTimeV2ValueType>(
|
||||
template void VecDateTimeValue::create_from_date_v2<DateTimeV2ValueType>(
|
||||
DateV2Value<DateTimeV2ValueType>&& value, TimeType type);
|
||||
|
||||
template int64_t VecDateTimeValue::second_diff<DateV2Value<DateV2ValueType>>(
|
||||
template int64_t VecDateTimeValue::datetime_diff_in_seconds<DateV2Value<DateV2ValueType>>(
|
||||
const DateV2Value<DateV2ValueType>& rhs) const;
|
||||
template int64_t VecDateTimeValue::second_diff<DateV2Value<DateTimeV2ValueType>>(
|
||||
template int64_t VecDateTimeValue::datetime_diff_in_seconds<DateV2Value<DateTimeV2ValueType>>(
|
||||
const DateV2Value<DateTimeV2ValueType>& rhs) const;
|
||||
|
||||
#define DELARE_DATE_ADD_INTERVAL(DateValueType1, DateValueType2) \
|
||||
|
||||
@ -167,6 +167,7 @@ const int TIME_MAX_VALUE_SECONDS = 3600 * TIME_MAX_HOUR + 60 * TIME_MAX_MINUTE +
|
||||
constexpr int HOUR_PER_DAY = 24;
|
||||
constexpr int64_t SECOND_PER_HOUR = 3600;
|
||||
constexpr int64_t SECOND_PER_MINUTE = 60;
|
||||
constexpr int64_t MS_PER_SECOND = 1000 * 1000;
|
||||
|
||||
inline constexpr int S_DAYS_IN_MONTH[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
||||
|
||||
@ -426,7 +427,7 @@ public:
|
||||
void unchecked_set_time(uint32_t year, uint32_t month, uint32_t day, uint32_t hour,
|
||||
uint32_t minute, uint32_t second);
|
||||
|
||||
int64_t daynr() const { return calc_daynr(_year, _month, _day); }
|
||||
uint32_t daynr() const { return calc_daynr(_year, _month, _day); }
|
||||
|
||||
int year() const { return _year; }
|
||||
int month() const { return _month; }
|
||||
@ -650,7 +651,7 @@ public:
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
int64_t second_diff(const T& rhs) const {
|
||||
int64_t datetime_diff_in_seconds(const T& rhs) const {
|
||||
return (daynr() - rhs.daynr()) * SECOND_PER_HOUR * HOUR_PER_DAY + time_part_diff(rhs);
|
||||
}
|
||||
|
||||
@ -892,6 +893,7 @@ public:
|
||||
|
||||
void unchecked_set_time(uint8_t hour, uint8_t minute, uint8_t second, uint32_t microsecond);
|
||||
|
||||
// we frequently use this to do arithmetic operation, so use signed int64_t to avoid overflow.
|
||||
int64_t daynr() const {
|
||||
return calc_daynr(date_v2_value_.year_, date_v2_value_.month_, date_v2_value_.day_);
|
||||
}
|
||||
@ -1136,34 +1138,57 @@ public:
|
||||
|
||||
//only calculate the diff of dd:mm:ss
|
||||
template <typename RHS>
|
||||
int64_t time_part_diff(const RHS& rhs) const {
|
||||
int64_t time_part_diff_without_ms(const RHS& rhs) const {
|
||||
return time_part_to_seconds() - rhs.time_part_to_seconds();
|
||||
}
|
||||
|
||||
//only calculate the diff of dd:mm:ss.SSSSSS
|
||||
template <typename RHS>
|
||||
int64_t time_part_diff_microsecond(const RHS& rhs) const {
|
||||
int64_t time_part_diff_in_ms(const RHS& rhs) const {
|
||||
return time_part_to_microsecond() - rhs.time_part_to_microsecond();
|
||||
}
|
||||
|
||||
template <typename RHS>
|
||||
int64_t second_diff(const RHS& rhs) const {
|
||||
return (daynr() - rhs.daynr()) * SECOND_PER_HOUR * HOUR_PER_DAY + time_part_diff(rhs);
|
||||
int64_t datetime_diff_in_seconds(const RHS& rhs) const {
|
||||
return (daynr() - rhs.daynr()) * SECOND_PER_HOUR * HOUR_PER_DAY +
|
||||
time_part_diff_without_ms(rhs);
|
||||
}
|
||||
|
||||
template <typename RHS>
|
||||
int32_t date_diff_in_days(const RHS& rhs) const {
|
||||
return daynr() - rhs.daynr(); // arithmetic calculation will auto promote to signed int32
|
||||
}
|
||||
|
||||
int32_t date_diff_in_days_round_to_zero_by_time(const auto& rhs) const {
|
||||
int32_t day = this->date_diff_in_days(rhs);
|
||||
int64_t ms_diff = this->time_part_diff_in_ms(rhs);
|
||||
if (day > 0 && ms_diff < 0) {
|
||||
day--;
|
||||
} else if (day < 0 && ms_diff > 0) {
|
||||
day++;
|
||||
}
|
||||
return day;
|
||||
}
|
||||
|
||||
// used by INT microseconds_diff(DATETIME enddate, DATETIME startdate)
|
||||
// return it's int type, so shouldn't have any limit.
|
||||
// return value is int type, so shouldn't have any limit.
|
||||
// when used by TIME TIMEDIFF(DATETIME expr1, DATETIME expr2), it's return time type, should have limited.
|
||||
template <typename RHS>
|
||||
int64_t microsecond_diff(const RHS& rhs) const {
|
||||
int64_t diff_m = (daynr() - rhs.daynr()) * SECOND_PER_HOUR * HOUR_PER_DAY * 1000 * 1000 +
|
||||
time_part_diff_microsecond(rhs);
|
||||
int64_t datetime_diff_in_microseconds(const RHS& rhs) const {
|
||||
int64_t diff_m = (daynr() - rhs.daynr()) * HOUR_PER_DAY * SECOND_PER_HOUR * MS_PER_SECOND +
|
||||
time_part_diff_in_ms(rhs);
|
||||
return diff_m;
|
||||
}
|
||||
|
||||
bool can_cast_to_date_without_loss_accuracy() {
|
||||
return this->hour() == 0 && this->minute() == 0 && this->second() == 0 &&
|
||||
this->microsecond() == 0;
|
||||
int64_t datetime_diff_in_seconds_round_to_zero_by_ms(const auto& rhs) const {
|
||||
int64_t second = this->datetime_diff_in_seconds(rhs);
|
||||
int32_t ms_diff = this->microsecond() - rhs.microsecond();
|
||||
if (second > 0 && ms_diff < 0) {
|
||||
second--;
|
||||
} else if (second < 0 && ms_diff > 0) {
|
||||
second++;
|
||||
}
|
||||
return second;
|
||||
}
|
||||
|
||||
underlying_value to_date_int_val() const { return int_val_; }
|
||||
@ -1388,17 +1413,17 @@ int64_t datetime_diff(const VecDateTimeValue& ts_value1, const VecDateTimeValue&
|
||||
return day;
|
||||
}
|
||||
case HOUR: {
|
||||
int64_t second = ts_value2.second_diff(ts_value1);
|
||||
int64_t second = ts_value2.datetime_diff_in_seconds(ts_value1);
|
||||
int64_t hour = second / 60 / 60;
|
||||
return hour;
|
||||
}
|
||||
case MINUTE: {
|
||||
int64_t second = ts_value2.second_diff(ts_value1);
|
||||
int64_t second = ts_value2.datetime_diff_in_seconds(ts_value1);
|
||||
int64_t minute = second / 60;
|
||||
return minute;
|
||||
}
|
||||
case SECOND: {
|
||||
int64_t second = ts_value2.second_diff(ts_value1);
|
||||
int64_t second = ts_value2.datetime_diff_in_seconds(ts_value1);
|
||||
return second;
|
||||
}
|
||||
}
|
||||
@ -1406,10 +1431,15 @@ int64_t datetime_diff(const VecDateTimeValue& ts_value1, const VecDateTimeValue&
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <TimeUnit unit, typename T0, typename T1>
|
||||
// ROUND the result TO ZERO( not FLOOR). for datetime_diff<year>, everything less than year is the remainder.
|
||||
// "ROUND TO ZERO" means `years_diff('2020-05-05', '2015-06-06')` gets 4 and
|
||||
// `years_diff('2015-06-06', '2020-05-05')` gets -4.
|
||||
template <TimeUnit UNIT, typename T0, typename T1>
|
||||
int64_t datetime_diff(const DateV2Value<T0>& ts_value1, const DateV2Value<T1>& ts_value2) {
|
||||
constexpr uint64_t uint64_minus_one = -1;
|
||||
switch (unit) {
|
||||
switch (UNIT) {
|
||||
// for YEAR and MONTH: calculate the diff of year or month, and use bitmask to get the remainder of all other
|
||||
// parts. then round to zero by the remainder.
|
||||
case YEAR: {
|
||||
int year = (ts_value2.year() - ts_value1.year());
|
||||
if constexpr (std::is_same_v<T0, T1>) {
|
||||
@ -1494,47 +1524,27 @@ int64_t datetime_diff(const DateV2Value<T0>& ts_value1, const DateV2Value<T1>& t
|
||||
return month;
|
||||
}
|
||||
case WEEK: {
|
||||
int day = ts_value2.daynr() - ts_value1.daynr();
|
||||
int64_t ms_diff = ts_value2.time_part_diff_microsecond(ts_value1);
|
||||
if (day > 0 && ms_diff < 0) {
|
||||
day--;
|
||||
} else if (day < 0 && ms_diff > 0) {
|
||||
day++;
|
||||
}
|
||||
return day / 7;
|
||||
return ts_value2.date_diff_in_days_round_to_zero_by_time(ts_value1) / 7;
|
||||
}
|
||||
case DAY: {
|
||||
int day = ts_value2.daynr() - ts_value1.daynr();
|
||||
int64_t ms_diff = ts_value2.time_part_diff_microsecond(ts_value1);
|
||||
if (day > 0 && ms_diff < 0) {
|
||||
day--;
|
||||
} else if (day < 0 && ms_diff > 0) {
|
||||
day++;
|
||||
}
|
||||
return day;
|
||||
return ts_value2.date_diff_in_days_round_to_zero_by_time(ts_value1);
|
||||
}
|
||||
case HOUR: {
|
||||
int64_t second = ts_value2.second_diff(ts_value1);
|
||||
int64_t hour = second / 60 / 60;
|
||||
return hour;
|
||||
return ts_value2.datetime_diff_in_seconds_round_to_zero_by_ms(ts_value1) / 60 / 60;
|
||||
}
|
||||
case MINUTE: {
|
||||
int64_t second = ts_value2.second_diff(ts_value1);
|
||||
int64_t minute = second / 60;
|
||||
return minute;
|
||||
return ts_value2.datetime_diff_in_seconds_round_to_zero_by_ms(ts_value1) / 60;
|
||||
}
|
||||
case SECOND: {
|
||||
int64_t second = ts_value2.second_diff(ts_value1);
|
||||
return second;
|
||||
return ts_value2.datetime_diff_in_seconds_round_to_zero_by_ms(ts_value1);
|
||||
}
|
||||
case MILLISECOND: {
|
||||
int64_t microsecond = ts_value2.microsecond_diff(ts_value1);
|
||||
int64_t millisecond = microsecond / 1000;
|
||||
return millisecond;
|
||||
// C++ naturally rounds to zero
|
||||
return ts_value2.datetime_diff_in_microseconds(ts_value1) / 1000;
|
||||
}
|
||||
case MICROSECOND: {
|
||||
int64_t microsecond = ts_value2.microsecond_diff(ts_value1);
|
||||
return microsecond;
|
||||
// no precision loss
|
||||
return ts_value2.datetime_diff_in_microseconds(ts_value1);
|
||||
}
|
||||
}
|
||||
// Rethink the default return value
|
||||
|
||||
@ -677,4 +677,207 @@ TEST(VDateTimeValueTest, date_v2_from_date_format_str_with_all_space) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(VDateTimeValueTest, datetime_diff_test) {
|
||||
// Test case 1: DATE to DATE - Different years, months, days
|
||||
{
|
||||
DateV2Value<DateV2ValueType> date1;
|
||||
std::string date_str1 = "2020-01-15";
|
||||
std::string format = "%Y-%m-%d";
|
||||
EXPECT_TRUE(date1.from_date_format_str(format.data(), format.size(), date_str1.data(),
|
||||
date_str1.size()));
|
||||
|
||||
DateV2Value<DateV2ValueType> date2;
|
||||
std::string date_str2 = "2023-08-20";
|
||||
EXPECT_TRUE(date2.from_date_format_str(format.data(), format.size(), date_str2.data(),
|
||||
date_str2.size()));
|
||||
|
||||
// Test all time units for DATE to DATE
|
||||
EXPECT_EQ(datetime_diff<TimeUnit::YEAR>(date1, date2), 3);
|
||||
EXPECT_EQ(datetime_diff<TimeUnit::MONTH>(date1, date2), 3 * 12 + 7);
|
||||
EXPECT_EQ(datetime_diff<TimeUnit::WEEK>(date1, date2), 187); // Approximately
|
||||
EXPECT_EQ(datetime_diff<TimeUnit::DAY>(date1, date2), 1313);
|
||||
EXPECT_EQ(datetime_diff<TimeUnit::HOUR>(date1, date2), 1313 * 24);
|
||||
EXPECT_EQ(datetime_diff<TimeUnit::MINUTE>(date1, date2), 1313 * 24 * 60);
|
||||
EXPECT_EQ(datetime_diff<TimeUnit::SECOND>(date1, date2), 1313 * 24 * 60 * 60);
|
||||
EXPECT_EQ(datetime_diff<TimeUnit::MILLISECOND>(date1, date2), 1313 * 24 * 60 * 60 * 1000LL);
|
||||
EXPECT_EQ(datetime_diff<TimeUnit::MICROSECOND>(date1, date2),
|
||||
1313 * 24 * 60 * 60 * 1000000LL);
|
||||
}
|
||||
|
||||
// Test case 2: DATETIME to DATETIME - Testing rounding consistency across units
|
||||
{
|
||||
// Test 2.1: Hour rounding - less than 1 hour should truncate to 0
|
||||
{
|
||||
DateV2Value<DateTimeV2ValueType> dt1;
|
||||
std::string dt_str1 = "2023-05-10 10:00:00.000000";
|
||||
std::string format = "%Y-%m-%d %H:%i:%s.%f";
|
||||
EXPECT_TRUE(dt1.from_date_format_str(format.data(), format.size(), dt_str1.data(),
|
||||
dt_str1.size()));
|
||||
|
||||
DateV2Value<DateTimeV2ValueType> dt2;
|
||||
std::string dt_str2 = "2023-05-10 10:59:59.999999";
|
||||
EXPECT_TRUE(dt2.from_date_format_str(format.data(), format.size(), dt_str2.data(),
|
||||
dt_str2.size()));
|
||||
|
||||
EXPECT_EQ(datetime_diff<TimeUnit::HOUR>(dt1, dt2), 0);
|
||||
}
|
||||
|
||||
// Test 2.2: Hour rounding - exactly 1 hour
|
||||
{
|
||||
DateV2Value<DateTimeV2ValueType> dt1;
|
||||
std::string dt_str1 = "2023-05-10 10:00:00.000000";
|
||||
std::string format = "%Y-%m-%d %H:%i:%s.%f";
|
||||
EXPECT_TRUE(dt1.from_date_format_str(format.data(), format.size(), dt_str1.data(),
|
||||
dt_str1.size()));
|
||||
|
||||
DateV2Value<DateTimeV2ValueType> dt2;
|
||||
std::string dt_str2 = "2023-05-10 11:00:00.000000";
|
||||
EXPECT_TRUE(dt2.from_date_format_str(format.data(), format.size(), dt_str2.data(),
|
||||
dt_str2.size()));
|
||||
|
||||
EXPECT_EQ(datetime_diff<TimeUnit::HOUR>(dt1, dt2), 1);
|
||||
}
|
||||
|
||||
// Test 2.3: Minute rounding - less than 1 minute should truncate to 0
|
||||
{
|
||||
DateV2Value<DateTimeV2ValueType> dt1;
|
||||
std::string dt_str1 = "2023-05-10 10:15:00.000000";
|
||||
std::string format = "%Y-%m-%d %H:%i:%s.%f";
|
||||
EXPECT_TRUE(dt1.from_date_format_str(format.data(), format.size(), dt_str1.data(),
|
||||
dt_str1.size()));
|
||||
|
||||
DateV2Value<DateTimeV2ValueType> dt2;
|
||||
std::string dt_str2 = "2023-05-10 10:15:59.999999";
|
||||
EXPECT_TRUE(dt2.from_date_format_str(format.data(), format.size(), dt_str2.data(),
|
||||
dt_str2.size()));
|
||||
|
||||
EXPECT_EQ(datetime_diff<TimeUnit::MINUTE>(dt1, dt2), 0);
|
||||
}
|
||||
|
||||
// Test 2.4: Minute rounding - exactly 1 minute
|
||||
{
|
||||
DateV2Value<DateTimeV2ValueType> dt1;
|
||||
std::string dt_str1 = "2023-05-10 10:15:00.000000";
|
||||
std::string format = "%Y-%m-%d %H:%i:%s.%f";
|
||||
EXPECT_TRUE(dt1.from_date_format_str(format.data(), format.size(), dt_str1.data(),
|
||||
dt_str1.size()));
|
||||
|
||||
DateV2Value<DateTimeV2ValueType> dt2;
|
||||
std::string dt_str2 = "2023-05-10 10:16:00.000000";
|
||||
EXPECT_TRUE(dt2.from_date_format_str(format.data(), format.size(), dt_str2.data(),
|
||||
dt_str2.size()));
|
||||
|
||||
EXPECT_EQ(datetime_diff<TimeUnit::MINUTE>(dt1, dt2), 1);
|
||||
}
|
||||
|
||||
// Test 2.5: Second rounding - less than 1 second should truncate to 0
|
||||
{
|
||||
DateV2Value<DateTimeV2ValueType> dt1;
|
||||
std::string dt_str1 = "2023-05-10 10:15:30.000000";
|
||||
std::string format = "%Y-%m-%d %H:%i:%s.%f";
|
||||
EXPECT_TRUE(dt1.from_date_format_str(format.data(), format.size(), dt_str1.data(),
|
||||
dt_str1.size()));
|
||||
|
||||
DateV2Value<DateTimeV2ValueType> dt2;
|
||||
std::string dt_str2 = "2023-05-10 10:15:30.999999";
|
||||
EXPECT_TRUE(dt2.from_date_format_str(format.data(), format.size(), dt_str2.data(),
|
||||
dt_str2.size()));
|
||||
|
||||
EXPECT_EQ(datetime_diff<TimeUnit::SECOND>(dt1, dt2), 0);
|
||||
}
|
||||
|
||||
// Test 2.6: Second rounding - exactly 1 second
|
||||
{
|
||||
DateV2Value<DateTimeV2ValueType> dt1;
|
||||
std::string dt_str1 = "2023-05-10 10:15:30.000000";
|
||||
std::string format = "%Y-%m-%d %H:%i:%s.%f";
|
||||
EXPECT_TRUE(dt1.from_date_format_str(format.data(), format.size(), dt_str1.data(),
|
||||
dt_str1.size()));
|
||||
|
||||
DateV2Value<DateTimeV2ValueType> dt2;
|
||||
std::string dt_str2 = "2023-05-10 10:15:31.000000";
|
||||
EXPECT_TRUE(dt2.from_date_format_str(format.data(), format.size(), dt_str2.data(),
|
||||
dt_str2.size()));
|
||||
|
||||
EXPECT_EQ(datetime_diff<TimeUnit::SECOND>(dt1, dt2), 1);
|
||||
}
|
||||
|
||||
// Test 2.7: Mixed unit truncating case - complex example with multiple units
|
||||
{
|
||||
DateV2Value<DateTimeV2ValueType> dt1;
|
||||
std::string dt_str1 = "2023-05-10 10:00:00.000000";
|
||||
std::string format = "%Y-%m-%d %H:%i:%s.%f";
|
||||
EXPECT_TRUE(dt1.from_date_format_str(format.data(), format.size(), dt_str1.data(),
|
||||
dt_str1.size()));
|
||||
|
||||
DateV2Value<DateTimeV2ValueType> dt2;
|
||||
std::string dt_str2 = "2023-05-10 11:29:45.750000";
|
||||
EXPECT_TRUE(dt2.from_date_format_str(format.data(), format.size(), dt_str2.data(),
|
||||
dt_str2.size()));
|
||||
|
||||
EXPECT_EQ(datetime_diff<TimeUnit::HOUR>(dt1, dt2),
|
||||
1); // 1h 29m 45.75s = 1.496h, truncates to 1
|
||||
EXPECT_EQ(datetime_diff<TimeUnit::MINUTE>(dt1, dt2),
|
||||
89); // 1h 29m 45.75s = 89.7625m, truncates to 89
|
||||
EXPECT_EQ(datetime_diff<TimeUnit::SECOND>(dt1, dt2),
|
||||
5385); // 1h 29m 45.75s = 5385.75s, truncates to 5385
|
||||
}
|
||||
|
||||
// Test 2.8: Negative differences with truncating - less than 1 unit
|
||||
{
|
||||
DateV2Value<DateTimeV2ValueType> dt1;
|
||||
std::string dt_str1 = "2023-05-10 10:15:00.000000";
|
||||
std::string format = "%Y-%m-%d %H:%i:%s.%f";
|
||||
EXPECT_TRUE(dt1.from_date_format_str(format.data(), format.size(), dt_str1.data(),
|
||||
dt_str1.size()));
|
||||
|
||||
DateV2Value<DateTimeV2ValueType> dt2;
|
||||
std::string dt_str2 = "2023-05-10 10:14:30.250000";
|
||||
EXPECT_TRUE(dt2.from_date_format_str(format.data(), format.size(), dt_str2.data(),
|
||||
dt_str2.size()));
|
||||
|
||||
EXPECT_EQ(datetime_diff<TimeUnit::MINUTE>(dt1, dt2), 0); // -0.5m truncates to 0
|
||||
EXPECT_EQ(datetime_diff<TimeUnit::SECOND>(dt1, dt2), -29); // -29.75s truncates to -29
|
||||
}
|
||||
|
||||
// Test 2.9: Negative differences with truncating - exact unit
|
||||
{
|
||||
DateV2Value<DateTimeV2ValueType> dt1;
|
||||
std::string dt_str1 = "2023-05-10 10:15:00.000000";
|
||||
std::string format = "%Y-%m-%d %H:%i:%s.%f";
|
||||
EXPECT_TRUE(dt1.from_date_format_str(format.data(), format.size(), dt_str1.data(),
|
||||
dt_str1.size()));
|
||||
|
||||
DateV2Value<DateTimeV2ValueType> dt2;
|
||||
std::string dt_str2 = "2023-05-10 10:14:00.000000";
|
||||
EXPECT_TRUE(dt2.from_date_format_str(format.data(), format.size(), dt_str2.data(),
|
||||
dt_str2.size()));
|
||||
|
||||
EXPECT_EQ(datetime_diff<TimeUnit::MINUTE>(dt1, dt2), -1); // Exactly -1 minute
|
||||
EXPECT_EQ(datetime_diff<TimeUnit::SECOND>(dt1, dt2), -60); // Exactly -60 seconds
|
||||
}
|
||||
|
||||
// Test 2.10: Negative differences with truncating - complex example
|
||||
{
|
||||
DateV2Value<DateTimeV2ValueType> dt1;
|
||||
std::string dt_str1 = "2023-05-10 11:30:30.750000";
|
||||
std::string format = "%Y-%m-%d %H:%i:%s.%f";
|
||||
EXPECT_TRUE(dt1.from_date_format_str(format.data(), format.size(), dt_str1.data(),
|
||||
dt_str1.size()));
|
||||
|
||||
DateV2Value<DateTimeV2ValueType> dt2;
|
||||
std::string dt_str2 = "2023-05-10 10:00:00.000000";
|
||||
EXPECT_TRUE(dt2.from_date_format_str(format.data(), format.size(), dt_str2.data(),
|
||||
dt_str2.size()));
|
||||
|
||||
EXPECT_EQ(datetime_diff<TimeUnit::HOUR>(dt1, dt2),
|
||||
-1); // -1h 30m 30.75s = -1.5085h, truncates to -1
|
||||
EXPECT_EQ(datetime_diff<TimeUnit::MINUTE>(dt1, dt2),
|
||||
-90); // -1h 30m 30.75s = -90.5125m, truncates to -90
|
||||
EXPECT_EQ(datetime_diff<TimeUnit::SECOND>(dt1, dt2),
|
||||
-5430); // -1h 30m 30.75s = -5430.75s, truncates to -5430
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace doris::vectorized
|
||||
|
||||
@ -0,0 +1,43 @@
|
||||
-- This file is automatically generated. You should know what you did if you want to edit this
|
||||
-- !sql_diff1 --
|
||||
0
|
||||
|
||||
-- !sql_diff2 --
|
||||
0
|
||||
|
||||
-- !sql_diff3 --
|
||||
0
|
||||
|
||||
-- !sql_diff4 --
|
||||
1
|
||||
|
||||
-- !sql_diff5 --
|
||||
23
|
||||
|
||||
-- !sql_diff6 --
|
||||
24
|
||||
|
||||
-- !sql_diff7 --
|
||||
1439
|
||||
|
||||
-- !sql_diff8 --
|
||||
1440
|
||||
|
||||
-- !sql_diff9 --
|
||||
86399
|
||||
|
||||
-- !sql_diff10 --
|
||||
86400
|
||||
|
||||
-- !sql_diff11 --
|
||||
86399900
|
||||
|
||||
-- !sql_diff12 --
|
||||
86400000
|
||||
|
||||
-- !sql_diff13 --
|
||||
86399900000
|
||||
|
||||
-- !sql_diff14 --
|
||||
86400000000
|
||||
|
||||
@ -1766,7 +1766,7 @@
|
||||
2022-05-18T12:00:00.123 2022-05-18T23:10:00.123456 4 ["2022-05-18 12:00:00", "2022-05-18 16:00:00", "2022-05-18 20:00:00"]
|
||||
|
||||
-- !table_select --
|
||||
2022-05-18T12:00:00.123 2022-05-18T12:16 5 ["2022-05-18 12:00:00", "2022-05-18 12:05:00", "2022-05-18 12:10:00", "2022-05-18 12:15:00"]
|
||||
2022-05-18T12:00:00.123 2022-05-18T12:16 5 ["2022-05-18 12:00:00", "2022-05-18 12:05:00", "2022-05-18 12:10:00"]
|
||||
|
||||
-- !table_select --
|
||||
2022-05-18T12:00:10 2022-05-18T12:00:30 6 ["2022-05-18 12:00:10", "2022-05-18 12:00:16", "2022-05-18 12:00:22", "2022-05-18 12:00:28"]
|
||||
|
||||
@ -0,0 +1,53 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
suite("test_date_function_v2") {
|
||||
sql """
|
||||
admin set frontend config ("enable_date_conversion"="true");
|
||||
"""
|
||||
|
||||
qt_sql_diff1 "select days_diff('2023-10-15 00:00:00', '2023-10-14 00:00:00.1');"
|
||||
testFoldConst("select days_diff('2023-10-15 00:00:00', '2023-10-14 00:00:00.1');")
|
||||
qt_sql_diff2 "select days_diff('2023-10-15 00:00:00', '2023-10-14 00:00:00.1');"
|
||||
testFoldConst("select days_diff('2023-10-15 00:00:00', '2023-10-14 00:00:00.1');")
|
||||
|
||||
qt_sql_diff3 "select weeks_diff('2023-10-15 00:00:00', '2023-10-08 00:00:00.1');"
|
||||
testFoldConst("select weeks_diff('2023-10-15 00:00:00', '2023-10-08 00:00:00.1');")
|
||||
qt_sql_diff4 "select weeks_diff('2023-10-15 00:00:00', '2023-10-08 00:00:00');"
|
||||
testFoldConst("select weeks_diff('2023-10-15 00:00:00', '2023-10-08 00:00:00');")
|
||||
|
||||
qt_sql_diff5 "select hours_diff('2023-10-15 00:00:00', '2023-10-14 00:00:00.1');"
|
||||
testFoldConst("select hours_diff('2023-10-15 00:00:00', '2023-10-14 00:00:00.1');")
|
||||
qt_sql_diff6 "select hours_diff('2023-10-15 00:00:00', '2023-10-14 00:00:00');"
|
||||
testFoldConst("select hours_diff('2023-10-15 00:00:00', '2023-10-14 00:00:00');")
|
||||
qt_sql_diff7 "select minutes_diff('2023-10-15 00:00:00', '2023-10-14 00:00:00.1');"
|
||||
testFoldConst("select minutes_diff('2023-10-15 00:00:00', '2023-10-14 00:00:00.1');")
|
||||
qt_sql_diff8 "select minutes_diff('2023-10-15 00:00:00', '2023-10-14 00:00:00');"
|
||||
testFoldConst("select minutes_diff('2023-10-15 00:00:00', '2023-10-14 00:00:00');")
|
||||
qt_sql_diff9 "select seconds_diff('2023-10-15 00:00:00', '2023-10-14 00:00:00.1');"
|
||||
testFoldConst("select seconds_diff('2023-10-15 00:00:00', '2023-10-14 00:00:00.1');")
|
||||
qt_sql_diff10 "select seconds_diff('2023-10-15 00:00:00', '2023-10-14 00:00:00');"
|
||||
testFoldConst("select seconds_diff('2023-10-15 00:00:00', '2023-10-14 00:00:00');")
|
||||
qt_sql_diff11 "select milliseconds_diff('2023-10-15 00:00:00', '2023-10-14 00:00:00.1');"
|
||||
testFoldConst("select milliseconds_diff('2023-10-15 00:00:00', '2023-10-14 00:00:00.1');")
|
||||
qt_sql_diff12 "select milliseconds_diff('2023-10-15 00:00:00', '2023-10-14 00:00:00');"
|
||||
testFoldConst("select milliseconds_diff('2023-10-15 00:00:00', '2023-10-14 00:00:00');")
|
||||
qt_sql_diff13 "select microseconds_diff('2023-10-15 00:00:00', '2023-10-14 00:00:00.1');"
|
||||
testFoldConst("select microseconds_diff('2023-10-15 00:00:00', '2023-10-14 00:00:00.1');")
|
||||
qt_sql_diff14 "select microseconds_diff('2023-10-15 00:00:00', '2023-10-14 00:00:00');"
|
||||
testFoldConst("select microseconds_diff('2023-10-15 00:00:00', '2023-10-14 00:00:00');")
|
||||
}
|
||||
Reference in New Issue
Block a user