mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-24 08:32:02 +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.
|
||||
|
||||
**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:
|
||||
|
||||
``` sql
|
||||
SELECT
|
||||
arrayJoin([100, 12345, 432546534]) AS number,
|
||||
formatReadableTimeDelta(number) AS time_delta
|
||||
arrayJoin([100, 12345, 432546534]) AS elapsed,
|
||||
formatReadableTimeDelta(elapsed) AS time_delta
|
||||
```
|
||||
|
||||
``` text
|
||||
┌─────number─┬─time_delta ─────────────────────────────────────────────────────┐
|
||||
┌────elapsed─┬─time_delta ─────────────────────────────────────────────────────┐
|
||||
│ 100 │ 1 minute and 40 seconds │
|
||||
│ 12345 │ 3 hours, 25 minutes and 45 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}
|
||||
|
||||
Returns the smallest value from a and b.
|
||||
|
@ -18,6 +18,7 @@ namespace DB
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int ILLEGAL_TYPE_OF_ARGUMENT;
|
||||
extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
|
||||
extern const int ILLEGAL_COLUMN;
|
||||
}
|
||||
|
||||
@ -285,23 +286,44 @@ public:
|
||||
static constexpr auto name = "formatReadableTimeDelta";
|
||||
static FunctionPtr create(const Context &) { return std::make_shared<FunctionFormatReadableTimeDelta>(); }
|
||||
|
||||
String getName() const override
|
||||
{
|
||||
return name;
|
||||
}
|
||||
String getName() const override { 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
|
||||
{
|
||||
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];
|
||||
|
||||
if (!isNativeNumber(type))
|
||||
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>();
|
||||
}
|
||||
|
||||
ColumnNumbers getArgumentsThatAreAlwaysConstant() const override { return {1}; }
|
||||
|
||||
bool useDefaultImplementationForConstants() const override { return true; }
|
||||
|
||||
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t /*input_rows_count*/) const override
|
||||
@ -322,46 +344,73 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
void formatReadableTimeDelta(double value, DB::WriteBuffer & out) const
|
||||
|
||||
void formatReadableTimeDelta(double value, String maximum_unit, DB::WriteBuffer & out) const
|
||||
{
|
||||
// 60 SECONDS = 1 MINUTE
|
||||
// 3600 SECONDS = 1 HOUR
|
||||
// 86400 SECONDS = 1 DAY
|
||||
// 30.5 DAYS = 1 MONTH
|
||||
// 365 DAYS = 1 YEAR
|
||||
// 60 SECONDS = 1 MINUTE
|
||||
// 3600 SECONDS = 1 HOUR
|
||||
// 86400 SECONDS = 1 DAY
|
||||
// 2635200 SECONDS = 30.5 DAYS = 1 MONTH
|
||||
// 31536000 SECONDS = 365 DAYS = 1 YEAR
|
||||
|
||||
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;
|
||||
|
||||
long long int date = value / 86400;
|
||||
double time = value - date * 86400;
|
||||
double aux = 0;
|
||||
|
||||
long long int hours = time / 3600;
|
||||
long long int minutes = (time - hours * 3600) / 60;
|
||||
double seconds = time - hours * 3600 - minutes * 60;
|
||||
|
||||
long long int years = date / 365;
|
||||
long long int months = (date - years * 365) / 30.5;
|
||||
long long int days = date - years * 365 - months * 30.5;
|
||||
long long int years = maximum_unit_int < 6 ? 0 : value / 31536000;
|
||||
aux += years * 31536000;
|
||||
long long int months = maximum_unit_int < 5 ? 0 : (value - aux) / 2635200;
|
||||
aux += months * 2635200;
|
||||
long long int days = maximum_unit_int < 4 ? 0 : (value - aux) / 86400;
|
||||
aux += days * 86400;
|
||||
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;
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
else
|
||||
{
|
||||
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)
|
||||
{
|
||||
parts.push_back(std::to_string(hours) + (hours==1?" hour":" hours"));
|
||||
@ -379,7 +428,6 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
String str_value;
|
||||
for(size_t i=0; i<parts.size(); i++)
|
||||
{
|
||||
@ -400,6 +448,17 @@ private:
|
||||
template <typename T>
|
||||
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()))
|
||||
{
|
||||
auto col_to = ColumnString::create();
|
||||
@ -415,7 +474,7 @@ private:
|
||||
|
||||
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);
|
||||
offsets_to[i] = buf_to.count();
|
||||
}
|
||||
|
@ -1,30 +1,30 @@
|
||||
1 second 1 second
|
||||
2 seconds 2 seconds
|
||||
7 seconds 7 seconds
|
||||
20 seconds 20 seconds
|
||||
54 seconds 54 seconds
|
||||
2 minutes and 28 seconds 2 minutes and 28 seconds
|
||||
6 minutes and 43 seconds 6 minutes and 43 seconds
|
||||
18 minutes and 16 seconds 18 minutes and 16 seconds
|
||||
49 minutes and 40 seconds 49 minutes and 40 seconds
|
||||
2 hours, 15 minutes and 3 seconds 2 hours, 15 minutes and 3 seconds
|
||||
6 hours, 7 minutes and 6 seconds 6 hours, 7 minutes and 6 seconds
|
||||
16 hours, 37 minutes and 54 seconds 16 hours, 37 minutes and 54 seconds
|
||||
1 day, 21 hours, 12 minutes and 34 seconds 1 day, 21 hours, 12 minutes and 34 seconds
|
||||
5 days, 2 hours, 53 minutes and 33 seconds 5 days, 2 hours, 53 minutes and 33 seconds
|
||||
13 days, 22 hours, 3 minutes and 24 seconds 13 days, 22 hours, 3 minutes and 24 seconds
|
||||
1month, 6 days, 20 hours, 3 minutes and 37 seconds 1month, 6 days, 20 hours, 3 minutes and 37 seconds
|
||||
3 months, 10 days, 20 hours, 21 minutes and 50 seconds 3 months, 10 days, 20 hours, 21 minutes and 50 seconds
|
||||
9 months, 4 days, 13 hours, 42 minutes and 32 seconds 9 months, 4 days, 13 hours, 42 minutes and 32 seconds
|
||||
2 years, 29 days, 22 hours, 52 minutes and 49 seconds 2 years, 29 days, 22 hours, 52 minutes and 49 seconds
|
||||
5 years, 7 months, 26 days, 18 hours and 25 minutes 5 years, 7 months, 26 days, 18 hours and 25 minutes
|
||||
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
|
||||
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
|
||||
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
|
||||
309 years, 2 days, 1 hour, 50 minutes and 46 seconds - 68 years, 1month, 4 days, 3 hours, 14 minutes and 8 seconds
|
||||
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
|
||||
2283 years, 3 months, 3 days, 55 minutes and 37 seconds - 68 years, 1month, 4 days, 3 hours, 14 minutes and 8 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
|
||||
16871 years, 1month, 19 days, 17 hours, 56 minutes and 42 seconds - 68 years, 1month, 4 days, 3 hours, 14 minutes and 8 seconds
|
||||
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
|
||||
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
|
||||
1 5.5 seconds
|
||||
60 5 minutes and 30 seconds
|
||||
3600 5 hours and 30 minutes
|
||||
86400 5 days and 12 hours
|
||||
2592000 5 months, 12 days and 12 hours
|
||||
31536000 5 years, 5 months and 30 days
|
||||
minutes 1 5.5 seconds
|
||||
minutes 60 5 minutes and 30 seconds
|
||||
minutes 3600 330 minutes
|
||||
minutes 86400 7920 minutes
|
||||
minutes 2592000 237600 minutes
|
||||
minutes 31536000 2890800 minutes
|
||||
hours 1 5.5 seconds
|
||||
hours 60 5 minutes and 30 seconds
|
||||
hours 3600 5 hours and 30 minutes
|
||||
hours 86400 132 hours
|
||||
hours 2592000 3960 hours
|
||||
hours 31536000 48180 hours
|
||||
days 1 5.5 seconds
|
||||
days 60 5 minutes and 30 seconds
|
||||
days 3600 5 hours and 30 minutes
|
||||
days 86400 5 days and 12 hours
|
||||
days 2592000 165 days
|
||||
days 31536000 2007 days and 12 hours
|
||||
months 1 5.5 seconds
|
||||
months 60 5 minutes and 30 seconds
|
||||
months 3600 5 hours and 30 minutes
|
||||
months 86400 5 days and 12 hours
|
||||
months 2592000 5 months, 12 days and 12 hours
|
||||
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
|
||||
formatReadableTimeDelta(y),
|
||||
formatReadableTimeDelta(z)
|
||||
FROM system.numbers
|
||||
LIMIT 30;
|
||||
SELECT
|
||||
arrayJoin([1, 60, 60*60, 60*60*24, 60*60*24*30, 60*60*24*365]) AS elapsed,
|
||||
formatReadableTimeDelta(elapsed*5.5) AS time_delta;
|
||||
SELECT
|
||||
'minutes' 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
|
||||
'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