Skip to content

Commit

Permalink
Merge pull request #62335 from Misz606/patch-5
Browse files Browse the repository at this point in the history
Added nano- micro- milliseconds unit for `date_trunc`
  • Loading branch information
yariks5s committed Apr 16, 2024
2 parents 7c63d99 + dcf8bff commit ffeec29
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 14 deletions.
3 changes: 3 additions & 0 deletions docs/en/sql-reference/functions/date-time-functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -1836,6 +1836,9 @@ Alias: `dateTrunc`.
- `unit` — The type of interval to truncate the result. [String Literal](../syntax.md#syntax-string-literal).
Possible values:

- `nanosecond` - Compatible only with DateTime64
- `microsecond` - Compatible only with DateTime64
- `milisecond` - Compatible only with DateTime64
- `second`
- `minute`
- `hour`
Expand Down
41 changes: 30 additions & 11 deletions src/Functions/date_trunc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,14 @@ class FunctionDateTrunc : public IFunction
{
/// The first argument is a constant string with the name of datepart.

auto result_type_is_date = false;
enum ResultType
{
Date,
DateTime,
DateTime64,
};
ResultType result_type;

String datepart_param;
auto check_first_argument = [&] {
const ColumnConst * datepart_column = checkAndGetColumnConst<ColumnString>(arguments[0].column.get());
Expand All @@ -56,13 +63,14 @@ class FunctionDateTrunc : public IFunction
if (!IntervalKind::tryParseString(datepart_param, datepart_kind))
throw Exception(ErrorCodes::BAD_ARGUMENTS, "{} doesn't look like datepart name in {}", datepart_param, getName());

if (datepart_kind == IntervalKind::Kind::Nanosecond || datepart_kind == IntervalKind::Kind::Microsecond
|| datepart_kind == IntervalKind::Kind::Millisecond)
throw Exception(ErrorCodes::BAD_ARGUMENTS, "{} doesn't support {}", getName(), datepart_param);

result_type_is_date = (datepart_kind == IntervalKind::Kind::Year)
|| (datepart_kind == IntervalKind::Kind::Quarter) || (datepart_kind == IntervalKind::Kind::Month)
|| (datepart_kind == IntervalKind::Kind::Week);
if ((datepart_kind == IntervalKind::Kind::Year) || (datepart_kind == IntervalKind::Kind::Quarter)
|| (datepart_kind == IntervalKind::Kind::Month) || (datepart_kind == IntervalKind::Kind::Week))
result_type = ResultType::Date;
else if ((datepart_kind == IntervalKind::Kind::Day) || (datepart_kind == IntervalKind::Kind::Hour)
|| (datepart_kind == IntervalKind::Kind::Minute) || (datepart_kind == IntervalKind::Kind::Second))
result_type = ResultType::DateTime;
else
result_type = ResultType::DateTime64;
};

bool second_argument_is_date = false;
Expand All @@ -84,7 +92,7 @@ class FunctionDateTrunc : public IFunction
"This argument is optional and must be a constant string with timezone name",
arguments[2].type->getName(), getName());

if (second_argument_is_date && result_type_is_date)
if (second_argument_is_date && result_type == ResultType::Date)
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
"The timezone argument of function {} with datepart '{}' "
"is allowed only when the 2nd argument has the type DateTime",
Expand All @@ -109,10 +117,21 @@ class FunctionDateTrunc : public IFunction
getName(), arguments.size());
}

if (result_type_is_date)
if (result_type == ResultType::Date)
return std::make_shared<DataTypeDate>();
else
else if (result_type == ResultType::DateTime)
return std::make_shared<DataTypeDateTime>(extractTimeZoneNameFromFunctionArguments(arguments, 2, 1, false));
else
{
size_t scale;
if (datepart_kind == IntervalKind::Kind::Millisecond)
scale = 3;
else if (datepart_kind == IntervalKind::Kind::Microsecond)
scale = 6;
else if (datepart_kind == IntervalKind::Kind::Nanosecond)
scale = 9;
return std::make_shared<DataTypeDateTime64>(scale, extractTimeZoneNameFromFunctionArguments(arguments, 2, 1, false));
}
}

bool useDefaultImplementationForConstants() const override { return true; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,15 @@
2022-03-01 00:00:00
2022-03-01
2022-02-28
2022-03-01 12:12:12.012000000
2022-03-01 12:12:12.012346
2022-03-01 12:12:12.012
2022-03-01 12:12:12.012300
2022-03-01 12:12:12.012
2022-03-01 12:12:12.012345670
1950-03-01 12:12:12.012000000
1951-03-01 12:12:12.012345
1952-03-01 12:12:12.012
1965-03-01 12:12:12.012300
1966-03-01 12:12:12.012
1967-03-01 12:12:12.012345670
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,21 @@ SELECT dateTrunc('Week', toDate('2022-03-01'));
SELECT dateTrunc('day', toDateTime('2022-03-01 12:55:55'));
SELECT dateTrunc('month', toDateTime64('2022-03-01 12:55:55', 2));
SELECT dateTrunc('week', toDate('2022-03-01'));
SELECT dateTrunc('Nanosecond', toDate('2022-03-01')); -- { serverError 36 }
SELECT dateTrunc('MicroSecond', toDate('2022-03-01')); -- { serverError 36 }
SELECT dateTrunc('MILLISECOND', toDate('2022-03-01')); -- { serverError 36 }
SELECT dateTrunc('Nanosecond', toDateTime64('2022-03-01 12:12:12.0123', 3));
SELECT dateTrunc('MicroSecond', toDateTime64('2022-03-01 12:12:12.0123456', 7));
SELECT dateTrunc('MILLISECOND', toDateTime64('2022-03-01 12:12:12.012324251', 9));
SELECT dateTrunc('mICROsECOND', toDateTime64('2022-03-01 12:12:12.0123', 4));
SELECT dateTrunc('mIllISecoNd', toDateTime64('2022-03-01 12:12:12.0123456', 6));
SELECT dateTrunc('NANoSecoND', toDateTime64('2022-03-01 12:12:12.012345678', 8));
SELECT dateTrunc('Nanosecond', toDateTime64('1950-03-01 12:12:12.0123', 3));
SELECT dateTrunc('MicroSecond', toDateTime64('1951-03-01 12:12:12.0123456', 7));
SELECT dateTrunc('MILLISECOND', toDateTime64('1952-03-01 12:12:12.012324251', 9));
SELECT dateTrunc('mICROsECOND', toDateTime64('1965-03-01 12:12:12.0123', 4));
SELECT dateTrunc('mIllISecoNd', toDateTime64('1966-03-01 12:12:12.0123456', 6));
SELECT dateTrunc('NANoSecoND', toDateTime64('1967-03-01 12:12:12.012345678', 8));
SELECT dateTrunc('Nanosecond', toDateTime('2022-03-01')); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT dateTrunc('MicroSecond', toDateTime('2022-03-01')); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT dateTrunc('MILLISECOND', toDateTime('2022-03-01')); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT dateTrunc('Nanosecond', toDate('2022-03-01')); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT dateTrunc('MicroSecond', toDate('2022-03-01')); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT dateTrunc('MILLISECOND', toDate('2022-03-01')); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }

0 comments on commit ffeec29

Please sign in to comment.