Skip to content

Commit a4244cd

Browse files
authored
Add some Datetime Function (#2458)
### What problem does this PR solve? _Add some Datetime Function such year, month, day, hour, minute, second_ Issue link: (#2033) ### Type of change - [x] New Feature (non-breaking change which adds functionality) - [x] Test cases
1 parent d7a7185 commit a4244cd

23 files changed

+3639
-1511
lines changed

python/test_pysdk/test_select.py

+125-2
Original file line numberDiff line numberDiff line change
@@ -1038,7 +1038,6 @@ def test_select_truncate(self, suffix):
10381038

10391039
res, extra_res = table_obj.output(["trunc(c1, 14)", "trunc(c2, 2)", "trunc(c3, 2)"]).to_df()
10401040
print(res)
1041-
print(res.dtypes)
10421041
pd.testing.assert_frame_equal(res, pd.DataFrame({'(c1 trunc 14)': ("2.12300000000000", "-2.12300000000000", "2.00000000000000", "2.10000000000000"),
10431042
'(c2 trunc 2)': ("2.12", "-2.12", "2.00", "2.10"),
10441043
'(c3 trunc 2)': ("2.12", "-2.12", "2.00", "2.10")
@@ -1062,10 +1061,134 @@ def test_select_reverse(self, suffix):
10621061

10631062
res, extra_res = table_obj.output(["reverse(c1)", "reverse(c2)"]).to_df()
10641063
print(res)
1065-
print(res.dtypes)
10661064
pd.testing.assert_frame_equal(res, pd.DataFrame({'reverse(c1)': ('cba', '321a', 'c', 'nmlkjihgfedcba'),
10671065
'reverse(c2)': ('CBA', '321a', 'C', 'NMLKJIHGFEDCBA')})
10681066
.astype({'reverse(c1)': dtype('str_'), 'reverse(c2)': dtype('str_')}))
10691067

10701068
res = db_obj.drop_table("test_select_reverse" + suffix)
1069+
assert res.error_code == ErrorCode.OK
1070+
1071+
1072+
def test_select_year(self, suffix):
1073+
db_obj = self.infinity_obj.get_database("default_db")
1074+
db_obj.drop_table("test_select_year" + suffix, ConflictType.Ignore)
1075+
table_obj = db_obj.create_table(
1076+
"test_select_year" + suffix, {
1077+
"c1": {"type": "date"},
1078+
"c2": {"type": "datetime"},
1079+
"c3": {"type": "timestamp"}},
1080+
ConflictType.Error)
1081+
table_obj = db_obj.get_table("test_select_year" + suffix)
1082+
table_obj.insert(
1083+
[{"c1": "2024-09-23", "c2": "2022-05-26 21:44:33", "c3":"2024-09-23 20:45:11"}])
1084+
1085+
res, extra_res = table_obj.output(["year(c1)", "year(c2)", "year(c3)"]).to_pl()
1086+
print(res)
1087+
assert res['year(c1)'][0] == 2024, "The value of year(c1) should be 2024"
1088+
assert res['year(c2)'][0] == 2022, "The value of year(c2) should be 2022"
1089+
assert res['year(c3)'][0] == 2024, "The value of year(c3) should be 2024"
1090+
1091+
res = db_obj.drop_table("test_select_year" + suffix)
1092+
assert res.error_code == ErrorCode.OK
1093+
1094+
1095+
def test_select_month(self, suffix):
1096+
db_obj = self.infinity_obj.get_database("default_db")
1097+
db_obj.drop_table("test_select_month" + suffix, ConflictType.Ignore)
1098+
table_obj = db_obj.create_table(
1099+
"test_select_month" + suffix, {
1100+
"c1": {"type": "date"},
1101+
"c2": {"type": "datetime"},
1102+
"c3": {"type": "timestamp"}},
1103+
ConflictType.Error)
1104+
table_obj = db_obj.get_table("test_select_month" + suffix)
1105+
table_obj.insert(
1106+
[{"c1": "2024-09-23", "c2": "2022-05-26 21:44:33", "c3":"2024-09-23 20:45:11"}])
1107+
1108+
res, extra_res = table_obj.output(["month(c1)", "month(c2)", "month(c3)"]).to_pl()
1109+
print(res)
1110+
assert res['month(c1)'][0] == 9, "The value of month(c1) should be 9"
1111+
assert res['month(c2)'][0] == 5, "The value of month(c2) should be 5"
1112+
assert res['month(c3)'][0] == 9, "The value of month(c3) should be 9"
1113+
res = db_obj.drop_table("test_select_month" + suffix)
1114+
assert res.error_code == ErrorCode.OK
1115+
1116+
1117+
def test_select_day(self, suffix):
1118+
db_obj = self.infinity_obj.get_database("default_db")
1119+
db_obj.drop_table("test_select_day" + suffix, ConflictType.Ignore)
1120+
db_obj.create_table("test_select_day" + suffix,
1121+
{"c1": {"type": "date"},
1122+
"c2": {"type": "datetime"},
1123+
"c3": {"type": "timestamp"}}, ConflictType.Error)
1124+
table_obj = db_obj.get_table("test_select_day" + suffix)
1125+
table_obj.insert(
1126+
[{"c1": "2024-09-23", "c2": "2022-05-26 21:44:33", "c3":"2024-09-23 20:45:11"}])
1127+
1128+
res, extra_res = table_obj.output(["day(c1)", "day(c2)", "day(c3)"]).to_pl()
1129+
print(res)
1130+
assert res['day(c1)'][0] == 23, "The value of day(c1) should be 23"
1131+
assert res['day(c2)'][0] == 26, "The value of day(c2) should be 26"
1132+
assert res['day(c3)'][0] == 23, "The value of day(c3) should be 23"
1133+
res = db_obj.drop_table("test_select_day" + suffix)
1134+
assert res.error_code == ErrorCode.OK
1135+
1136+
1137+
def test_select_hour(self, suffix):
1138+
db_obj = self.infinity_obj.get_database("default_db")
1139+
db_obj.drop_table("test_select_hour" + suffix, ConflictType.Ignore)
1140+
db_obj.create_table("test_select_hour" + suffix,
1141+
{"c1": {"type": "time"},
1142+
"c2": {"type": "datetime"},
1143+
"c3": {"type": "timestamp"}}, ConflictType.Error)
1144+
table_obj = db_obj.get_table("test_select_hour" + suffix)
1145+
table_obj.insert(
1146+
[{"c1":"0:0:0", "c2": "2022-05-26 21:44:33", "c3":"2024-09-23 20:45:11"}])
1147+
1148+
res, extra_res = table_obj.output(["hour(c1)" ,"hour(c2)", "hour(c3)"]).to_pl()
1149+
print(res)
1150+
assert res['hour(c1)'][0] == 0, "The value of hour(c1) should be 0"
1151+
assert res['hour(c2)'][0] == 21, "The value of hour(c2) should be 21"
1152+
assert res['hour(c3)'][0] == 20, "The value of hour(c3) should be 20"
1153+
1154+
res = db_obj.drop_table("test_select_hour" + suffix)
1155+
assert res.error_code == ErrorCode.OK
1156+
1157+
def test_select_minute(self, suffix):
1158+
db_obj = self.infinity_obj.get_database("default_db")
1159+
db_obj.drop_table("test_select_minute" + suffix, ConflictType.Ignore)
1160+
db_obj.create_table("test_select_minute" + suffix,
1161+
{"c1": {"type": "time"},
1162+
"c2": {"type": "datetime"},"c3": {"type": "timestamp"}}, ConflictType.Error)
1163+
table_obj = db_obj.get_table("test_select_minute" + suffix)
1164+
table_obj.insert(
1165+
[{"c1":"0:0:0", "c2": "2022-05-26 21:44:33", "c3":"2024-09-23 20:45:11"}])
1166+
1167+
res, extra_res = table_obj.output(["minute(c1)", "minute(c2)", "minute(c3)"]).to_pl()
1168+
print(res)
1169+
assert res['minute(c1)'][0] == 0, "The value of minute(c1) should be 0"
1170+
assert res['minute(c2)'][0] == 44, "The value of minute(c2) should be 44"
1171+
assert res['minute(c3)'][0] == 45, "The value of minute(c3) should be 45"
1172+
1173+
res = db_obj.drop_table("test_select_minute" + suffix)
1174+
assert res.error_code == ErrorCode.OK
1175+
1176+
def test_select_second(self, suffix):
1177+
db_obj = self.infinity_obj.get_database("default_db")
1178+
db_obj.drop_table("test_select_second" + suffix, ConflictType.Ignore)
1179+
db_obj.create_table("test_select_second" + suffix,
1180+
{"c1": {"type": "time"},
1181+
"c2": {"type": "datetime"},
1182+
"c3": {"type": "timestamp"}}, ConflictType.Error)
1183+
table_obj = db_obj.get_table("test_select_second" + suffix)
1184+
table_obj.insert(
1185+
[{"c1":"0:0:0", "c2": "2022-05-26 21:44:33", "c3":"2024-09-23 20:45:11"}])
1186+
1187+
res, extra_res = table_obj.output(["second(c1)", "second(c2)", "second(c3)"]).to_pl()
1188+
print(res)
1189+
assert res['second(c1)'][0] == 0, "The value of second(c1) should be 0"
1190+
assert res['second(c2)'][0] == 33, "The value of second(c2) should be 33"
1191+
assert res['second(c3)'][0] == 11, "The value of second(c3) should be 11"
1192+
1193+
res = db_obj.drop_table("test_select_second" + suffix)
10711194
assert res.error_code == ErrorCode.OK

src/function/builtin_functions.cpp

+14
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,12 @@ import like;
4848
import minus;
4949
import modulo;
5050
import multiply;
51+
import year;
52+
import month;
53+
import day;
54+
import hour;
55+
import minute;
56+
import second;
5157
import not_func;
5258
import or_func;
5359
import plus;
@@ -148,6 +154,14 @@ void BuiltinFunctions::RegisterScalarFunction() {
148154
RegisterRtrimFunction(catalog_ptr_);
149155
RegisterTrimFunction(catalog_ptr_);
150156
RegisterPositionFunction(catalog_ptr_);
157+
158+
// date and time functions
159+
RegisterYearFunction(catalog_ptr_);
160+
RegisterMonthFunction(catalog_ptr_);
161+
RegisterDayFunction(catalog_ptr_);
162+
RegisterHourFunction(catalog_ptr_);
163+
RegisterMinuteFunction(catalog_ptr_);
164+
RegisterSecondFunction(catalog_ptr_);
151165
}
152166

153167
void BuiltinFunctions::RegisterTableFunction() {}

src/function/scalar/day.cpp

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// Copyright(C) 2025 InfiniFlow, Inc. All rights reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
module;
15+
module day;
16+
import stl;
17+
import catalog;
18+
import status;
19+
import logical_type;
20+
import infinity_exception;
21+
import scalar_function;
22+
import scalar_function_set;
23+
import third_party;
24+
import internal_types;
25+
import data_type;
26+
import column_vector;
27+
28+
namespace infinity {
29+
30+
struct DayFunction {
31+
template <typename TA, typename TB>
32+
static inline bool Run(TA left, TB &result) {
33+
Status status = Status::NotSupport("Not implemented");
34+
RecoverableError(status);
35+
return false;
36+
}
37+
38+
};
39+
40+
template <>
41+
inline bool DayFunction::Run(DateT left, BigIntT &result) {
42+
result = DateT::GetDatePart(left, TimeUnit::kDay);
43+
return true;
44+
}
45+
46+
template <>
47+
inline bool DayFunction::Run(DateTimeT left, BigIntT &result) {
48+
result = DateTimeT::GetDateTimePart(left, TimeUnit::kDay);
49+
return true;
50+
}
51+
52+
template <>
53+
inline bool DayFunction::Run(TimestampT left, BigIntT &result) {
54+
result = TimestampT::GetDateTimePart(left, TimeUnit::kDay);
55+
return true;
56+
}
57+
58+
void RegisterDayFunction(const UniquePtr<Catalog> &catalog_ptr) {
59+
String func_name = "day";
60+
61+
SharedPtr<ScalarFunctionSet> function_set_ptr = MakeShared<ScalarFunctionSet>(func_name);
62+
63+
ScalarFunction day_date_function(func_name,
64+
{DataType(LogicalType::kDate)},
65+
{DataType(LogicalType::kBigInt)},
66+
&ScalarFunction::UnaryFunctionWithFailure<DateT, BigIntT, DayFunction>);
67+
function_set_ptr->AddFunction(day_date_function);
68+
69+
ScalarFunction day_datetime_function(func_name,
70+
{DataType(LogicalType::kDateTime)},
71+
{DataType(LogicalType::kBigInt)},
72+
&ScalarFunction::UnaryFunctionWithFailure<DateTimeT, BigIntT, DayFunction>);
73+
function_set_ptr->AddFunction(day_datetime_function);
74+
75+
ScalarFunction day_timestamp_function(func_name,
76+
{DataType(LogicalType::kTimestamp)},
77+
{DataType(LogicalType::kBigInt)},
78+
&ScalarFunction::UnaryFunctionWithFailure<TimestampT, BigIntT, DayFunction>);
79+
function_set_ptr->AddFunction(day_timestamp_function);
80+
81+
Catalog::AddFunctionSet(catalog_ptr.get(), function_set_ptr);
82+
}
83+
84+
} // namespace infinity

src/function/scalar/day.cppm

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright(C) 2025 InfiniFlow, Inc. All rights reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
module;
16+
17+
import stl;
18+
19+
export module day;
20+
21+
namespace infinity {
22+
23+
class Catalog;
24+
25+
export void RegisterDayFunction(const UniquePtr<Catalog> &catalog_ptr);
26+
27+
} // namespace infinity

src/function/scalar/hour.cpp

+85
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// Copyright(C) 2025 InfiniFlow, Inc. All rights reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
module;
15+
module hour;
16+
import stl;
17+
import catalog;
18+
import status;
19+
import logical_type;
20+
import infinity_exception;
21+
import scalar_function;
22+
import scalar_function_set;
23+
import third_party;
24+
import internal_types;
25+
import data_type;
26+
import column_vector;
27+
28+
namespace infinity {
29+
30+
struct HourFunction {
31+
template <typename TA, typename TB>
32+
static inline bool Run(TA left, TB &result) {
33+
Status status = Status::NotSupport("Not implemented");
34+
RecoverableError(status);
35+
return false;
36+
}
37+
38+
};
39+
40+
template <>
41+
inline bool HourFunction::Run(DateTimeT left, BigIntT &result) {
42+
result = DateTimeT::GetDateTimePart(left, TimeUnit::kHour);
43+
return true;
44+
}
45+
46+
template <>
47+
inline bool HourFunction::Run(TimeT left, BigIntT &result) {
48+
result = TimeT::GetTimePart(left, TimeUnit::kHour);
49+
return true;
50+
}
51+
52+
template <>
53+
inline bool HourFunction::Run(TimestampT left, BigIntT &result) {
54+
result = TimestampT::GetDateTimePart(left, TimeUnit::kHour);
55+
return true;
56+
}
57+
58+
void RegisterHourFunction(const UniquePtr<Catalog> &catalog_ptr) {
59+
String func_name = "hour";
60+
61+
SharedPtr<ScalarFunctionSet> function_set_ptr = MakeShared<ScalarFunctionSet>(func_name);
62+
63+
ScalarFunction hour_datetime_function(func_name,
64+
{DataType(LogicalType::kDateTime)},
65+
{DataType(LogicalType::kBigInt)},
66+
&ScalarFunction::UnaryFunctionWithFailure<DateTimeT, BigIntT, HourFunction>);
67+
function_set_ptr->AddFunction(hour_datetime_function);
68+
69+
ScalarFunction hour_time_function(func_name,
70+
{DataType(LogicalType::kTime)},
71+
{DataType(LogicalType::kBigInt)},
72+
&ScalarFunction::UnaryFunctionWithFailure<TimeT, BigIntT, HourFunction>);
73+
function_set_ptr->AddFunction(hour_time_function);
74+
75+
ScalarFunction hour_timestamp_function(func_name,
76+
{DataType(LogicalType::kTimestamp)},
77+
{DataType(LogicalType::kBigInt)},
78+
&ScalarFunction::UnaryFunctionWithFailure<TimestampT, BigIntT, HourFunction>);
79+
function_set_ptr->AddFunction(hour_timestamp_function);
80+
81+
82+
Catalog::AddFunctionSet(catalog_ptr.get(), function_set_ptr);
83+
}
84+
85+
} // namespace infinity

0 commit comments

Comments
 (0)