Add support for Date, filled documentation

This commit is contained in:
Alexander Krasheninnikov 2018-09-18 03:32:24 +03:00
parent ff9ff462fc
commit 64533ff4df
5 changed files with 135 additions and 51 deletions

View File

@ -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)

View File

@ -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

View File

@ -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')

View File

@ -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|%|

View File

@ -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|
|%%|символ %|%|