Merge pull request #39425 from arenadata/ADQM-485

Add support of dates from year 1900 to 2299 for Date32 and DateTime64
This commit is contained in:
Alexey Milovidov 2022-08-11 05:01:53 +03:00 committed by GitHub
commit 8374f31306
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 356 additions and 340 deletions

View File

@ -5,7 +5,7 @@ sidebar_label: Date32
# Date32
A date. Supports the date range same with [Datetime64](../../sql-reference/data-types/datetime64.md). Stored in four bytes as the number of days since 1925-01-01. Allows storing values till 2283-11-11.
A date. Supports the date range same with [Datetime64](../../sql-reference/data-types/datetime64.md). Stored in four bytes as the number of days since 1900-01-01. Allows storing values till 2299-12-31.
**Examples**
@ -36,5 +36,5 @@ SELECT * FROM new;
- [toDate32](../../sql-reference/functions/type-conversion-functions.md#todate32)
- [toDate32OrZero](../../sql-reference/functions/type-conversion-functions.md#todate32-or-zero)
- [toDate32OrNull](../../sql-reference/functions/type-conversion-functions.md#todate32-or-null)
- [toDate32OrNull](../../sql-reference/functions/type-conversion-functions.md#todate32-or-null)

View File

@ -18,7 +18,7 @@ DateTime64(precision, [timezone])
Internally, stores data as a number of ticks since epoch start (1970-01-01 00:00:00 UTC) as Int64. The tick resolution is determined by the precision parameter. Additionally, the `DateTime64` type can store time zone that is the same for the entire column, that affects how the values of the `DateTime64` type values are displayed in text format and how the values specified as strings are parsed (2020-01-01 05:00:01.000). The time zone is not stored in the rows of the table (or in resultset), but is stored in the column metadata. See details in [DateTime](../../sql-reference/data-types/datetime.md).
Supported range of values: \[1925-01-01 00:00:00, 2283-11-11 23:59:59.99999999\] (Note: The precision of the maximum value is 8).
Supported range of values: \[1900-01-01 00:00:00, 2299-12-31 23:59:59.99999999\] (Note: The precision of the maximum value is 8).
## Examples

View File

@ -266,8 +266,8 @@ Result:
└────────────────┘
```
:::note
The return type `toStartOf*` functions described below is `Date` or `DateTime`. Though these functions can take `DateTime64` as an argument, passing them a `DateTime64` that is out of the normal range (years 1925 - 2283) will give an incorrect result.
:::note
The return type `toStartOf*` functions described below is `Date` or `DateTime`. Though these functions can take `DateTime64` as an argument, passing them a `DateTime64` that is out of the normal range (years 1900 - 2299) will give an incorrect result.
:::
## toStartOfYear
@ -291,7 +291,7 @@ Returns the date.
Rounds down a date or date with time to the first day of the month.
Returns the date.
:::note
:::note
The behavior of parsing incorrect dates is implementation specific. ClickHouse may return zero date, throw an exception or do “natural” overflow.
:::

View File

@ -218,23 +218,23 @@ SELECT toDate32('1955-01-01') AS value, toTypeName(value);
2. The value is outside the range:
``` sql
SELECT toDate32('1924-01-01') AS value, toTypeName(value);
SELECT toDate32('1899-01-01') AS value, toTypeName(value);
```
``` text
┌──────value─┬─toTypeName(toDate32('1925-01-01'))─┐
│ 1925-01-01 │ Date32 │
┌──────value─┬─toTypeName(toDate32('1899-01-01'))─┐
│ 1900-01-01 │ Date32 │
└────────────┴────────────────────────────────────┘
```
3. With `Date`-type argument:
``` sql
SELECT toDate32(toDate('1924-01-01')) AS value, toTypeName(value);
SELECT toDate32(toDate('1899-01-01')) AS value, toTypeName(value);
```
``` text
┌──────value─┬─toTypeName(toDate32(toDate('1924-01-01')))─┐
┌──────value─┬─toTypeName(toDate32(toDate('1899-01-01')))─┐
│ 1970-01-01 │ Date32 │
└────────────┴────────────────────────────────────────────┘
```
@ -248,14 +248,14 @@ The same as [toDate32](#todate32) but returns the min value of [Date32](../../sq
Query:
``` sql
SELECT toDate32OrZero('1924-01-01'), toDate32OrZero('');
SELECT toDate32OrZero('1899-01-01'), toDate32OrZero('');
```
Result:
``` text
┌─toDate32OrZero('1924-01-01')─┬─toDate32OrZero('')─┐
│ 1925-01-01 │ 1925-01-01 │
┌─toDate32OrZero('1899-01-01')─┬─toDate32OrZero('')─┐
│ 1900-01-01 │ 1900-01-01 │
└──────────────────────────────┴────────────────────┘
```

View File

@ -5,7 +5,7 @@ sidebar_label: Date32
# Date32 {#data_type-datetime32}
Дата. Поддерживается такой же диапазон дат, как для типа [Datetime64](../../sql-reference/data-types/datetime64.md). Значение хранится в четырех байтах и соответствует числу дней с 1925-01-01 по 2283-11-11.
Дата. Поддерживается такой же диапазон дат, как для типа [Datetime64](../../sql-reference/data-types/datetime64.md). Значение хранится в четырех байтах и соответствует числу дней с 1900-01-01 по 2299-12-31.
**Пример**
@ -36,5 +36,5 @@ SELECT * FROM new;
- [toDate32](../../sql-reference/functions/type-conversion-functions.md#todate32)
- [toDate32OrZero](../../sql-reference/functions/type-conversion-functions.md#todate32-or-zero)
- [toDate32OrNull](../../sql-reference/functions/type-conversion-functions.md#todate32-or-null)
- [toDate32OrNull](../../sql-reference/functions/type-conversion-functions.md#todate32-or-null)

View File

@ -18,7 +18,7 @@ DateTime64(precision, [timezone])
Данные хранятся в виде количества ‘тиков’, прошедших с момента начала эпохи (1970-01-01 00:00:00 UTC), в Int64. Размер тика определяется параметром precision. Дополнительно, тип `DateTime64` позволяет хранить часовой пояс, единый для всей колонки, который влияет на то, как будут отображаться значения типа `DateTime64` в текстовом виде и как будут парситься значения заданные в виде строк (2020-01-01 05:00:01.000). Часовой пояс не хранится в строках таблицы (выборки), а хранится в метаданных колонки. Подробнее см. [DateTime](datetime.md).
Диапазон значений: \[1925-01-01 00:00:00, 2283-11-11 23:59:59.99999999\] (Примечание: Точность максимального значения составляет 8).
Диапазон значений: \[1900-01-01 00:00:00, 2299-12-31 23:59:59.99999999\] (Примечание: Точность максимального значения составляет 8).
## Примеры {#examples}

View File

@ -57,7 +57,7 @@ toTimezone(value, timezone)
**Аргументы**
- `value` — время или дата с временем. [DateTime64](../../sql-reference/data-types/datetime64.md).
- `timezone` — часовой пояс для возвращаемого значения. [String](../../sql-reference/data-types/string.md). Этот аргумент является константой, потому что `toTimezone` изменяет часовой пояс столбца (часовой пояс является атрибутом типов `DateTime*`).
- `timezone` — часовой пояс для возвращаемого значения. [String](../../sql-reference/data-types/string.md). Этот аргумент является константой, потому что `toTimezone` изменяет часовой пояс столбца (часовой пояс является атрибутом типов `DateTime*`).
**Возвращаемое значение**
@ -267,7 +267,7 @@ SELECT toUnixTimestamp('2017-11-05 08:07:47', 'Asia/Tokyo') AS unix_timestamp;
```
:::note "Attention"
`Date` или `DateTime` это возвращаемый тип функций `toStartOf*`, который описан ниже. Несмотря на то, что эти функции могут принимать `DateTime64` в качестве аргумента, если переданное значение типа `DateTime64` выходит за пределы нормального диапазона (с 1925 по 2283 год), то это даст неверный результат.
`Date` или `DateTime` это возвращаемый тип функций `toStartOf*`, который описан ниже. Несмотря на то, что эти функции могут принимать `DateTime64` в качестве аргумента, если переданное значение типа `DateTime64` выходит за пределы нормального диапазона (с 1900 по 2299 год), то это даст неверный результат.
:::
## toStartOfYear {#tostartofyear}

View File

@ -209,7 +209,7 @@ SELECT toDate32('1955-01-01') AS value, toTypeName(value);
```
``` text
┌──────value─┬─toTypeName(toDate32('1925-01-01'))─┐
┌──────value─┬─toTypeName(toDate32('1955-01-01'))─┐
│ 1955-01-01 │ Date32 │
└────────────┴────────────────────────────────────┘
```
@ -217,23 +217,23 @@ SELECT toDate32('1955-01-01') AS value, toTypeName(value);
2. Значение выходит за границы диапазона:
``` sql
SELECT toDate32('1924-01-01') AS value, toTypeName(value);
SELECT toDate32('1899-01-01') AS value, toTypeName(value);
```
``` text
┌──────value─┬─toTypeName(toDate32('1925-01-01'))─┐
│ 1925-01-01 │ Date32 │
┌──────value─┬─toTypeName(toDate32('1899-01-01'))─┐
│ 1900-01-01 │ Date32 │
└────────────┴────────────────────────────────────┘
```
3. С аргументом типа `Date`:
``` sql
SELECT toDate32(toDate('1924-01-01')) AS value, toTypeName(value);
SELECT toDate32(toDate('1899-01-01')) AS value, toTypeName(value);
```
``` text
┌──────value─┬─toTypeName(toDate32(toDate('1924-01-01')))─┐
┌──────value─┬─toTypeName(toDate32(toDate('1899-01-01')))─┐
│ 1970-01-01 │ Date32 │
└────────────┴────────────────────────────────────────────┘
```
@ -247,14 +247,14 @@ SELECT toDate32(toDate('1924-01-01')) AS value, toTypeName(value);
Запрос:
``` sql
SELECT toDate32OrZero('1924-01-01'), toDate32OrZero('');
SELECT toDate32OrZero('1899-01-01'), toDate32OrZero('');
```
Результат:
``` text
┌─toDate32OrZero('1924-01-01')─┬─toDate32OrZero('')─┐
│ 1925-01-01 │ 1925-01-01 │
┌─toDate32OrZero('1899-01-01')─┬─toDate32OrZero('')─┐
│ 1900-01-01 │ 1900-01-01 │
└──────────────────────────────┴────────────────────┘
```

View File

@ -19,7 +19,7 @@ DateTime64(precision, [timezone])
在内部此类型以Int64类型将数据存储为自Linux纪元开始(1970-01-01 00:00:00UTC)的时间刻度数ticks。时间刻度的分辨率由precision参数确定。此外`DateTime64` 类型可以像存储其他数据列一样存储时区信息,时区会影响 `DateTime64` 类型的值如何以文本格式显示,以及如何解析以字符串形式指定的时间数据 (2020-01-01 05:00:01.000)。时区不存储在表的行中也不在resultset中而是存储在列的元数据中。详细信息请参考 [DateTime](datetime.md) 数据类型.
值的范围: \[1925-01-01 00:00:00, 2283-11-11 23:59:59.99999999\] (注意: 最大值的精度是8)。
值的范围: \[1900-01-01 00:00:00, 2299-12-31 23:59:59.99999999\] (注意: 最大值的精度是8)。
## 示例 {#examples}

View File

@ -263,8 +263,8 @@ SELECT toUnixTimestamp('2017-11-05 08:07:47', 'Asia/Tokyo') AS unix_timestamp
└────────────────┘
```
:::注意
下面描述的返回类型 `toStartOf` 函数是 `Date``DateTime`。尽管这些函数可以将 `DateTime64` 作为参数但将超出正常范围1925年-2283年)的 `DateTime64` 传递给它们会给出不正确的结果。
:::注意
下面描述的返回类型 `toStartOf` 函数是 `Date``DateTime`。尽管这些函数可以将 `DateTime64` 作为参数但将超出正常范围1900年-2299年)的 `DateTime64` 传递给它们会给出不正确的结果。
:::
## toStartOfYear {#tostartofyear}
@ -1221,4 +1221,4 @@ SELECT fromModifiedJulianDayOrNull(58849);
└────────────────────────────────────┘
```
[Original article](https://clickhouse.com/docs/en/query_language/functions/date_time_functions/) <!--hide-->
[Original article](https://clickhouse.com/docs/en/query_language/functions/date_time_functions/) <!--hide-->

View File

@ -10,20 +10,23 @@
#include <type_traits>
#define DATE_LUT_MIN_YEAR 1925 /// 1925 since wast majority of timezones changed to 15-minute aligned offsets somewhere in 1924 or earlier.
#define DATE_LUT_MAX_YEAR 2283 /// Last supported year (complete)
#define DATE_LUT_MIN_YEAR 1900 /// 1900 since majority of financial organizations consider 1900 as an initial year.
#define DATE_LUT_MAX_YEAR 2299 /// Last supported year (complete)
#define DATE_LUT_YEARS (1 + DATE_LUT_MAX_YEAR - DATE_LUT_MIN_YEAR) /// Number of years in lookup table
#define DATE_LUT_SIZE 0x20000
#define DATE_LUT_SIZE 0x23AB1
#define DATE_LUT_MAX (0xFFFFFFFFU - 86400)
#define DATE_LUT_MAX_DAY_NUM 0xFFFF
#define DAYNUM_OFFSET_EPOCH 25567
/// Max int value of Date32, DATE LUT cache size minus daynum_offset_epoch
#define DATE_LUT_MAX_EXTEND_DAY_NUM (DATE_LUT_SIZE - 16436)
#define DATE_LUT_MAX_EXTEND_DAY_NUM (DATE_LUT_SIZE - DAYNUM_OFFSET_EPOCH)
/// A constant to add to time_t so every supported time point becomes non-negative and still has the same remainder of division by 3600.
/// If we treat "remainder of division" operation in the sense of modular arithmetic (not like in C++).
#define DATE_LUT_ADD ((1970 - DATE_LUT_MIN_YEAR) * 366 * 86400)
#define DATE_LUT_ADD ((1970 - DATE_LUT_MIN_YEAR) * 366L * 86400)
#if defined(__PPC__)
@ -64,62 +67,78 @@ private:
// Same as above but select different function overloads for zero saturation.
STRONG_TYPEDEF(UInt32, LUTIndexWithSaturation)
static inline LUTIndex normalizeLUTIndex(UInt32 index)
{
if (index >= DATE_LUT_SIZE)
return LUTIndex(DATE_LUT_SIZE - 1);
return LUTIndex{index};
}
static inline LUTIndex normalizeLUTIndex(Int64 index)
{
if (unlikely(index < 0))
return LUTIndex(0);
if (index >= DATE_LUT_SIZE)
return LUTIndex(DATE_LUT_SIZE - 1);
return LUTIndex{index};
}
template <typename T>
friend inline LUTIndex operator+(const LUTIndex & index, const T v)
{
return LUTIndex{(index.toUnderType() + UInt32(v)) & date_lut_mask};
return normalizeLUTIndex(index.toUnderType() + UInt32(v));
}
template <typename T>
friend inline LUTIndex operator+(const T v, const LUTIndex & index)
{
return LUTIndex{(v + index.toUnderType()) & date_lut_mask};
return normalizeLUTIndex(static_cast<Int64>(v + index.toUnderType()));
}
friend inline LUTIndex operator+(const LUTIndex & index, const LUTIndex & v)
{
return LUTIndex{(index.toUnderType() + v.toUnderType()) & date_lut_mask};
return normalizeLUTIndex(static_cast<UInt32>(index.toUnderType() + v.toUnderType()));
}
template <typename T>
friend inline LUTIndex operator-(const LUTIndex & index, const T v)
{
return LUTIndex{(index.toUnderType() - UInt32(v)) & date_lut_mask};
return normalizeLUTIndex(static_cast<Int64>(index.toUnderType() - UInt32(v)));
}
template <typename T>
friend inline LUTIndex operator-(const T v, const LUTIndex & index)
{
return LUTIndex{(v - index.toUnderType()) & date_lut_mask};
return normalizeLUTIndex(static_cast<Int64>(v - index.toUnderType()));
}
friend inline LUTIndex operator-(const LUTIndex & index, const LUTIndex & v)
{
return LUTIndex{(index.toUnderType() - v.toUnderType()) & date_lut_mask};
return normalizeLUTIndex(static_cast<Int64>(index.toUnderType() - v.toUnderType()));
}
template <typename T>
friend inline LUTIndex operator*(const LUTIndex & index, const T v)
{
return LUTIndex{(index.toUnderType() * UInt32(v)) & date_lut_mask};
return normalizeLUTIndex(index.toUnderType() * UInt32(v));
}
template <typename T>
friend inline LUTIndex operator*(const T v, const LUTIndex & index)
{
return LUTIndex{(v * index.toUnderType()) & date_lut_mask};
return normalizeLUTIndex(v * index.toUnderType());
}
template <typename T>
friend inline LUTIndex operator/(const LUTIndex & index, const T v)
{
return LUTIndex{(index.toUnderType() / UInt32(v)) & date_lut_mask};
return normalizeLUTIndex(index.toUnderType() / UInt32(v));
}
template <typename T>
friend inline LUTIndex operator/(const T v, const LUTIndex & index)
{
return LUTIndex{(UInt32(v) / index.toUnderType()) & date_lut_mask};
return normalizeLUTIndex(UInt32(v) / index.toUnderType());
}
public:
@ -168,14 +187,9 @@ public:
static_assert(sizeof(Values) == 16);
private:
/// Mask is all-ones to allow efficient protection against overflow.
static constexpr UInt32 date_lut_mask = 0x1ffff;
static_assert(date_lut_mask == DATE_LUT_SIZE - 1);
/// Offset to epoch in days (ExtendedDayNum) of the first day in LUT.
/// "epoch" is the Unix Epoch (starts at unix timestamp zero)
static constexpr UInt32 daynum_offset_epoch = 16436;
static constexpr UInt32 daynum_offset_epoch = 25567;
static_assert(daynum_offset_epoch == (1970 - DATE_LUT_MIN_YEAR) * 365 + (1970 - DATE_LUT_MIN_YEAR / 4 * 4) / 4);
/// Lookup table is indexed by LUTIndex.
@ -232,12 +246,12 @@ private:
static inline LUTIndex toLUTIndex(DayNum d)
{
return LUTIndex{(d + daynum_offset_epoch) & date_lut_mask};
return normalizeLUTIndex(d + daynum_offset_epoch);
}
static inline LUTIndex toLUTIndex(ExtendedDayNum d)
{
return LUTIndex{static_cast<UInt32>(d + daynum_offset_epoch) & date_lut_mask};
return normalizeLUTIndex(static_cast<UInt32>(d + daynum_offset_epoch));
}
inline LUTIndex toLUTIndex(Time t) const
@ -1062,7 +1076,7 @@ public:
auto year_lut_index = (year - DATE_LUT_MIN_YEAR) * 12 + month - 1;
UInt32 index = years_months_lut[year_lut_index].toUnderType() + day_of_month - 1;
/// When date is out of range, default value is DATE_LUT_SIZE - 1 (2283-11-11)
/// When date is out of range, default value is DATE_LUT_SIZE - 1 (2299-12-31)
return LUTIndex{std::min(index, static_cast<UInt32>(DATE_LUT_SIZE - 1))};
}

View File

@ -79,12 +79,13 @@ FailuresCount countFailures(const ::testing::TestResult & test_result)
TEST(DateLUTTest, makeDayNumTest)
{
const DateLUTImpl & lut = DateLUT::instance("UTC");
EXPECT_EQ(0, lut.makeDayNum(1924, 12, 31));
EXPECT_EQ(-1, lut.makeDayNum(1924, 12, 31, -1));
EXPECT_EQ(0, lut.makeDayNum(1899, 12, 31));
EXPECT_EQ(-1, lut.makeDayNum(1899, 12, 31, -1));
EXPECT_EQ(-25567, lut.makeDayNum(1900, 1, 1));
EXPECT_EQ(-16436, lut.makeDayNum(1925, 1, 1));
EXPECT_EQ(0, lut.makeDayNum(1970, 1, 1));
EXPECT_EQ(114635, lut.makeDayNum(2283, 11, 11));
EXPECT_EQ(114635, lut.makeDayNum(2500, 12, 25));
EXPECT_EQ(120529, lut.makeDayNum(2300, 12, 31));
EXPECT_EQ(120529, lut.makeDayNum(2500, 12, 25));
}

View File

@ -599,8 +599,9 @@ template <typename Name> struct ConvertImpl<DataTypeFloat32, DataTypeDateTime, N
template <typename Name> struct ConvertImpl<DataTypeFloat64, DataTypeDateTime, Name>
: DateTimeTransformImpl<DataTypeFloat64, DataTypeDateTime, ToDateTimeTransform64Signed<Float64, UInt32>> {};
const time_t LUT_MIN_TIME = -1420070400l; // 1925-01-01 UTC
const time_t LUT_MAX_TIME = 9877248000l; // 2282-12-31 UTC
const time_t LUT_MIN_TIME = -2208988800l; // 1900-01-01 UTC
const time_t LUT_MAX_TIME = 10413791999l; // 2299-12-31 UTC
/** Conversion of numeric to DateTime64
*/

View File

@ -164,9 +164,9 @@ struct MakeDate32Traits
using ReturnDataType = DataTypeDate32;
using ReturnColumnType = ColumnInt32;
static constexpr auto MIN_YEAR = 1925;
static constexpr auto MAX_YEAR = 2283;
static constexpr auto MAX_DATE = YearMonthDayToSingleInt(MAX_YEAR, 11, 11);
static constexpr auto MIN_YEAR = 1900;
static constexpr auto MAX_YEAR = 2299;
static constexpr auto MAX_DATE = YearMonthDayToSingleInt(MAX_YEAR, 12, 31);
};
/// Common implementation for makeDateTime, makeDateTime64

View File

@ -220,7 +220,10 @@ ColumnPtr fillColumnWithRandomData(
{
auto column = ColumnInt32::create();
column->getData().resize(limit);
fillBufferWithRandomData(reinterpret_cast<char *>(column->getData().data()), limit * sizeof(Int32), rng);
for (size_t i = 0; i < limit; ++i)
column->getData()[i] = (rng() % static_cast<UInt64>(DATE_LUT_SIZE)) - DAYNUM_OFFSET_EPOCH;
return column;
}
case TypeIndex::UInt32: [[fallthrough]];

View File

@ -2126,9 +2126,9 @@ def materialized_database_mysql_date_type_to_date32(
mysql_node.query(
"CREATE TABLE test_database.a (a INT(11) NOT NULL PRIMARY KEY, b date DEFAULT NULL)"
)
# can't support date that less than 1925 year for now
mysql_node.query("INSERT INTO test_database.a VALUES(1, '1900-04-16')")
# test date that is older than 1925
# can't support date that less than 1900 year for now
mysql_node.query("INSERT INTO test_database.a VALUES(1, '1899-04-16')")
# test date that is older than 1900
mysql_node.query("INSERT INTO test_database.a VALUES(3, '1971-02-16')")
mysql_node.query("INSERT INTO test_database.a VALUES(4, '2101-05-16')")

View File

@ -26,9 +26,9 @@ def test_overflow_toDate(start_cluster):
def test_overflow_toDate32(start_cluster):
assert node.query("SELECT toDate32('2999-12-31','UTC')") == "2283-11-11\n"
assert node.query("SELECT toDate32('2999-12-31','UTC')") == "2299-12-31\n"
assert node.query("SELECT toDate32('2021-12-21','UTC')") == "2021-12-21\n"
assert node.query("SELECT toDate32('1000-12-31','UTC')") == "1925-01-01\n"
assert node.query("SELECT toDate32('1000-12-31','UTC')") == "1900-01-01\n"
def test_overflow_toDateTime(start_cluster):

View File

@ -137,7 +137,7 @@ toStartOfInterval
2015-01-01
2019-01-01
2019-01-01
2018-10-01
2018-07-01
2019-02-01
2019-01-01
2018-10-01
@ -164,7 +164,7 @@ toStartOfInterval
2015-01-01
2019-01-01
2019-01-01
2018-10-01
2018-07-01
2019-02-01
2019-01-01
2018-10-01

View File

@ -70,16 +70,16 @@ DateTime64(3, \'UTC\') DateTime64(6, \'UTC\') DateTime64(6, \'UTC\')
1992-12-28 09:26:04.030 1971-07-29 06:20:38.230976 1980-03-26 15:49:55.428516
2051-12-11 07:09:13.162 1982-01-12 00:25:45.754492 2010-05-17 07:01:28.452864
Date32
1934-01-06
2039-08-16
2103-11-03
2064-08-14
2187-08-21
2099-04-08
1947-06-22
2012-01-19
2170-07-09
2263-01-17
2120-04-24
1908-10-02
2105-09-04
2129-03-23
1921-04-05
2020-04-14
2251-12-25
2266-03-27
2161-02-18
2172-07-24
-
Float32 Float64
-1.3551149e32 1.2262973812461839e235

View File

@ -4,6 +4,6 @@ Asia/Makassar 1234567891011 2009-02-14 07:31:31.011 1970-01-15 14:56:07.891011 1
non-const column
1234567891011 2009-02-13 23:31:31.011 1970-01-15 06:56:07.891011 1970-01-01 00:20:34.567891011
upper range bound
9904447342 2283-11-10 19:22:22.123 2283-11-10 19:22:22.123456 1925-01-01 00:00:00.413905173
10413688942 2299-12-30 19:22:22.123 2299-12-30 19:22:22.123456 1900-01-01 00:00:00.413905173
lower range bound
-1420066799 1925-01-01 01:00:00.877 1925-01-01 01:00:00.876544 1925-01-01 01:00:00.876543211
-2208985199 1900-01-01 01:00:00.877 1900-01-01 01:00:00.876544 1900-01-01 01:00:00.876543211

View File

@ -46,10 +46,10 @@ SELECT
SELECT 'upper range bound';
WITH
9904447342 AS timestamp,
CAST(9904447342123 AS Int64) AS milli,
CAST(9904447342123456 AS Int64) AS micro,
CAST(9904447342123456789 AS Int64) AS nano,
10413688942 AS timestamp,
CAST(10413688942123 AS Int64) AS milli,
CAST(10413688942123456 AS Int64) AS micro,
CAST(10413688942123456789 AS Int64) AS nano,
'UTC' AS tz
SELECT
timestamp,
@ -59,13 +59,13 @@ SELECT
SELECT 'lower range bound';
WITH
-1420066799 AS timestamp,
CAST(-1420066799123 AS Int64) AS milli,
CAST(-1420066799123456 AS Int64) AS micro,
CAST(-1420066799123456789 AS Int64) AS nano,
-2208985199 AS timestamp,
CAST(-2208985199123 AS Int64) AS milli,
CAST(-2208985199123456 AS Int64) AS micro,
CAST(-2208985199123456789 AS Int64) AS nano,
'UTC' AS tz
SELECT
timestamp,
fromUnixTimestamp64Milli(milli, tz),
fromUnixTimestamp64Micro(micro, tz),
fromUnixTimestamp64Nano(nano, tz);
fromUnixTimestamp64Nano(nano, tz);

View File

@ -18,10 +18,10 @@ SELECT toDateTime64(toFloat32(bitShiftLeft(toUInt64(1),33)), 2, 'Asia/Istanbul')
SELECT toDateTime64(toFloat64(bitShiftLeft(toUInt64(1),33)), 2, 'Asia/Istanbul') FORMAT Null;
-- These are outsize of extended range and hence clamped
SELECT toDateTime64(-1 * bitShiftLeft(toUInt64(1), 35), 2, 'Asia/Istanbul');
1925-01-01 02:00:00.00
1900-01-01 01:56:56.00
SELECT CAST(-1 * bitShiftLeft(toUInt64(1), 35) AS DateTime64(3, 'Asia/Istanbul'));
1925-01-01 02:00:00.000
1900-01-01 01:56:56.000
SELECT CAST(bitShiftLeft(toUInt64(1), 35) AS DateTime64(3, 'Asia/Istanbul'));
2282-12-31 03:00:00.000
2299-12-31 23:59:59.000
SELECT toDateTime64(bitShiftLeft(toUInt64(1), 35), 2, 'Asia/Istanbul');
2282-12-31 03:00:00.00
2299-12-31 23:59:59.00

View File

@ -1,4 +1,4 @@
1940-10-09 21:13:17.6
2283-11-11 23:46:43.6
2283-11-11 23:46:40.1
1925-01-01 00:00:00.9
2284-06-04 23:46:43.6
2299-12-31 23:40:00.1
1900-01-01 00:00:00.9

View File

@ -1,4 +1,4 @@
SELECT toString(toDateTime('-922337203.6854775808', 1, 'Asia/Istanbul'));
SELECT toString(toDateTime('9922337203.6854775808', 1, 'Asia/Istanbul'));
SELECT toDateTime64(CAST('10000000000.1' AS Decimal64(1)), 1, 'Asia/Istanbul');
SELECT toDateTime64(CAST('-10000000000.1' AS Decimal64(1)), 1, 'Asia/Istanbul');
SELECT toDateTime64(CAST('10500000000.1' AS Decimal64(1)), 1, 'Asia/Istanbul');
SELECT toDateTime64(CAST('-10500000000.1' AS Decimal64(1)), 1, 'Asia/Istanbul');

View File

@ -1,2 +1,2 @@
2283-11-11 23:48:05.4775806
2283-11-11 23:52:48.54775806
2299-12-31 23:48:05.4775806
2299-12-31 23:52:48.54775806

View File

@ -1,19 +1,19 @@
1925-01-01
1925-01-01
2282-12-31
2283-11-11
1900-01-01
1900-01-01
2299-12-15
2299-12-31
2021-06-22
-------toYear---------
1925
1925
2282
2283
1900
1900
2299
2299
2021
-------toMonth---------
1
1
12
11
12
6
-------toQuarter---------
1
@ -24,83 +24,83 @@
-------toDayOfMonth---------
1
1
15
31
11
22
-------toDayOfWeek---------
4
4
7
1
1
5
7
2
-------toDayOfYear---------
1
1
365
315
349
364
173
-------toHour---------
-------toMinute---------
-------toSecond---------
-------toStartOfDay---------
2061-02-06 07:28:16
2061-02-06 07:28:16
2010-10-17 11:03:28
2011-08-28 11:03:28
2036-02-07 07:31:20
2036-02-07 07:31:20
2027-10-01 11:03:28
2027-10-17 11:03:28
2021-06-22 00:00:00
-------toMonday---------
2104-06-04
2104-06-04
2103-07-21
2104-05-31
2079-06-07
2079-06-07
2120-07-06
2120-07-20
2021-06-21
-------toISOWeek---------
1
1
50
52
45
25
-------toISOYear---------
1925
1925
2282
2283
1900
1900
2299
2299
2021
-------toWeek---------
0
0
50
53
45
25
-------toYearWeek---------
192452
192452
228253
228345
189953
189953
229950
229953
202125
-------toStartOfWeek---------
2104-06-03
2104-06-03
2103-07-27
2104-06-06
2079-06-06
2079-06-06
2120-07-05
2120-07-26
2021-06-20
-------toStartOfMonth---------
2104-06-07
2104-06-07
2103-06-27
2104-05-27
2079-06-07
2079-06-07
2120-06-26
2120-06-26
2021-06-01
-------toStartOfQuarter---------
2104-06-07
2104-06-07
2103-04-27
2104-04-26
2079-06-07
2079-06-07
2120-04-26
2120-04-26
2021-04-01
-------toStartOfYear---------
2104-06-07
2104-06-07
2102-07-28
2103-07-28
2079-06-07
2079-06-07
2119-07-28
2119-07-28
2021-01-01
-------toStartOfSecond---------
-------toStartOfMinute---------
@ -109,183 +109,183 @@
-------toStartOfFifteenMinutes---------
-------toStartOfHour---------
-------toStartOfISOYear---------
2104-06-04
2104-06-04
2102-07-29
2103-07-28
2079-06-07
2079-06-07
2119-07-29
2119-07-29
2021-01-04
-------toRelativeYearNum---------
1925
1925
2282
2283
1900
1900
2299
2299
2021
-------toRelativeQuarterNum---------
7700
7700
9131
9135
7600
7600
9199
9199
8085
-------toRelativeMonthNum---------
23101
23101
27396
27407
22801
22801
27600
27600
24258
-------toRelativeWeekNum---------
63189
63189
16331
63188
61885
61885
17216
17217
2686
-------toRelativeDayNum---------
49100
49100
48784
49099
39969
39969
54977
54993
18800
-------toRelativeHourNum---------
4294572852
4294572852
2743677
2751237
4294353708
4294353708
2892309
2892693
451197
-------toRelativeMinuteNum---------
4271299336
4271299336
164620620
165074220
4258150699
4258150699
173538540
173561580
27071820
-------toRelativeSecondNum---------
2874889696
2874889696
1287302608
1314518608
2085971480
2085971480
1822377808
1823760208
1624309200
-------toTime---------
-------toYYYYMM---------
192501
192501
228212
228311
190001
190001
229912
229912
202106
-------toYYYYMMDD---------
19250101
19250101
22821231
22831111
19000101
19000101
22991215
22991231
20210622
-------toYYYYMMDDhhmmss---------
19250101000000
19250101000000
22821231000000
22831111000000
19000101000000
19000101000000
22991215000000
22991231000000
20210622000000
-------addSeconds---------
1925-01-01 01:00:00.000
1925-01-01 01:00:00.000
2282-12-31 01:00:00.000
2283-11-11 01:00:00.000
1900-01-01 01:00:00.000
1900-01-01 01:00:00.000
2299-12-15 01:00:00.000
2299-12-31 01:00:00.000
2021-06-22 01:00:00.000
-------addMinutes---------
1925-01-01 01:00:00.000
1925-01-01 01:00:00.000
2282-12-31 01:00:00.000
2283-11-11 01:00:00.000
1900-01-01 01:00:00.000
1900-01-01 01:00:00.000
2299-12-15 01:00:00.000
2299-12-31 01:00:00.000
2021-06-22 01:00:00.000
-------addHours---------
1925-01-01 01:00:00.000
1925-01-01 01:00:00.000
2282-12-31 01:00:00.000
2283-11-11 01:00:00.000
1900-01-01 01:00:00.000
1900-01-01 01:00:00.000
2299-12-15 01:00:00.000
2299-12-31 01:00:00.000
2021-06-22 01:00:00.000
-------addDays---------
1925-01-08
1925-01-08
2283-01-07
1925-01-07
1900-01-08
1900-01-08
2299-12-22
2299-12-31
2021-06-29
-------addWeeks---------
1925-01-08
1925-01-08
2283-01-07
1925-01-07
1900-01-08
1900-01-08
2299-12-22
2299-12-31
2021-06-29
-------addMonths---------
1925-02-01
1925-02-01
2283-01-31
2283-11-11
1900-02-01
1900-02-01
2299-12-31
2299-12-31
2021-07-22
-------addQuarters---------
1925-04-01
1925-04-01
2283-03-31
2283-11-11
1900-04-01
1900-04-01
2299-12-31
2299-12-31
2021-09-22
-------addYears---------
1926-01-01
1926-01-01
2283-11-11
2283-11-11
1901-01-01
1901-01-01
2299-12-31
2299-12-31
2022-06-22
-------subtractSeconds---------
1925-01-01 00:00:00.000
1925-01-01 00:00:00.000
2282-12-30 23:00:00.000
2283-11-10 23:00:00.000
1900-01-01 00:00:00.000
1900-01-01 00:00:00.000
2299-12-14 23:00:00.000
2299-12-30 23:00:00.000
2021-06-21 23:00:00.000
-------subtractMinutes---------
1925-01-01 00:00:00.000
1925-01-01 00:00:00.000
2282-12-30 23:00:00.000
2283-11-10 23:00:00.000
1900-01-01 00:00:00.000
1900-01-01 00:00:00.000
2299-12-14 23:00:00.000
2299-12-30 23:00:00.000
2021-06-21 23:00:00.000
-------subtractHours---------
1925-01-01 00:00:00.000
1925-01-01 00:00:00.000
2282-12-30 23:00:00.000
2283-11-10 23:00:00.000
1900-01-01 00:00:00.000
1900-01-01 00:00:00.000
2299-12-14 23:00:00.000
2299-12-30 23:00:00.000
2021-06-21 23:00:00.000
-------subtractDays---------
2283-11-05
2283-11-05
2282-12-24
2283-11-04
2299-12-31
2299-12-31
2299-12-08
2299-12-24
2021-06-15
-------subtractWeeks---------
2283-11-05
2283-11-05
2282-12-24
2283-11-04
2299-12-31
2299-12-31
2299-12-08
2299-12-24
2021-06-15
-------subtractMonths---------
1925-01-01
1925-01-01
2282-11-30
2283-10-11
1900-01-01
1900-01-01
2299-11-15
2299-11-30
2021-05-22
-------subtractQuarters---------
1925-01-01
1925-01-01
2282-09-30
2283-08-11
1900-01-01
1900-01-01
2299-09-15
2299-09-30
2021-03-22
-------subtractYears---------
1925-01-01
1925-01-01
2281-12-31
2282-11-11
1900-01-01
1900-01-01
2298-12-15
2298-12-31
2020-06-22
-------toDate32---------
1925-01-01 2000-01-01
1925-01-01 1925-01-01
1925-01-01 \N
1925-01-01
1900-01-01 2000-01-01
1900-01-01 1900-01-01
1900-01-01 \N
1900-01-01
\N
1925-01-01
1900-01-01
1969-12-31
1970-01-01
2149-06-06
2149-06-07
2283-11-11
2299-12-31

View File

@ -1,7 +1,7 @@
drop table if exists t1;
create table t1(x1 Date32) engine Memory;
insert into t1 values ('1925-01-01'),('1924-01-01'),('2282-12-31'),('2283-12-31'),('2021-06-22');
insert into t1 values ('1900-01-01'),('1899-01-01'),('2299-12-15'),('2300-12-31'),('2021-06-22');
select x1 from t1;
select '-------toYear---------';
@ -113,20 +113,19 @@ select subtractQuarters(x1, 1) from t1;
select '-------subtractYears---------';
select subtractYears(x1, 1) from t1;
select '-------toDate32---------';
select toDate32('1925-01-01'), toDate32(toDate('2000-01-01'));
select toDate32OrZero('1924-01-01'), toDate32OrNull('1924-01-01');
select toDate32('1900-01-01'), toDate32(toDate('2000-01-01'));
select toDate32OrZero('1899-01-01'), toDate32OrNull('1899-01-01');
select toDate32OrZero(''), toDate32OrNull('');
select (select toDate32OrZero(''));
select (select toDate32OrNull(''));
SELECT toString(T.d) dateStr
FROM
(
SELECT '1925-01-01'::Date32 d
SELECT '1900-01-01'::Date32 d
UNION ALL SELECT '1969-12-31'::Date32
UNION ALL SELECT '1970-01-01'::Date32
UNION ALL SELECT '2149-06-06'::Date32
UNION ALL SELECT '2149-06-07'::Date32
UNION ALL SELECT '2283-11-11'::Date32
UNION ALL SELECT '2299-12-31'::Date32
) AS T
ORDER BY T.d

View File

@ -28,10 +28,9 @@ Nullable(Date32)
1969-01-01
1969-12-01
1969-12-31
2282-01-01
2283-01-01
2283-11-11
1970-01-01
2298-01-01
2299-01-01
2299-12-31
1970-01-01
1970-01-01
1970-01-01

View File

@ -39,14 +39,13 @@ select makeDate32(2150,1,1);
select makeDate32(1969,1,1);
select makeDate32(1969,12,1);
select makeDate32(1969,12,31);
select makeDate32(2282,1,1);
select makeDate32(2283,1,1);
select makeDate32(2283,11,11);
select makeDate32(2283,11,12);
select makeDate32(2284,1,1);
select makeDate32(1924,1,1);
select makeDate32(1924,12,1);
select makeDate32(1924,12,31);
select makeDate32(2298,1,1);
select makeDate32(2299,1,1);
select makeDate32(2299,12,31);
select makeDate32(2300,1,1);
select makeDate32(1899,1,1);
select makeDate32(1899,12,1);
select makeDate32(1899,12,31);
select makeDate32(1970,0,0);
select makeDate32(1970,0,1);
select makeDate32(1970,1,0);

View File

@ -8,9 +8,9 @@ DateTime64(3)
DateTime64(6)
DateTime64(7, \'CET\')
DateTime64(7, \'UTC\')
1925-01-01 00:00:00.000000000
1925-01-01 00:00:00.000000000
2283-11-11 23:59:59.99999999
1900-01-01 00:00:00.000000000
1900-01-01 00:00:00.000000000
2299-12-31 23:59:59.99999999
2262-04-11 23:47:16.854775807
2262-04-11 23:47:16.85477581
1991-08-24 21:04:00
@ -23,10 +23,10 @@ DateTime64(7, \'UTC\')
1991-08-24 21:04:00.0001234
1991-08-24 21:04:00.00001234
1991-08-24 21:04:00.000001234
1925-01-01 00:00:00.000000000
1925-01-01 00:00:00.000000000
1925-01-01 00:00:00.000000000
1925-01-01 00:00:00.000000000
1900-01-01 00:00:00.000000000
1900-01-01 00:00:00.000000000
1900-01-01 00:00:00.000000000
1900-01-01 00:00:00.000000000
1984-01-02 01:00:00.000000000
1984-01-01 01:10:00.000000000
1984-01-01 00:01:10.000000000
@ -37,22 +37,22 @@ DateTime64(7, \'UTC\')
1983-03-02 02:03:04.000000005
1984-03-02 02:03:04.000000005
1983-03-03 02:03:04.000000005
1925-01-01 00:00:00.000000000
1925-01-01 00:00:00.000000000
1925-01-01 00:00:00.000000000
1925-01-01 00:00:00.000000000
1925-01-01 00:00:00.000000000
1925-01-01 00:00:00.000000000
1925-01-01 00:00:00.000000000
1925-01-01 00:00:00.000000000
1900-01-01 00:00:00.000000000
1900-01-01 00:00:00.000000000
1900-01-01 00:00:00.000000000
1900-01-01 00:00:00.000000000
1900-01-01 00:00:00.000000000
1900-01-01 00:00:00.000000000
1900-01-01 00:00:00.000000000
1900-01-01 00:00:00.000000000
1984-01-01 02:03:04.000000000
1925-01-01 00:00:00.000000000
1925-01-01 00:00:00.000000000
1925-01-01 00:00:00.000000000
1925-01-01 00:00:00.000000000
1925-01-01 00:00:00.000000000
1925-01-01 00:00:00.000000000
1925-01-01 00:00:00.000000000
1900-01-01 00:00:00.000000000
1900-01-01 00:00:00.000000000
1900-01-01 00:00:00.000000000
1900-01-01 00:00:00.000000000
1900-01-01 00:00:00.000000000
1900-01-01 00:00:00.000000000
1900-01-01 00:00:00.000000000
1984-01-01 00:00:00.000000000
1984-01-01 00:00:00.000000000
1984-01-01 00:00:00.000000000
@ -61,9 +61,9 @@ DateTime64(7, \'UTC\')
1984-01-01 00:00:00.000000000
1984-01-01 00:00:00.000000000
1984-01-01 00:00:00.000000000
2283-11-11 23:59:59.999
1925-01-01 00:00:00.000
1925-01-01 00:00:00.000
1925-01-01 00:00:00.000
1925-01-01 00:00:00.000
1925-01-01 00:00:00.000
2299-12-31 23:59:59.999
1900-01-01 00:00:00.000
1900-01-01 00:00:00.000
1900-01-01 00:00:00.000
1900-01-01 00:00:00.000
1900-01-01 00:00:00.000

View File

@ -10,10 +10,10 @@ select toTypeName(makeDateTime64(1991, 8, 24, 21, 4, 0, 1234, 6));
select toTypeName(makeDateTime64(1991, 8, 24, 21, 4, 0, 1234, 7, 'CET'));
select toTypeName(cast(makeDateTime64(1991, 8, 24, 21, 4, 0, 1234, 7, 'CET') as DateTime64(7, 'UTC')));
select makeDateTime64(1925, 1, 1, 0, 0, 0, 0, 9, 'UTC');
select makeDateTime64(1924, 12, 31, 23, 59, 59, 999999999, 9, 'UTC');
select makeDateTime64(2283, 11, 11, 23, 59, 59, 99999999, 8, 'UTC');
select makeDateTime64(2283, 11, 11, 23, 59, 59, 999999999, 9, 'UTC'); -- { serverError 407 }
select makeDateTime64(1900, 1, 1, 0, 0, 0, 0, 9, 'UTC');
select makeDateTime64(1899, 12, 31, 23, 59, 59, 999999999, 9, 'UTC');
select makeDateTime64(2299, 12, 31, 23, 59, 59, 99999999, 8, 'UTC');
select makeDateTime64(2299, 12, 31, 23, 59, 59, 999999999, 9, 'UTC'); -- { serverError 407 }
select makeDateTime64(2262, 4, 11, 23, 47, 16, 854775807, 9, 'UTC');
select makeDateTime64(2262, 4, 11, 23, 47, 16, 854775808, 9, 'UTC'); -- { serverError 407 }
select makeDateTime64(2262, 4, 11, 23, 47, 16, 85477581, 8, 'UTC');

View File

@ -1,63 +1,63 @@
1
1979-12-12 21:21:21.127 3.7 0
2283-11-11 23:37:36.788 1.1 0
2283-11-11 23:37:36.789 2.34 0
2299-12-31 23:37:36.788 1.1 0
2299-12-31 23:37:36.789 2.34 0
1979-12-12 21:21:21.129 2.1 0
1979-12-12 21:21:22.000 1.3345 0
1979-12-12 21:21:23.000 1.54 0.20550000000000002
1979-12-12 21:21:23.000 1.54 0
1979-12-12 21:21:21.127 3.7 0
2283-11-11 23:37:36.788 1.1 0
2283-11-11 23:37:36.789 2.34 0
2299-12-31 23:37:36.788 1.1 0
2299-12-31 23:37:36.789 2.34 0
1979-12-12 21:21:21.129 2.1 0
1979-12-12 21:21:22.000 1.3345 0
1979-12-12 21:21:23.000 1.54 6.165000000000001e-10
1979-12-12 21:21:23.000 1.54 0
1979-12-12 21:21:21.127 3.7 0
2283-11-11 23:37:36.788 1.1 0
2283-11-11 23:37:36.789 2.34 0
2299-12-31 23:37:36.788 1.1 0
2299-12-31 23:37:36.789 2.34 0
1979-12-12 21:21:21.129 2.1 0
1979-12-12 21:21:22.000 1.3345 0
1979-12-12 21:21:23.000 1.54 8.22e-7
1979-12-12 21:21:23.000 1.54 0
1979-12-12 21:21:21.127 3.7 0
2283-11-11 23:37:36.788 1.1 0
2283-11-11 23:37:36.789 2.34 0
2299-12-31 23:37:36.788 1.1 0
2299-12-31 23:37:36.789 2.34 0
1979-12-12 21:21:21.129 2.1 0
1979-12-12 21:21:22.000 1.3345 0
1979-12-12 21:21:23.000 1.54 0.0010275000000000002
1979-12-12 21:21:23.000 1.54 0
1979-12-12 21:21:21.127 3.7 0
2283-11-11 23:37:36.788 1.1 0
2283-11-11 23:37:36.789 2.34 0
2299-12-31 23:37:36.788 1.1 0
2299-12-31 23:37:36.789 2.34 0
1979-12-12 21:21:21.129 2.1 0
1979-12-12 21:21:22.000 1.3345 0
1979-12-12 21:21:23.000 1.54 1.233
1979-12-12 21:21:23.000 1.54 0
1979-12-12 21:21:21.127 3.7 0
2283-11-11 23:37:36.788 1.1 0
2283-11-11 23:37:36.789 2.34 0
2299-12-31 23:37:36.788 1.1 0
2299-12-31 23:37:36.789 2.34 0
1979-12-12 21:21:21.129 2.1 0
1979-12-12 21:21:22.000 1.3345 0
1979-12-12 21:21:23.000 1.54 86.31
1979-12-12 21:21:23.000 1.54 0
1979-12-12 21:21:21.127 3.7 0
2283-11-11 23:37:36.788 1.1 0
2283-11-11 23:37:36.789 2.34 0
2299-12-31 23:37:36.788 1.1 0
2299-12-31 23:37:36.789 2.34 0
1979-12-12 21:21:21.129 2.1 0
1979-12-12 21:21:22.000 1.3345 0
1979-12-12 21:21:23.000 1.54 5918.400000000001
1979-12-12 21:21:23.000 1.54 0
1979-12-12 21:21:21.127 3.7 0
2283-11-11 23:37:36.788 1.1 0
2283-11-11 23:37:36.789 2.34 0
2299-12-31 23:37:36.788 1.1 0
2299-12-31 23:37:36.789 2.34 0
1979-12-12 21:21:21.129 2.1 0
1979-12-12 21:21:22.000 1.3345 0
1979-12-12 21:21:23.000 1.54 159796.80000000002
1979-12-12 21:21:23.000 1.54 0
1979-12-12 21:21:21.127 3.7 0
2283-11-11 23:37:36.788 1.1 0
2283-11-11 23:37:36.789 2.34 0
2299-12-31 23:37:36.788 1.1 0
2299-12-31 23:37:36.789 2.34 0
1979-12-12 21:21:21.129 2.1 0
1979-12-12 21:21:22.000 1.3345 0
1979-12-12 21:21:23.000 1.54 1242864