Skip to content

Commit 61df8aa

Browse files
authored
Merge pull request ClickHouse#60598 from jrdi/week-default-mode
Add setting `first_day_of_week` for function `toStartOfInterval`
2 parents c6d21ae + 9ed1b94 commit 61df8aa

File tree

12 files changed

+137
-64
lines changed

12 files changed

+137
-64
lines changed

docs/en/operations/settings/settings.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4384,6 +4384,17 @@ Possible values:
43844384

43854385
Default value: `ignore`.
43864386

4387+
## first_day_of_week
4388+
4389+
The first day of the week assumed by [`toStartOfInterval`](../../sql-reference/functions/date-time-functions.md#toStartOfInterval) function when using weeks as unit.
4390+
4391+
Possible values:
4392+
4393+
- Monday - Week starts on Monday
4394+
- Sunday - Week starts on Sunday
4395+
4396+
Default value: 'Monday'.
4397+
43874398
## optimize_move_to_prewhere {#optimize_move_to_prewhere}
43884399

43894400
Enables or disables automatic [PREWHERE](../../sql-reference/statements/select/prewhere.md) optimization in [SELECT](../../sql-reference/statements/select/index.md) queries.

docs/en/sql-reference/functions/date-time-functions.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1052,7 +1052,7 @@ toStartOfWeek(t[, mode[, timezone]])
10521052
**Arguments**
10531053

10541054
- `t` - a [Date](../data-types/date.md), [Date32](../data-types/date32.md), [DateTime](../data-types/datetime.md) or [DateTime64](../data-types/datetime64.md)
1055-
- `mode` - determines the first day of the week as described in the [toWeek()](date-time-functions#toweek) function
1055+
- `mode` - determines the first day of the week as described in the [toWeek()](date-time-functions#toweek) function. Default: 0
10561056
- `timezone` - Optional parameter, it behaves like any other conversion function
10571057

10581058
**Returned value**
@@ -1413,7 +1413,7 @@ toStartOfFifteenMinutes(toDateTime('2023-04-21 10:20:00')): 2023-04-21 10:15:00
14131413
toStartOfFifteenMinutes(toDateTime('2023-04-21 10:23:00')): 2023-04-21 10:15:00
14141414
```
14151415

1416-
## toStartOfInterval(date_or_date_with_time, INTERVAL x unit \[, time_zone\])
1416+
## toStartOfInterval
14171417

14181418
This function generalizes other `toStartOf*()` functions. For example,
14191419
- `toStartOfInterval(t, INTERVAL 1 year)` returns the same as `toStartOfYear(t)`,
@@ -1440,6 +1440,8 @@ The calculation is performed relative to specific points in time:
14401440
(*) hour intervals are special: the calculation is always performed relative to 00:00:00 (midnight) of the current day. As a result, only
14411441
hour values between 1 and 23 are useful.
14421442

1443+
If unit `week` was specified, `toStartOfInterval` assumes by default that weeks start on Monday. You can change this behavior with setting [`first_day_of_week`](../../operations/settings/settings.md/#first-day-of-week)
1444+
14431445
**See Also**
14441446

14451447
- [date_trunc](#date_trunc)
@@ -1673,7 +1675,7 @@ Like [fromDaysSinceYearZero](#fromDaysSinceYearZero) but returns a [Date32](../.
16731675
Returns the `unit` component of the difference between `startdate` and `enddate`. The difference is calculated using a precision of 1 nanosecond.
16741676
E.g. the difference between `2021-12-29` and `2022-01-01` is 3 days for `day` unit, 0 months for `month` unit, 0 years for `year` unit.
16751677

1676-
For an alternative to `age`, see function `date\_diff`.
1678+
For an alternative to `age`, see function `date_diff`.
16771679

16781680
**Syntax**
16791681

@@ -1747,9 +1749,9 @@ Result:
17471749
Returns the count of the specified `unit` boundaries crossed between the `startdate` and the `enddate`.
17481750
The difference is calculated using relative units, e.g. the difference between `2021-12-29` and `2022-01-01` is 3 days for unit `day` (see [toRelativeDayNum](#torelativedaynum)), 1 month for unit `month` (see [toRelativeMonthNum](#torelativemonthnum)) and 1 year for unit `year` (see [toRelativeYearNum](#torelativeyearnum)).
17491751

1750-
If unit `week` was specified, `date\_diff` assumes that weeks start on Monday. Note that this behavior is different from that of function `toWeek()` in which weeks start by default on Sunday.
1752+
If unit `week` was specified, `date_diff` assumes that weeks start on Monday. Note that this behavior is different from that of function `toWeek()` in which weeks start by default on Sunday.
17511753

1752-
For an alternative to `date\_diff`, see function `age`.
1754+
For an alternative to `date_diff`, see function `age`.
17531755

17541756
**Syntax**
17551757

@@ -2843,7 +2845,7 @@ Result:
28432845

28442846
## fromUnixTimestamp
28452847

2846-
This function converts a Unix timestamp to a calendar date and a time of a day.
2848+
This function converts a Unix timestamp to a calendar date and a time of a day.
28472849

28482850
It can be called in two ways:
28492851

src/Common/DateLUTImpl.h

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1048,16 +1048,20 @@ class DateLUTImpl
10481048

10491049
template <typename Date>
10501050
requires std::is_same_v<Date, DayNum> || std::is_same_v<Date, ExtendedDayNum>
1051-
auto toStartOfWeekInterval(Date d, UInt64 weeks) const
1051+
auto toStartOfWeekInterval(Date d, UInt64 weeks, UInt8 week_mode) const
10521052
{
10531053
if (weeks == 1)
1054-
return toFirstDayNumOfWeek(d);
1054+
return toFirstDayNumOfWeek(d, week_mode);
1055+
1056+
bool monday_first_mode = week_mode & static_cast<UInt8>(WeekModeFlag::MONDAY_FIRST);
1057+
// January 1st 1970 was Thursday so we need this 4-days offset to make weeks start on Monday, or
1058+
// 3 days to start on Sunday.
1059+
auto offset = monday_first_mode ? 4 : 3;
10551060
UInt64 days = weeks * 7;
1056-
// January 1st 1970 was Thursday so we need this 4-days offset to make weeks start on Monday.
10571061
if constexpr (std::is_same_v<Date, DayNum>)
1058-
return DayNum(4 + (d - 4) / days * days);
1062+
return DayNum(offset + (d - offset) / days * days);
10591063
else
1060-
return ExtendedDayNum(static_cast<Int32>(4 + (d - 4) / days * days));
1064+
return ExtendedDayNum(static_cast<Int32>(offset + (d - offset) / days * days));
10611065
}
10621066

10631067
template <typename Date>

src/Core/Settings.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,7 @@ class IColumn;
549549
M(Bool, formatdatetime_parsedatetime_m_is_month_name, true, "Formatter '%M' in functions 'formatDateTime()' and 'parseDateTime()' print/parse the month name instead of minutes.", 0) \
550550
M(Bool, parsedatetime_parse_without_leading_zeros, true, "Formatters '%c', '%l' and '%k' in function 'parseDateTime()' parse months and hours without leading zeros.", 0) \
551551
M(Bool, formatdatetime_format_without_leading_zeros, false, "Formatters '%c', '%l' and '%k' in function 'formatDateTime()' print months and hours without leading zeros.", 0) \
552+
M(FirstDayOfWeek, first_day_of_week, FirstDayOfWeek::Monday, "The first day of the week (Monday or Sunday) used by date/time functions (default: Monday).", 0) \
552553
\
553554
M(UInt64, max_partitions_per_insert_block, 100, "Limit maximum number of partitions in single INSERTed block. Zero means unlimited. Throw exception if the block contains too many partitions. This setting is a safety threshold, because using large number of partitions is a common misconception.", 0) \
554555
M(Bool, throw_on_max_partitions_per_insert_block, true, "Used with max_partitions_per_insert_block. If true (default), an exception will be thrown when max_partitions_per_insert_block is reached. If false, details of the insert query reaching this limit with the number of partitions will be logged. This can be useful if you're trying to understand the impact on users when changing max_partitions_per_insert_block.", 0) \

src/Core/SettingsChangesHistory.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ static std::map<ClickHouseVersion, SettingsChangesHistory::SettingsChanges> sett
9090
{"lightweight_deletes_sync", 2, 2, "The same as 'mutation_sync', but controls only execution of lightweight deletes"},
9191
{"query_cache_system_table_handling", "save", "throw", "The query cache no longer caches results of queries against system tables"},
9292
{"input_format_hive_text_allow_variable_number_of_columns", false, true, "Ignore extra columns in Hive Text input (if file has more columns than expected) and treat missing fields in Hive Text input as default values."},
93+
{"first_day_of_week", "Monday", "Monday", "Added a setting for the first day of the week for date/time functions"},
9394
}},
9495
{"24.3", {{"s3_connect_timeout_ms", 1000, 1000, "Introduce new dedicated setting for s3 connection timeout"},
9596
{"allow_experimental_shared_merge_tree", false, true, "The setting is obsolete"},

src/Core/SettingsEnums.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,4 +229,8 @@ IMPLEMENT_SETTING_ENUM(SQLSecurityType, ErrorCodes::BAD_ARGUMENTS,
229229
{{"DEFINER", SQLSecurityType::DEFINER},
230230
{"INVOKER", SQLSecurityType::INVOKER},
231231
{"NONE", SQLSecurityType::NONE}})
232+
233+
IMPLEMENT_SETTING_ENUM(FirstDayOfWeek, ErrorCodes::BAD_ARGUMENTS,
234+
{{"Monday", FirstDayOfWeek::Monday},
235+
{"Sunday", FirstDayOfWeek::Sunday}})
232236
}

src/Core/SettingsEnums.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,4 +370,12 @@ DECLARE_SETTING_ENUM(SchemaInferenceMode)
370370
DECLARE_SETTING_ENUM_WITH_RENAME(DateTimeOverflowBehavior, FormatSettings::DateTimeOverflowBehavior)
371371

372372
DECLARE_SETTING_ENUM(SQLSecurityType)
373+
374+
enum class FirstDayOfWeek
375+
{
376+
Monday,
377+
Sunday
378+
};
379+
380+
DECLARE_SETTING_ENUM(FirstDayOfWeek)
373381
}

0 commit comments

Comments
 (0)