Add new function toLastDayOfMonth

This commit is contained in:
Habibullah Oladepo 2022-02-07 21:38:36 +01:00
parent 15bcbb97e5
commit 57ff05b6e6
7 changed files with 83 additions and 2 deletions

View File

@ -393,6 +393,13 @@ This is a generalization of other functions named `toStartOf*`. For example,
`toStartOfInterval(t, INTERVAL 1 day)` returns the same as `toStartOfDay(t)`,
`toStartOfInterval(t, INTERVAL 15 minute)` returns the same as `toStartOfFifteenMinutes(t)` etc.
## toLastDayOfMonth {#toLastDayOfMonth}
Rounds up a date or date with time to the last day of the month.
Returns the date.
Alias: `LAST_DAY`.
## toTime {#totime}
Converts a date with time to a certain fixed date, while preserving the time.

View File

@ -360,6 +360,27 @@ public:
return toDayNum(LUTIndex(i - (lut[i].day_of_month - 1)));
}
/// Round up to last day of month.
template <typename DateOrTime>
inline Time toLastDayOfMonth(DateOrTime v) const
{
const LUTIndex i = toLUTIndex(v);
if constexpr (std::is_unsigned_v<DateOrTime> || std::is_same_v<DateOrTime, DayNum>)
return lut_saturated[i - lut[i].day_of_month + lut[i].days_in_month].date;
else
return lut[i - lut[i].day_of_month + lut[i].days_in_month].date;
}
template <typename DateOrTime>
inline auto toLastDayNumOfMonth(DateOrTime v) const
{
const LUTIndex i = toLUTIndex(v);
if constexpr (std::is_unsigned_v<DateOrTime> || std::is_same_v<DateOrTime, DayNum>)
return toDayNum(LUTIndexWithSaturation(i - lut[i].day_of_month + lut[i].days_in_month));
else
return toDayNum(LUTIndex(i - lut[i].day_of_month + lut[i].days_in_month));
}
/// Round down to start of quarter.
template <typename DateOrTime>
inline auto toFirstDayNumOfQuarter(DateOrTime v) const

View File

@ -142,6 +142,8 @@ TEST(DateLUTTest, TimeValuesInMiddleOfRange)
EXPECT_EQ(lut.addYears(time, 10), 1884270011 /*time_t*/);
EXPECT_EQ(lut.timeToString(time), "2019-09-16 19:20:11" /*std::string*/);
EXPECT_EQ(lut.dateToString(time), "2019-09-16" /*std::string*/);
EXPECT_EQ(lut.toLastDayOfMonth(time), 1569790800 /*time_t*/);
EXPECT_EQ(lut.toLastDayNumOfMonth(time), DayNum(18169) /*DayNum*/);
}
@ -202,6 +204,8 @@ TEST(DateLUTTest, TimeValuesAtLeftBoderOfRange)
EXPECT_EQ(lut.addYears(time, 10), 315532800 /*time_t*/);
EXPECT_EQ(lut.timeToString(time), "1970-01-01 00:00:00" /*std::string*/);
EXPECT_EQ(lut.dateToString(time), "1970-01-01" /*std::string*/);
EXPECT_EQ(lut.toLastDayOfMonth(time), 2592000 /*time_t*/);
EXPECT_EQ(lut.toLastDayNumOfMonth(time), DayNum(30) /*DayNum*/);
}
TEST(DateLUTTest, TimeValuesAtRightBoderOfRangeOfOldLUT)
@ -264,6 +268,8 @@ TEST(DateLUTTest, TimeValuesAtRightBoderOfRangeOfOldLUT)
EXPECT_EQ(lut.timeToString(time), "2106-01-31 01:17:53" /*std::string*/);
EXPECT_EQ(lut.dateToString(time), "2106-01-31" /*std::string*/);
EXPECT_EQ(lut.toLastDayOfMonth(time), 4294339200 /*time_t*/); // 2016-01-01
EXPECT_EQ(lut.toLastDayNumOfMonth(time), DayNum(49703));
}

View File

@ -174,6 +174,30 @@ struct ToStartOfMonthImpl
using FactorTransform = ZeroTransform;
};
struct ToLastDayOfMonthImpl
{
static constexpr auto name = "toLastDayOfMonth";
static inline UInt16 execute(Int64 t, const DateLUTImpl & time_zone)
{
return time_zone.toLastDayNumOfMonth(time_zone.toDayNum(t));
}
static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone)
{
return time_zone.toLastDayNumOfMonth(time_zone.toDayNum(t));
}
static inline UInt16 execute(Int32 d, const DateLUTImpl & time_zone)
{
return time_zone.toLastDayNumOfMonth(ExtendedDayNum(d));
}
static inline UInt16 execute(UInt16 d, const DateLUTImpl & time_zone)
{
return time_zone.toLastDayNumOfMonth(DayNum(d));
}
using FactorTransform = ZeroTransform;
};
struct ToStartOfQuarterImpl
{
static constexpr auto name = "toStartOfQuarter";

View File

@ -20,6 +20,7 @@ void registerFunctionToISOYear(FunctionFactory &);
void registerFunctionToCustomWeek(FunctionFactory &);
void registerFunctionToModifiedJulianDay(FunctionFactory &);
void registerFunctionToStartOfMonth(FunctionFactory &);
void registerFunctionToLastDayOfMonth(FunctionFactory &);
void registerFunctionToStartOfQuarter(FunctionFactory &);
void registerFunctionToStartOfYear(FunctionFactory &);
void registerFunctionToStartOfMinute(FunctionFactory &);
@ -91,6 +92,7 @@ void registerFunctionsDateTime(FunctionFactory & factory)
registerFunctionToCustomWeek(factory);
registerFunctionToModifiedJulianDay(factory);
registerFunctionToStartOfMonth(factory);
registerFunctionToLastDayOfMonth(factory);
registerFunctionToStartOfQuarter(factory);
registerFunctionToStartOfYear(factory);
registerFunctionToStartOfSecond(factory);

View File

@ -0,0 +1,21 @@
#include <Functions/FunctionFactory.h>
#include <Functions/DateTimeTransforms.h>
#include <Functions/FunctionDateOrDateTimeToSomething.h>
namespace DB
{
using FunctionToLastDayOfMonth = FunctionDateOrDateTimeToSomething<DataTypeDate, ToLastDayOfMonthImpl>;
void registerFunctionToLastDayOfMonth(FunctionFactory & factory)
{
factory.registerFunction<FunctionToLastDayOfMonth>();
/// MysQL compatibility alias.
factory.registerFunction<FunctionToLastDayOfMonth>("LAST_DAY", FunctionFactory::CaseInsensitive);
}
}

View File

@ -229,7 +229,7 @@ std::map<std::string, FuncRet> func_to_return_type = {
{"torelativeweeknum", FuncRet(Type::i, "")}, {"torelativedaynum", FuncRet(Type::i, "")}, {"torelativehournum", FuncRet(Type::i, "")},
{"torelativeminutenum", FuncRet(Type::i, "")}, {"torelativesecondsnum", FuncRet(Type::i, "")}, {"datediff", FuncRet(Type::d | Type::dt, "")},
{"formatdatetime", FuncRet(Type::s, "")}, {"now", FuncRet(Type::dt | Type::d, "now()")}, {"today", FuncRet(Type::d | Type::dt, "today()")},
{"yesterday", FuncRet(Type::d | Type::dt, "yesterday()")}
{"yesterday", FuncRet(Type::d | Type::dt, "yesterday()")}, {"tolastdayofmonth", FuncRet(Type::dt | Type::d, "")}
};
std::set<std::string> func_args_same_types = {
@ -253,7 +253,7 @@ std::map<std::string, ColumnType> func_to_param_type = {
{"tostartofinterval", Type::d | Type::dt}, {"totime", Type::d | Type::dt}, {"torelativehonthnum", Type::d | Type::dt},
{"torelativeweeknum", Type::d | Type::dt}, {"torelativedaynum", Type::d | Type::dt}, {"torelativehournum", Type::d | Type::dt},
{"torelativeminutenum", Type::d | Type::dt}, {"torelativesecondnum", Type::d | Type::dt}, {"datediff", Type::d | Type::dt},
{"formatdatetime", Type::dt}
{"formatdatetime", Type::dt}, {"tolastdayofmonth", Type::d | Type::dt}
};