Merge pull request #45233 from ClickHouse/improve_week_day

Revert "Revert "Improve week day""
This commit is contained in:
Alexey Milovidov 2023-01-27 02:44:17 +03:00 committed by GitHub
commit 5b257ab806
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 232 additions and 125 deletions

View File

@ -209,10 +209,25 @@ Aliases: `DAYOFMONTH`, `DAY`.
## toDayOfWeek ## toDayOfWeek
Converts a date or date with time to a UInt8 number containing the number of the day of the week (Monday is 1, and Sunday is 7). Converts a date or date with time to a UInt8 number containing the number of the day of the week.
The two-argument form of `toDayOfWeek()` enables you to specify whether the week starts on Monday or Sunday, and whether the return value should be in the range from 0 to 6 or 1 to 7. If the mode argument is ommited, the default mode is 0. The time zone of the date can be specified as the third argument.
| Mode | First day of week | Range |
|------|-------------------|------------------------------------------------|
| 0 | Monday | 1-7, Monday = 1, Tuesday = 2, ..., Sunday = 7 |
| 1 | Monday | 0-6, Monday = 0, Tuesday = 1, ..., Sunday = 6 |
| 2 | Sunday | 0-6, Sunday = 0, Monday = 1, ..., Saturday = 6 |
| 3 | Sunday | 1-7, Sunday = 1, Monday = 2, ..., Saturday = 7 |
Alias: `DAYOFWEEK`. Alias: `DAYOFWEEK`.
**Syntax**
``` sql
toDayOfWeek(t[, mode[, timezone]])
```
## toHour ## toHour
Converts a date with time to a UInt8 number containing the number of the hour in 24-hour time (0-23). Converts a date with time to a UInt8 number containing the number of the hour in 24-hour time (0-23).
@ -316,11 +331,17 @@ If `toLastDayOfMonth` is called with an argument of type `Date` greater then 214
Rounds down a date, or date with time, to the nearest Monday. Rounds down a date, or date with time, to the nearest Monday.
Returns the date. Returns the date.
## toStartOfWeek(t\[,mode\]) ## toStartOfWeek
Rounds down a date, or date with time, to the nearest Sunday or Monday by mode. Rounds a date or date with time down to the nearest Sunday or Monday.
Returns the date. Returns the date.
The mode argument works exactly like the mode argument to toWeek(). For the single-argument syntax, a mode value of 0 is used. The mode argument works exactly like the mode argument in function `toWeek()`. If no mode is specified, mode is assumed as 0.
**Syntax**
``` sql
toStartOfWeek(t[, mode[, timezone]])
```
## toStartOfDay ## toStartOfDay
@ -455,10 +476,12 @@ Converts a date, or date with time, to a UInt16 number containing the ISO Year n
Converts a date, or date with time, to a UInt8 number containing the ISO Week number. Converts a date, or date with time, to a UInt8 number containing the ISO Week number.
## toWeek(date\[,mode\]) ## toWeek
This function returns the week number for date or datetime. The two-argument form of `toWeek()` enables you to specify whether the week starts on Sunday or Monday and whether the return value should be in the range from 0 to 53 or from 1 to 53. If the mode argument is omitted, the default mode is 0.
`toISOWeek()` is a compatibility function that is equivalent to `toWeek(date,3)`.
This function returns the week number for date or datetime. The two-argument form of toWeek() enables you to specify whether the week starts on Sunday or Monday and whether the return value should be in the range from 0 to 53 or from 1 to 53. If the mode argument is omitted, the default mode is 0.
`toISOWeek()`is a compatibility function that is equivalent to `toWeek(date,3)`.
The following table describes how the mode argument works. The following table describes how the mode argument works.
| Mode | First day of week | Range | Week 1 is the first week … | | Mode | First day of week | Range | Week 1 is the first week … |
@ -482,13 +505,15 @@ For mode values with a meaning of “with 4 or more days this year,” weeks are
For mode values with a meaning of “contains January 1”, the week contains January 1 is week 1. It does not matter how many days in the new year the week contained, even if it contained only one day. For mode values with a meaning of “contains January 1”, the week contains January 1 is week 1. It does not matter how many days in the new year the week contained, even if it contained only one day.
**Syntax**
``` sql ``` sql
toWeek(date, [, mode][, Timezone]) toWeek(t[, mode[, time_zone]])
``` ```
**Arguments** **Arguments**
- `date` Date or DateTime. - `t` Date or DateTime.
- `mode` Optional parameter, Range of values is \[0,9\], default is 0. - `mode` Optional parameter, Range of values is \[0,9\], default is 0.
- `Timezone` Optional parameter, it behaves like any other conversion function. - `Timezone` Optional parameter, it behaves like any other conversion function.
@ -504,13 +529,19 @@ SELECT toDate('2016-12-27') AS date, toWeek(date) AS week0, toWeek(date,1) AS we
└────────────┴───────┴───────┴───────┘ └────────────┴───────┴───────┴───────┘
``` ```
## toYearWeek(date\[,mode\]) ## toYearWeek
Returns year and week for a date. The year in the result may be different from the year in the date argument for the first and the last week of the year. Returns year and week for a date. The year in the result may be different from the year in the date argument for the first and the last week of the year.
The mode argument works exactly like the mode argument to toWeek(). For the single-argument syntax, a mode value of 0 is used. The mode argument works exactly like the mode argument to `toWeek()`. For the single-argument syntax, a mode value of 0 is used.
`toISOYear()`is a compatibility function that is equivalent to `intDiv(toYearWeek(date,3),100)`. `toISOYear()` is a compatibility function that is equivalent to `intDiv(toYearWeek(date,3),100)`.
**Syntax**
``` sql
toYearWeek(t[, mode[, timezone]])
```
**Example** **Example**

View File

@ -39,6 +39,15 @@ enum class WeekModeFlag : UInt8
}; };
using YearWeek = std::pair<UInt16, UInt8>; using YearWeek = std::pair<UInt16, UInt8>;
/// Modes for toDayOfWeek() function.
enum class WeekDayMode
{
WeekStartsMonday1 = 0,
WeekStartsMonday0 = 1,
WeekStartsSunday0 = 2,
WeekStartsSunday1 = 3
};
/** Lookup table to conversion of time to date, and to month / year / day of week / day of month and so on. /** Lookup table to conversion of time to date, and to month / year / day of week / day of month and so on.
* First time was implemented for OLAPServer, that needed to do billions of such transformations. * First time was implemented for OLAPServer, that needed to do billions of such transformations.
*/ */
@ -619,9 +628,28 @@ public:
template <typename DateOrTime> template <typename DateOrTime>
inline Int16 toYear(DateOrTime v) const { return lut[toLUTIndex(v)].year; } inline Int16 toYear(DateOrTime v) const { return lut[toLUTIndex(v)].year; }
/// 1-based, starts on Monday
template <typename DateOrTime> template <typename DateOrTime>
inline UInt8 toDayOfWeek(DateOrTime v) const { return lut[toLUTIndex(v)].day_of_week; } inline 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
{
WeekDayMode mode = check_week_day_mode(week_day_mode);
UInt8 res = toDayOfWeek(v);
using enum WeekDayMode;
bool start_from_sunday = (mode == WeekStartsSunday0 || mode == WeekStartsSunday1);
bool zero_based = (mode == WeekStartsMonday0 || mode == WeekStartsSunday0);
if (start_from_sunday)
res = res % 7 + 1;
if (zero_based)
--res;
return res;
}
template <typename DateOrTime> template <typename DateOrTime>
inline UInt8 toDayOfMonth(DateOrTime v) const { return lut[toLUTIndex(v)].day_of_month; } inline UInt8 toDayOfMonth(DateOrTime v) const { return lut[toLUTIndex(v)].day_of_month; }
@ -844,6 +872,12 @@ public:
return week_format; return week_format;
} }
/// Check and change mode to effective.
inline WeekDayMode check_week_day_mode(UInt8 mode) const /// NOLINT
{
return static_cast<WeekDayMode>(mode & 3);
}
/** Calculate weekday from d. /** Calculate weekday from d.
* Returns 0 for monday, 1 for tuesday... * Returns 0 for monday, 1 for tuesday...
*/ */

View File

@ -786,21 +786,21 @@ struct ToDayOfWeekImpl
{ {
static constexpr auto name = "toDayOfWeek"; static constexpr auto name = "toDayOfWeek";
static inline UInt8 execute(Int64 t, const DateLUTImpl & time_zone) static inline UInt8 execute(Int64 t, UInt8 mode, const DateLUTImpl & time_zone)
{ {
return time_zone.toDayOfWeek(t); return time_zone.toDayOfWeek(t, mode);
} }
static inline UInt8 execute(UInt32 t, const DateLUTImpl & time_zone) static inline UInt8 execute(UInt32 t, UInt8 mode, const DateLUTImpl & time_zone)
{ {
return time_zone.toDayOfWeek(t); return time_zone.toDayOfWeek(t, mode);
} }
static inline UInt8 execute(Int32 d, const DateLUTImpl & time_zone) static inline UInt8 execute(Int32 d, UInt8 mode, const DateLUTImpl & time_zone)
{ {
return time_zone.toDayOfWeek(ExtendedDayNum(d)); return time_zone.toDayOfWeek(ExtendedDayNum(d), mode);
} }
static inline UInt8 execute(UInt16 d, const DateLUTImpl & time_zone) static inline UInt8 execute(UInt16 d, UInt8 mode, const DateLUTImpl & time_zone)
{ {
return time_zone.toDayOfWeek(DayNum(d)); return time_zone.toDayOfWeek(DayNum(d), mode);
} }
using FactorTransform = ToMondayImpl; using FactorTransform = ToMondayImpl;

View File

@ -82,8 +82,8 @@ protected:
arguments[0].type->getName(), getName()); arguments[0].type->getName(), getName());
if (!isUInt8(arguments[1].type)) if (!isUInt8(arguments[1].type))
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
"Illegal type of 2nd (optional) argument of function {}. Must be constant UInt8 (week mode).", "Illegal type {} of 2nd (optional) argument of function {}. Must be constant UInt8 (week mode).",
getName()); arguments[1].type->getName(), getName());
} }
else if (arguments.size() == 3) else if (arguments.size() == 3)
{ {
@ -93,12 +93,12 @@ protected:
arguments[0].type->getName(), getName()); arguments[0].type->getName(), getName());
if (!isUInt8(arguments[1].type)) if (!isUInt8(arguments[1].type))
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
"Illegal type of 2nd (optional) argument of function {}. Must be constant UInt8 (week mode).", "Illegal type {} of 2nd (optional) argument of function {}. Must be constant UInt8 (week mode).",
getName()); arguments[1].type->getName(), getName());
if (!isString(arguments[2].type)) if (!isString(arguments[2].type))
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
"Illegal type of 3rd (optional) argument of function {}. Must be constant string (timezone name).", "Illegal type {} of 3rd (optional) argument of function {}. Must be constant string (timezone name).",
getName()); arguments[2].type->getName(), getName());
if ((isDate(arguments[0].type) || isDate32(arguments[0].type)) && is_result_type_date_or_date32) if ((isDate(arguments[0].type) || isDate32(arguments[0].type)) && is_result_type_date_or_date32)
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
"The timezone argument of function {} is allowed only when the 1st argument is DateTime or DateTime64.", "The timezone argument of function {} is allowed only when the 1st argument is DateTime or DateTime64.",

View File

@ -225,8 +225,8 @@ public:
} }
else if constexpr (std::is_same_v<TransformX, TransformDateTime64<ToRelativeWeekNumImpl<ResultPrecision::Extended>>>) else if constexpr (std::is_same_v<TransformX, TransformDateTime64<ToRelativeWeekNumImpl<ResultPrecision::Extended>>>)
{ {
auto x_day_of_week = TransformDateTime64<ToDayOfWeekImpl>(transform_x.getScaleMultiplier()).execute(x, timezone_x); auto x_day_of_week = TransformDateTime64<ToDayOfWeekImpl>(transform_x.getScaleMultiplier()).execute(x, 0, timezone_x);
auto y_day_of_week = TransformDateTime64<ToDayOfWeekImpl>(transform_y.getScaleMultiplier()).execute(y, timezone_y); auto y_day_of_week = TransformDateTime64<ToDayOfWeekImpl>(transform_y.getScaleMultiplier()).execute(y, 0, timezone_y);
if ((x_day_of_week > y_day_of_week) if ((x_day_of_week > y_day_of_week)
|| ((x_day_of_week == y_day_of_week) && (a_comp.time.hour > b_comp.time.hour)) || ((x_day_of_week == y_day_of_week) && (a_comp.time.hour > b_comp.time.hour))
|| ((a_comp.time.hour == b_comp.time.hour) && ((a_comp.time.minute > b_comp.time.minute) || ((a_comp.time.hour == b_comp.time.hour) && ((a_comp.time.minute > b_comp.time.minute)

View File

@ -276,7 +276,7 @@ private:
{ {
static inline void write(WriteBuffer & buffer, Time source, const DateLUTImpl & timezone) static inline void write(WriteBuffer & buffer, Time source, const DateLUTImpl & timezone)
{ {
const auto day = ToDayOfWeekImpl::execute(source, timezone); const auto day = ToDayOfWeekImpl::execute(source, 0, timezone);
static constexpr std::string_view day_names[] = static constexpr std::string_view day_names[] =
{ {
"Monday", "Monday",

View File

@ -344,13 +344,13 @@ private:
static size_t mysqlDayOfWeek(char * dest, Time source, UInt64, UInt32, const DateLUTImpl & timezone) static size_t mysqlDayOfWeek(char * dest, Time source, UInt64, UInt32, const DateLUTImpl & timezone)
{ {
*dest = '0' + ToDayOfWeekImpl::execute(source, timezone); *dest = '0' + ToDayOfWeekImpl::execute(source, 0, timezone);
return 1; return 1;
} }
static size_t mysqlDayOfWeek0To6(char * dest, Time source, UInt64, UInt32, const DateLUTImpl & timezone) static size_t mysqlDayOfWeek0To6(char * dest, Time source, UInt64, UInt32, const DateLUTImpl & timezone)
{ {
auto day = ToDayOfWeekImpl::execute(source, timezone); auto day = ToDayOfWeekImpl::execute(source, 0, timezone);
*dest = '0' + (day == 7 ? 0 : day); *dest = '0' + (day == 7 ? 0 : day);
return 1; return 1;
} }
@ -499,13 +499,13 @@ private:
static size_t jodaDayOfWeek1Based(size_t min_represent_digits, char * dest, Time source, UInt64, UInt32, const DateLUTImpl & timezone) static size_t jodaDayOfWeek1Based(size_t min_represent_digits, char * dest, Time source, UInt64, UInt32, const DateLUTImpl & timezone)
{ {
auto week_day = ToDayOfWeekImpl::execute(source, timezone); auto week_day = ToDayOfWeekImpl::execute(source, 0, timezone);
return writeNumberWithPadding(dest, week_day, min_represent_digits); return writeNumberWithPadding(dest, week_day, min_represent_digits);
} }
static size_t jodaDayOfWeekText(size_t min_represent_digits, char * dest, Time source, UInt64, UInt32, const DateLUTImpl & timezone) static size_t jodaDayOfWeekText(size_t min_represent_digits, char * dest, Time source, UInt64, UInt32, const DateLUTImpl & timezone)
{ {
auto week_day = ToDayOfWeekImpl::execute(source, timezone); auto week_day = ToDayOfWeekImpl::execute(source, 0, timezone);
if (week_day == 7) if (week_day == 7)
week_day = 0; week_day = 0;

View File

@ -1,13 +1,12 @@
#include <Functions/FunctionFactory.h> #include <Functions/FunctionFactory.h>
#include <Functions/DateTimeTransforms.h> #include <Functions/DateTimeTransforms.h>
#include <Functions/FunctionDateOrDateTimeToSomething.h>
#include <DataTypes/DataTypesNumber.h> #include <DataTypes/DataTypesNumber.h>
#include <Functions/FunctionCustomWeekToSomething.h>
namespace DB namespace DB
{ {
using FunctionToDayOfWeek = FunctionDateOrDateTimeToSomething<DataTypeUInt8, ToDayOfWeekImpl>; using FunctionToDayOfWeek = FunctionCustomWeekToSomething<DataTypeUInt8, ToDayOfWeekImpl>;
REGISTER_FUNCTION(ToDayOfWeek) REGISTER_FUNCTION(ToDayOfWeek)
{ {

View File

@ -6,7 +6,6 @@
<value>toSecond</value> <value>toSecond</value>
<value>toMinute</value> <value>toMinute</value>
<value>toHour</value> <value>toHour</value>
<value>toDayOfWeek</value>
<value>toDayOfMonth</value> <value>toDayOfMonth</value>
<value>toDayOfYear</value> <value>toDayOfYear</value>
<value>toMonth</value> <value>toMonth</value>
@ -47,21 +46,33 @@
<value>toUnixTimestamp</value> <value>toUnixTimestamp</value>
</values> </values>
</substitution> </substitution>
<substitution>
<name>datetime_transform_with_mode</name>
<values>
<value>toDayOfWeek</value>
<value>toStartOfWeek</value>
<value>toWeek</value>
<value>toYearWeek</value>
</values>
</substitution>
<substitution> <substitution>
<name>date_transform</name> <name>date_transform</name>
<values> <values>
<value>toDayOfWeek</value>
<value>toDayOfMonth</value> <value>toDayOfMonth</value>
<value>toDayOfWeek</value>
<value>toDayOfYear</value> <value>toDayOfYear</value>
<value>toWeek</value>
<value>toMonth</value> <value>toMonth</value>
<value>toQuarter</value> <value>toQuarter</value>
<value>toYear</value> <value>toYear</value>
<value>toYearWeek</value>
<value>toISOWeek</value> <value>toISOWeek</value>
<value>toISOYear</value> <value>toISOYear</value>
<value>toDate</value> <value>toDate</value>
<value>toMonday</value> <value>toMonday</value>
<value>toStartOfDay</value> <value>toStartOfDay</value>
<value>toStartOfWeek</value>
<value>toStartOfMonth</value> <value>toStartOfMonth</value>
<value>toStartOfQuarter</value> <value>toStartOfQuarter</value>
<value>toStartOfYear</value> <value>toStartOfYear</value>
@ -79,14 +90,6 @@
<value>toRelativeQuarterNum</value> <value>toRelativeQuarterNum</value>
</values> </values>
</substitution> </substitution>
<substitution>
<name>time_zone</name>
<values>
<value>UTC</value>
<value>Asia/Istanbul</value>
<value>Asia/Kolkata</value>
</values>
</substitution>
<substitution> <substitution>
<name>binary_function</name> <name>binary_function</name>
<values> <values>
@ -116,11 +119,21 @@
<value>subtractYears</value> <value>subtractYears</value>
</values> </values>
</substitution> </substitution>
<substitution>
<name>time_zone</name>
<values>
<value>UTC</value>
<value>Asia/Istanbul</value>
<value>Asia/Kolkata</value>
</values>
</substitution>
</substitutions> </substitutions>
<query>SELECT count() FROM numbers(50000000) WHERE NOT ignore(toDateTime('2017-01-01 00:00:00') + number % 100000000 + rand() % 100000 AS t, {datetime_transform}(t, '{time_zone}'))</query> <query>SELECT count() FROM numbers(50000000) WHERE NOT ignore(toDateTime('2017-01-01 00:00:00') + number % 100000000 + rand() % 100000 AS t, {datetime_transform}(t, '{time_zone}'))</query>
<query>SELECT count() FROM numbers(50000000) WHERE NOT ignore(toDateTime('2017-01-01 00:00:00') + number % 100000000 + rand() % 100000 AS t, {datetime_transform_with_mode}(t, 0, '{time_zone}'))</query>
<query>SELECT count() FROM numbers(50000000) WHERE NOT ignore(toDate('2017-01-01') + number % 1000 + rand() % 10 AS t, {date_transform}(t))</query> <query>SELECT count() FROM numbers(50000000) WHERE NOT ignore(toDate('2017-01-01') + number % 1000 + rand() % 10 AS t, {date_transform}(t))</query>
<query>SELECT count() FROM numbers(50000000) WHERE NOT ignore(toDateTime('2017-01-01 00:00:00') + number % 100000000 + rand() % 100000 AS t, {binary_function}(t, 1))</query> <query>SELECT count() FROM numbers(50000000) WHERE NOT ignore(toDateTime('2017-01-01 00:00:00') + number % 100000000 + rand() % 100000 AS t, {binary_function}(t, 1))</query>
<query>SELECT count() FROM numbers(50000000) WHERE NOT ignore(toDateTime('2017-01-01 00:00:00') + number % 100000000 + rand() % 100000 AS t, toStartOfInterval(t, INTERVAL 1 month))</query> <query>SELECT count() FROM numbers(50000000) WHERE NOT ignore(toDateTime('2017-01-01 00:00:00') + number % 100000000 + rand() % 100000 AS t, toStartOfInterval(t, INTERVAL 1 month))</query>
<query>SELECT count() FROM numbers(50000000) WHERE NOT ignore(toDateTime('2017-01-01 00:00:00') + number % 100000000 + rand() % 100000 AS t, date_trunc('month', t))</query> <query>SELECT count() FROM numbers(50000000) WHERE NOT ignore(toDateTime('2017-01-01 00:00:00') + number % 100000000 + rand() % 100000 AS t, date_trunc('month', t))</query>
</test> </test>

View File

@ -1,15 +1,12 @@
<!--
This is a performance smoke test for DateTime and Date. Some other basic functions are tested by date_time_64.xml, and a more
exhaustive list of functions is in date_time_long.xml (it's about an hour so we can't afford to test it on each commit).
-->
<test> <test>
<!--
This is a short screening test for DateTime and Date. Some
other basic functions are tested by date_time_64, and a more
exhaustive list of functions is in date_time_long.xml (it's
about an hour so we can't afford to test it on each commit).
-->
<substitutions> <substitutions>
<substitution> <substitution>
<name>date_transform</name> <name>date_transform</name>
<values> <values>
<value>toDayOfWeek</value>
<value>toMonday</value> <value>toMonday</value>
<value>toRelativeDayNum</value> <value>toRelativeDayNum</value>
<value>toYYYYMMDDhhmmss</value> <value>toYYYYMMDDhhmmss</value>
@ -32,16 +29,24 @@
</substitution> </substitution>
</substitutions> </substitutions>
<!-- date_transform --> <!-- {date_transform} -->
<query>SELECT count() FROM numbers(50000000) WHERE NOT ignore(toDateTime('2017-01-01 00:00:00') + number % 100000000 + rand() % 100000 AS t, {date_transform}(t, '{time_zone}'))</query> <query>SELECT count() FROM numbers(50000000) WHERE NOT ignore(toDateTime('2017-01-01 00:00:00') + number % 100000000 + rand() % 100000 AS t, {date_transform}(t, '{time_zone}'))</query>
<query>SELECT count() FROM numbers(50000000) WHERE NOT ignore(toDate('2017-01-01') + number % 1000 + rand() % 10 AS t, {date_transform}(t))</query> <query>SELECT count() FROM numbers(50000000) WHERE NOT ignore(toDate('2017-01-01') + number % 1000 + rand() % 10 AS t, {date_transform}(t))</query>
<!-- toUnixTimestamp() --> <!-- toUnixTimestamp() -->
<query>SELECT count() FROM numbers(50000000) WHERE NOT ignore(toDateTime('2017-01-01 00:00:00') + number % 100000000 + rand() % 100000 AS t, toUnixTimestamp(t, '{time_zone}'))</query> <query>SELECT count() FROM numbers(50000000) WHERE NOT ignore(toDateTime('2017-01-01 00:00:00') + number % 100000000 + rand() % 100000 AS t, toUnixTimestamp(t, '{time_zone}'))</query>
<!-- toUnixTimestamp(Date()) is pro5bit, wrap Date() with toUInt16() to overcome --> <!-- toUnixTimestamp(Date()) is prohibited, wrap Date() with toUInt16() to overcome -->
<query>SELECT count() FROM numbers(50000000) WHERE NOT ignore(toDate('2017-01-01') + number % 1000 + rand() % 10 AS t, toUnixTimestamp(toUInt16(t)))</query> <query>SELECT count() FROM numbers(50000000) WHERE NOT ignore(toDate('2017-01-01') + number % 1000 + rand() % 10 AS t, toUnixTimestamp(toUInt16(t)))</query>
<!-- {binary_function} -->
<query>SELECT count() FROM numbers(50000000) WHERE NOT ignore(toDateTime('2017-01-01 00:00:00') + number % 100000000 + rand() % 100000 AS t, {binary_function}(t, 1))</query> <query>SELECT count() FROM numbers(50000000) WHERE NOT ignore(toDateTime('2017-01-01 00:00:00') + number % 100000000 + rand() % 100000 AS t, {binary_function}(t, 1))</query>
<!-- misc -->
<query>SELECT count() FROM numbers(50000000) WHERE NOT ignore(toDateTime('2017-01-01 00:00:00') + number % 100000000 + rand() % 100000 AS t, toStartOfInterval(t, INTERVAL 1 month))</query> <query>SELECT count() FROM numbers(50000000) WHERE NOT ignore(toDateTime('2017-01-01 00:00:00') + number % 100000000 + rand() % 100000 AS t, toStartOfInterval(t, INTERVAL 1 month))</query>
<query>SELECT count() FROM numbers(50000000) WHERE NOT ignore(toDateTime('2017-01-01 00:00:00') + number % 100000000 + rand() % 100000 AS t, date_trunc('month', t))</query> <query>SELECT count() FROM numbers(50000000) WHERE NOT ignore(toDateTime('2017-01-01 00:00:00') + number % 100000000 + rand() % 100000 AS t, date_trunc('month', t))</query>
<query>SELECT count() FROM numbers(50000000) WHERE NOT ignore(toDateTime('2017-01-01 00:00:00') + number % 100000000 + rand() % 100000 AS t, toDayOfWeek(t, 0, '{time_zone}'))</query>
<query>SELECT count() FROM numbers(50000000) WHERE NOT ignore(toDate('2017-01-01') + number % 1000 + rand() % 10 AS t, toDayOfWeek(t))</query>
</test> </test>

View File

@ -120,11 +120,11 @@ SELECT toDayOfMonth(toDateTime(1412106600), 'Pacific/Pitcairn');
/* toDayOfWeek */ /* toDayOfWeek */
SELECT 'toDayOfWeek'; SELECT 'toDayOfWeek';
SELECT toDayOfWeek(toDateTime(1412106600), 'Asia/Istanbul'); SELECT toDayOfWeek(toDateTime(1412106600), 0, 'Asia/Istanbul');
SELECT toDayOfWeek(toDateTime(1412106600), 'Europe/Paris'); SELECT toDayOfWeek(toDateTime(1412106600), 0, 'Europe/Paris');
SELECT toDayOfWeek(toDateTime(1412106600), 'Europe/London'); SELECT toDayOfWeek(toDateTime(1412106600), 0, 'Europe/London');
SELECT toDayOfWeek(toDateTime(1412106600), 'Asia/Tokyo'); SELECT toDayOfWeek(toDateTime(1412106600), 0, 'Asia/Tokyo');
SELECT toDayOfWeek(toDateTime(1412106600), 'Pacific/Pitcairn'); SELECT toDayOfWeek(toDateTime(1412106600), 0, 'Pacific/Pitcairn');
/* toHour */ /* toHour */

View File

@ -7,14 +7,14 @@ import sys
import argparse import argparse
# Create SQL statement to verify dateTime64 is accepted as argument to functions taking DateTime. # Create SQL statement to verify dateTime64 is accepted as argument to functions taking DateTime.
FUNCTIONS=""" FUNCTIONS = """
toTimeZone(N, 'UTC') toTimeZone(N, 'UTC')
toYear(N, 'Asia/Istanbul') toYear(N, 'Asia/Istanbul')
toQuarter(N, 'Asia/Istanbul') toQuarter(N, 'Asia/Istanbul')
toMonth(N, 'Asia/Istanbul') toMonth(N, 'Asia/Istanbul')
toDayOfYear(N, 'Asia/Istanbul') toDayOfYear(N, 'Asia/Istanbul')
toDayOfMonth(N, 'Asia/Istanbul') toDayOfMonth(N, 'Asia/Istanbul')
toDayOfWeek(N, 'Asia/Istanbul') toDayOfWeek(N, 0, 'Asia/Istanbul')
toHour(N, 'Asia/Istanbul') toHour(N, 'Asia/Istanbul')
toMinute(N, 'Asia/Istanbul') toMinute(N, 'Asia/Istanbul')
toSecond(N, 'Asia/Istanbul') toSecond(N, 'Asia/Istanbul')
@ -90,68 +90,51 @@ formatDateTime(N, '%C %d %D %e %F %H %I %j %m %M %p %R %S %T %u %V %w %y %Y %%',
extra_ops = [ extra_ops = [
# With same type: # With same type:
( (
['N {op} N'], ["N {op} N"],
{ {
'op': "op": [
[ "- ", # does not work, but should it?
'- ', # does not work, but should it? "+ ", # does not work, but should it?
'+ ', # does not work, but should it? "!=",
'!=', '==', # equality and inequality supposed to take sub-second part in account "==", # equality and inequality supposed to take sub-second part in account
'< ', "< ",
'<=', "<=",
'> ', "> ",
'>=' ">=",
] ]
} },
), ),
# With other DateTime types: # With other DateTime types:
( (
[ ["N {op} {arg}", "{arg} {op} N"],
'N {op} {arg}',
'{arg} {op} N'
],
{ {
'op': "op": [
[ "-", # does not work, but should it?
'-', # does not work, but should it? "!=",
'!=', '==', "==",
# these are naturally expected to work, but they don't: # these are naturally expected to work, but they don't:
'< ', "< ",
'<=', "<=",
'> ', "> ",
'>=' ">=",
], ],
'arg': ['DT', 'D', 'DT64'], "arg": ["DT", "D", "DT64"],
} },
), ),
# With arithmetic types # With arithmetic types
( (
[ ["N {op} {arg}", "{arg} {op} N"],
'N {op} {arg}',
'{arg} {op} N'
],
{ {
'op': "op": ["+ ", "- ", "==", "!=", "< ", "<=", "> ", ">="],
[ "arg": [
'+ ', "toUInt8(1)",
'- ', "toInt8(-1)",
'==', "toUInt16(1)",
'!=', "toInt16(-1)",
'< ', "toUInt32(1)",
'<=', "toInt32(-1)",
'> ', "toUInt64(1)",
'>=' "toInt64(-1)",
],
'arg':
[
'toUInt8(1)',
'toInt8(-1)',
'toUInt16(1)',
'toInt16(-1)',
'toUInt32(1)',
'toInt32(-1)',
'toUInt64(1)',
'toInt64(-1)'
], ],
}, },
), ),
@ -167,14 +150,17 @@ for funcs, args in extra_ops:
# filter out empty lines and commented out lines # filter out empty lines and commented out lines
COMMENTED_OUT_LINE_RE = re.compile(r"^\s*#") COMMENTED_OUT_LINE_RE = re.compile(r"^\s*#")
FUNCTIONS = list([f for f in FUNCTIONS if len(f) != 0 and COMMENTED_OUT_LINE_RE.match(f) == None]) FUNCTIONS = list(
TYPES = ['D', 'DT', 'DT64'] [f for f in FUNCTIONS if len(f) != 0 and COMMENTED_OUT_LINE_RE.match(f) == None]
)
TYPES = ["D", "DT", "DT64"]
def escape_string(s): def escape_string(s):
if sys.version_info[0] > 2: if sys.version_info[0] > 2:
return s.encode('unicode_escape').decode('utf-8').replace("'", "\\'") return s.encode("unicode_escape").decode("utf-8").replace("'", "\\'")
else: else:
return s.encode('string-escape').decode('utf-8') return s.encode("string-escape").decode("utf-8")
def execute_functions_for_types(functions, types): def execute_functions_for_types(functions, types):
@ -186,18 +172,39 @@ def execute_functions_for_types(functions, types):
WITH \ WITH \
toDateTime64('2019-09-16 19:20:11.234', 3, 'Europe/Minsk') as DT64, \ toDateTime64('2019-09-16 19:20:11.234', 3, 'Europe/Minsk') as DT64, \
toDateTime('2019-09-16 19:20:11', 'Europe/Minsk') as DT, \ toDateTime('2019-09-16 19:20:11', 'Europe/Minsk') as DT, \
toDate('2019-09-16') as D, {X} as N".format(X=dt) toDate('2019-09-16') as D, {X} as N".format(
print(("""{prologue} SELECT toTypeName(r), {func} as r FORMAT CSV;""".format(prologue=prologue, func=func))) X=dt
)
print(
(
"""{prologue} SELECT toTypeName(r), {func} as r FORMAT CSV;""".format(
prologue=prologue, func=func
)
)
)
print("""SELECT '------------------------------------------';""") print("""SELECT '------------------------------------------';""")
def main(): def main():
def parse_args(): def parse_args():
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument('--functions_re', type=re.compile, help="RE to enable functions", default=None) parser.add_argument(
parser.add_argument('--types_re', "--functions_re",
type=lambda s: re.compile('^(' + s + ')$'), type=re.compile,
help="RE to enable types, supported types: " + ",".join(TYPES), default=None) help="RE to enable functions",
parser.add_argument('--list_functions', action='store_true', help="List all functions to be tested and exit") default=None,
)
parser.add_argument(
"--types_re",
type=lambda s: re.compile("^(" + s + ")$"),
help="RE to enable types, supported types: " + ",".join(TYPES),
default=None,
)
parser.add_argument(
"--list_functions",
action="store_true",
help="List all functions to be tested and exit",
)
return parser.parse_args() return parser.parse_args()
args = parse_args() args = parse_args()
@ -223,5 +230,6 @@ def main():
execute_functions_for_types(functions, types) execute_functions_for_types(functions, types)
if __name__ == '__main__':
if __name__ == "__main__":
exit(main()) exit(main())

View File

@ -28,7 +28,7 @@ SELECT toDayOfMonth(N, \'Asia/Istanbul\')
"UInt8",16 "UInt8",16
"UInt8",16 "UInt8",16
------------------------------------------ ------------------------------------------
SELECT toDayOfWeek(N, \'Asia/Istanbul\') SELECT toDayOfWeek(N, 0, \'Asia/Istanbul\')
"UInt8",1 "UInt8",1
"UInt8",1 "UInt8",1
"UInt8",1 "UInt8",1

View File

@ -0,0 +1,7 @@
1 7
1 7
0 6
1 0
2 1
1 7
0 6

View File

@ -0,0 +1,10 @@
with toDate('2023-01-09') as date_mon, date_mon - 1 as date_sun select toDayOfWeek(date_mon), toDayOfWeek(date_sun);
with toDate('2023-01-09') as date_mon, date_mon - 1 as date_sun select toDayOfWeek(date_mon, 0), toDayOfWeek(date_sun, 0);
with toDate('2023-01-09') as date_mon, date_mon - 1 as date_sun select toDayOfWeek(date_mon, 1), toDayOfWeek(date_sun, 1);
with toDate('2023-01-09') as date_mon, date_mon - 1 as date_sun select toDayOfWeek(date_mon, 2), toDayOfWeek(date_sun, 2);
with toDate('2023-01-09') as date_mon, date_mon - 1 as date_sun select toDayOfWeek(date_mon, 3), toDayOfWeek(date_sun, 3);
with toDate('2023-01-09') as date_mon, date_mon - 1 as date_sun select toDayOfWeek(date_mon, 4), toDayOfWeek(date_sun, 4);
with toDate('2023-01-09') as date_mon, date_mon - 1 as date_sun select toDayOfWeek(date_mon, 5), toDayOfWeek(date_sun, 5);
select toDayOfWeek(today(), -1); -- { serverError 43 }