mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-23 08:02:02 +00:00
Add fraction part to the time argument, add docs, better test
This commit is contained in:
parent
2b4594e375
commit
c1f59eccd5
@ -137,6 +137,51 @@ Like [makeDateTime](#makedatetime) but produces a [DateTime64](../../sql-referen
|
||||
makeDateTime32(year, month, day, hour, minute, second[, fraction[, precision[, timezone]]])
|
||||
```
|
||||
|
||||
## timestamp
|
||||
|
||||
Converts the first argument 'expr' to type DateTime64(6).
|
||||
If the second argument 'expr_time' is provided, it adds the specified time to the converted value.
|
||||
|
||||
**Syntax**
|
||||
|
||||
``` sql
|
||||
timestamp(expr[, expr_time])
|
||||
```
|
||||
|
||||
**Arguments**
|
||||
- `expr` - Date or date with time. Type: [String](../../sql-reference/data-types/string.md).
|
||||
- `expr_time` - Time to add. [String](../../sql-reference/data-types/string.md).
|
||||
|
||||
**Examples**
|
||||
|
||||
``` sql
|
||||
SELECT timestamp('2013-12-31') as ts;
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
``` text
|
||||
┌─────────────────────────ts─┐
|
||||
│ 2013-12-31 00:00:00.000000 │
|
||||
└────────────────────────────┘
|
||||
```
|
||||
|
||||
``` sql
|
||||
SELECT timestamp('2013-12-31 12:00:00', '12:00:00.11') as ts;
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
``` text
|
||||
┌─────────────────────────ts─┐
|
||||
│ 2014-01-01 00:00:00.110000 │
|
||||
└────────────────────────────┘
|
||||
```
|
||||
|
||||
**Returned value**
|
||||
|
||||
- [DateTime64](../../sql-reference/data-types/datetime64.md)(6)
|
||||
|
||||
## timeZone
|
||||
|
||||
Returns the timezone of the current session, i.e. the value of setting [session_timezone](../../operations/settings/settings.md#session_timezone).
|
||||
|
@ -110,9 +110,6 @@ public:
|
||||
readDateTime64Text(value, col_to->getScale(), read_buffer, *local_time_zone);
|
||||
vec_to[i] = value;
|
||||
|
||||
// if (!isAllRead(read_buffer))
|
||||
// throwExceptionForIncompletelyParsedValue(read_buffer, *res_type);
|
||||
|
||||
current_offset = next_offset;
|
||||
}
|
||||
}
|
||||
@ -133,9 +130,6 @@ public:
|
||||
readDateTime64Text(value, col_to->getScale(), read_buffer, *local_time_zone);
|
||||
vec_to[i] = value;
|
||||
|
||||
// if (!isAllRead(read_buffer))
|
||||
// throwExceptionForIncompletelyParsedValue(read_buffer, *res_type);
|
||||
|
||||
current_offset = next_offset;
|
||||
}
|
||||
}
|
||||
@ -150,9 +144,6 @@ public:
|
||||
if (arguments.size() == 1)
|
||||
return col_to;
|
||||
|
||||
/// hh-mm-ss
|
||||
static constexpr auto time_length = 8;
|
||||
|
||||
const IColumn * col_time = arguments[1].column.get();
|
||||
|
||||
if (const ColumnString * col_time_string = checkAndGetColumn<ColumnString>(col_time))
|
||||
@ -167,20 +158,11 @@ public:
|
||||
const size_t next_offset = (*offsets)[i];
|
||||
const size_t string_size = next_offset - current_offset - 1;
|
||||
|
||||
if (string_size != time_length)
|
||||
throw Exception(ErrorCodes::ILLEGAL_COLUMN,
|
||||
"Illegal size of argument of argument of 2nd argument of function {}",
|
||||
col_date->getName());
|
||||
ReadBufferFromMemory read_buffer(&(*chars)[current_offset], string_size);
|
||||
|
||||
const UInt8 * s = chars->data() + current_offset;
|
||||
|
||||
UInt8 hour = (s[0] - '0') * 10 + (s[1] - '0');
|
||||
UInt8 minute = (s[3] - '0') * 10 + (s[4] - '0');
|
||||
UInt8 second = (s[6] - '0') * 10 + (s[7] - '0');
|
||||
|
||||
time_t time_offset = hour * 3600 + minute * 60 + second;
|
||||
|
||||
vec_to[i] += time_offset * common::exp10_i32(DATETIME_SCALE);
|
||||
Decimal64 value = 0;
|
||||
readTime64Text(value, col_to->getScale(), read_buffer);
|
||||
vec_to[i] += value;
|
||||
|
||||
current_offset = next_offset;
|
||||
}
|
||||
@ -190,26 +172,17 @@ public:
|
||||
const ColumnString::Chars * chars = &col_time_fixed_string->getChars();
|
||||
const size_t fixed_string_size = col_time_fixed_string->getN();
|
||||
|
||||
if (fixed_string_size != time_length)
|
||||
throw Exception(ErrorCodes::ILLEGAL_COLUMN,
|
||||
"Illegal size of argument of argument of 2nd argument of function {}",
|
||||
getName());
|
||||
|
||||
size_t current_offset = 0;
|
||||
|
||||
for (size_t i = 0; i < input_rows_count; ++i)
|
||||
{
|
||||
const size_t next_offset = current_offset + fixed_string_size;
|
||||
|
||||
const UInt8 * s = chars->data() + current_offset;
|
||||
ReadBufferFromMemory read_buffer(&(*chars)[current_offset], fixed_string_size);
|
||||
|
||||
UInt8 hour = (s[0] - '0') * 10 + (s[1] - '0');
|
||||
UInt8 minute = (s[3] - '0') * 10 + (s[4] - '0');
|
||||
UInt8 second = (s[6] - '0') * 10 + (s[7] - '0');
|
||||
|
||||
time_t time_offset = hour * 3600 + minute * 60 + second;
|
||||
|
||||
vec_to[i] += time_offset * common::exp10_i32(DATETIME_SCALE);
|
||||
Decimal64 value = 0;
|
||||
readTime64Text(value, col_to->getScale(), read_buffer);
|
||||
vec_to[i] += value;
|
||||
|
||||
current_offset = next_offset;
|
||||
}
|
||||
@ -230,7 +203,23 @@ public:
|
||||
|
||||
REGISTER_FUNCTION(Timestamp)
|
||||
{
|
||||
factory.registerFunction<FunctionTimestamp>({}, FunctionFactory::CaseInsensitive);
|
||||
factory.registerFunction<FunctionTimestamp>(FunctionDocumentation{
|
||||
.description = R"(
|
||||
Converts the first argument 'expr' to type DateTime64(6).
|
||||
If the second argument 'expr_time' is provided, it adds the specified time to the converted value.
|
||||
:::)",
|
||||
.syntax = "timestamp(expr[, expr_time])",
|
||||
.arguments = {
|
||||
{"expr", "Date or date with time. Type: String."},
|
||||
{"expr_time", "Time to add. Type: String."}
|
||||
},
|
||||
.returned_value = "The result of conversion and, optionally, addition. Type: DateTime64(6).",
|
||||
.examples = {
|
||||
{"timestamp", "SELECT timestamp('2013-12-31')", "2013-12-31 00:00:00.000000"},
|
||||
{"timestamp", "SELECT timestamp('2013-12-31 12:00:00')", "2013-12-31 12:00:00.000000"},
|
||||
{"timestamp", "SELECT timestamp('2013-12-31 12:00:00', '12:00:00.11')", "2014-01-01 00:00:00.110000"},
|
||||
},
|
||||
.categories{"DateTime"}}, FunctionFactory::CaseInsensitive);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1080,6 +1080,98 @@ inline void readDateTimeText(LocalDateTime & datetime, ReadBuffer & buf)
|
||||
datetime.second((s[6] - '0') * 10 + (s[7] - '0'));
|
||||
}
|
||||
|
||||
/// In (hh)h:mm:ss format.
|
||||
|
||||
template <typename ReturnType = void>
|
||||
inline ReturnType readTimeTextImpl(time_t & time, ReadBuffer & buf)
|
||||
{
|
||||
static constexpr bool throw_exception = std::is_same_v<ReturnType, void>;
|
||||
|
||||
int16_t hours;
|
||||
int16_t minutes;
|
||||
int16_t seconds;
|
||||
|
||||
readIntText(hours, buf);
|
||||
|
||||
int negative_multiplier = hours < 0 ? -1 : 1;
|
||||
|
||||
// :mm:ss
|
||||
const size_t remaining_time_size = 6;
|
||||
|
||||
char s[remaining_time_size];
|
||||
|
||||
size_t size = buf.read(s, remaining_time_size);
|
||||
if (size != remaining_time_size)
|
||||
{
|
||||
s[size] = 0;
|
||||
|
||||
if constexpr (throw_exception)
|
||||
throw ParsingException(ErrorCodes::CANNOT_PARSE_DATETIME, "Cannot parse DateTime {}", s);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
minutes = (s[1] - '0') * 10 + (s[2] - '0');
|
||||
seconds = (s[4] - '0') * 10 + (s[5] - '0');
|
||||
|
||||
time = hours * 3600 + (minutes * 60 + seconds) * negative_multiplier;
|
||||
|
||||
return ReturnType(true);
|
||||
}
|
||||
|
||||
template <typename ReturnType>
|
||||
inline ReturnType readTimeTextImpl(Decimal64 & time64, UInt32 scale, ReadBuffer & buf)
|
||||
{
|
||||
time_t whole;
|
||||
if (!readTimeTextImpl<bool>(whole, buf))
|
||||
{
|
||||
return ReturnType(false);
|
||||
}
|
||||
|
||||
DB::DecimalUtils::DecimalComponents<Decimal64> components{static_cast<Decimal64::NativeType>(whole), 0};
|
||||
|
||||
if (!buf.eof() && *buf.position() == '.')
|
||||
{
|
||||
++buf.position();
|
||||
|
||||
/// Read digits, up to 'scale' positions.
|
||||
for (size_t i = 0; i < scale; ++i)
|
||||
{
|
||||
if (!buf.eof() && isNumericASCII(*buf.position()))
|
||||
{
|
||||
components.fractional *= 10;
|
||||
components.fractional += *buf.position() - '0';
|
||||
++buf.position();
|
||||
}
|
||||
else
|
||||
{
|
||||
/// Adjust to scale.
|
||||
components.fractional *= 10;
|
||||
}
|
||||
}
|
||||
|
||||
/// Ignore digits that are out of precision.
|
||||
while (!buf.eof() && isNumericASCII(*buf.position()))
|
||||
++buf.position();
|
||||
}
|
||||
|
||||
bool is_ok = true;
|
||||
if constexpr (std::is_same_v<ReturnType, void>)
|
||||
{
|
||||
time64 = DecimalUtils::decimalFromComponents<Decimal64>(components, scale);
|
||||
}
|
||||
else
|
||||
{
|
||||
is_ok = DecimalUtils::tryGetDecimalFromComponents<Decimal64>(components, scale, time64);
|
||||
}
|
||||
|
||||
return ReturnType(is_ok);
|
||||
}
|
||||
|
||||
inline void readTime64Text(Decimal64 & time64, UInt32 scale, ReadBuffer & buf)
|
||||
{
|
||||
readTimeTextImpl<void>(time64, scale, buf);
|
||||
}
|
||||
|
||||
/// Generic methods to read value in native binary format.
|
||||
template <typename T>
|
||||
|
@ -690,7 +690,6 @@ throwIf
|
||||
tid
|
||||
timeSlot
|
||||
timeSlots
|
||||
timestamp
|
||||
timezoneOf
|
||||
timezoneOffset
|
||||
toBool
|
||||
|
@ -1,4 +1,15 @@
|
||||
2003-12-31 00:00:00.000000
|
||||
2004-01-01 00:00:00.000000
|
||||
2003-12-31 00:00:00.000000
|
||||
2004-01-01 00:00:00.000000
|
||||
2013-12-31 00:00:00.000000
|
||||
2013-12-31 12:00:00.000000
|
||||
2013-12-31 12:00:00.111111
|
||||
2014-01-01 00:01:02.000000
|
||||
2014-01-01 00:01:02.100000
|
||||
2014-01-01 00:01:02.110000
|
||||
2014-01-01 00:01:02.111000
|
||||
2014-01-01 00:01:02.111100
|
||||
2014-01-01 00:01:02.111110
|
||||
2014-01-01 00:01:02.111111
|
||||
2013-12-30 23:58:57.888889
|
||||
2013-12-31 10:58:57.888889
|
||||
2013-12-27 07:58:57.888889
|
||||
2013-12-31 00:00:00.000000
|
||||
2014-01-01 00:00:00.000000
|
||||
|
@ -1,5 +1,21 @@
|
||||
SELECT TIMESTAMP('2003-12-31');
|
||||
SELECT TIMESTAMP('2003-12-31 12:00:00', '12:00:00');
|
||||
SELECT TIMESTAMP('2013-12-31');
|
||||
SELECT TIMESTAMP('2013-12-31 12:00:00');
|
||||
SELECT TIMESTAMP('2013-12-31 12:00:00.111111');
|
||||
SELECT TIMESTAMP('2013-12-31 12:00:00', '12:01:02');
|
||||
SELECT TIMESTAMP('2013-12-31 12:00:00', '12:01:02.1');
|
||||
SELECT TIMESTAMP('2013-12-31 12:00:00', '12:01:02.11');
|
||||
SELECT TIMESTAMP('2013-12-31 12:00:00', '12:01:02.111');
|
||||
SELECT TIMESTAMP('2013-12-31 12:00:00', '12:01:02.1111');
|
||||
SELECT TIMESTAMP('2013-12-31 12:00:00', '12:01:02.11111');
|
||||
SELECT TIMESTAMP('2013-12-31 12:00:00', '12:01:02.111111');
|
||||
SELECT TIMESTAMP('2013-12-31 12:00:00', '-12:01:02.111111');
|
||||
SELECT TIMESTAMP('2013-12-31 12:00:00', '-1:01:02.111111');
|
||||
SELECT TIMESTAMP('2013-12-31 12:00:00', '-100:01:02.111111');
|
||||
|
||||
SELECT TIMESTAMP(materialize('2003-12-31'));
|
||||
SELECT TIMESTAMP(materialize('2003-12-31 12:00:00'), materialize('12:00:00'));
|
||||
SELECT TIMESTAMP(materialize('2013-12-31'));
|
||||
SELECT TIMESTAMP(materialize('2013-12-31 12:00:00'), materialize('12:00:00'));
|
||||
|
||||
SELECT TIMESTAMP(); -- { serverError NUMBER_OF_ARGUMENTS_DOESNT_MATCH }
|
||||
SELECT TIMESTAMP('2013-12-31 12:00:00', '12:00:00', ''); -- { serverError NUMBER_OF_ARGUMENTS_DOESNT_MATCH }
|
||||
SELECT TIMESTAMP(1); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
|
||||
SELECT TIMESTAMP(1, 2); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
|
||||
|
Loading…
Reference in New Issue
Block a user