diff --git a/dbms/src/DataTypes/DataTypeInterval.cpp b/dbms/src/DataTypes/DataTypeInterval.cpp index ab2993b884a..c7ee3ede334 100644 --- a/dbms/src/DataTypes/DataTypeInterval.cpp +++ b/dbms/src/DataTypes/DataTypeInterval.cpp @@ -19,6 +19,7 @@ void registerDataTypeInterval(DataTypeFactory & factory) factory.registerSimpleDataType("IntervalDay", [] { return DataTypePtr(std::make_shared(DataTypeInterval::Day)); }); factory.registerSimpleDataType("IntervalWeek", [] { return DataTypePtr(std::make_shared(DataTypeInterval::Week)); }); factory.registerSimpleDataType("IntervalMonth", [] { return DataTypePtr(std::make_shared(DataTypeInterval::Month)); }); + factory.registerSimpleDataType("IntervalQuarter", [] { return DataTypePtr(std::make_shared(DataTypeInterval::Quarter)); }); factory.registerSimpleDataType("IntervalYear", [] { return DataTypePtr(std::make_shared(DataTypeInterval::Year)); }); } diff --git a/dbms/src/DataTypes/DataTypeInterval.h b/dbms/src/DataTypes/DataTypeInterval.h index afbcf2d6a45..6f4f08c16c0 100644 --- a/dbms/src/DataTypes/DataTypeInterval.h +++ b/dbms/src/DataTypes/DataTypeInterval.h @@ -25,6 +25,7 @@ public: Day, Week, Month, + Quarter, Year }; @@ -46,6 +47,7 @@ public: case Day: return "Day"; case Week: return "Week"; case Month: return "Month"; + case Quarter: return "Quarter"; case Year: return "Year"; default: __builtin_unreachable(); } diff --git a/dbms/src/Functions/FunctionDateOrDateTimeAddInterval.h b/dbms/src/Functions/FunctionDateOrDateTimeAddInterval.h index c4b7639908f..9b27282ec19 100644 --- a/dbms/src/Functions/FunctionDateOrDateTimeAddInterval.h +++ b/dbms/src/Functions/FunctionDateOrDateTimeAddInterval.h @@ -113,6 +113,21 @@ struct AddMonthsImpl } }; +struct AddQuartersImpl +{ + static constexpr auto name = "addQuarters"; + + static inline UInt32 execute(UInt32 t, Int64 delta, const DateLUTImpl & time_zone) + { + return time_zone.addQuarters(t, delta); + } + + static inline UInt16 execute(UInt16 d, Int64 delta, const DateLUTImpl & time_zone) + { + return time_zone.addQuarters(DayNum(d), delta); + } +}; + struct AddYearsImpl { static constexpr auto name = "addYears"; @@ -149,6 +164,7 @@ struct SubtractHoursImpl : SubtractIntervalImpl { static constexpr struct SubtractDaysImpl : SubtractIntervalImpl { static constexpr auto name = "subtractDays"; }; struct SubtractWeeksImpl : SubtractIntervalImpl { static constexpr auto name = "subtractWeeks"; }; struct SubtractMonthsImpl : SubtractIntervalImpl { static constexpr auto name = "subtractMonths"; }; +struct SubtractQuartersImpl : SubtractIntervalImpl { static constexpr auto name = "subtractQuarters"; }; struct SubtractYearsImpl : SubtractIntervalImpl { static constexpr auto name = "subtractYears"; }; diff --git a/dbms/src/Functions/FunctionsConversion.cpp b/dbms/src/Functions/FunctionsConversion.cpp index fdfc153f594..a83a756010c 100644 --- a/dbms/src/Functions/FunctionsConversion.cpp +++ b/dbms/src/Functions/FunctionsConversion.cpp @@ -89,6 +89,7 @@ void registerFunctionsConversion(FunctionFactory & factory) factory.registerFunction>(); factory.registerFunction>(); factory.registerFunction>(); + factory.registerFunction>(); factory.registerFunction>(); } diff --git a/dbms/src/Functions/FunctionsConversion.h b/dbms/src/Functions/FunctionsConversion.h index 1428fec4f48..6b42bec10df 100644 --- a/dbms/src/Functions/FunctionsConversion.h +++ b/dbms/src/Functions/FunctionsConversion.h @@ -738,6 +738,7 @@ DEFINE_NAME_TO_INTERVAL(Hour) DEFINE_NAME_TO_INTERVAL(Day) DEFINE_NAME_TO_INTERVAL(Week) DEFINE_NAME_TO_INTERVAL(Month) +DEFINE_NAME_TO_INTERVAL(Quarter) DEFINE_NAME_TO_INTERVAL(Year) #undef DEFINE_NAME_TO_INTERVAL diff --git a/dbms/src/Functions/addQuarters.cpp b/dbms/src/Functions/addQuarters.cpp new file mode 100644 index 00000000000..c37fb5561c8 --- /dev/null +++ b/dbms/src/Functions/addQuarters.cpp @@ -0,0 +1,18 @@ +#include +#include +#include + + +namespace DB +{ + +using FunctionAddQuarters = FunctionDateOrDateTimeAddInterval; + +void registerFunctionAddQuarters(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + diff --git a/dbms/src/Functions/registerFunctionsDateTime.cpp b/dbms/src/Functions/registerFunctionsDateTime.cpp index 3e7f2a6affd..fe2734a7b75 100644 --- a/dbms/src/Functions/registerFunctionsDateTime.cpp +++ b/dbms/src/Functions/registerFunctionsDateTime.cpp @@ -47,6 +47,7 @@ void registerFunctionAddHours(FunctionFactory &); void registerFunctionAddDays(FunctionFactory &); void registerFunctionAddWeeks(FunctionFactory &); void registerFunctionAddMonths(FunctionFactory &); +void registerFunctionAddQuarters(FunctionFactory &); void registerFunctionAddYears(FunctionFactory &); void registerFunctionSubtractSeconds(FunctionFactory &); void registerFunctionSubtractMinutes(FunctionFactory &); @@ -54,6 +55,7 @@ void registerFunctionSubtractHours(FunctionFactory &); void registerFunctionSubtractDays(FunctionFactory &); void registerFunctionSubtractWeeks(FunctionFactory &); void registerFunctionSubtractMonths(FunctionFactory &); +void registerFunctionSubtractQuarters(FunctionFactory &); void registerFunctionSubtractYears(FunctionFactory &); void registerFunctionDateDiff(FunctionFactory &); void registerFunctionToTimeZone(FunctionFactory &); @@ -106,13 +108,14 @@ void registerFunctionsDateTime(FunctionFactory & factory) registerFunctionAddDays(factory); registerFunctionAddWeeks(factory); registerFunctionAddMonths(factory); + registerFunctionAddQuarters(factory); registerFunctionAddYears(factory); registerFunctionSubtractSeconds(factory); registerFunctionSubtractMinutes(factory); registerFunctionSubtractHours(factory); registerFunctionSubtractDays(factory); registerFunctionSubtractWeeks(factory); - registerFunctionSubtractMonths(factory); + registerFunctionSubtractQuarters(factory); registerFunctionSubtractYears(factory); registerFunctionDateDiff(factory); registerFunctionToTimeZone(factory); diff --git a/dbms/src/Functions/subtractQuarters.cpp b/dbms/src/Functions/subtractQuarters.cpp new file mode 100644 index 00000000000..6c066ed17a1 --- /dev/null +++ b/dbms/src/Functions/subtractQuarters.cpp @@ -0,0 +1,18 @@ +#include +#include +#include + + +namespace DB +{ + +using FunctionSubtractQuarters = FunctionDateOrDateTimeAddInterval; + +void registerFunctionSubtractQuarters(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} + + diff --git a/dbms/src/Parsers/ExpressionListParsers.cpp b/dbms/src/Parsers/ExpressionListParsers.cpp index ef75267cffe..9365606f5dd 100644 --- a/dbms/src/Parsers/ExpressionListParsers.cpp +++ b/dbms/src/Parsers/ExpressionListParsers.cpp @@ -621,6 +621,8 @@ bool ParserIntervalOperatorExpression::parseImpl(Pos & pos, ASTPtr & node, Expec function_name = "toIntervalWeek"; else if (ParserKeyword("MONTH").ignore(pos, expected)) function_name = "toIntervalMonth"; + else if (ParserKeyword("QUARTER").ignore(pos, expected)) + function_name = "toIntervalQuarter"; else if (ParserKeyword("YEAR").ignore(pos, expected)) function_name = "toIntervalYear"; else diff --git a/dbms/tests/queries/0_stateless/00514_interval_operators.reference b/dbms/tests/queries/0_stateless/00514_interval_operators.reference index 8af8f56eb87..43238eecb3d 100644 --- a/dbms/tests/queries/0_stateless/00514_interval_operators.reference +++ b/dbms/tests/queries/0_stateless/00514_interval_operators.reference @@ -36,3 +36,4 @@ 2029-02-28 01:02:03 2017-03-29 01:02:03 2030-02-28 01:02:03 2017-04-29 01:02:03 2031-02-28 01:02:03 2017-05-29 01:02:03 +2015-11-29 01:02:03 diff --git a/dbms/tests/queries/0_stateless/00514_interval_operators.sql b/dbms/tests/queries/0_stateless/00514_interval_operators.sql index 9dc2f67322b..a4b6c983abf 100644 --- a/dbms/tests/queries/0_stateless/00514_interval_operators.sql +++ b/dbms/tests/queries/0_stateless/00514_interval_operators.sql @@ -2,3 +2,4 @@ SELECT toDateTime('2017-10-30 08:18:19') + INTERVAL 1 DAY + INTERVAL 1 MONTH - I SELECT toDateTime('2017-10-30 08:18:19') + INTERVAL 1 HOUR + INTERVAL 1000 MINUTE + INTERVAL 10 SECOND; SELECT toDateTime('2017-10-30 08:18:19') + INTERVAL 1 DAY + INTERVAL number MONTH FROM system.numbers LIMIT 20; SELECT toDateTime('2016-02-29 01:02:03') + INTERVAL number YEAR, toDateTime('2016-02-29 01:02:03') + INTERVAL number MONTH FROM system.numbers LIMIT 16; +SELECT toDateTime('2016-02-29 01:02:03') - INTERVAL 1 QUARTER; diff --git a/libs/libcommon/include/common/DateLUTImpl.h b/libs/libcommon/include/common/DateLUTImpl.h index 56d9cc04dd1..55a94f3733a 100644 --- a/libs/libcommon/include/common/DateLUTImpl.h +++ b/libs/libcommon/include/common/DateLUTImpl.h @@ -584,6 +584,16 @@ public: } } + inline time_t addQuarters(time_t t, Int64 delta) const + { + return addMonths(t, delta * 3); + } + + inline DayNum addQuarters(DayNum d, Int64 delta) const + { + return addMonths(d, delta * 3); + } + /// Saturation can occur if 29 Feb is mapped to non-leap year. inline time_t addYears(time_t t, Int64 delta) const {