This commit is contained in:
Robert Schulze 2023-09-11 12:40:49 +00:00
parent 08bad4d440
commit 73ce1993fb
No known key found for this signature in database
GPG Key ID: 26703B55FB13728A
9 changed files with 900 additions and 158 deletions

View File

@ -1290,6 +1290,8 @@ Rounds the time to the half hour.
Converts a date or date with time to a UInt32 number containing the year and month number (YYYY \* 100 + MM). Accepts a second optional timezone argument. If provided, the timezone must be a string constant.
This functions is the opposite of function `YYYYMMDDToDate()`.
**Example**
``` sql
@ -1312,8 +1314,7 @@ Converts a date or date with time to a UInt32 number containing the year and mon
**Example**
```sql
SELECT
toYYYYMMDD(now(), 'US/Eastern')
SELECT toYYYYMMDD(now(), 'US/Eastern')
```
Result:
@ -1331,8 +1332,7 @@ Converts a date or date with time to a UInt64 number containing the year and mon
**Example**
```sql
SELECT
toYYYYMMDDhhmmss(now(), 'US/Eastern')
SELECT toYYYYMMDDhhmmss(now(), 'US/Eastern')
```
Result:
@ -1343,6 +1343,93 @@ Result:
└───────────────────────────────────────┘
```
## YYYYMMDDToDate
Converts a number containing the year, month and day number to a [Date](../../sql-reference/data-types/date.md).
This functions is the opposite of function `toYYYYMMDD()`.
The output is undefined if the input does not encode a valid Date value.
**Syntax**
```sql
YYYYMMDDToDate(yyyymmdd);
```
**Arguments**
- `yyyymmdd` - A number representing the year, month and day. [Integer](../../sql-reference/data-types/int-uint.md), [Float](../../sql-reference/data-types/float.md) or [Decimal](../../sql-reference/data-types/decimal.md).
**Returned value**
- a date created from the arguments.
Type: [Date](../../sql-reference/data-types/date.md).
**Example**
```sql
SELECT YYYYMMDDToDate(20230911);
```
Result:
```response
┌─toYYYYMMDD(20230911)─┐
│ 2023-09-11 │
└──────────────────────┘
```
## YYYYMMDDToDate32
Like function `YYYYMMDDToDate()` but produces a [Date32](../../sql-reference/data-types/date32.md).
## YYYYMMDDhhmmssToDateTime
Converts a number containing the year, month and day number to a [DateTime](../../sql-reference/data-types/datetime.md).
The output is undefined if the input does not encode a valid DateTime value.
This functions is the opposite of function `toYYYYMMDD()`.
**Syntax**
```sql
YYYYMMDDhhmmssToDateTime(yyyymmddhhmmss[, timezone]);
```
**Arguments**
- `yyyymmddhhmmss` - A number representing the year, month and day. [Integer](../../sql-reference/data-types/int-uint.md), [Float](../../sql-reference/data-types/float.md) or [Decimal](../../sql-reference/data-types/decimal.md).
- `timezone` - [Timezone](../../operations/server-configuration-parameters/settings.md#server_configuration_parameters-timezone) for the returned value (optional).
**Returned value**
- a date with time created from the arguments.
Type: [DateTime](../../sql-reference/data-types/datetime.md).
**Example**
```sql
SELECT YYYYMMDDToDateTime(20230911131415);
```
Result:
```response
┌────toYYYYMMDDhhmmssToDateTime(20230911131415)─┐
│ 2023-09-11 13:14:15 │
└───────────────────────────────────────────────┘
```
## YYYYMMDDhhmmssToDateTime64
Like function `YYYYMMDDhhmmssToDate()` but produces a [DateTime64](../../sql-reference/data-types/datetime64.md).
Accepts an additional, optional `precision` parameter after the `timezone` parameter.
## addYears, addMonths, addWeeks, addDays, addHours, addMinutes, addSeconds, addQuarters
Function adds a Date/DateTime interval to a Date/DateTime and then return the Date/DateTime. For example:

View File

@ -71,14 +71,14 @@ private:
// Same as above but select different function overloads for zero saturation.
STRONG_TYPEDEF(UInt32, LUTIndexWithSaturation)
static inline LUTIndex normalizeLUTIndex(UInt32 index)
static LUTIndex normalizeLUTIndex(UInt32 index)
{
if (index >= DATE_LUT_SIZE)
return LUTIndex(DATE_LUT_SIZE - 1);
return LUTIndex{index};
}
static inline LUTIndex normalizeLUTIndex(Int64 index)
static LUTIndex normalizeLUTIndex(Int64 index)
{
if (unlikely(index < 0))
return LUTIndex(0);
@ -88,59 +88,59 @@ private:
}
template <typename T>
friend inline LUTIndex operator+(const LUTIndex & index, const T v)
friend LUTIndex operator+(const LUTIndex & index, const T v)
{
return normalizeLUTIndex(index.toUnderType() + UInt32(v));
}
template <typename T>
friend inline LUTIndex operator+(const T v, const LUTIndex & index)
friend LUTIndex operator+(const T v, const LUTIndex & index)
{
return normalizeLUTIndex(static_cast<Int64>(v + index.toUnderType()));
}
friend inline LUTIndex operator+(const LUTIndex & index, const LUTIndex & v)
friend LUTIndex operator+(const LUTIndex & index, const LUTIndex & v)
{
return normalizeLUTIndex(static_cast<UInt32>(index.toUnderType() + v.toUnderType()));
}
template <typename T>
friend inline LUTIndex operator-(const LUTIndex & index, const T v)
friend LUTIndex operator-(const LUTIndex & index, const T v)
{
return normalizeLUTIndex(static_cast<Int64>(index.toUnderType() - UInt32(v)));
}
template <typename T>
friend inline LUTIndex operator-(const T v, const LUTIndex & index)
friend LUTIndex operator-(const T v, const LUTIndex & index)
{
return normalizeLUTIndex(static_cast<Int64>(v - index.toUnderType()));
}
friend inline LUTIndex operator-(const LUTIndex & index, const LUTIndex & v)
friend LUTIndex operator-(const LUTIndex & index, const LUTIndex & v)
{
return normalizeLUTIndex(static_cast<Int64>(index.toUnderType() - v.toUnderType()));
}
template <typename T>
friend inline LUTIndex operator*(const LUTIndex & index, const T v)
friend LUTIndex operator*(const LUTIndex & index, const T v)
{
return normalizeLUTIndex(index.toUnderType() * UInt32(v));
}
template <typename T>
friend inline LUTIndex operator*(const T v, const LUTIndex & index)
friend LUTIndex operator*(const T v, const LUTIndex & index)
{
return normalizeLUTIndex(v * index.toUnderType());
}
template <typename T>
friend inline LUTIndex operator/(const LUTIndex & index, const T v)
friend LUTIndex operator/(const LUTIndex & index, const T v)
{
return normalizeLUTIndex(index.toUnderType() / UInt32(v));
}
template <typename T>
friend inline LUTIndex operator/(const T v, const LUTIndex & index)
friend LUTIndex operator/(const T v, const LUTIndex & index)
{
return normalizeLUTIndex(UInt32(v) / index.toUnderType());
}
@ -172,12 +172,12 @@ public:
Int8 amount_of_offset_change_value; /// Usually -4 or 4, but look at Lord Howe Island. Multiply by OffsetChangeFactor
UInt8 time_at_offset_change_value; /// In seconds from beginning of the day. Multiply by OffsetChangeFactor
inline Int32 amount_of_offset_change() const /// NOLINT
Int32 amount_of_offset_change() const /// NOLINT
{
return static_cast<Int32>(amount_of_offset_change_value) * OffsetChangeFactor;
}
inline UInt32 time_at_offset_change() const /// NOLINT
UInt32 time_at_offset_change() const /// NOLINT
{
return static_cast<UInt32>(time_at_offset_change_value) * OffsetChangeFactor;
}
@ -221,7 +221,7 @@ private:
/// Time zone name.
std::string time_zone;
inline LUTIndex findIndex(Time t) const
LUTIndex findIndex(Time t) const
{
/// First guess.
Time guess = (t / 86400) + daynum_offset_epoch;
@ -248,34 +248,34 @@ private:
return LUTIndex(guess ? static_cast<unsigned>(guess) - 1 : 0);
}
static inline LUTIndex toLUTIndex(DayNum d)
static LUTIndex toLUTIndex(DayNum d)
{
return normalizeLUTIndex(d + daynum_offset_epoch);
}
static inline LUTIndex toLUTIndex(ExtendedDayNum d)
static LUTIndex toLUTIndex(ExtendedDayNum d)
{
return normalizeLUTIndex(static_cast<Int64>(d + daynum_offset_epoch));
}
inline LUTIndex toLUTIndex(Time t) const
LUTIndex toLUTIndex(Time t) const
{
return findIndex(t);
}
static inline LUTIndex toLUTIndex(LUTIndex i)
static LUTIndex toLUTIndex(LUTIndex i)
{
return i;
}
template <typename DateOrTime>
inline const Values & find(DateOrTime v) const
const Values & find(DateOrTime v) const
{
return lut[toLUTIndex(v)];
}
template <typename DateOrTime, typename Divisor>
inline DateOrTime roundDown(DateOrTime x, Divisor divisor) const
DateOrTime roundDown(DateOrTime x, Divisor divisor) const
{
static_assert(std::is_integral_v<DateOrTime> && std::is_integral_v<Divisor>);
assert(divisor > 0);
@ -336,7 +336,7 @@ public:
}
template <typename DateOrTime>
inline auto toDayNum(DateOrTime v) const
auto toDayNum(DateOrTime v) const
{
if constexpr (std::is_unsigned_v<DateOrTime> || std::is_same_v<DateOrTime, DayNum>)
return DayNum{static_cast<DayNum::UnderlyingType>(saturateMinus(toLUTIndex(v).toUnderType(), daynum_offset_epoch))};
@ -346,7 +346,7 @@ public:
/// Round down to start of monday.
template <typename DateOrTime>
inline Time toFirstDayOfWeek(DateOrTime v) const
Time toFirstDayOfWeek(DateOrTime v) const
{
const LUTIndex i = toLUTIndex(v);
if constexpr (std::is_unsigned_v<DateOrTime> || std::is_same_v<DateOrTime, DayNum>)
@ -356,7 +356,7 @@ public:
}
template <typename DateOrTime>
inline auto toFirstDayNumOfWeek(DateOrTime v) const
auto toFirstDayNumOfWeek(DateOrTime v) const
{
const LUTIndex i = toLUTIndex(v);
if constexpr (std::is_unsigned_v<DateOrTime> || std::is_same_v<DateOrTime, DayNum>)
@ -367,7 +367,7 @@ public:
/// Round up to the last day of week.
template <typename DateOrTime>
inline Time toLastDayOfWeek(DateOrTime v) const
Time toLastDayOfWeek(DateOrTime v) const
{
const LUTIndex i = toLUTIndex(v);
if constexpr (std::is_unsigned_v<DateOrTime> || std::is_same_v<DateOrTime, DayNum>)
@ -377,7 +377,7 @@ public:
}
template <typename DateOrTime>
inline auto toLastDayNumOfWeek(DateOrTime v) const
auto toLastDayNumOfWeek(DateOrTime v) const
{
const LUTIndex i = toLUTIndex(v);
if constexpr (std::is_unsigned_v<DateOrTime> || std::is_same_v<DateOrTime, DayNum>)
@ -388,7 +388,7 @@ public:
/// Round down to start of month.
template <typename DateOrTime>
inline Time toFirstDayOfMonth(DateOrTime v) const
Time toFirstDayOfMonth(DateOrTime v) const
{
const LUTIndex i = toLUTIndex(v);
if constexpr (std::is_unsigned_v<DateOrTime> || std::is_same_v<DateOrTime, DayNum>)
@ -398,7 +398,7 @@ public:
}
template <typename DateOrTime>
inline auto toFirstDayNumOfMonth(DateOrTime v) const
auto toFirstDayNumOfMonth(DateOrTime v) const
{
const LUTIndex i = toLUTIndex(v);
if constexpr (std::is_unsigned_v<DateOrTime> || std::is_same_v<DateOrTime, DayNum>)
@ -409,7 +409,7 @@ public:
/// Round up to last day of month.
template <typename DateOrTime>
inline Time toLastDayOfMonth(DateOrTime v) const
Time toLastDayOfMonth(DateOrTime v) const
{
const LUTIndex i = toLUTIndex(v);
if constexpr (std::is_unsigned_v<DateOrTime> || std::is_same_v<DateOrTime, DayNum>)
@ -419,7 +419,7 @@ public:
}
template <typename DateOrTime>
inline auto toLastDayNumOfMonth(DateOrTime v) const
auto toLastDayNumOfMonth(DateOrTime v) const
{
const LUTIndex i = toLUTIndex(v);
if constexpr (std::is_unsigned_v<DateOrTime> || std::is_same_v<DateOrTime, DayNum>)
@ -430,7 +430,7 @@ public:
/// Round down to start of quarter.
template <typename DateOrTime>
inline auto toFirstDayNumOfQuarter(DateOrTime v) const
auto toFirstDayNumOfQuarter(DateOrTime v) const
{
if constexpr (std::is_unsigned_v<DateOrTime> || std::is_same_v<DateOrTime, DayNum>)
return toDayNum(LUTIndexWithSaturation(toFirstDayOfQuarterIndex(v)));
@ -439,7 +439,7 @@ public:
}
template <typename DateOrTime>
inline LUTIndex toFirstDayOfQuarterIndex(DateOrTime v) const
LUTIndex toFirstDayOfQuarterIndex(DateOrTime v) const
{
LUTIndex index = toLUTIndex(v);
size_t month_inside_quarter = (lut[index].month - 1) % 3;
@ -455,25 +455,25 @@ public:
}
template <typename DateOrTime>
inline Time toFirstDayOfQuarter(DateOrTime v) const
Time toFirstDayOfQuarter(DateOrTime v) const
{
return toDate(toFirstDayOfQuarterIndex(v));
}
/// Round down to start of year.
inline Time toFirstDayOfYear(Time t) const
Time toFirstDayOfYear(Time t) const
{
return lut[years_lut[lut[findIndex(t)].year - DATE_LUT_MIN_YEAR]].date;
}
template <typename DateOrTime>
inline LUTIndex toFirstDayNumOfYearIndex(DateOrTime v) const
LUTIndex toFirstDayNumOfYearIndex(DateOrTime v) const
{
return years_lut[lut[toLUTIndex(v)].year - DATE_LUT_MIN_YEAR];
}
template <typename DateOrTime>
inline auto toFirstDayNumOfYear(DateOrTime v) const
auto toFirstDayNumOfYear(DateOrTime v) const
{
if constexpr (std::is_unsigned_v<DateOrTime> || std::is_same_v<DateOrTime, DayNum>)
return toDayNum(LUTIndexWithSaturation(toFirstDayNumOfYearIndex(v)));
@ -481,14 +481,14 @@ public:
return toDayNum(LUTIndex(toFirstDayNumOfYearIndex(v)));
}
inline Time toFirstDayOfNextMonth(Time t) const
Time toFirstDayOfNextMonth(Time t) const
{
LUTIndex index = findIndex(t);
index += 32 - lut[index].day_of_month;
return lut[index - (lut[index].day_of_month - 1)].date;
}
inline Time toFirstDayOfPrevMonth(Time t) const
Time toFirstDayOfPrevMonth(Time t) const
{
LUTIndex index = findIndex(t);
index -= lut[index].day_of_month;
@ -496,13 +496,13 @@ public:
}
template <typename DateOrTime>
inline UInt8 daysInMonth(DateOrTime value) const
UInt8 daysInMonth(DateOrTime value) const
{
const LUTIndex i = toLUTIndex(value);
return lut[i].days_in_month;
}
inline UInt8 daysInMonth(Int16 year, UInt8 month) const
UInt8 daysInMonth(Int16 year, UInt8 month) const
{
UInt16 idx = year - DATE_LUT_MIN_YEAR;
if (unlikely(idx >= DATE_LUT_YEARS))
@ -515,12 +515,12 @@ public:
/** Round to start of day, then shift for specified amount of days.
*/
inline Time toDateAndShift(Time t, Int32 days) const
Time toDateAndShift(Time t, Int32 days) const
{
return lut[findIndex(t) + days].date;
}
inline Time toTime(Time t) const
Time toTime(Time t) const
{
const LUTIndex index = findIndex(t);
@ -532,7 +532,7 @@ public:
return res - offset_at_start_of_epoch; /// Starting at 1970-01-01 00:00:00 local time.
}
inline unsigned toHour(Time t) const
unsigned toHour(Time t) const
{
const LUTIndex index = findIndex(t);
@ -552,7 +552,7 @@ public:
* then subtract the former from the latter to get the offset result.
* The boundaries when meets DST(daylight saving time) change should be handled very carefully.
*/
inline Time timezoneOffset(Time t) const
Time timezoneOffset(Time t) const
{
const LUTIndex index = findIndex(t);
@ -574,7 +574,7 @@ public:
}
inline unsigned toSecond(Time t) const
unsigned toSecond(Time t) const
{
if (likely(offset_is_whole_number_of_minutes_during_epoch))
{
@ -593,7 +593,7 @@ public:
return time % 60;
}
inline unsigned toMinute(Time t) const
unsigned toMinute(Time t) const
{
if (t >= 0 && offset_is_whole_number_of_hours_during_epoch)
return (t / 60) % 60;
@ -630,11 +630,11 @@ public:
* because the same calendar day starts/ends at different timestamps in different time zones)
*/
inline Time fromDayNum(DayNum d) const { return lut_saturated[toLUTIndex(d)].date; }
inline Time fromDayNum(ExtendedDayNum d) const { return lut[toLUTIndex(d)].date; }
Time fromDayNum(DayNum d) const { return lut_saturated[toLUTIndex(d)].date; }
Time fromDayNum(ExtendedDayNum d) const { return lut[toLUTIndex(d)].date; }
template <typename DateOrTime>
inline Time toDate(DateOrTime v) const
Time toDate(DateOrTime v) const
{
if constexpr (std::is_unsigned_v<DateOrTime> || std::is_same_v<DateOrTime, DayNum>)
return lut_saturated[toLUTIndex(v)].date;
@ -643,20 +643,20 @@ public:
}
template <typename DateOrTime>
inline UInt8 toMonth(DateOrTime v) const { return lut[toLUTIndex(v)].month; }
UInt8 toMonth(DateOrTime v) const { return lut[toLUTIndex(v)].month; }
template <typename DateOrTime>
inline UInt8 toQuarter(DateOrTime v) const { return (lut[toLUTIndex(v)].month - 1) / 3 + 1; }
UInt8 toQuarter(DateOrTime v) const { return (lut[toLUTIndex(v)].month - 1) / 3 + 1; }
template <typename DateOrTime>
inline Int16 toYear(DateOrTime v) const { return lut[toLUTIndex(v)].year; }
Int16 toYear(DateOrTime v) const { return lut[toLUTIndex(v)].year; }
/// 1-based, starts on Monday
template <typename DateOrTime>
inline UInt8 toDayOfWeek(DateOrTime v) const { return lut[toLUTIndex(v)].day_of_week; }
UInt8 toDayOfWeek(DateOrTime v) const { return lut[toLUTIndex(v)].day_of_week; }
template <typename DateOrTime>
inline UInt8 toDayOfWeek(DateOrTime v, UInt8 week_day_mode) const
UInt8 toDayOfWeek(DateOrTime v, UInt8 week_day_mode) const
{
WeekDayMode mode = check_week_day_mode(week_day_mode);
@ -674,10 +674,10 @@ public:
}
template <typename DateOrTime>
inline UInt8 toDayOfMonth(DateOrTime v) const { return lut[toLUTIndex(v)].day_of_month; }
UInt8 toDayOfMonth(DateOrTime v) const { return lut[toLUTIndex(v)].day_of_month; }
template <typename DateOrTime>
inline UInt16 toDayOfYear(DateOrTime v) const
UInt16 toDayOfYear(DateOrTime v) const
{
// TODO: different overload for ExtendedDayNum
const LUTIndex i = toLUTIndex(v);
@ -688,7 +688,7 @@ public:
/// (round down to monday and divide DayNum by 7; we made an assumption,
/// that in domain of the function there was no weeks with any other number of days than 7)
template <typename DateOrTime>
inline Int32 toRelativeWeekNum(DateOrTime v) const
Int32 toRelativeWeekNum(DateOrTime v) const
{
const LUTIndex i = toLUTIndex(v);
/// We add 8 to avoid underflow at beginning of unix epoch.
@ -697,7 +697,7 @@ public:
/// Get year that contains most of the current week. Week begins at monday.
template <typename DateOrTime>
inline Int16 toISOYear(DateOrTime v) const
Int16 toISOYear(DateOrTime v) const
{
const LUTIndex i = toLUTIndex(v);
/// That's effectively the year of thursday of current week.
@ -708,7 +708,7 @@ public:
/// Example: ISO year 2019 begins at 2018-12-31. And ISO year 2017 begins at 2017-01-02.
/// https://en.wikipedia.org/wiki/ISO_week_date
template <typename DateOrTime>
inline LUTIndex toFirstDayNumOfISOYearIndex(DateOrTime v) const
LUTIndex toFirstDayNumOfISOYearIndex(DateOrTime v) const
{
const LUTIndex i = toLUTIndex(v);
auto iso_year = toISOYear(i);
@ -722,7 +722,7 @@ public:
}
template <typename DateOrTime>
inline auto toFirstDayNumOfISOYear(DateOrTime v) const
auto toFirstDayNumOfISOYear(DateOrTime v) const
{
if constexpr (std::is_unsigned_v<DateOrTime> || std::is_same_v<DateOrTime, DayNum>)
return toDayNum(LUTIndexWithSaturation(toFirstDayNumOfISOYearIndex(v)));
@ -730,7 +730,7 @@ public:
return toDayNum(LUTIndex(toFirstDayNumOfISOYearIndex(v)));
}
inline Time toFirstDayOfISOYear(Time t) const
Time toFirstDayOfISOYear(Time t) const
{
return lut[toFirstDayNumOfISOYearIndex(t)].date;
}
@ -738,7 +738,7 @@ public:
/// ISO 8601 week number. Week begins at monday.
/// The week number 1 is the first week in year that contains 4 or more days (that's more than half).
template <typename DateOrTime>
inline UInt8 toISOWeek(DateOrTime v) const
UInt8 toISOWeek(DateOrTime v) const
{
return 1 + (toFirstDayNumOfWeek(v) - toDayNum(toFirstDayNumOfISOYearIndex(v))) / 7;
}
@ -777,7 +777,7 @@ public:
next week is week 1.
*/
template <typename DateOrTime>
inline YearWeek toYearWeek(DateOrTime v, UInt8 week_mode) const
YearWeek toYearWeek(DateOrTime v, UInt8 week_mode) const
{
const bool newyear_day_mode = week_mode & static_cast<UInt8>(WeekModeFlag::NEWYEAR_DAY);
week_mode = check_week_mode(week_mode);
@ -836,7 +836,7 @@ public:
/// Calculate week number of WeekModeFlag::NEWYEAR_DAY mode
/// The week number 1 is the first week in year that contains January 1,
template <typename DateOrTime>
inline YearWeek toYearWeekOfNewyearMode(DateOrTime v, bool monday_first_mode) const
YearWeek toYearWeekOfNewyearMode(DateOrTime v, bool monday_first_mode) const
{
YearWeek yw(0, 0);
UInt16 offset_day = monday_first_mode ? 0U : 1U;
@ -870,7 +870,7 @@ public:
/// Get first day of week with week_mode, return Sunday or Monday
template <typename DateOrTime>
inline auto toFirstDayNumOfWeek(DateOrTime v, UInt8 week_mode) const
auto toFirstDayNumOfWeek(DateOrTime v, UInt8 week_mode) const
{
bool monday_first_mode = week_mode & static_cast<UInt8>(WeekModeFlag::MONDAY_FIRST);
if (monday_first_mode)
@ -889,7 +889,7 @@ public:
/// Get last day of week with week_mode, return Saturday or Sunday
template <typename DateOrTime>
inline auto toLastDayNumOfWeek(DateOrTime v, UInt8 week_mode) const
auto toLastDayNumOfWeek(DateOrTime v, UInt8 week_mode) const
{
bool monday_first_mode = week_mode & static_cast<UInt8>(WeekModeFlag::MONDAY_FIRST);
if (monday_first_mode)
@ -908,7 +908,7 @@ public:
}
/// Check and change mode to effective.
inline UInt8 check_week_mode(UInt8 mode) const /// NOLINT
UInt8 check_week_mode(UInt8 mode) const /// NOLINT
{
UInt8 week_format = (mode & 7);
if (!(week_format & static_cast<UInt8>(WeekModeFlag::MONDAY_FIRST)))
@ -917,7 +917,7 @@ public:
}
/// Check and change mode to effective.
inline WeekDayMode check_week_day_mode(UInt8 mode) const /// NOLINT
WeekDayMode check_week_day_mode(UInt8 mode) const /// NOLINT
{
return static_cast<WeekDayMode>(mode & 3);
}
@ -926,7 +926,7 @@ public:
* Returns 0 for monday, 1 for tuesday...
*/
template <typename DateOrTime>
inline UInt8 calc_weekday(DateOrTime v, bool sunday_first_day_of_week) const /// NOLINT
UInt8 calc_weekday(DateOrTime v, bool sunday_first_day_of_week) const /// NOLINT
{
const LUTIndex i = toLUTIndex(v);
if (!sunday_first_day_of_week)
@ -936,28 +936,28 @@ public:
}
/// Calculate days in one year.
inline UInt16 calc_days_in_year(Int32 year) const /// NOLINT
UInt16 calc_days_in_year(Int32 year) const /// NOLINT
{
return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)) ? 366 : 365);
}
/// Number of month from some fixed moment in the past (year * 12 + month)
template <typename DateOrTime>
inline Int32 toRelativeMonthNum(DateOrTime v) const
Int32 toRelativeMonthNum(DateOrTime v) const
{
const LUTIndex i = toLUTIndex(v);
return lut[i].year * 12 + lut[i].month;
}
template <typename DateOrTime>
inline Int32 toRelativeQuarterNum(DateOrTime v) const
Int32 toRelativeQuarterNum(DateOrTime v) const
{
const LUTIndex i = toLUTIndex(v);
return lut[i].year * 4 + (lut[i].month - 1) / 3;
}
/// We count all hour-length intervals, unrelated to offset changes.
inline Time toRelativeHourNum(Time t) const
Time toRelativeHourNum(Time t) const
{
if (t >= 0 && offset_is_whole_number_of_hours_during_epoch)
return t / 3600;
@ -968,37 +968,37 @@ public:
}
template <typename DateOrTime>
inline Time toRelativeHourNum(DateOrTime v) const
Time toRelativeHourNum(DateOrTime v) const
{
return toRelativeHourNum(lut[toLUTIndex(v)].date);
}
/// The same formula is used for positive time (after Unix epoch) and negative time (before Unix epoch).
/// Its needed for correct work of dateDiff function.
inline Time toStableRelativeHourNum(Time t) const
Time toStableRelativeHourNum(Time t) const
{
return (t + DATE_LUT_ADD + 86400 - offset_at_start_of_epoch) / 3600 - (DATE_LUT_ADD / 3600);
}
template <typename DateOrTime>
inline Time toStableRelativeHourNum(DateOrTime v) const
Time toStableRelativeHourNum(DateOrTime v) const
{
return toStableRelativeHourNum(lut[toLUTIndex(v)].date);
}
inline Time toRelativeMinuteNum(Time t) const /// NOLINT
Time toRelativeMinuteNum(Time t) const /// NOLINT
{
return (t + DATE_LUT_ADD) / 60 - (DATE_LUT_ADD / 60);
}
template <typename DateOrTime>
inline Time toRelativeMinuteNum(DateOrTime v) const
Time toRelativeMinuteNum(DateOrTime v) const
{
return toRelativeMinuteNum(lut[toLUTIndex(v)].date);
}
template <typename DateOrTime>
inline auto toStartOfYearInterval(DateOrTime v, UInt64 years) const
auto toStartOfYearInterval(DateOrTime v, UInt64 years) const
{
if (years == 1)
return toFirstDayNumOfYear(v);
@ -1019,7 +1019,7 @@ public:
template <typename Date>
requires std::is_same_v<Date, DayNum> || std::is_same_v<Date, ExtendedDayNum>
inline auto toStartOfQuarterInterval(Date d, UInt64 quarters) const
auto toStartOfQuarterInterval(Date d, UInt64 quarters) const
{
if (quarters == 1)
return toFirstDayNumOfQuarter(d);
@ -1028,7 +1028,7 @@ public:
template <typename Date>
requires std::is_same_v<Date, DayNum> || std::is_same_v<Date, ExtendedDayNum>
inline auto toStartOfMonthInterval(Date d, UInt64 months) const
auto toStartOfMonthInterval(Date d, UInt64 months) const
{
if (months == 1)
return toFirstDayNumOfMonth(d);
@ -1042,7 +1042,7 @@ public:
template <typename Date>
requires std::is_same_v<Date, DayNum> || std::is_same_v<Date, ExtendedDayNum>
inline auto toStartOfWeekInterval(Date d, UInt64 weeks) const
auto toStartOfWeekInterval(Date d, UInt64 weeks) const
{
if (weeks == 1)
return toFirstDayNumOfWeek(d);
@ -1056,7 +1056,7 @@ public:
template <typename Date>
requires std::is_same_v<Date, DayNum> || std::is_same_v<Date, ExtendedDayNum>
inline Time toStartOfDayInterval(Date d, UInt64 days) const
Time toStartOfDayInterval(Date d, UInt64 days) const
{
if (days == 1)
return toDate(d);
@ -1152,7 +1152,7 @@ public:
return static_cast<DateOrTime>(roundDown(t, seconds));
}
inline LUTIndex makeLUTIndex(Int16 year, UInt8 month, UInt8 day_of_month) const
LUTIndex makeLUTIndex(Int16 year, UInt8 month, UInt8 day_of_month) const
{
if (unlikely(year < DATE_LUT_MIN_YEAR || month < 1 || month > 12 || day_of_month < 1 || day_of_month > 31))
return LUTIndex(0);
@ -1167,7 +1167,7 @@ public:
}
/// Create DayNum from year, month, day of month.
inline ExtendedDayNum makeDayNum(Int16 year, UInt8 month, UInt8 day_of_month, Int32 default_error_day_num = 0) const
ExtendedDayNum makeDayNum(Int16 year, UInt8 month, UInt8 day_of_month, Int32 default_error_day_num = 0) const
{
if (unlikely(year < DATE_LUT_MIN_YEAR || month < 1 || month > 12 || day_of_month < 1 || day_of_month > 31))
return ExtendedDayNum(default_error_day_num);
@ -1175,14 +1175,14 @@ public:
return toDayNum(makeLUTIndex(year, month, day_of_month));
}
inline Time makeDate(Int16 year, UInt8 month, UInt8 day_of_month) const
Time makeDate(Int16 year, UInt8 month, UInt8 day_of_month) const
{
return lut[makeLUTIndex(year, month, day_of_month)].date;
}
/** Does not accept daylight saving time as argument: in case of ambiguity, it choose greater timestamp.
*/
inline Time makeDateTime(Int16 year, UInt8 month, UInt8 day_of_month, UInt8 hour, UInt8 minute, UInt8 second) const
Time makeDateTime(Int16 year, UInt8 month, UInt8 day_of_month, UInt8 hour, UInt8 minute, UInt8 second) const
{
size_t index = makeLUTIndex(year, month, day_of_month);
Time time_offset = hour * 3600 + minute * 60 + second;
@ -1194,28 +1194,28 @@ public:
}
template <typename DateOrTime>
inline const Values & getValues(DateOrTime v) const { return lut[toLUTIndex(v)]; }
const Values & getValues(DateOrTime v) const { return lut[toLUTIndex(v)]; }
template <typename DateOrTime>
inline UInt32 toNumYYYYMM(DateOrTime v) const
UInt32 toNumYYYYMM(DateOrTime v) const
{
const Values & values = getValues(v);
return values.year * 100 + values.month;
}
template <typename DateOrTime>
inline UInt32 toNumYYYYMMDD(DateOrTime v) const
UInt32 toNumYYYYMMDD(DateOrTime v) const
{
const Values & values = getValues(v);
return values.year * 10000 + values.month * 100 + values.day_of_month;
}
inline Time YYYYMMDDToDate(UInt32 num) const /// NOLINT
Time YYYYMMDDToDate(UInt32 num) const /// NOLINT
{
return makeDate(num / 10000, num / 100 % 100, num % 100);
}
inline ExtendedDayNum YYYYMMDDToDayNum(UInt32 num) const /// NOLINT
ExtendedDayNum YYYYMMDDToDayNum(UInt32 num) const /// NOLINT
{
return makeDayNum(num / 10000, num / 100 % 100, num % 100);
}
@ -1241,13 +1241,13 @@ public:
TimeComponents time;
};
inline DateComponents toDateComponents(Time t) const
DateComponents toDateComponents(Time t) const
{
const Values & values = getValues(t);
return { values.year, values.month, values.day_of_month };
}
inline DateTimeComponents toDateTimeComponents(Time t) const
DateTimeComponents toDateTimeComponents(Time t) const
{
const LUTIndex index = findIndex(t);
const Values & values = lut[index];
@ -1283,12 +1283,12 @@ public:
}
template <typename DateOrTime>
inline DateTimeComponents toDateTimeComponents(DateOrTime v) const
DateTimeComponents toDateTimeComponents(DateOrTime v) const
{
return toDateTimeComponents(lut[toLUTIndex(v)].date);
}
inline UInt64 toNumYYYYMMDDhhmmss(Time t) const
UInt64 toNumYYYYMMDDhhmmss(Time t) const
{
DateTimeComponents components = toDateTimeComponents(t);
@ -1301,7 +1301,7 @@ public:
+ UInt64(components.date.year) * 10000000000;
}
inline Time YYYYMMDDhhmmssToTime(UInt64 num) const /// NOLINT
Time YYYYMMDDhhmmssToTime(UInt64 num) const /// NOLINT
{
return makeDateTime(
num / 10000000000,
@ -1315,7 +1315,7 @@ public:
/// Adding calendar intervals.
/// Implementation specific behaviour when delta is too big.
inline NO_SANITIZE_UNDEFINED Time addDays(Time t, Int64 delta) const
NO_SANITIZE_UNDEFINED Time addDays(Time t, Int64 delta) const
{
const LUTIndex index = findIndex(t);
const Values & values = lut[index];
@ -1332,12 +1332,12 @@ public:
return lut[new_index].date + time;
}
inline NO_SANITIZE_UNDEFINED Time addWeeks(Time t, Int64 delta) const
NO_SANITIZE_UNDEFINED Time addWeeks(Time t, Int64 delta) const
{
return addDays(t, delta * 7);
}
inline UInt8 saturateDayOfMonth(Int16 year, UInt8 month, UInt8 day_of_month) const
UInt8 saturateDayOfMonth(Int16 year, UInt8 month, UInt8 day_of_month) const
{
if (likely(day_of_month <= 28))
return day_of_month;
@ -1351,7 +1351,7 @@ public:
}
template <typename DateOrTime>
inline LUTIndex NO_SANITIZE_UNDEFINED addMonthsIndex(DateOrTime v, Int64 delta) const
LUTIndex NO_SANITIZE_UNDEFINED addMonthsIndex(DateOrTime v, Int64 delta) const
{
const Values & values = lut[toLUTIndex(v)];
@ -1375,11 +1375,11 @@ public:
}
}
/// If resulting month has less deys than source month, then saturation can happen.
/// If resulting month has less days than source month, then saturation can happen.
/// Example: 31 Aug + 1 month = 30 Sep.
template <typename DateTime>
requires std::is_same_v<DateTime, UInt32> || std::is_same_v<DateTime, Int64> || std::is_same_v<DateTime, time_t>
inline Time NO_SANITIZE_UNDEFINED addMonths(DateTime t, Int64 delta) const
Time NO_SANITIZE_UNDEFINED addMonths(DateTime t, Int64 delta) const
{
const auto result_day = addMonthsIndex(t, delta);
@ -1405,7 +1405,7 @@ public:
template <typename Date>
requires std::is_same_v<Date, DayNum> || std::is_same_v<Date, ExtendedDayNum>
inline auto NO_SANITIZE_UNDEFINED addMonths(Date d, Int64 delta) const
auto NO_SANITIZE_UNDEFINED addMonths(Date d, Int64 delta) const
{
if constexpr (std::is_same_v<Date, DayNum>)
return toDayNum(LUTIndexWithSaturation(addMonthsIndex(d, delta)));
@ -1414,13 +1414,13 @@ public:
}
template <typename DateOrTime>
inline auto NO_SANITIZE_UNDEFINED addQuarters(DateOrTime d, Int64 delta) const
auto NO_SANITIZE_UNDEFINED addQuarters(DateOrTime d, Int64 delta) const
{
return addMonths(d, delta * 3);
}
template <typename DateOrTime>
inline LUTIndex NO_SANITIZE_UNDEFINED addYearsIndex(DateOrTime v, Int64 delta) const
LUTIndex NO_SANITIZE_UNDEFINED addYearsIndex(DateOrTime v, Int64 delta) const
{
const Values & values = lut[toLUTIndex(v)];
@ -1438,7 +1438,7 @@ public:
/// Saturation can occur if 29 Feb is mapped to non-leap year.
template <typename DateTime>
requires std::is_same_v<DateTime, UInt32> || std::is_same_v<DateTime, Int64> || std::is_same_v<DateTime, time_t>
inline Time addYears(DateTime t, Int64 delta) const
Time addYears(DateTime t, Int64 delta) const
{
auto result_day = addYearsIndex(t, delta);
@ -1464,7 +1464,7 @@ public:
template <typename Date>
requires std::is_same_v<Date, DayNum> || std::is_same_v<Date, ExtendedDayNum>
inline auto addYears(Date d, Int64 delta) const
auto addYears(Date d, Int64 delta) const
{
if constexpr (std::is_same_v<Date, DayNum>)
return toDayNum(LUTIndexWithSaturation(addYearsIndex(d, delta)));
@ -1473,7 +1473,7 @@ public:
}
inline std::string timeToString(Time t) const
std::string timeToString(Time t) const
{
DateTimeComponents components = toDateTimeComponents(t);
@ -1498,7 +1498,7 @@ public:
return s;
}
inline std::string dateToString(Time t) const
std::string dateToString(Time t) const
{
const Values & values = getValues(t);
@ -1516,7 +1516,7 @@ public:
return s;
}
inline std::string dateToString(ExtendedDayNum d) const
std::string dateToString(ExtendedDayNum d) const
{
const Values & values = getValues(d);

View File

@ -28,7 +28,9 @@ namespace ErrorCodes
namespace
{
/// Functions common to makeDate, makeDate32, makeDateTime, makeDateTime64
/// Functionality common to
/// - makeDate, makeDate32, makeDateTime, makeDateTime64,
/// - YYYYMMDDToDate, YYYYMMDDToDate32, YYYYMMDDhhmmssToDateTime, YYYYMMDDhhmmssToDateTime64
class FunctionWithNumericParamsBase : public IFunction
{
public:
@ -48,11 +50,11 @@ public:
size_t getNumberOfArguments() const override { return 0; }
protected:
template <class ArgumentNames>
template <class DataType = DataTypeFloat32, class ArgumentNames>
Columns convertMandatoryArguments(const ColumnsWithTypeAndName & arguments, const ArgumentNames & argument_names) const
{
Columns converted_arguments;
const DataTypePtr converted_argument_type = std::make_shared<DataTypeFloat32>();
const DataTypePtr converted_argument_type = std::make_shared<DataType>();
for (size_t i = 0; i < argument_names.size(); ++i)
{
ColumnPtr argument_column = castColumn(arguments[i], converted_argument_type);
@ -63,7 +65,7 @@ protected:
}
};
/// Common implementation for makeDate, makeDate32
/// Implementation of makeDate, makeDate32
template <typename Traits>
class FunctionMakeDate : public FunctionWithNumericParamsBase
{
@ -72,7 +74,7 @@ private:
static constexpr std::array mandatory_argument_names_year_dayofyear = {"year", "dayofyear"};
public:
static constexpr auto name = Traits::name;
static constexpr auto name = Traits::makeDateName;
static FunctionPtr create(ContextPtr) { return std::make_shared<FunctionMakeDate>(); }
@ -80,9 +82,9 @@ public:
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
{
const bool isYearMonthDayVariant = (arguments.size() == 3);
const bool is_year_month_variant = (arguments.size() == 3);
if (isYearMonthDayVariant)
if (is_year_month_variant)
{
FunctionArgumentDescriptors args{
{mandatory_argument_names_year_month_day[0], &isNumber<IDataType>, nullptr, "Number"},
@ -105,10 +107,10 @@ public:
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override
{
const bool isYearMonthDayVariant = (arguments.size() == 3);
const bool is_year_month_day_variant = (arguments.size() == 3);
Columns converted_arguments;
if (isYearMonthDayVariant)
if (is_year_month_day_variant)
converted_arguments = convertMandatoryArguments(arguments, mandatory_argument_names_year_month_day);
else
converted_arguments = convertMandatoryArguments(arguments, mandatory_argument_names_year_dayofyear);
@ -119,7 +121,7 @@ public:
const auto & date_lut = DateLUT::instance();
const Int32 max_days_since_epoch = date_lut.makeDayNum(Traits::MAX_DATE[0], Traits::MAX_DATE[1], Traits::MAX_DATE[2]);
if (isYearMonthDayVariant)
if (is_year_month_day_variant)
{
const auto & year_data = typeid_cast<const ColumnFloat32 &>(*converted_arguments[0]).getData();
const auto & month_data = typeid_cast<const ColumnFloat32 &>(*converted_arguments[1]).getData();
@ -133,8 +135,7 @@ public:
Int32 day_num = 0;
if (year >= Traits::MIN_YEAR &&
year <= Traits::MAX_YEAR &&
if (year >= Traits::MIN_YEAR && year <= Traits::MAX_YEAR &&
month >= 1 && month <= 12 &&
day >= 1 && day <= 31)
{
@ -158,8 +159,7 @@ public:
Int32 day_num = 0;
if (year >= Traits::MIN_YEAR &&
year <= Traits::MAX_YEAR &&
if (year >= Traits::MIN_YEAR && year <= Traits::MAX_YEAR &&
dayofyear >= 1 && dayofyear <= 365)
{
Int32 days_since_epoch = date_lut.makeDayNum(static_cast<Int16>(year), 1, 1) + static_cast<Int32>(dayofyear) - 1;
@ -175,20 +175,87 @@ public:
}
};
struct MakeDateTraits
/// Implementation of YYYYMMDDToDate, YYYYMMDDToDate32
template<typename Traits>
class FunctionYYYYYMMDDToDate : public FunctionWithNumericParamsBase
{
static constexpr auto name = "makeDate";
private:
static constexpr std::array mandatory_argument_names = { "YYYYMMDD" };
public:
static constexpr auto name = Traits::YYYYMMDDName;
static FunctionPtr create(ContextPtr) { return std::make_shared<FunctionYYYYYMMDDToDate>(); }
String getName() const override { return name; }
bool isVariadic() const override { return false; }
size_t getNumberOfArguments() const override { return mandatory_argument_names.size(); }
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
{
FunctionArgumentDescriptors args{
{mandatory_argument_names[0], &isNumber<IDataType>, nullptr, "Number"}
};
validateFunctionArgumentTypes(*this, arguments, args);
return std::make_shared<typename Traits::ReturnDataType>();
}
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override
{
Columns converted_arguments = convertMandatoryArguments<DataTypeFloat64>(arguments, mandatory_argument_names);
auto res_column = Traits::ReturnDataType::ColumnType::create(input_rows_count);
auto & result_data = res_column->getData();
const auto & yyyymmdd_data = typeid_cast<const ColumnFloat64 &>(*converted_arguments[0]).getData();
const auto & date_lut = DateLUT::instance();
const Int32 max_days_since_epoch = date_lut.makeDayNum(Traits::MAX_DATE[0], Traits::MAX_DATE[1], Traits::MAX_DATE[2]);
for (size_t i = 0; i < input_rows_count; ++i)
{
const auto yyyymmdd = static_cast<UInt64>(yyyymmdd_data[i]);
const auto year = yyyymmdd / 10'000;
const auto month = yyyymmdd / 100 % 100;
const auto day = yyyymmdd % 100;
Int32 day_num = 0;
if (year >= Traits::MIN_YEAR && year <= Traits::MAX_YEAR &&
month >= 1 && month <= 12 &&
day >= 1 && day <= 31)
{
Int32 days_since_epoch = date_lut.makeDayNum(static_cast<Int16>(year), static_cast<UInt8>(month), static_cast<UInt8>(day));
if (days_since_epoch <= max_days_since_epoch)
day_num = days_since_epoch;
}
result_data[i] = day_num;
}
return res_column;
}
};
struct DateTraits
{
static constexpr auto makeDateName = "makeDate";
static constexpr auto YYYYMMDDName = "YYYYMMDDToDate";
using ReturnDataType = DataTypeDate;
static constexpr auto MIN_YEAR = 1970;
static constexpr auto MAX_YEAR = 2149;
/// This date has the maximum day number that fits in 16-bit uint
static constexpr std::array MAX_DATE = {MAX_YEAR, 6, 6};
};
struct MakeDate32Traits
struct Date32Traits
{
static constexpr auto name = "makeDate32";
static constexpr auto makeDateName = "makeDate32";
static constexpr auto YYYYMMDDName = "YYYYMMDDToDate32";
using ReturnDataType = DataTypeDate32;
static constexpr auto MIN_YEAR = 1900;
@ -196,11 +263,11 @@ struct MakeDate32Traits
static constexpr std::array MAX_DATE = {MAX_YEAR, 12, 31};
};
/// Common implementation for makeDateTime, makeDateTime64
class FunctionMakeDateTimeBase : public FunctionWithNumericParamsBase
/// Functionality common to makeDateTime, makeDateTime64, YYYYMMDDhhmmssToDateTime, YYYYMMDDhhmmssToDateTime64
class FunctionDateTimeBase : public FunctionWithNumericParamsBase
{
protected:
static constexpr std::array mandatory_argument_names = {"year", "month", "day", "hour", "minute", "second"};
static constexpr UInt32 DEFAULT_PRECISION = 3;
template <typename T>
static Int64 dateTime(T year, T month, T day_of_month, T hour, T minute, T second, const DateLUTImpl & lut)
@ -233,14 +300,35 @@ protected:
std::string extractTimezone(const ColumnWithTypeAndName & timezone_argument) const
{
std::string timezone;
if (!isStringOrFixedString(timezone_argument.type) || !timezone_argument.column || (timezone_argument.column->size() != 1 && !typeid_cast<const ColumnConst*>(timezone_argument.column.get())))
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
"Argument 'timezone' for function {} must be const string", getName());
timezone = timezone_argument.column->getDataAt(0).toString();
String timezone = timezone_argument.column->getDataAt(0).toString();
return timezone;
}
UInt32 extractPrecision(const ColumnWithTypeAndName & precision_argument) const
{
if (!isNumber(precision_argument.type) || !precision_argument.column || (precision_argument.column->size() != 1 && !typeid_cast<const ColumnConst*>(precision_argument.column.get())))
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
"Argument 'precision' for function {} must be constant number", getName());
Int64 precision = precision_argument.column->getInt(0);
if (precision < 0 || precision > 9)
throw Exception(ErrorCodes::ARGUMENT_OUT_OF_BOUND,
"Argument 'precision' for function {} must be in range [0, 9]", getName());
return static_cast<UInt32>(precision);
}
};
class FunctionMakeDateTimeBase : public FunctionDateTimeBase
{
protected:
static constexpr std::array mandatory_argument_names = {"year", "month", "day", "hour", "minute", "second"};
};
/// makeDateTime(year, month, day, hour, minute, second, [timezone])
@ -268,7 +356,7 @@ public:
};
FunctionArgumentDescriptors optional_args{
{optional_argument_names[0], &isString<IDataType>, nullptr, "String"}
{optional_argument_names[0], &isString<IDataType>, isColumnConst, "const String"}
};
validateFunctionArgumentTypes(*this, arguments, mandatory_args, optional_args);
@ -329,7 +417,6 @@ class FunctionMakeDateTime64 : public FunctionMakeDateTimeBase
{
private:
static constexpr std::array optional_argument_names = {"fraction", "precision", "timezone"};
static constexpr UInt8 DEFAULT_PRECISION = 3;
public:
static constexpr auto name = "makeDateTime64";
@ -350,9 +437,9 @@ public:
};
FunctionArgumentDescriptors optional_args{
{optional_argument_names[0], &isNumber<IDataType>, nullptr, "Number"},
{optional_argument_names[1], &isNumber<IDataType>, nullptr, "Number"},
{optional_argument_names[2], &isString<IDataType>, nullptr, "String"}
{optional_argument_names[0], &isNumber<IDataType>, isColumnConst, "const Number"},
{optional_argument_names[1], &isNumber<IDataType>, isColumnConst, "const Number"},
{optional_argument_names[2], &isString<IDataType>, isColumnConst, "const String"}
};
validateFunctionArgumentTypes(*this, arguments, mandatory_args, optional_args);
@ -456,20 +543,179 @@ public:
return res_column;
}
};
class FunctionYYYYMMDDhhmmssToDateTimeBase : public FunctionDateTimeBase
{
protected:
static constexpr std::array mandatory_argument_names = { "YYYYMMDDhhmmss" };
};
/// YYYYMMDDhhmmssToDateTime
class FunctionYYYYMMDDhhmmssToDateTime : public FunctionYYYYMMDDhhmmssToDateTimeBase
{
private:
UInt8 extractPrecision(const ColumnWithTypeAndName & precision_argument) const
{
Int64 precision = DEFAULT_PRECISION;
if (!isNumber(precision_argument.type) || !precision_argument.column || (precision_argument.column->size() != 1 && !typeid_cast<const ColumnConst*>(precision_argument.column.get())))
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
"Argument 'precision' for function {} must be constant number", getName());
precision = precision_argument.column->getInt(0);
if (precision < 0 || precision > 9)
throw Exception(ErrorCodes::ARGUMENT_OUT_OF_BOUND,
"Argument 'precision' for function {} must be in range [0, 9]", getName());
static constexpr std::array optional_argument_names = { "timezone" };
return precision;
public:
static constexpr auto name = "YYYYMMDDhhmmssToDateTime";
static FunctionPtr create(ContextPtr) { return std::make_shared<FunctionYYYYMMDDhhmmssToDateTime>(); }
String getName() const override { return name; }
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
{
FunctionArgumentDescriptors mandatory_args{
{mandatory_argument_names[0], &isNumber<IDataType>, nullptr, "Number"}
};
FunctionArgumentDescriptors optional_args{
{optional_argument_names[0], &isString<IDataType>, isColumnConst, "const String"}
};
validateFunctionArgumentTypes(*this, arguments, mandatory_args, optional_args);
/// Optional timezone argument
std::string timezone;
if (arguments.size() == mandatory_argument_names.size() + 1)
timezone = extractTimezone(arguments.back());
return std::make_shared<DataTypeDateTime>(timezone);
}
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override
{
std::string timezone;
if (arguments.size() == mandatory_argument_names.size() + 1)
timezone = extractTimezone(arguments.back());
Columns converted_arguments = convertMandatoryArguments<DataTypeFloat64>(arguments, mandatory_argument_names);
auto res_column = ColumnDateTime::create(input_rows_count);
auto & result_data = res_column->getData();
const auto & yyyymmddhhmmss_data = typeid_cast<const ColumnFloat64 &>(*converted_arguments[0]).getData();
const auto & date_lut = DateLUT::instance(timezone);
for (size_t i = 0; i < input_rows_count; i++)
{
const auto yyyymmddhhmmss = static_cast<Int64>(yyyymmddhhmmss_data[i]);
const auto yyyymmdd = yyyymmddhhmmss / 1'000'000;
const auto hhmmss = yyyymmddhhmmss % 1'000'000;
const auto year = yyyymmdd / 10'000;
const auto month = yyyymmdd / 100 % 100;
const auto day = yyyymmdd % 100;
const auto hour = hhmmss / 10'000;
const auto minute = hhmmss / 100 % 100;
const auto second = hhmmss % 100;
auto date_time = dateTime(year, month, day, hour, minute, second, date_lut);
if (date_time < 0) [[unlikely]]
date_time = 0;
else if (date_time > 0x0ffffffffll) [[unlikely]]
date_time = 0x0ffffffffll;
result_data[i] = static_cast<UInt32>(date_time);
}
return res_column;
}
};
/// YYYYMMDDhhmmssToDateTime64
class FunctionYYYYMMDDhhmmssToDateTime64 : public FunctionYYYYMMDDhhmmssToDateTimeBase
{
private:
static constexpr std::array optional_argument_names = { "precision", "timezone" };
public:
static constexpr auto name = "YYYYMMDDhhmmssToDateTime64";
static FunctionPtr create(ContextPtr) { return std::make_shared<FunctionYYYYMMDDhhmmssToDateTime64>(); }
String getName() const override { return name; }
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
{
FunctionArgumentDescriptors mandatory_args{
{mandatory_argument_names[0], &isNumber<IDataType>, nullptr, "Number"}
};
FunctionArgumentDescriptors optional_args{
{optional_argument_names[0], &isNumber<IDataType>, isColumnConst, "const Number"},
{optional_argument_names[0], &isString<IDataType>, isColumnConst, "const String"}
};
validateFunctionArgumentTypes(*this, arguments, mandatory_args, optional_args);
/// Optional precision argument
auto precision = DEFAULT_PRECISION;
if (arguments.size() >= mandatory_argument_names.size() + 1)
precision = extractPrecision(arguments[mandatory_argument_names.size()]);
/// Optional timezone argument
std::string timezone;
if (arguments.size() == mandatory_argument_names.size() + 2)
timezone = extractTimezone(arguments.back());
return std::make_shared<DataTypeDateTime64>(precision, timezone);
}
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override
{
UInt32 precision = DEFAULT_PRECISION;
if (arguments.size() >= mandatory_argument_names.size() + 1)
precision = extractPrecision(arguments[mandatory_argument_names.size()]);
std::string timezone;
if (arguments.size() == mandatory_argument_names.size() + 2)
timezone = extractTimezone(arguments.back());
Columns converted_arguments = convertMandatoryArguments<DataTypeFloat64>(arguments, mandatory_argument_names);
auto res_column = ColumnDateTime64::create(input_rows_count, static_cast<UInt32>(precision));
auto & result_data = res_column->getData();
const auto & yyyymmddhhmmss_data = typeid_cast<const ColumnFloat64 &>(*converted_arguments[0]).getData();
const auto & date_lut = DateLUT::instance(timezone);
const auto fraction_pow = common::exp10_i32(precision);
for (size_t i = 0; i < input_rows_count; i++)
{
const auto float_date = yyyymmddhhmmss_data[i];
const auto yyyymmddhhmmss = static_cast<UInt64>(float_date);
const auto yyyymmdd = yyyymmddhhmmss / 1'000'000;
const auto hhmmss = yyyymmddhhmmss % 1'000'000;
const auto decimal = float_date - yyyymmddhhmmss;
const auto year = yyyymmdd / 10'000;
const auto month = yyyymmdd / 100 % 100;
const auto day = yyyymmdd % 100;
const auto hour = hhmmss / 10'000;
const auto minute = hhmmss / 100 % 100;
const auto second = hhmmss % 100;
auto fraction = static_cast<Int32>(decimal * fraction_pow);
auto date_time = dateTime(year, month, day, hour, minute, second, date_lut);
result_data[i] = DecimalUtils::decimalFromComponents<DateTime64>(
date_time,
static_cast<Int64>(fraction),
static_cast<UInt32>(precision));
}
return res_column;
}
};
@ -477,10 +723,15 @@ private:
REGISTER_FUNCTION(MakeDate)
{
factory.registerFunction<FunctionMakeDate<MakeDateTraits>>({}, FunctionFactory::CaseInsensitive);
factory.registerFunction<FunctionMakeDate<MakeDate32Traits>>();
factory.registerFunction<FunctionMakeDate<DateTraits>>({}, FunctionFactory::CaseInsensitive);
factory.registerFunction<FunctionMakeDate<Date32Traits>>();
factory.registerFunction<FunctionMakeDateTime>();
factory.registerFunction<FunctionMakeDateTime64>();
factory.registerFunction<FunctionYYYYYMMDDToDate<DateTraits>>();
factory.registerFunction<FunctionYYYYYMMDDToDate<Date32Traits>>();
factory.registerFunction<FunctionYYYYMMDDhhmmssToDateTime>();
factory.registerFunction<FunctionYYYYMMDDhhmmssToDateTime64>();
}
}

View File

@ -86,4 +86,4 @@ select makeDateTime64(year, 1, 1, 1, 0, 0, 0, precision, timezone) from (
select 1984 as year, 5 as precision, 'UTC' as timezone
union all
select 1985 as year, 5 as precision, 'UTC' as timezone
); -- { serverError 43 }
); -- { serverError 44 }

View File

@ -56,6 +56,10 @@ URLHierarchy
URLPathHierarchy
UUIDNumToString
UUIDStringToNum
YYYYMMDDToDate
YYYYMMDDToDate32
YYYYMMDDhhmmssToDateTime
YYYYMMDDhhmmssToDateTime64
_CAST
__bitBoolMaskAnd
__bitBoolMaskOr

View File

@ -0,0 +1,85 @@
--- YYYYMMDDToDateTime
Invalid input types are rejected
Result type is DateTime
DateTime
Nullable(DateTime)
Check correctness, integer arguments
1970-01-02 11:59:59
1970-01-01 00:00:00
2020-02-29 11:11:11
2023-09-11 15:05:05
2106-02-07 06:28:15
2106-02-07 06:28:15
Check correctness, float arguments
1970-01-02 11:59:59
1970-01-01 00:00:00
2020-02-29 11:11:11
2023-09-11 15:05:05
2106-02-07 06:28:15
2106-02-07 06:28:15
Check correctness, decimal arguments
1970-01-02 11:59:59
1970-01-01 00:00:00
2020-02-29 11:11:11
2023-09-11 15:05:05
2106-02-07 06:28:15
2106-02-07 06:28:15
Special cases
1970-01-01 00:00:00
1970-01-01 00:00:00
1970-01-01 00:00:00
1970-01-01 00:00:00
2106-02-07 06:28:15
1970-01-01 00:00:00
1970-01-01 00:00:00
1970-01-01 00:00:00
1970-01-01 00:00:00
2023-02-28 11:11:11
1970-01-01 00:00:00
1970-01-01 00:00:00
\N
1970-01-01 00:00:00
1970-01-01 00:00:00
--- YYYYMMDDToDateTime64
Invalid input types are rejected
Result type is DateTime
DateTime64(3)
DateTime64(5)
Nullable(DateTime64(3))
Check correctness, integer arguments
1900-01-01 00:00:00.000
1900-01-01 00:00:00.000
2020-02-29 11:11:11.000
2023-09-11 15:05:05.000
2299-12-31 23:59:59.000
2299-12-31 23:59:59.000
Check correctness, float arguments
1900-01-01 00:00:00.900
1900-01-01 00:00:00.899
2020-02-29 11:11:11.101
2023-09-11 15:05:05.101
2299-12-31 23:59:59.101
2299-12-31 23:59:59.101
Check correctness, decimal arguments
1900-01-01 00:00:00.900
1900-01-01 00:00:00.899
2020-02-29 11:11:11.101
2023-09-11 15:05:05.101
2299-12-31 23:59:59.101
2299-12-31 23:59:59.101
Special cases
1900-01-01 00:00:00.648
1900-01-01 00:00:00.000
1900-01-01 00:00:00.000
1900-01-01 00:00:00.000
2299-12-31 23:59:59.000
1900-01-01 00:00:00.000
1900-01-01 00:00:00.000
1900-01-01 00:00:00.000
1900-01-01 00:00:00.000
2023-02-28 11:11:11.000
1900-01-01 00:00:00.000
1900-01-01 00:00:00.000
\N
1900-01-01 00:00:00.000
1900-01-01 00:00:00.000

View File

@ -0,0 +1,119 @@
SET session_timezone = 'UTC'; -- no time zone randomization, please
-----------------------------------------------------------
SELECT '--- YYYYMMDDToDateTime';
SELECT 'Invalid input types are rejected';
SELECT YYYYMMDDhhmmssToDateTime(); -- { serverError NUMBER_OF_ARGUMENTS_DOESNT_MATCH }
SELECT YYYYMMDDhhmmssToDateTime(toDate('2023-09-11')); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT YYYYMMDDhhmmssToDateTime(toDate32('2023-09-11')); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT YYYYMMDDhhmmssToDateTime(toDateTime('2023-09-11 12:18:00')); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT YYYYMMDDhhmmssToDateTime(toDateTime64('2023-09-11 12:18:00', 3)); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT YYYYMMDDhhmmssToDateTime('2023-09-11'); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT YYYYMMDDhhmmssToDateTime(20230911134254, 3); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT YYYYMMDDhhmmssToDateTime(20230911134254, 'invalid tz'); -- { serverError BAD_ARGUMENTS }
SELECT YYYYMMDDhhmmssToDateTime(20230911134254, 'Europe/Berlin', 'bad'); -- { serverError NUMBER_OF_ARGUMENTS_DOESNT_MATCH }
SELECT 'Result type is DateTime';
SELECT toTypeName(YYYYMMDDhhmmssToDateTime(19910824));
SELECT toTypeName(YYYYMMDDhhmmssToDateTime(cast(19910824 AS Nullable(UInt64))));
--
SELECT 'Check correctness, integer arguments';
SELECT YYYYMMDDhhmmssToDateTime(19691231595959);
SELECT YYYYMMDDhhmmssToDateTime(19700101000000);
SELECT YYYYMMDDhhmmssToDateTime(20200229111111); -- leap day
SELECT YYYYMMDDhhmmssToDateTime(20230911150505);
SELECT YYYYMMDDhhmmssToDateTime(21060207062815);
SELECT YYYYMMDDhhmmssToDateTime(21060207062816);
SELECT 'Check correctness, float arguments';
SELECT YYYYMMDDhhmmssToDateTime(19691231595959.1);
SELECT YYYYMMDDhhmmssToDateTime(19700101000000.1);
SELECT YYYYMMDDhhmmssToDateTime(20200229111111.1); -- leap day
SELECT YYYYMMDDhhmmssToDateTime(20230911150505.1);
SELECT YYYYMMDDhhmmssToDateTime(21060207062815.1);
SELECT YYYYMMDDhhmmssToDateTime(21060207062816.1);
SELECT 'Check correctness, decimal arguments';
SELECT YYYYMMDDhhmmssToDateTime(toDecimal64(19691231595959.1, 5));
SELECT YYYYMMDDhhmmssToDateTime(toDecimal64(19700101000000.1, 5));
SELECT YYYYMMDDhhmmssToDateTime(toDecimal64(20200229111111.1, 5)); -- leap day
SELECT YYYYMMDDhhmmssToDateTime(toDecimal64(20230911150505.1, 5));
SELECT YYYYMMDDhhmmssToDateTime(toDecimal64(21060207062815.1, 5));
SELECT YYYYMMDDhhmmssToDateTime(toDecimal64(21060207062816.1, 5));
SELECT 'Special cases';
SELECT YYYYMMDDhhmmssToDateTime(-20230911111111); -- negative
SELECT YYYYMMDDhhmmssToDateTime(110); -- invalid everything
SELECT YYYYMMDDhhmmssToDateTime(999999999999999999); -- huge value
SELECT YYYYMMDDhhmmssToDateTime(15001113111111); -- year out of range
SELECT YYYYMMDDhhmmssToDateTime(35001113111111); -- year out of range
SELECT YYYYMMDDhhmmssToDateTime(20231620111111); -- invalid month
SELECT YYYYMMDDhhmmssToDateTime(20230020111111); -- invalid month
SELECT YYYYMMDDhhmmssToDateTime(20230940111111); -- invalid day
SELECT YYYYMMDDhhmmssToDateTime(20230900111111); -- invalid day
SELECT YYYYMMDDhhmmssToDateTime(20230228111111); -- leap day when there is none
SELECT YYYYMMDDhhmmssToDateTime(True);
SELECT YYYYMMDDhhmmssToDateTime(False);
SELECT YYYYMMDDhhmmssToDateTime(NULL);
SELECT YYYYMMDDhhmmssToDateTime(yyyymmdd) FROM (SELECT 19840121 AS yyyymmdd UNION ALL SELECT 20230911 AS yyyymmdd) ORDER BY yyyymmdd; -- non-const
-----------------------------------------------------------
SELECT '--- YYYYMMDDToDateTime64';
SELECT 'Invalid input types are rejected';
SELECT YYYYMMDDhhmmssToDateTime64(); -- { serverError NUMBER_OF_ARGUMENTS_DOESNT_MATCH }
SELECT YYYYMMDDhhmmssToDateTime64(toDate('2023-09-11')); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT YYYYMMDDhhmmssToDateTime64(toDate32('2023-09-11')); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT YYYYMMDDhhmmssToDateTime64(toDateTime('2023-09-11 12:18:00')); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT YYYYMMDDhhmmssToDateTime64(toDateTime64('2023-09-11 12:18:00', 3)); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT YYYYMMDDhhmmssToDateTime64('2023-09-11'); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT YYYYMMDDhhmmssToDateTime64('2023-09-11', 'invalid precision'); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT YYYYMMDDhhmmssToDateTime64(20230911134254, 3, 3); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT YYYYMMDDhhmmssToDateTime64(20230911134254, 3, 'invalid tz'); -- { serverError BAD_ARGUMENTS }
SELECT YYYYMMDDhhmmssToDateTime64(20230911134254, 3, 'Europe/Berlin', 'no more args'); -- { serverError NUMBER_OF_ARGUMENTS_DOESNT_MATCH }
SELECT 'Result type is DateTime';
SELECT toTypeName(YYYYMMDDhhmmssToDateTime64(19910824));
SELECT toTypeName(YYYYMMDDhhmmssToDateTime64(19910824, 5));
SELECT toTypeName(YYYYMMDDhhmmssToDateTime64(cast(19910824 AS Nullable(UInt64))));
SELECT 'Check correctness, integer arguments';
SELECT YYYYMMDDhhmmssToDateTime64(189912315959);
SELECT YYYYMMDDhhmmssToDateTime64(19000101000000);
SELECT YYYYMMDDhhmmssToDateTime64(20200229111111); -- leap day
SELECT YYYYMMDDhhmmssToDateTime64(20230911150505);
SELECT YYYYMMDDhhmmssToDateTime64(22991231235959);
SELECT YYYYMMDDhhmmssToDateTime64(23000101000000);
SELECT 'Check correctness, float arguments';
SELECT YYYYMMDDhhmmssToDateTime64(189912315959.1);
SELECT YYYYMMDDhhmmssToDateTime64(19000101000000.1);
SELECT YYYYMMDDhhmmssToDateTime64(20200229111111.1); -- leap day
SELECT YYYYMMDDhhmmssToDateTime64(20230911150505.1);
SELECT YYYYMMDDhhmmssToDateTime64(22991231235959.1);
SELECT YYYYMMDDhhmmssToDateTime64(23000101000000.1);
SELECT 'Check correctness, decimal arguments';
SELECT YYYYMMDDhhmmssToDateTime64(toDecimal64(189912315959.1, 5));
SELECT YYYYMMDDhhmmssToDateTime64(toDecimal64(19000101000000.1, 5));
SELECT YYYYMMDDhhmmssToDateTime64(toDecimal64(20200229111111.1, 5)); -- leap day
SELECT YYYYMMDDhhmmssToDateTime64(toDecimal64(20230911150505.1, 5));
SELECT YYYYMMDDhhmmssToDateTime64(toDecimal64(22991231235959.1, 5));
SELECT YYYYMMDDhhmmssToDateTime64(toDecimal64(23000101000000.1, 5));
SELECT 'Special cases';
SELECT YYYYMMDDhhmmssToDateTime64(-20230911111111); -- negative
SELECT YYYYMMDDhhmmssToDateTime64(110); -- invalid everything
SELECT YYYYMMDDhhmmssToDateTime64(999999999999999999); -- huge value
SELECT YYYYMMDDhhmmssToDateTime64(15001113111111); -- year out of range
SELECT YYYYMMDDhhmmssToDateTime64(35001113111111); -- year out of range
SELECT YYYYMMDDhhmmssToDateTime64(20231620111111); -- invalid month
SELECT YYYYMMDDhhmmssToDateTime64(20230020111111); -- invalid month
SELECT YYYYMMDDhhmmssToDateTime64(20230940111111); -- invalid day
SELECT YYYYMMDDhhmmssToDateTime64(20230900111111); -- invalid day
SELECT YYYYMMDDhhmmssToDateTime64(20230228111111); -- leap day when there is none
SELECT YYYYMMDDhhmmssToDateTime64(True);
SELECT YYYYMMDDhhmmssToDateTime64(False);
SELECT YYYYMMDDhhmmssToDateTime64(NULL);
SELECT YYYYMMDDhhmmssToDateTime64(yyyymmdd) FROM (SELECT 19840121 AS yyyymmdd UNION ALL SELECT 20230911 AS yyyymmdd) ORDER BY yyyymmdd; -- non-const

View File

@ -0,0 +1,84 @@
--- YYYYMMDDToDate
Invalid input types are rejected
Result type is Date
Date
Nullable(Date)
Check correctness, integer arguments
1970-01-01
1970-01-01
2020-02-29
2023-09-11
2149-06-06
1970-01-01
Check correctness, float arguments
1970-01-01
1970-01-01
2020-02-29
2023-09-11
2149-06-06
1970-01-01
Check correctness, decimal arguments
1970-01-01
1970-01-01
2020-02-29
2023-09-11
2149-06-06
1970-01-01
Special cases
1970-01-01
1970-01-01
1970-01-01
1970-01-01
1970-01-01
1970-01-01
1970-01-01
1970-01-01
1970-01-01
2023-02-28
1970-01-01
1970-01-01
\N
1984-01-21
2023-09-11
--- YYYYMMDDToDate32
Invalid input types are rejected
Result type is Date32
Date32
Nullable(Date32)
Check correctness, integer arguments
1970-01-01
1900-01-01
2020-02-29
2023-09-11
2299-12-31
1970-01-01
Check correctness, float arguments
1970-01-01
1900-01-01
2020-02-29
2023-09-11
2299-12-31
1970-01-01
Check correctness, decimal arguments
1970-01-01
1900-01-01
2020-02-29
2023-09-11
2299-12-31
1970-01-01
Special cases
1970-01-01
1970-01-01
1970-01-01
1970-01-01
1970-01-01
1970-01-01
1970-01-01
1970-01-01
1970-01-01
2023-02-28
1970-01-01
1970-01-01
\N
1984-01-21
2023-09-11

View File

@ -0,0 +1,112 @@
-----------------------------------------------------------
SELECT '--- YYYYMMDDToDate';
SELECT 'Invalid input types are rejected';
SELECT YYYYMMDDToDate(); -- { serverError NUMBER_OF_ARGUMENTS_DOESNT_MATCH }
SELECT YYYYMMDDToDate(toDate('2023-09-11')); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT YYYYMMDDToDate(toDate32('2023-09-11')); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT YYYYMMDDToDate(toDateTime('2023-09-11 12:18:00')); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT YYYYMMDDToDate(toDateTime64('2023-09-11 12:18:00', 3)); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT YYYYMMDDToDate('2023-09-11'); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT YYYYMMDDToDate(2023, 09, 11); -- { serverError NUMBER_OF_ARGUMENTS_DOESNT_MATCH }
SELECT YYYYMMDDToDate(2023, 110); -- { serverError NUMBER_OF_ARGUMENTS_DOESNT_MATCH }
SELECT 'Result type is Date';
SELECT toTypeName(YYYYMMDDToDate(19910824));
SELECT toTypeName(YYYYMMDDToDate(cast(19910824 AS Nullable(UInt64))));
SELECT 'Check correctness, integer arguments';
SELECT YYYYMMDDToDate(19691231);
SELECT YYYYMMDDToDate(19700101);
SELECT YYYYMMDDToDate(20200229); -- leap day
SELECT YYYYMMDDToDate(20230911);
SELECT YYYYMMDDToDate(21490606);
SELECT YYYYMMDDToDate(21490607);
SELECT 'Check correctness, float arguments';
SELECT YYYYMMDDToDate(19691231.1);
SELECT YYYYMMDDToDate(19700101.1);
SELECT YYYYMMDDToDate(20200229.1); -- leap day
SELECT YYYYMMDDToDate(20230911.1);
SELECT YYYYMMDDToDate(21490606.1);
SELECT YYYYMMDDToDate(21490607.1);
SELECT 'Check correctness, decimal arguments';
SELECT YYYYMMDDToDate(toDecimal64(19691231.1, 5));
SELECT YYYYMMDDToDate(toDecimal64(19700101.1, 5));
SELECT YYYYMMDDToDate(toDecimal64(20200229.1, 5)); -- leap day
SELECT YYYYMMDDToDate(toDecimal64(20230911.1, 5));
SELECT YYYYMMDDToDate(toDecimal64(21490606.1, 5));
SELECT YYYYMMDDToDate(toDecimal64(21490607.1, 5));
SELECT 'Special cases';
SELECT YYYYMMDDToDate(-20230911); -- negative
SELECT YYYYMMDDToDate(110); -- invalid everything
SELECT YYYYMMDDToDate(9999999999999); -- huge value
SELECT YYYYMMDDToDate(15001113); -- year out of range
SELECT YYYYMMDDToDate(35001113); -- year out of range
SELECT YYYYMMDDToDate(20231620); -- invalid month
SELECT YYYYMMDDToDate(20230020); -- invalid month
SELECT YYYYMMDDToDate(20230940); -- invalid day
SELECT YYYYMMDDToDate(20230900); -- invalid day
SELECT YYYYMMDDToDate(20230228); -- leap day when there is none
SELECT YYYYMMDDToDate(True);
SELECT YYYYMMDDToDate(False);
SELECT YYYYMMDDToDate(NULL);
SELECT YYYYMMDDToDate(yyyymmdd) FROM (SELECT 19840121 AS yyyymmdd UNION ALL SELECT 20230911 AS yyyymmdd) ORDER BY yyyymmdd; -- non-const
-----------------------------------------------------------
SELECT '--- YYYYMMDDToDate32';
SELECT 'Invalid input types are rejected';
SELECT YYYYMMDDToDate32(toDate('2023-09-11')); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT YYYYMMDDToDate32(toDate32('2023-09-11')); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT YYYYMMDDToDate32(toDateTime('2023-09-11 12:18:00')); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT YYYYMMDDToDate32(toDateTime64('2023-09-11 12:18:00', 3)); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT YYYYMMDDToDate32('2023-09-11'); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT YYYYMMDDToDate32(2023, 09, 11); -- { serverError NUMBER_OF_ARGUMENTS_DOESNT_MATCH }
SELECT YYYYMMDDToDate32(2023, 110); -- { serverError NUMBER_OF_ARGUMENTS_DOESNT_MATCH }
SELECT 'Result type is Date32';
SELECT toTypeName(YYYYMMDDToDate32(19910824));
SELECT toTypeName(YYYYMMDDToDate32(cast(19910824 AS Nullable(UInt64))));
SELECT 'Check correctness, integer arguments';
SELECT YYYYMMDDToDate32(18991231);
SELECT YYYYMMDDToDate32(19000101);
SELECT YYYYMMDDToDate32(20200229); -- leap day
SELECT YYYYMMDDToDate32(20230911);
SELECT YYYYMMDDToDate32(22991231);
SELECT YYYYMMDDToDate32(23000101);
SELECT 'Check correctness, float arguments';
SELECT YYYYMMDDToDate32(18991231.1);
SELECT YYYYMMDDToDate32(19000101.1);
SELECT YYYYMMDDToDate32(20200229.1); -- leap day
SELECT YYYYMMDDToDate32(20230911.1);
SELECT YYYYMMDDToDate32(22991231.1);
SELECT YYYYMMDDToDate32(23000101.1);
SELECT 'Check correctness, decimal arguments';
SELECT YYYYMMDDToDate32(toDecimal64(18991231.1, 5));
SELECT YYYYMMDDToDate32(toDecimal64(19000101.1, 5));
SELECT YYYYMMDDToDate32(toDecimal64(20200229.1, 5)); -- leap day
SELECT YYYYMMDDToDate32(toDecimal64(20230911.1, 5));
SELECT YYYYMMDDToDate32(toDecimal64(22991231.1, 5));
SELECT YYYYMMDDToDate32(toDecimal64(23000101.1, 5));
SELECT 'Special cases';
SELECT YYYYMMDDToDate32(-20230911); -- negative
SELECT YYYYMMDDToDate32(110); -- invalid everything
SELECT YYYYMMDDToDate32(9999999999999); -- huge value
SELECT YYYYMMDDToDate32(15001113); -- year out of range
SELECT YYYYMMDDToDate32(35001113); -- year out of range
SELECT YYYYMMDDToDate32(20231620); -- invalid month
SELECT YYYYMMDDToDate32(20230020); -- invalid month
SELECT YYYYMMDDToDate32(20230940); -- invalid day
SELECT YYYYMMDDToDate32(20230900); -- invalid day
SELECT YYYYMMDDToDate32(20230228); -- leap day when there is none
SELECT YYYYMMDDToDate32(True);
SELECT YYYYMMDDToDate32(False);
SELECT YYYYMMDDToDate32(NULL);
SELECT YYYYMMDDToDate32(yyyymmdd) FROM (SELECT 19840121 AS yyyymmdd UNION ALL SELECT 20230911 AS yyyymmdd) ORDER BY yyyymmdd; -- non-const