mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-21 15:12:02 +00:00
Add support for Date, filled documentation
This commit is contained in:
parent
ff9ff462fc
commit
64533ff4df
@ -1618,6 +1618,7 @@ private:
|
||||
|
||||
public:
|
||||
|
||||
// format DateTime
|
||||
void action(char *& target, UInt32 source, const DateLUTImpl & timezone)
|
||||
{
|
||||
if(operation)
|
||||
@ -1626,6 +1627,13 @@ private:
|
||||
copy(target, source, timezone);
|
||||
}
|
||||
|
||||
// format Date (convert to DateTime implicitly)
|
||||
void action(char *& target, UInt16 date, const DateLUTImpl & timezone)
|
||||
{
|
||||
const UInt32 datetime = timezone.fromDayNum(DayNum(date));
|
||||
action(target, datetime, timezone);
|
||||
}
|
||||
|
||||
void copy(char *& target, UInt32 , const DateLUTImpl & )
|
||||
{
|
||||
auto tmp = source + source_position_to_copy;
|
||||
@ -1696,9 +1704,7 @@ private:
|
||||
|
||||
static void format_j(char *& target, UInt32 source, const DateLUTImpl & timezone)
|
||||
{
|
||||
auto today = timezone.toDayNum(source);
|
||||
auto first_year_day = ToStartOfYearImpl::execute(source, timezone);
|
||||
writeNumberWidth(target, today - first_year_day + 1, 3);
|
||||
writeNumberWidth(target, ToDayOfYearImpl::execute(source, timezone), 3);
|
||||
}
|
||||
|
||||
static void format_m(char *& target, UInt32 source, const DateLUTImpl & timezone)
|
||||
@ -1832,7 +1838,7 @@ public:
|
||||
+ toString(arguments.size()) + ", should be 2 or 3",
|
||||
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
||||
|
||||
if (!WhichDataType(arguments[0].type).isDateTime())
|
||||
if (!WhichDataType(arguments[0].type).isDateOrDateTime())
|
||||
throw Exception("Illegal type " + arguments[0].type->getName() + " of 1 argument of function " + getName() +
|
||||
". Should be a date or a date with time", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
||||
|
||||
@ -1852,55 +1858,65 @@ public:
|
||||
|
||||
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t /*input_rows_count*/) override
|
||||
{
|
||||
auto times = checkAndGetColumn<ColumnUInt32>(block.getByPosition(arguments[0]).column.get());
|
||||
auto const_times = checkAndGetColumnConst<ColumnUInt32>(block.getByPosition(arguments[0]).column.get());
|
||||
|
||||
if (const_times)
|
||||
throw Exception("Constant times are not supported yet");
|
||||
|
||||
const ColumnConst * pattern_column = checkAndGetColumnConst<ColumnString>(block.getByPosition(arguments[1]).column.get());
|
||||
|
||||
if (!pattern_column)
|
||||
throw Exception("Illegal column " + block.getByPosition(arguments[1]).column->getName()
|
||||
+ " of second ('format') argument of function " + getName()
|
||||
+ ". Must be constant string.",
|
||||
if (!executeType<UInt32>(block, arguments, result) && !executeType<UInt16>(block, arguments, result))
|
||||
throw Exception("Illegal column " + block.getByPosition(arguments[0]).column->getName()
|
||||
+ " of function " + getName() + ", must be Date or DateTime",
|
||||
ErrorCodes::ILLEGAL_COLUMN);
|
||||
}
|
||||
|
||||
String pattern = pattern_column->getValue<String>();
|
||||
|
||||
std::vector<FormattingOperation> instructions = {};
|
||||
size_t result_length = parsePattern(pattern, instructions);
|
||||
|
||||
const DateLUTImpl * time_zone_tmp = nullptr;
|
||||
if (arguments.size() == 3)
|
||||
time_zone_tmp = &extractTimeZoneFromFunctionArguments(block, arguments, 2, 0);
|
||||
else
|
||||
time_zone_tmp = &DateLUT::instance();
|
||||
|
||||
const DateLUTImpl & time_zone = *time_zone_tmp;
|
||||
|
||||
const ColumnUInt32::Container & vec = times->getData();
|
||||
|
||||
auto col_res = ColumnString::create();
|
||||
auto & dst_data = col_res->getChars();
|
||||
auto & dst_offsets = col_res->getOffsets();
|
||||
dst_data.resize(vec.size() * (result_length + 1));
|
||||
dst_offsets.resize(vec.size());
|
||||
|
||||
auto begin = reinterpret_cast<char *>(dst_data.data());
|
||||
auto pos = begin;
|
||||
|
||||
for (size_t i = 0; i < vec.size(); ++i)
|
||||
template <typename T>
|
||||
bool executeType(Block & block, const ColumnNumbers & arguments, size_t result)
|
||||
{
|
||||
if (auto * times = checkAndGetColumn<ColumnVector<T>>(block.getByPosition(arguments[0]).column.get()))
|
||||
{
|
||||
for(auto & instruction : instructions) {
|
||||
instruction.action(pos, vec[i], time_zone);
|
||||
const ColumnConst * pattern_column = checkAndGetColumnConst<ColumnString>(block.getByPosition(arguments[1]).column.get());
|
||||
|
||||
if (!pattern_column)
|
||||
throw Exception("Illegal column " + block.getByPosition(arguments[1]).column->getName()
|
||||
+ " of second ('format') argument of function " + getName()
|
||||
+ ". Must be constant string.",
|
||||
ErrorCodes::ILLEGAL_COLUMN);
|
||||
|
||||
String pattern = pattern_column->getValue<String>();
|
||||
|
||||
std::vector<FormattingOperation> instructions = {};
|
||||
size_t result_length = parsePattern(pattern, instructions);
|
||||
|
||||
const DateLUTImpl * time_zone_tmp = nullptr;
|
||||
if (arguments.size() == 3)
|
||||
time_zone_tmp = &extractTimeZoneFromFunctionArguments(block, arguments, 2, 0);
|
||||
else
|
||||
time_zone_tmp = &DateLUT::instance();
|
||||
|
||||
const DateLUTImpl & time_zone = *time_zone_tmp;
|
||||
|
||||
const typename ColumnVector<T>::Container & vec = times->getData();
|
||||
|
||||
auto col_res = ColumnString::create();
|
||||
auto & dst_data = col_res->getChars();
|
||||
auto & dst_offsets = col_res->getOffsets();
|
||||
dst_data.resize(vec.size() * (result_length + 1));
|
||||
dst_offsets.resize(vec.size());
|
||||
|
||||
auto begin = reinterpret_cast<char *>(dst_data.data());
|
||||
auto pos = begin;
|
||||
|
||||
for (size_t i = 0; i < vec.size(); ++i)
|
||||
{
|
||||
for(auto & instruction : instructions) {
|
||||
instruction.action(pos, vec[i], time_zone);
|
||||
}
|
||||
*pos++ = '\0';
|
||||
dst_offsets[i] = pos - begin;
|
||||
}
|
||||
*pos++ = '\0';
|
||||
dst_offsets[i] = pos - begin;
|
||||
dst_data.resize(pos - begin);
|
||||
|
||||
block.getByPosition(result).column = std::move(col_res);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
block.getByPosition(result).column = std::move(col_res);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t parsePattern(String & pattern, std::vector<FormattingOperation> & instructions)
|
||||
|
@ -27,3 +27,5 @@ PM
|
||||
2018
|
||||
%
|
||||
no formatting pattern
|
||||
2018-01-01 00:00:00
|
||||
2018-01-01 01:00:00 2018-01-01 04:00:00
|
||||
|
@ -3,7 +3,8 @@ SELECT formatDateTime('not a datetime', 'IGNORED'); -- { serverError 43 }
|
||||
SELECT formatDateTime(now(), now()); -- { serverError 43 }
|
||||
SELECT formatDateTime(now(), 'good format pattern', now()); -- { serverError 43 }
|
||||
SELECT formatDateTime(now(), 'unescaped %'); -- { serverError 36 }
|
||||
|
||||
SELECT formatDateTime(toDateTime('2018-01-02 22:33:44'), '%U'); -- { serverError 43 }
|
||||
SELECT formatDateTime(toDateTime('2018-01-02 22:33:44'), '%W'); -- { serverError 43 }
|
||||
|
||||
SELECT formatDateTime(toDateTime('2018-01-02 22:33:44'), '%C');
|
||||
SELECT formatDateTime(toDateTime('2018-01-02 22:33:44'), '%d');
|
||||
@ -30,10 +31,13 @@ SELECT formatDateTime(toDateTime('2018-01-02 22:33:44'), '%T');
|
||||
SELECT formatDateTime(toDateTime('2018-01-01 22:33:44'), '%u'), formatDateTime(toDateTime('2018-01-07 22:33:44'), '%u');
|
||||
SELECT formatDateTime(toDateTime('1996-01-01 22:33:44'), '%V'), formatDateTime(toDateTime('1996-12-31 22:33:44'), '%V'),
|
||||
formatDateTime(toDateTime('1999-01-01 22:33:44'), '%V'), formatDateTime(toDateTime('1999-12-31 22:33:44'), '%V');
|
||||
SELECT formatDateTime(toDateTime('2018-01-02 22:33:44'), '%U'); -- { serverError 43 }
|
||||
SELECT formatDateTime(toDateTime('2018-01-02 22:33:44'), '%W'); -- { serverError 43 }
|
||||
SELECT formatDateTime(toDateTime('2018-01-01 22:33:44'), '%w'), formatDateTime(toDateTime('2018-01-07 22:33:44'), '%w');
|
||||
SELECT formatDateTime(toDateTime('2018-01-02 22:33:44'), '%y');
|
||||
SELECT formatDateTime(toDateTime('2018-01-02 22:33:44'), '%Y');
|
||||
SELECT formatDateTime(toDateTime('2018-01-02 22:33:44'), '%%');
|
||||
SELECT formatDateTime(toDateTime('2018-01-02 22:33:44'), 'no formatting pattern');
|
||||
SELECT formatDateTime(toDateTime('2018-01-02 22:33:44'), 'no formatting pattern');
|
||||
|
||||
SELECT formatDateTime(toDate('2018-01-01'), '%F %T');
|
||||
SELECT
|
||||
formatDateTime(toDateTime('2018-01-01 01:00:00', 'UTC'), '%F %T', 'UTC'),
|
||||
formatDateTime(toDateTime('2018-01-01 01:00:00', 'UTC'), '%F %T', 'Europe/Moscow')
|
@ -151,3 +151,34 @@ For a time interval starting at 'StartTime' and continuing for 'Duration' second
|
||||
For example, `timeSlots(toDateTime('2012-01-01 12:20:00'), 600) = [toDateTime('2012-01-01 12:00:00'), toDateTime('2012-01-01 12:30:00')]`.
|
||||
This is necessary for searching for pageviews in the corresponding session.
|
||||
|
||||
## formatDateTime(Time, Format\[, Timezone\])
|
||||
|
||||
Function formats a Time according given Format string. N.B.: Format is a constant expression, e.g. you can not have multiple formats for single result column.
|
||||
|
||||
Supported modifiers for Format:
|
||||
("Example" column shows formatting result for time `2018-01-02 22:33:44`)
|
||||
|
||||
| Modifier | Description | Example |
|
||||
| ----------- | -------- | --------------- |
|
||||
|%C|year divided by 100 and truncated to integer (00-99)|20
|
||||
|%d|day of the month, zero-padded (01-31)|02
|
||||
|%D|Short MM/DD/YY date, equivalent to %m/%d/%y|01/02/2018|
|
||||
|%e|day of the month, space-padded ( 1-31)| 2|
|
||||
|%F|short YYYY-MM-DD date, equivalent to %Y-%m-%d|2018-01-02
|
||||
|%H|hour in 24h format (00-23)|22|
|
||||
|%I|hour in 12h format (01-12)|10|
|
||||
|%j|day of the year (001-366)|002|
|
||||
|%m|month as a decimal number (01-12)|01|
|
||||
|%M|minute (00-59)|33|
|
||||
|%n|new-line character ('\n')||
|
||||
|%p|AM or PM designation|PM|
|
||||
|%R|24-hour HH:MM time, equivalent to %H:%M|22:33|
|
||||
|%S|second (00-59)|44|
|
||||
|%t|horizontal-tab character ('\t')||
|
||||
|%T|ISO 8601 time format (HH:MM:SS), equivalent to %H:%M:%S|22:33:44|
|
||||
|%u|ISO 8601 weekday as number with Monday as 1 (1-7)|2|
|
||||
|%V|ISO 8601 week number (01-53)|01|
|
||||
|%w|weekday as a decimal number with Sunday as 0 (0-6)|2|
|
||||
|%y|Year, last two digits (00-99)|18|
|
||||
|%Y|Year|2018|
|
||||
|%%|a % sign|%|
|
||||
|
@ -122,3 +122,34 @@ SELECT
|
||||
Для интервала времени, начинающегося в StartTime и продолжающегося Duration секунд, возвращает массив моментов времени, состоящий из округлений вниз до получаса точек из этого интервала.
|
||||
Например, `timeSlots(toDateTime('2012-01-01 12:20:00'), toUInt32(600)) = [toDateTime('2012-01-01 12:00:00'), toDateTime('2012-01-01 12:30:00')]`.
|
||||
Это нужно для поиска хитов, входящих в соответствующий визит.
|
||||
|
||||
## formatDateTime(Time, Format\[, Timezone\])
|
||||
Функция преобразования даты-с-временем в String согласно заданному шаблону. Важно - шаблон является константным выражением, т.е. невозможно использование разных шаблонов в одной колонке.
|
||||
|
||||
Поддерживаемые модификаторы в шаблоне Format:
|
||||
(колонка "Пример" показана для времени `2018-01-02 22:33:44`)
|
||||
|
||||
| Модификатор | Описание | Пример |
|
||||
| ----------- | -------- | --------------- |
|
||||
|%C|номер года, поделённый на 100 (00-99)|20
|
||||
|%d|день месяца, с ведущим нулём (01-31)|02
|
||||
|%D|короткая запись %m/%d/%y|01/02/2018|
|
||||
|%e|день месяца, с ведущим пробелом ( 1-31)| 2|
|
||||
|%F|короткая запись %Y-%m-%d|2018-01-02
|
||||
|%H|час в 24-часовом формате (00-23)|22|
|
||||
|%I|час в 12-часовом формате (01-12)|10|
|
||||
|%j|номер дня в году, с ведущими нулями (001-366)|002|
|
||||
|%m|месяц, с ведущим нулём (01-12)|01|
|
||||
|%M|минуты, с ведущим нулём (00-59)|33|
|
||||
|%n|символ переноса строки ('\n')||
|
||||
|%p|обозначения AM или PM|PM|
|
||||
|%R|короткая запись %H:%M|22:33|
|
||||
|%S|секунды, с ведущими нулями (00-59)|44|
|
||||
|%t|символ табуляции ('\t')||
|
||||
|%T|формат времени ISO 8601, одинаковый с %H:%M:%S|22:33:44|
|
||||
|%u|номер дня недели согласно ISO 8601, понедельник - 1, воскресенье - 7|2|
|
||||
|%V|номер недели согласно ISO 8601 (01-53)|01|
|
||||
|%w|номер дня недели, начиная с воскресенья (0-6)|2|
|
||||
|%y|год, последние 2 цифры (00-99)|18|
|
||||
|%Y|год, 4 цифры|2018|
|
||||
|%%|символ %|%|
|
||||
|
Loading…
Reference in New Issue
Block a user