mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-28 02:21:59 +00:00
add maximum_unit arg to formatReadableTimeDelta function
This commit is contained in:
parent
077ee81177
commit
146f973437
@ -538,26 +538,51 @@ SELECT
|
|||||||
└────────────────┴───────────────────┘
|
└────────────────┴───────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
## formatReadableTimeDelta(x) {#formatreadabletimedeltax}
|
## formatReadableTimeDelta {#formatreadabletimedelta}
|
||||||
|
|
||||||
Accepts the time delta in seconds. Returns a time delta with (year, month, day, hour, minute, second) as a string.
|
Accepts the time delta in seconds. Returns a time delta with (year, month, day, hour, minute, second) as a string.
|
||||||
|
|
||||||
|
**Syntax**
|
||||||
|
|
||||||
|
``` sql
|
||||||
|
formatReadableTimeDelta(column[, maximum_unit])
|
||||||
|
```
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
- `column` — A column with numeric time delta.
|
||||||
|
- `maximum_unit` — Optional. Maximum unit to show. Acceptable values seconds, minutes, hours, days, months, years.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
``` sql
|
``` sql
|
||||||
SELECT
|
SELECT
|
||||||
arrayJoin([100, 12345, 432546534]) AS number,
|
arrayJoin([100, 12345, 432546534]) AS elapsed,
|
||||||
formatReadableTimeDelta(number) AS time_delta
|
formatReadableTimeDelta(elapsed) AS time_delta
|
||||||
```
|
```
|
||||||
|
|
||||||
``` text
|
``` text
|
||||||
┌─────number─┬─time_delta ─────────────────────────────────────────────────────┐
|
┌────elapsed─┬─time_delta ─────────────────────────────────────────────────────┐
|
||||||
│ 100 │ 1 minute and 40 seconds │
|
│ 100 │ 1 minute and 40 seconds │
|
||||||
│ 12345 │ 3 hours, 25 minutes and 45 seconds │
|
│ 12345 │ 3 hours, 25 minutes and 45 seconds │
|
||||||
│ 432546534 │ 13 years, 8 months, 17 days, 7 hours, 48 minutes and 54 seconds │
|
│ 432546534 │ 13 years, 8 months, 17 days, 7 hours, 48 minutes and 54 seconds │
|
||||||
└────────────┴─────────────────────────────────────────────────────────────────┘
|
└────────────┴─────────────────────────────────────────────────────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
|
``` sql
|
||||||
|
SELECT
|
||||||
|
arrayJoin([100, 12345, 432546534]) AS elapsed,
|
||||||
|
formatReadableTimeDelta(elapsed, 'minutes') AS time_delta
|
||||||
|
```
|
||||||
|
|
||||||
|
``` text
|
||||||
|
┌────elapsed─┬─time_delta ─────────────────────────────────────────────────────┐
|
||||||
|
│ 100 │ 1 minute and 40 seconds │
|
||||||
|
│ 12345 │ 205 minutes and 45 seconds │
|
||||||
|
│ 432546534 │ 7209108 minutes and 54 seconds │
|
||||||
|
└────────────┴─────────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
## least(a, b) {#leasta-b}
|
## least(a, b) {#leasta-b}
|
||||||
|
|
||||||
Returns the smallest value from a and b.
|
Returns the smallest value from a and b.
|
||||||
|
@ -18,6 +18,7 @@ namespace DB
|
|||||||
namespace ErrorCodes
|
namespace ErrorCodes
|
||||||
{
|
{
|
||||||
extern const int ILLEGAL_TYPE_OF_ARGUMENT;
|
extern const int ILLEGAL_TYPE_OF_ARGUMENT;
|
||||||
|
extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
|
||||||
extern const int ILLEGAL_COLUMN;
|
extern const int ILLEGAL_COLUMN;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -285,23 +286,44 @@ public:
|
|||||||
static constexpr auto name = "formatReadableTimeDelta";
|
static constexpr auto name = "formatReadableTimeDelta";
|
||||||
static FunctionPtr create(const Context &) { return std::make_shared<FunctionFormatReadableTimeDelta>(); }
|
static FunctionPtr create(const Context &) { return std::make_shared<FunctionFormatReadableTimeDelta>(); }
|
||||||
|
|
||||||
String getName() const override
|
String getName() const override { return name; }
|
||||||
{
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t getNumberOfArguments() const override { return 1; }
|
bool isVariadic() const override { return true; }
|
||||||
|
|
||||||
|
size_t getNumberOfArguments() const override { return 0; }
|
||||||
|
|
||||||
DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
|
DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
|
||||||
{
|
{
|
||||||
|
if (arguments.size() < 1)
|
||||||
|
throw Exception(
|
||||||
|
"Number of arguments for function " + getName() + " doesn't match: passed " + toString(arguments.size())
|
||||||
|
+ ", should be at least 1.",
|
||||||
|
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
||||||
|
|
||||||
|
if (arguments.size() > 2)
|
||||||
|
throw Exception(
|
||||||
|
"Number of arguments for function " + getName() + " doesn't match: passed " + toString(arguments.size())
|
||||||
|
+ ", should be at most 2.",
|
||||||
|
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
||||||
|
|
||||||
const IDataType & type = *arguments[0];
|
const IDataType & type = *arguments[0];
|
||||||
|
|
||||||
if (!isNativeNumber(type))
|
if (!isNativeNumber(type))
|
||||||
throw Exception("Cannot format " + type.getName() + " as time delta", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
throw Exception("Cannot format " + type.getName() + " as time delta", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
||||||
|
|
||||||
|
if (arguments.size() == 2)
|
||||||
|
{
|
||||||
|
const auto * maximum_unit_arg = arguments[1].get();
|
||||||
|
if (!isStringOrFixedString(maximum_unit_arg))
|
||||||
|
throw Exception("Illegal type " + maximum_unit_arg->getName() + " of argument maximum_unit of function "
|
||||||
|
+ getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
||||||
|
}
|
||||||
|
|
||||||
return std::make_shared<DataTypeString>();
|
return std::make_shared<DataTypeString>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ColumnNumbers getArgumentsThatAreAlwaysConstant() const override { return {1}; }
|
||||||
|
|
||||||
bool useDefaultImplementationForConstants() const override { return true; }
|
bool useDefaultImplementationForConstants() const override { return true; }
|
||||||
|
|
||||||
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t /*input_rows_count*/) const override
|
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t /*input_rows_count*/) const override
|
||||||
@ -322,46 +344,73 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void formatReadableTimeDelta(double value, DB::WriteBuffer & out) const
|
|
||||||
|
void formatReadableTimeDelta(double value, String maximum_unit, DB::WriteBuffer & out) const
|
||||||
{
|
{
|
||||||
// 60 SECONDS = 1 MINUTE
|
// 60 SECONDS = 1 MINUTE
|
||||||
// 3600 SECONDS = 1 HOUR
|
// 3600 SECONDS = 1 HOUR
|
||||||
// 86400 SECONDS = 1 DAY
|
// 86400 SECONDS = 1 DAY
|
||||||
// 30.5 DAYS = 1 MONTH
|
// 2635200 SECONDS = 30.5 DAYS = 1 MONTH
|
||||||
// 365 DAYS = 1 YEAR
|
// 31536000 SECONDS = 365 DAYS = 1 YEAR
|
||||||
|
|
||||||
char sig = value<0?-1:1;
|
char sig = value<0?-1:1;
|
||||||
|
int maximum_unit_int = 6;
|
||||||
|
|
||||||
|
if (maximum_unit == "seconds")
|
||||||
|
maximum_unit_int = 1;
|
||||||
|
else if (maximum_unit == "minutes")
|
||||||
|
maximum_unit_int = 2;
|
||||||
|
else if (maximum_unit == "hours")
|
||||||
|
maximum_unit_int = 3;
|
||||||
|
else if (maximum_unit == "days")
|
||||||
|
maximum_unit_int = 4;
|
||||||
|
else if (maximum_unit == "months")
|
||||||
|
maximum_unit_int = 5;
|
||||||
|
else if (maximum_unit == "years")
|
||||||
|
maximum_unit_int = 6;
|
||||||
|
|
||||||
value *= sig;
|
value *= sig;
|
||||||
|
|
||||||
long long int date = value / 86400;
|
double aux = 0;
|
||||||
double time = value - date * 86400;
|
|
||||||
|
|
||||||
long long int hours = time / 3600;
|
long long int years = maximum_unit_int < 6 ? 0 : value / 31536000;
|
||||||
long long int minutes = (time - hours * 3600) / 60;
|
aux += years * 31536000;
|
||||||
double seconds = time - hours * 3600 - minutes * 60;
|
long long int months = maximum_unit_int < 5 ? 0 : (value - aux) / 2635200;
|
||||||
|
aux += months * 2635200;
|
||||||
long long int years = date / 365;
|
long long int days = maximum_unit_int < 4 ? 0 : (value - aux) / 86400;
|
||||||
long long int months = (date - years * 365) / 30.5;
|
aux += days * 86400;
|
||||||
long long int days = date - years * 365 - months * 30.5;
|
long long int hours = maximum_unit_int < 3 ? 0 : (value - aux) / 3600;
|
||||||
|
aux += hours * 3600;
|
||||||
|
long long int minutes = maximum_unit_int < 2 ? 0 : (value - aux) / 60;
|
||||||
|
aux += minutes * 60;
|
||||||
|
double seconds = maximum_unit_int < 1 ? 0 : value - aux;
|
||||||
|
|
||||||
std::vector<String> parts;
|
std::vector<String> parts;
|
||||||
|
|
||||||
if (years)
|
/* If value is bigger than 2**64 (292471208677 years) overflow happens
|
||||||
|
To prevent wrong results the function shows only the year
|
||||||
|
and maximum_unit is ignored
|
||||||
|
*/
|
||||||
|
if (value > 9223372036854775808.0)
|
||||||
{
|
{
|
||||||
parts.push_back(std::to_string(years) + (years==1?" year":" years"));
|
std::string years_str = std::to_string(value/31536000.0);
|
||||||
|
years_str.erase(years_str.find('.'), std::string::npos);
|
||||||
|
parts.push_back(years_str + " years");
|
||||||
}
|
}
|
||||||
if (months)
|
else
|
||||||
{
|
|
||||||
parts.push_back(std::to_string(months) + (months==1?"month":" months"));
|
|
||||||
}
|
|
||||||
if (days)
|
|
||||||
{
|
|
||||||
parts.push_back(std::to_string(days) + (days==1?" day":" days"));
|
|
||||||
}
|
|
||||||
// Test overflow 2^64
|
|
||||||
// If overflow happens then hide the time
|
|
||||||
if (time < 9223372036854775808.0)
|
|
||||||
{
|
{
|
||||||
|
if (years)
|
||||||
|
{
|
||||||
|
parts.push_back(std::to_string(years) + (years==1?" year":" years"));
|
||||||
|
}
|
||||||
|
if (months)
|
||||||
|
{
|
||||||
|
parts.push_back(std::to_string(months) + (months==1?"month":" months"));
|
||||||
|
}
|
||||||
|
if (days)
|
||||||
|
{
|
||||||
|
parts.push_back(std::to_string(days) + (days==1?" day":" days"));
|
||||||
|
}
|
||||||
if (hours)
|
if (hours)
|
||||||
{
|
{
|
||||||
parts.push_back(std::to_string(hours) + (hours==1?" hour":" hours"));
|
parts.push_back(std::to_string(hours) + (hours==1?" hour":" hours"));
|
||||||
@ -379,7 +428,6 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
String str_value;
|
String str_value;
|
||||||
for(size_t i=0; i<parts.size(); i++)
|
for(size_t i=0; i<parts.size(); i++)
|
||||||
{
|
{
|
||||||
@ -400,6 +448,17 @@ private:
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
bool executeType(Block & block, const ColumnNumbers & arguments, size_t result) const
|
bool executeType(Block & block, const ColumnNumbers & arguments, size_t result) const
|
||||||
{
|
{
|
||||||
|
String maximum_unit = "";
|
||||||
|
if (arguments.size() == 2)
|
||||||
|
{
|
||||||
|
const ColumnPtr & maximum_unit_column = block.getByPosition(arguments[1]).column;
|
||||||
|
if (const ColumnConst * maximum_unit_const_col = checkAndGetColumnConstStringOrFixedString(maximum_unit_column.get()))
|
||||||
|
maximum_unit = maximum_unit_const_col->getValue<String>();
|
||||||
|
else
|
||||||
|
throw Exception(
|
||||||
|
"Illegal column " + maximum_unit_const_col->getName() + " of argument of function " + getName(), ErrorCodes::ILLEGAL_COLUMN);
|
||||||
|
}
|
||||||
|
|
||||||
if (const ColumnVector<T> * col_from = checkAndGetColumn<ColumnVector<T>>(block.getByPosition(arguments[0]).column.get()))
|
if (const ColumnVector<T> * col_from = checkAndGetColumn<ColumnVector<T>>(block.getByPosition(arguments[0]).column.get()))
|
||||||
{
|
{
|
||||||
auto col_to = ColumnString::create();
|
auto col_to = ColumnString::create();
|
||||||
@ -415,7 +474,7 @@ private:
|
|||||||
|
|
||||||
for (size_t i = 0; i < size; ++i)
|
for (size_t i = 0; i < size; ++i)
|
||||||
{
|
{
|
||||||
formatReadableTimeDelta(static_cast<double>(vec_from[i]), buf_to);
|
formatReadableTimeDelta(static_cast<double>(vec_from[i]), maximum_unit, buf_to);
|
||||||
writeChar(0, buf_to);
|
writeChar(0, buf_to);
|
||||||
offsets_to[i] = buf_to.count();
|
offsets_to[i] = buf_to.count();
|
||||||
}
|
}
|
||||||
|
@ -1,30 +1,30 @@
|
|||||||
1 second 1 second
|
1 5.5 seconds
|
||||||
2 seconds 2 seconds
|
60 5 minutes and 30 seconds
|
||||||
7 seconds 7 seconds
|
3600 5 hours and 30 minutes
|
||||||
20 seconds 20 seconds
|
86400 5 days and 12 hours
|
||||||
54 seconds 54 seconds
|
2592000 5 months, 12 days and 12 hours
|
||||||
2 minutes and 28 seconds 2 minutes and 28 seconds
|
31536000 5 years, 5 months and 30 days
|
||||||
6 minutes and 43 seconds 6 minutes and 43 seconds
|
minutes 1 5.5 seconds
|
||||||
18 minutes and 16 seconds 18 minutes and 16 seconds
|
minutes 60 5 minutes and 30 seconds
|
||||||
49 minutes and 40 seconds 49 minutes and 40 seconds
|
minutes 3600 330 minutes
|
||||||
2 hours, 15 minutes and 3 seconds 2 hours, 15 minutes and 3 seconds
|
minutes 86400 7920 minutes
|
||||||
6 hours, 7 minutes and 6 seconds 6 hours, 7 minutes and 6 seconds
|
minutes 2592000 237600 minutes
|
||||||
16 hours, 37 minutes and 54 seconds 16 hours, 37 minutes and 54 seconds
|
minutes 31536000 2890800 minutes
|
||||||
1 day, 21 hours, 12 minutes and 34 seconds 1 day, 21 hours, 12 minutes and 34 seconds
|
hours 1 5.5 seconds
|
||||||
5 days, 2 hours, 53 minutes and 33 seconds 5 days, 2 hours, 53 minutes and 33 seconds
|
hours 60 5 minutes and 30 seconds
|
||||||
13 days, 22 hours, 3 minutes and 24 seconds 13 days, 22 hours, 3 minutes and 24 seconds
|
hours 3600 5 hours and 30 minutes
|
||||||
1month, 6 days, 20 hours, 3 minutes and 37 seconds 1month, 6 days, 20 hours, 3 minutes and 37 seconds
|
hours 86400 132 hours
|
||||||
3 months, 10 days, 20 hours, 21 minutes and 50 seconds 3 months, 10 days, 20 hours, 21 minutes and 50 seconds
|
hours 2592000 3960 hours
|
||||||
9 months, 4 days, 13 hours, 42 minutes and 32 seconds 9 months, 4 days, 13 hours, 42 minutes and 32 seconds
|
hours 31536000 48180 hours
|
||||||
2 years, 29 days, 22 hours, 52 minutes and 49 seconds 2 years, 29 days, 22 hours, 52 minutes and 49 seconds
|
days 1 5.5 seconds
|
||||||
5 years, 7 months, 26 days, 18 hours and 25 minutes 5 years, 7 months, 26 days, 18 hours and 25 minutes
|
days 60 5 minutes and 30 seconds
|
||||||
15 years, 4 months, 18 days, 8 hours, 6 minutes and 35 seconds 15 years, 4 months, 18 days, 8 hours, 6 minutes and 35 seconds
|
days 3600 5 hours and 30 minutes
|
||||||
41 years, 9 months, 24 days, 1 hour, 42 minutes and 14 seconds 41 years, 9 months, 24 days, 1 hour, 42 minutes and 14 seconds
|
days 86400 5 days and 12 hours
|
||||||
113 years, 8 months, 3 days, 1 hour, 7 minutes and 26 seconds - 68 years, 1month, 4 days, 3 hours, 14 minutes and 8 seconds
|
days 2592000 165 days
|
||||||
309 years, 2 days, 1 hour, 50 minutes and 46 seconds - 68 years, 1month, 4 days, 3 hours, 14 minutes and 8 seconds
|
days 31536000 2007 days and 12 hours
|
||||||
839 years, 11 months, 16 days, 1 hour, 28 minutes and 49 seconds - 68 years, 1month, 4 days, 3 hours, 14 minutes and 8 seconds
|
months 1 5.5 seconds
|
||||||
2283 years, 3 months, 3 days, 55 minutes and 37 seconds - 68 years, 1month, 4 days, 3 hours, 14 minutes and 8 seconds
|
months 60 5 minutes and 30 seconds
|
||||||
6206 years, 6 months, 15 days, 23 hours, 57 minutes and 8 seconds - 68 years, 1month, 4 days, 3 hours, 14 minutes and 8 seconds
|
months 3600 5 hours and 30 minutes
|
||||||
16871 years, 1month, 19 days, 17 hours, 56 minutes and 42 seconds - 68 years, 1month, 4 days, 3 hours, 14 minutes and 8 seconds
|
months 86400 5 days and 12 hours
|
||||||
45860 years, 6 months, 3 days, 9 hours, 24 minutes and 52 seconds - 68 years, 1month, 4 days, 3 hours, 14 minutes and 8 seconds
|
months 2592000 5 months, 12 days and 12 hours
|
||||||
124661 years, 9 months, 14 days, 8 hours, 45 minutes and 42 seconds - 68 years, 1month, 4 days, 3 hours, 14 minutes and 8 seconds
|
months 31536000 65 months and 25 days
|
||||||
|
@ -1,6 +1,19 @@
|
|||||||
WITH round(exp(number), 6) AS x, toUInt64(x) AS y, toInt32(x) AS z
|
SELECT
|
||||||
SELECT
|
arrayJoin([1, 60, 60*60, 60*60*24, 60*60*24*30, 60*60*24*365]) AS elapsed,
|
||||||
formatReadableTimeDelta(y),
|
formatReadableTimeDelta(elapsed*5.5) AS time_delta;
|
||||||
formatReadableTimeDelta(z)
|
SELECT
|
||||||
FROM system.numbers
|
'minutes' AS maximum_unit,
|
||||||
LIMIT 30;
|
arrayJoin([1, 60, 60*60, 60*60*24, 60*60*24*30, 60*60*24*365]) AS elapsed,
|
||||||
|
formatReadableTimeDelta(elapsed*5.5, maximum_unit) AS time_delta;
|
||||||
|
SELECT
|
||||||
|
'hours' AS maximum_unit,
|
||||||
|
arrayJoin([1, 60, 60*60, 60*60*24, 60*60*24*30, 60*60*24*365]) AS elapsed,
|
||||||
|
formatReadableTimeDelta(elapsed*5.5, maximum_unit) AS time_delta;
|
||||||
|
SELECT
|
||||||
|
'days' AS maximum_unit,
|
||||||
|
arrayJoin([1, 60, 60*60, 60*60*24, 60*60*24*30, 60*60*24*365]) AS elapsed,
|
||||||
|
formatReadableTimeDelta(elapsed*5.5, maximum_unit) AS time_delta;
|
||||||
|
SELECT
|
||||||
|
'months' AS maximum_unit,
|
||||||
|
arrayJoin([1, 60, 60*60, 60*60*24, 60*60*24*30, 60*60*24*365]) AS elapsed,
|
||||||
|
formatReadableTimeDelta(elapsed*5.5, maximum_unit) AS time_delta;
|
||||||
|
Loading…
Reference in New Issue
Block a user