Skip to content

Commit f1a7b0d

Browse files
jpedroantunesanthonylouisbsb
authored andcommitted
ARROW-12205: [C++][Gandiva] Implement TO_TIME([number] seconds) and TO_TIMESTAMP([number] seconds) function
ImpleImplement TO_TIME([number] seconds) and TO_TIMESTAMP([number] seconds) function Closes apache#9890 from jpedroantunes/feature/to-timestamp-function and squashes the following commits: 315a6db <Anthony Louis> Change return type of to_time functions 31fdbd2 <João Pedro> Correct values used on to time test ec3919f <João Pedro Antunes Ferreira> Correct comments on to_time test 7421142 <João Pedro> Apply corrections on to time tests to try to handle floating points 0df0a3b <João Pedro> Define input timestamp comments 805a2d9 <João Pedro> Apply corrections on to time tests to handle floating points 93f8ec5 <João Pedro> Correct dev lint options 4999fd5 <João Pedro> Correct dev lint options f117af6 <João Pedro> Add necessary static casts on tests a6a396e <João Pedro> Add case tests for to_timestamp with fractional parts de64aae <João Pedro> Add case tests for to_timestamp with fractional parts de93dc2 <João Pedro> Fix to time implementation to get the time of the day b44aea0 <João Pedro> Fix local lint errors 2013d44 <João Pedro> Fix to time function to consider seconds as input 3af0718 <João Pedro> Change to time implementation to handle secs and not millis b5c6ca1 <João Pedro> Fix lint problems on time.cc file f904a3b <João Pedro> Fix tests for timestamp and time to not need casting f090220 <João Pedro> Add tests for to timestamp function bf81503 <João Pedro> Add to_time definition for numeric types d9119ee <João Pedro> Change definition of to_timestamp function to work for numeric types 33230ca <João Pedro> Remove unused function on time.cc b41c3c2 <João Pedro> Add function registry for to_timestamp method b5a80ed <João Pedro> Add unit tests for to_timestamp method d26179e <João Pedro> Add base declaration for to_timestamp for numeric in gandiva types.h d19f3f6 <João Pedro> Add base implementation for to_timestamp for numeric in gandiva Lead-authored-by: João Pedro <joaop@simbioseventures.com> Co-authored-by: João Pedro Antunes Ferreira <42006402+jpedroantunes@users.noreply.github.com> Co-authored-by: Anthony Louis <anthony@simbioseventures.com> Signed-off-by: Praveen <praveen@dremio.com>
1 parent 3e3ab3b commit f1a7b0d

6 files changed

Lines changed: 161 additions & 9 deletions

File tree

cpp/src/gandiva/function_registry_common.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -229,12 +229,16 @@ typedef std::unordered_map<const FunctionSignature*, const NativeFunction*, KeyH
229229
NativeFunction::kNeedsContext | NativeFunction::kCanReturnErrors)
230230

231231
// Iterate the inner macro over all numeric types
232-
#define NUMERIC_TYPES(INNER, NAME, ALIASES) \
232+
#define BASE_NUMERIC_TYPES(INNER, NAME, ALIASES) \
233233
INNER(NAME, ALIASES, int8), INNER(NAME, ALIASES, int16), INNER(NAME, ALIASES, int32), \
234234
INNER(NAME, ALIASES, int64), INNER(NAME, ALIASES, uint8), \
235235
INNER(NAME, ALIASES, uint16), INNER(NAME, ALIASES, uint32), \
236236
INNER(NAME, ALIASES, uint64), INNER(NAME, ALIASES, float32), \
237-
INNER(NAME, ALIASES, float64), INNER(NAME, ALIASES, decimal128)
237+
INNER(NAME, ALIASES, float64)
238+
239+
// Iterate the inner macro over all base numeric types
240+
#define NUMERIC_TYPES(INNER, NAME, ALIASES) \
241+
BASE_NUMERIC_TYPES(INNER, NAME, ALIASES), INNER(NAME, ALIASES, decimal128)
238242

239243
// Iterate the inner macro over numeric and date/time types
240244
#define NUMERIC_DATE_TYPES(INNER, NAME, ALIASES) \

cpp/src/gandiva/function_registry_datetime.cc

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,14 @@ namespace gandiva {
2929
DATE_TYPES(INNER, name##Hour, {}), DATE_TYPES(INNER, name##Minute, {}), \
3030
DATE_TYPES(INNER, name##Second, {})
3131

32+
#define TO_TIMESTAMP_SAFE_NULL_IF_NULL(NAME, ALIASES, TYPE) \
33+
NativeFunction(#NAME, std::vector<std::string> ALIASES, DataTypeVector{TYPE()}, \
34+
timestamp(), kResultNullIfNull, ARROW_STRINGIFY(NAME##_##TYPE))
35+
36+
#define TO_TIME_SAFE_NULL_IF_NULL(NAME, ALIASES, TYPE) \
37+
NativeFunction(#NAME, std::vector<std::string> ALIASES, DataTypeVector{TYPE()}, \
38+
time32(), kResultNullIfNull, ARROW_STRINGIFY(NAME##_##TYPE))
39+
3240
#define TIME_EXTRACTION_FNS(name) \
3341
TIME_TYPES(EXTRACT_SAFE_NULL_IF_NULL, name##Hour, {}), \
3442
TIME_TYPES(EXTRACT_SAFE_NULL_IF_NULL, name##Minute, {}), \
@@ -86,7 +94,9 @@ std::vector<NativeFunction> GetDateTimeFunctionRegistry() {
8694
NativeFunction("extractDay", {}, DataTypeVector{day_time_interval()}, int64(),
8795
kResultNullIfNull, "extractDay_daytimeinterval"),
8896

89-
DATE_TYPES(LAST_DAY_SAFE_NULL_IF_NULL, last_day, {})};
97+
DATE_TYPES(LAST_DAY_SAFE_NULL_IF_NULL, last_day, {}),
98+
BASE_NUMERIC_TYPES(TO_TIME_SAFE_NULL_IF_NULL, to_time, {}),
99+
BASE_NUMERIC_TYPES(TO_TIMESTAMP_SAFE_NULL_IF_NULL, to_timestamp, {})};
90100

91101
return date_time_fn_registry_;
92102
}

cpp/src/gandiva/precompiled/epoch_time_point.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -87,18 +87,18 @@ class EpochTimePoint {
8787

8888
int64_t MillisSinceEpoch() const { return tp_.time_since_epoch().count(); }
8989

90-
private:
91-
arrow_vendored::date::year_month_day YearMonthDay() const {
92-
return arrow_vendored::date::year_month_day{
93-
arrow_vendored::date::floor<arrow_vendored::date::days>(tp_)}; // NOLINT
94-
}
95-
9690
arrow_vendored::date::time_of_day<std::chrono::milliseconds> TimeOfDay() const {
9791
auto millis_since_midnight =
9892
tp_ - arrow_vendored::date::floor<arrow_vendored::date::days>(tp_);
9993
return arrow_vendored::date::time_of_day<std::chrono::milliseconds>(
10094
millis_since_midnight);
10195
}
10296

97+
private:
98+
arrow_vendored::date::year_month_day YearMonthDay() const {
99+
return arrow_vendored::date::year_month_day{
100+
arrow_vendored::date::floor<arrow_vendored::date::days>(tp_)}; // NOLINT
101+
}
102+
103103
std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds> tp_;
104104
};

cpp/src/gandiva/precompiled/time.cc

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,19 @@ extern "C" {
4040
INNER(date64) \
4141
INNER(timestamp)
4242

43+
// Expand inner macro for all base numeric types.
44+
#define NUMERIC_TYPES(INNER) \
45+
INNER(int8) \
46+
INNER(int16) \
47+
INNER(int32) \
48+
INNER(int64) \
49+
INNER(uint8) \
50+
INNER(uint16) \
51+
INNER(uint32) \
52+
INNER(uint64) \
53+
INNER(float32) \
54+
INNER(float64)
55+
4356
// Extract millennium
4457
#define EXTRACT_MILLENNIUM(TYPE) \
4558
FORCE_INLINE \
@@ -828,4 +841,23 @@ gdv_int64 castBIGINT_daytimeinterval(gdv_day_time_interval in) {
828841
extractDay_daytimeinterval(in) * MILLIS_IN_DAY;
829842
}
830843

844+
// Convert the seconds since epoch argument to timestamp
845+
#define TO_TIMESTAMP(TYPE) \
846+
FORCE_INLINE \
847+
gdv_timestamp to_timestamp##_##TYPE(gdv_##TYPE seconds) { \
848+
return static_cast<gdv_timestamp>(seconds * MILLIS_IN_SEC); \
849+
}
850+
851+
NUMERIC_TYPES(TO_TIMESTAMP)
852+
853+
// Convert the seconds since epoch argument to time
854+
#define TO_TIME(TYPE) \
855+
FORCE_INLINE \
856+
gdv_time32 to_time##_##TYPE(gdv_##TYPE seconds) { \
857+
EpochTimePoint tp(static_cast<int64_t>(seconds * MILLIS_IN_SEC)); \
858+
return static_cast<gdv_time32>(tp.TimeOfDay().to_duration().count()); \
859+
}
860+
861+
NUMERIC_TYPES(TO_TIME)
862+
831863
} // extern "C"

cpp/src/gandiva/precompiled/time_test.cc

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -743,4 +743,100 @@ TEST(TestTime, TestLastDay) {
743743
EXPECT_EQ(StringToTimestamp("2015-12-31 00:00:00"), out);
744744
}
745745

746+
TEST(TestTime, TestToTimestamp) {
747+
auto ts = StringToTimestamp("1970-01-01 00:00:00");
748+
EXPECT_EQ(ts, to_timestamp_int32(0));
749+
EXPECT_EQ(ts, to_timestamp_int64(0));
750+
EXPECT_EQ(ts, to_timestamp_float32(0));
751+
EXPECT_EQ(ts, to_timestamp_float64(0));
752+
753+
ts = StringToTimestamp("1970-01-01 00:00:01");
754+
EXPECT_EQ(ts, to_timestamp_int32(1));
755+
EXPECT_EQ(ts, to_timestamp_int64(1));
756+
EXPECT_EQ(ts, to_timestamp_float32(1));
757+
EXPECT_EQ(ts, to_timestamp_float64(1));
758+
759+
ts = StringToTimestamp("1970-01-01 00:01:00");
760+
EXPECT_EQ(ts, to_timestamp_int32(60));
761+
EXPECT_EQ(ts, to_timestamp_int64(60));
762+
EXPECT_EQ(ts, to_timestamp_float32(60));
763+
EXPECT_EQ(ts, to_timestamp_float64(60));
764+
765+
ts = StringToTimestamp("1970-01-01 01:00:00");
766+
EXPECT_EQ(ts, to_timestamp_int32(3600));
767+
EXPECT_EQ(ts, to_timestamp_int64(3600));
768+
EXPECT_EQ(ts, to_timestamp_float32(3600));
769+
EXPECT_EQ(ts, to_timestamp_float64(3600));
770+
771+
ts = StringToTimestamp("1970-01-02 00:00:00");
772+
EXPECT_EQ(ts, to_timestamp_int32(86400));
773+
EXPECT_EQ(ts, to_timestamp_int64(86400));
774+
EXPECT_EQ(ts, to_timestamp_float32(86400));
775+
EXPECT_EQ(ts, to_timestamp_float64(86400));
776+
777+
// tests with fractional part
778+
ts = StringToTimestamp("1970-01-01 00:00:01") + 500;
779+
EXPECT_EQ(ts, to_timestamp_float32(1.500f));
780+
EXPECT_EQ(ts, to_timestamp_float64(1.500));
781+
782+
ts = StringToTimestamp("1970-01-01 00:01:01") + 600;
783+
EXPECT_EQ(ts, to_timestamp_float32(61.600f));
784+
EXPECT_EQ(ts, to_timestamp_float64(61.600));
785+
786+
ts = StringToTimestamp("1970-01-01 01:00:01") + 400;
787+
EXPECT_EQ(ts, to_timestamp_float32(3601.400f));
788+
EXPECT_EQ(ts, to_timestamp_float64(3601.400));
789+
}
790+
791+
TEST(TestTime, TestToTimeNumeric) {
792+
// input timestamp in seconds: 1970-01-01 00:00:00
793+
int64_t expected_output = 0; // 0 milliseconds
794+
EXPECT_EQ(expected_output, to_time_int32(0));
795+
EXPECT_EQ(expected_output, to_time_int64(0));
796+
EXPECT_EQ(expected_output, to_time_float32(0.000f));
797+
EXPECT_EQ(expected_output, to_time_float64(0.000));
798+
799+
// input timestamp in seconds: 1970-01-01 00:00:01
800+
expected_output = 1000; // 1 seconds
801+
EXPECT_EQ(expected_output, to_time_int32(1));
802+
EXPECT_EQ(expected_output, to_time_int64(1));
803+
EXPECT_EQ(expected_output, to_time_float32(1.000f));
804+
EXPECT_EQ(expected_output, to_time_float64(1.000));
805+
806+
// input timestamp in seconds: 1970-01-01 01:00:00
807+
expected_output = 3600000; // 3600 seconds
808+
EXPECT_EQ(expected_output, to_time_int32(3600));
809+
EXPECT_EQ(expected_output, to_time_int64(3600));
810+
EXPECT_EQ(expected_output, to_time_float32(3600.000f));
811+
EXPECT_EQ(expected_output, to_time_float64(3600.000));
812+
813+
// input timestamp in seconds: 1970-01-01 23:59:59
814+
expected_output = 86399000; // 86399 seconds
815+
EXPECT_EQ(expected_output, to_time_int32(86399));
816+
EXPECT_EQ(expected_output, to_time_int64(86399));
817+
EXPECT_EQ(expected_output, to_time_float32(86399.000f));
818+
EXPECT_EQ(expected_output, to_time_float64(86399.000));
819+
820+
// input timestamp in seconds: 2020-01-01 00:00:01
821+
expected_output = 1000; // 1 second
822+
EXPECT_EQ(expected_output, to_time_int64(1577836801));
823+
EXPECT_EQ(expected_output, to_time_float64(1577836801.000));
824+
825+
// tests with fractional part
826+
// input timestamp in seconds: 1970-01-01 00:00:01.500
827+
expected_output = 1500; // 1.5 seconds
828+
EXPECT_EQ(expected_output, to_time_float32(1.500f));
829+
EXPECT_EQ(expected_output, to_time_float64(1.500));
830+
831+
// input timestamp in seconds: 1970-01-01 00:01:01.500
832+
expected_output = 61500; // 61.5 seconds
833+
EXPECT_EQ(expected_output, to_time_float32(61.500f));
834+
EXPECT_EQ(expected_output, to_time_float64(61.500));
835+
836+
// input timestamp in seconds: 1970-01-01 01:00:01.500
837+
expected_output = 3601500; // 3601.5 seconds
838+
EXPECT_EQ(expected_output, to_time_float32(3601.500f));
839+
EXPECT_EQ(expected_output, to_time_float64(3601.500));
840+
}
841+
746842
} // namespace gandiva

cpp/src/gandiva/precompiled/types.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,16 @@ gdv_int64 add_int32_timestamp(gdv_int32, gdv_timestamp);
100100
gdv_int64 date_add_int64_timestamp(gdv_int64, gdv_timestamp);
101101
gdv_timestamp add_date64_int64(gdv_date64, gdv_int64);
102102

103+
gdv_timestamp to_timestamp_int32(gdv_int32);
104+
gdv_timestamp to_timestamp_int64(gdv_int64);
105+
gdv_timestamp to_timestamp_float32(gdv_float32);
106+
gdv_timestamp to_timestamp_float64(gdv_float64);
107+
108+
gdv_time32 to_time_int32(gdv_int32);
109+
gdv_time32 to_time_int64(gdv_int64);
110+
gdv_time32 to_time_float32(gdv_float32);
111+
gdv_time32 to_time_float64(gdv_float64);
112+
103113
gdv_int64 date_sub_timestamp_int32(gdv_timestamp, gdv_int32);
104114
gdv_int64 subtract_timestamp_int32(gdv_timestamp, gdv_int32);
105115
gdv_int64 date_diff_timestamp_int64(gdv_timestamp, gdv_int64);

0 commit comments

Comments
 (0)