diff --git a/cpp/src/gandiva/function_registry_common.h b/cpp/src/gandiva/function_registry_common.h index abe861e3385e..8471de2d5a28 100644 --- a/cpp/src/gandiva/function_registry_common.h +++ b/cpp/src/gandiva/function_registry_common.h @@ -55,6 +55,8 @@ inline DataTypePtr time32() { return arrow::time32(arrow::TimeUnit::MILLI); } inline DataTypePtr time64() { return arrow::time64(arrow::TimeUnit::MICRO); } inline DataTypePtr timestamp() { return arrow::timestamp(arrow::TimeUnit::MILLI); } +inline DataTypePtr timestamp_micro() { return arrow::timestamp(arrow::TimeUnit::MICRO); } +inline DataTypePtr timestamp_nano() { return arrow::timestamp(arrow::TimeUnit::NANO); } inline DataTypePtr decimal128() { return arrow::decimal128(38, 0); } struct KeyHash { diff --git a/cpp/src/gandiva/function_registry_timestamp_arithmetic.cc b/cpp/src/gandiva/function_registry_timestamp_arithmetic.cc index 188bd60d9eac..403bb2f3cfad 100644 --- a/cpp/src/gandiva/function_registry_timestamp_arithmetic.cc +++ b/cpp/src/gandiva/function_registry_timestamp_arithmetic.cc @@ -50,6 +50,33 @@ namespace gandiva { BINARY_GENERIC_SAFE_NULL_IF_NULL(name, ALIASES, date64, int64, date64), \ BINARY_GENERIC_SAFE_NULL_IF_NULL(name, ALIASES, timestamp, int64, timestamp) +// Macro to register timestamp arithmetic functions for specific precision types +// NAME: base function name (e.g., timestampaddDay) +// PRECISION_SUFFIX: suffix for precision (e.g., micro, nano) +// TS_TYPE_FN: timestamp type function (e.g., timestamp_micro) +#define TIMESTAMP_ADD_PRECISION_FNS(NAME, PRECISION_SUFFIX, TS_TYPE_FN) \ + NativeFunction(#NAME, {}, DataTypeVector{int32(), TS_TYPE_FN()}, TS_TYPE_FN(), \ + kResultNullIfNull, \ + ARROW_STRINGIFY(NAME##_##PRECISION_SUFFIX##_int32_timestamp)), \ + NativeFunction(#NAME, {}, DataTypeVector{TS_TYPE_FN(), int32()}, TS_TYPE_FN(), \ + kResultNullIfNull, \ + ARROW_STRINGIFY(NAME##_##PRECISION_SUFFIX##_timestamp_int32)), \ + NativeFunction(#NAME, {}, DataTypeVector{int64(), TS_TYPE_FN()}, TS_TYPE_FN(), \ + kResultNullIfNull, \ + ARROW_STRINGIFY(NAME##_##PRECISION_SUFFIX##_int64_timestamp)), \ + NativeFunction(#NAME, {}, DataTypeVector{TS_TYPE_FN(), int64()}, TS_TYPE_FN(), \ + kResultNullIfNull, \ + ARROW_STRINGIFY(NAME##_##PRECISION_SUFFIX##_timestamp_int64)) + +// Macro to register timestampdiff functions for specific precision types +// NAME: base function name (e.g., timestampdiffDay) +// PRECISION_SUFFIX: suffix for precision (e.g., micro, nano) +// TS_TYPE_FN: timestamp type function (e.g., timestamp_micro) +#define TIMESTAMP_DIFF_PRECISION_FN(NAME, PRECISION_SUFFIX, TS_TYPE_FN) \ + NativeFunction(#NAME, {}, DataTypeVector{TS_TYPE_FN(), TS_TYPE_FN()}, int32(), \ + kResultNullIfNull, \ + ARROW_STRINGIFY(NAME##_##PRECISION_SUFFIX##_timestamp_timestamp)) + std::vector GetDateTimeArithmeticFunctionRegistry() { static std::vector datetime_fn_registry_ = { BINARY_GENERIC_SAFE_NULL_IF_NULL(months_between, {}, date64, date64, float64), @@ -57,30 +84,41 @@ std::vector GetDateTimeArithmeticFunctionRegistry() { TIMESTAMP_DIFF_FN(timestampdiffSecond, {}), TIMESTAMP_DIFF_FN(timestampdiffMinute, {}), - TIMESTAMP_DIFF_FN(timestampdiffHour, {}), - TIMESTAMP_DIFF_FN(timestampdiffDay, {}), - TIMESTAMP_DIFF_FN(timestampdiffWeek, {}), - TIMESTAMP_DIFF_FN(timestampdiffMonth, {}), + TIMESTAMP_DIFF_FN(timestampdiffHour, {}), TIMESTAMP_DIFF_FN(timestampdiffDay, {}), + TIMESTAMP_DIFF_FN(timestampdiffWeek, {}), TIMESTAMP_DIFF_FN(timestampdiffMonth, {}), TIMESTAMP_DIFF_FN(timestampdiffQuarter, {}), TIMESTAMP_DIFF_FN(timestampdiffYear, {}), + // timestampdiff for microsecond timestamps + TIMESTAMP_DIFF_PRECISION_FN(timestampdiffSecond, micro, timestamp_micro), + TIMESTAMP_DIFF_PRECISION_FN(timestampdiffMinute, micro, timestamp_micro), + TIMESTAMP_DIFF_PRECISION_FN(timestampdiffHour, micro, timestamp_micro), + TIMESTAMP_DIFF_PRECISION_FN(timestampdiffDay, micro, timestamp_micro), + TIMESTAMP_DIFF_PRECISION_FN(timestampdiffWeek, micro, timestamp_micro), + + // timestampdiff for nanosecond timestamps + TIMESTAMP_DIFF_PRECISION_FN(timestampdiffSecond, nano, timestamp_nano), + TIMESTAMP_DIFF_PRECISION_FN(timestampdiffMinute, nano, timestamp_nano), + TIMESTAMP_DIFF_PRECISION_FN(timestampdiffHour, nano, timestamp_nano), + TIMESTAMP_DIFF_PRECISION_FN(timestampdiffDay, nano, timestamp_nano), + TIMESTAMP_DIFF_PRECISION_FN(timestampdiffWeek, nano, timestamp_nano), + TIMESTAMP_ADD_FNS(timestampaddSecond, {}), - TIMESTAMP_ADD_FNS(timestampaddMinute, {}), - TIMESTAMP_ADD_FNS(timestampaddHour, {}), + TIMESTAMP_ADD_FNS(timestampaddMinute, {}), TIMESTAMP_ADD_FNS(timestampaddHour, {}), TIMESTAMP_ADD_FNS(timestampaddDay, {}), + TIMESTAMP_ADD_PRECISION_FNS(timestampaddDay, micro, timestamp_micro), + TIMESTAMP_ADD_PRECISION_FNS(timestampaddDay, nano, timestamp_nano), + TIMESTAMP_ADD_FNS(timestampaddWeek, {}), TIMESTAMP_ADD_FNS(timestampaddMonth, {"add_months"}), - TIMESTAMP_ADD_FNS(timestampaddQuarter, {}), - TIMESTAMP_ADD_FNS(timestampaddYear, {}), + TIMESTAMP_ADD_FNS(timestampaddQuarter, {}), TIMESTAMP_ADD_FNS(timestampaddYear, {}), - DATE_ADD_FNS(date_add, {}), - DATE_ADD_FNS(add, {}), + DATE_ADD_FNS(date_add, {}), DATE_ADD_FNS(add, {}), NativeFunction("add", {}, DataTypeVector{date64(), int64()}, timestamp(), kResultNullIfNull, "add_date64_int64"), - DATE_DIFF_FNS(date_sub, {}), - DATE_DIFF_FNS(subtract, {}), + DATE_DIFF_FNS(date_sub, {}), DATE_DIFF_FNS(subtract, {}), DATE_DIFF_FNS(date_diff, {})}; return datetime_fn_registry_; diff --git a/cpp/src/gandiva/precompiled/testing.h b/cpp/src/gandiva/precompiled/testing.h index c41bc5471483..867beda0a6e7 100644 --- a/cpp/src/gandiva/precompiled/testing.h +++ b/cpp/src/gandiva/precompiled/testing.h @@ -40,4 +40,17 @@ static inline gdv_timestamp StringToTimestamp(const std::string& s) { return out * 1000; } +// Parse timestamp with optional fractional seconds, returning value in the specified +// unit. Supports formats like "YYYY-MM-DD HH:MM:SS" or "YYYY-MM-DD HH:MM:SS.sssssssss" +// where fractional seconds can have 1-9 digits depending on the time unit. +static inline gdv_timestamp StringToTimestampWithUnit(const std::string& s, + ::arrow::TimeUnit::type unit) { + int64_t out = 0; + bool success = ::arrow::internal::ParseTimestampISO8601( + s.c_str(), s.length(), unit, &out, /*out_zone_offset_present=*/nullptr); + DCHECK(success); + ARROW_UNUSED(success); + return out; +} + } // namespace gandiva diff --git a/cpp/src/gandiva/precompiled/time_constants.h b/cpp/src/gandiva/precompiled/time_constants.h index 015ef4bf9f7d..7ee14a5c0cb5 100644 --- a/cpp/src/gandiva/precompiled/time_constants.h +++ b/cpp/src/gandiva/precompiled/time_constants.h @@ -17,7 +17,7 @@ #pragma once -#define MILLIS_IN_SEC (1000) +#define MILLIS_IN_SEC (1000LL) #define MILLIS_IN_MIN (60 * MILLIS_IN_SEC) #define MILLIS_IN_HOUR (60 * MILLIS_IN_MIN) #define MILLIS_IN_DAY (24 * MILLIS_IN_HOUR) @@ -28,3 +28,30 @@ #define MILLIS_TO_HOUR(millis) ((millis) / MILLIS_IN_HOUR) #define MILLIS_TO_DAY(millis) ((millis) / MILLIS_IN_DAY) #define MILLIS_TO_WEEK(millis) ((millis) / MILLIS_IN_WEEK) + +#define MICROS_IN_MILLIS (1000LL) +#define MICROS_IN_SEC (MICROS_IN_MILLIS * MILLIS_IN_SEC) +#define MICROS_IN_MIN (MICROS_IN_MILLIS * MILLIS_IN_MIN) +#define MICROS_IN_HOUR (MICROS_IN_MILLIS * MILLIS_IN_HOUR) +#define MICROS_IN_DAY (MICROS_IN_MILLIS * MILLIS_IN_DAY) +#define MICROS_IN_WEEK (MICROS_IN_MILLIS * MILLIS_IN_WEEK) + +#define MICROS_TO_SEC(micros) ((micros) / MICROS_IN_SEC) +#define MICROS_TO_MINS(micros) ((micros) / MICROS_IN_MIN) +#define MICROS_TO_HOUR(micros) ((micros) / MICROS_IN_HOUR) +#define MICROS_TO_DAY(micros) ((micros) / MICROS_IN_DAY) +#define MICROS_TO_WEEK(micros) ((micros) / MICROS_IN_WEEK) + +#define NANOS_IN_MICROS (1000LL) +#define NANOS_IN_MILLIS (NANOS_IN_MICROS * MICROS_IN_MILLIS) +#define NANOS_IN_SEC (NANOS_IN_MICROS * MICROS_IN_SEC) +#define NANOS_IN_MIN (NANOS_IN_MICROS * MICROS_IN_MIN) +#define NANOS_IN_HOUR (NANOS_IN_MICROS * MICROS_IN_HOUR) +#define NANOS_IN_DAY (NANOS_IN_MICROS * MICROS_IN_DAY) +#define NANOS_IN_WEEK (NANOS_IN_MICROS * MICROS_IN_WEEK) + +#define NANOS_TO_SEC(nanos) ((nanos) / NANOS_IN_SEC) +#define NANOS_TO_MINS(nanos) ((nanos) / NANOS_IN_MIN) +#define NANOS_TO_HOUR(nanos) ((nanos) / NANOS_IN_HOUR) +#define NANOS_TO_DAY(nanos) ((nanos) / NANOS_IN_DAY) +#define NANOS_TO_WEEK(nanos) ((nanos) / NANOS_IN_WEEK) diff --git a/cpp/src/gandiva/precompiled/time_test.cc b/cpp/src/gandiva/precompiled/time_test.cc index bdaf3dc2a5fa..d8e2b8e9a866 100644 --- a/cpp/src/gandiva/precompiled/time_test.cc +++ b/cpp/src/gandiva/precompiled/time_test.cc @@ -499,6 +499,112 @@ TEST(TestTime, TimeStampAdd) { StringToTimestamp("1999-03-01 00:00:00")); } +TEST(TestTime, TimeStampAddMicroNano) { + // Test timestampaddDay for microsecond timestamps using StringToTimestampWithUnit + gdv_timestamp ts_micro = + StringToTimestampWithUnit("2000-05-01 10:20:34", arrow::TimeUnit::MICRO); + gdv_timestamp expected_micro = + StringToTimestampWithUnit("2000-05-06 10:20:34", arrow::TimeUnit::MICRO); + + EXPECT_EQ(timestampaddDay_micro_int32_timestamp(5, ts_micro), expected_micro); + EXPECT_EQ(timestampaddDay_micro_timestamp_int32(ts_micro, 5), expected_micro); + EXPECT_EQ(timestampaddDay_micro_int64_timestamp(5, ts_micro), expected_micro); + EXPECT_EQ(timestampaddDay_micro_timestamp_int64(ts_micro, 5), expected_micro); + + // Test negative days + expected_micro = + StringToTimestampWithUnit("2000-04-26 10:20:34", arrow::TimeUnit::MICRO); + EXPECT_EQ(timestampaddDay_micro_int32_timestamp(-5, ts_micro), expected_micro); + EXPECT_EQ(timestampaddDay_micro_timestamp_int32(ts_micro, -5), expected_micro); + + // Test timestampaddDay for nanosecond timestamps using StringToTimestampWithUnit + gdv_timestamp ts_nano = + StringToTimestampWithUnit("2000-05-01 10:20:34", arrow::TimeUnit::NANO); + gdv_timestamp expected_nano = + StringToTimestampWithUnit("2000-05-06 10:20:34", arrow::TimeUnit::NANO); + + EXPECT_EQ(timestampaddDay_nano_int32_timestamp(5, ts_nano), expected_nano); + EXPECT_EQ(timestampaddDay_nano_timestamp_int32(ts_nano, 5), expected_nano); + EXPECT_EQ(timestampaddDay_nano_int64_timestamp(5, ts_nano), expected_nano); + EXPECT_EQ(timestampaddDay_nano_timestamp_int64(ts_nano, 5), expected_nano); + + // Test negative days + expected_nano = StringToTimestampWithUnit("2000-04-26 10:20:34", arrow::TimeUnit::NANO); + EXPECT_EQ(timestampaddDay_nano_int32_timestamp(-5, ts_nano), expected_nano); + EXPECT_EQ(timestampaddDay_nano_timestamp_int32(ts_nano, -5), expected_nano); + + // Test that sub-second precision is preserved using fractional seconds + // Parse timestamp with 500 microseconds + ts_micro = + StringToTimestampWithUnit("2000-05-01 10:20:34.000500", arrow::TimeUnit::MICRO); + expected_micro = + StringToTimestampWithUnit("2000-05-02 10:20:34.000500", arrow::TimeUnit::MICRO); + EXPECT_EQ(timestampaddDay_micro_int32_timestamp(1, ts_micro), expected_micro); + + // Parse timestamp with 500 nanoseconds + ts_nano = + StringToTimestampWithUnit("2000-05-01 10:20:34.000000500", arrow::TimeUnit::NANO); + expected_nano = + StringToTimestampWithUnit("2000-05-02 10:20:34.000000500", arrow::TimeUnit::NANO); + EXPECT_EQ(timestampaddDay_nano_int32_timestamp(1, ts_nano), expected_nano); + + // Test with milliseconds too + gdv_timestamp ts_milli = + StringToTimestampWithUnit("2000-05-01 10:20:34.123", arrow::TimeUnit::MILLI); + gdv_timestamp expected_milli = + StringToTimestampWithUnit("2000-05-02 10:20:34.123", arrow::TimeUnit::MILLI); + EXPECT_EQ(timestampaddDay_int32_timestamp(1, ts_milli), expected_milli); +} + +TEST(TestTime, TimeStampDiffMicroNano) { + // Test timestampdiff for microsecond timestamps + gdv_timestamp start_micro = + StringToTimestampWithUnit("2000-05-01 10:20:34", arrow::TimeUnit::MICRO); + gdv_timestamp end_micro = + StringToTimestampWithUnit("2000-05-06 12:25:40", arrow::TimeUnit::MICRO); + + // Difference: 5 days, 2 hours, 5 minutes, 6 seconds + EXPECT_EQ(timestampdiffDay_micro_timestamp_timestamp(start_micro, end_micro), 5); + EXPECT_EQ(timestampdiffHour_micro_timestamp_timestamp(start_micro, end_micro), 122); + EXPECT_EQ(timestampdiffMinute_micro_timestamp_timestamp(start_micro, end_micro), 7325); + EXPECT_EQ(timestampdiffSecond_micro_timestamp_timestamp(start_micro, end_micro), + 439506); + EXPECT_EQ(timestampdiffWeek_micro_timestamp_timestamp(start_micro, end_micro), 0); + + // Test negative difference + EXPECT_EQ(timestampdiffDay_micro_timestamp_timestamp(end_micro, start_micro), -5); + + // Test timestampdiff for nanosecond timestamps + gdv_timestamp start_nano = + StringToTimestampWithUnit("2000-05-01 10:20:34", arrow::TimeUnit::NANO); + gdv_timestamp end_nano = + StringToTimestampWithUnit("2000-05-06 12:25:40", arrow::TimeUnit::NANO); + + EXPECT_EQ(timestampdiffDay_nano_timestamp_timestamp(start_nano, end_nano), 5); + EXPECT_EQ(timestampdiffHour_nano_timestamp_timestamp(start_nano, end_nano), 122); + EXPECT_EQ(timestampdiffMinute_nano_timestamp_timestamp(start_nano, end_nano), 7325); + EXPECT_EQ(timestampdiffSecond_nano_timestamp_timestamp(start_nano, end_nano), 439506); + EXPECT_EQ(timestampdiffWeek_nano_timestamp_timestamp(start_nano, end_nano), 0); + + // Test negative difference + EXPECT_EQ(timestampdiffDay_nano_timestamp_timestamp(end_nano, start_nano), -5); + + // Test week difference with larger gap + gdv_timestamp start_week_micro = + StringToTimestampWithUnit("2000-05-01 00:00:00", arrow::TimeUnit::MICRO); + gdv_timestamp end_week_micro = + StringToTimestampWithUnit("2000-05-22 00:00:00", arrow::TimeUnit::MICRO); + EXPECT_EQ(timestampdiffWeek_micro_timestamp_timestamp(start_week_micro, end_week_micro), + 3); + + gdv_timestamp start_week_nano = + StringToTimestampWithUnit("2000-05-01 00:00:00", arrow::TimeUnit::NANO); + gdv_timestamp end_week_nano = + StringToTimestampWithUnit("2000-05-22 00:00:00", arrow::TimeUnit::NANO); + EXPECT_EQ(timestampdiffWeek_nano_timestamp_timestamp(start_week_nano, end_week_nano), + 3); +} + // test cases from http://www.staff.science.uu.nl/~gent0113/calendar/isocalendar.htm TEST(TestTime, TestExtractWeek) { std::vector data; diff --git a/cpp/src/gandiva/precompiled/timestamp_arithmetic.cc b/cpp/src/gandiva/precompiled/timestamp_arithmetic.cc index 695605b3cc77..fee1679ba637 100644 --- a/cpp/src/gandiva/precompiled/timestamp_arithmetic.cc +++ b/cpp/src/gandiva/precompiled/timestamp_arithmetic.cc @@ -138,6 +138,20 @@ extern "C" { TIMESTAMP_DIFF(timestamp) +// timestampdiff for microsecond timestamps +TIMESTAMP_DIFF_FIXED_UNITS(timestamp, timestampdiffSecond_micro, MICROS_TO_SEC) +TIMESTAMP_DIFF_FIXED_UNITS(timestamp, timestampdiffMinute_micro, MICROS_TO_MINS) +TIMESTAMP_DIFF_FIXED_UNITS(timestamp, timestampdiffHour_micro, MICROS_TO_HOUR) +TIMESTAMP_DIFF_FIXED_UNITS(timestamp, timestampdiffDay_micro, MICROS_TO_DAY) +TIMESTAMP_DIFF_FIXED_UNITS(timestamp, timestampdiffWeek_micro, MICROS_TO_WEEK) + +// timestampdiff for nanosecond timestamps +TIMESTAMP_DIFF_FIXED_UNITS(timestamp, timestampdiffSecond_nano, NANOS_TO_SEC) +TIMESTAMP_DIFF_FIXED_UNITS(timestamp, timestampdiffMinute_nano, NANOS_TO_MINS) +TIMESTAMP_DIFF_FIXED_UNITS(timestamp, timestampdiffHour_nano, NANOS_TO_HOUR) +TIMESTAMP_DIFF_FIXED_UNITS(timestamp, timestampdiffDay_nano, NANOS_TO_DAY) +TIMESTAMP_DIFF_FIXED_UNITS(timestamp, timestampdiffWeek_nano, NANOS_TO_WEEK) + #define ADD_INT32_TO_TIMESTAMP_FIXED_UNITS(TYPE, NAME, TO_MILLIS) \ FORCE_INLINE \ gdv_##TYPE NAME##_int32_##TYPE(gdv_int32 count, gdv_##TYPE millis) { \ @@ -240,6 +254,14 @@ TIMESTAMP_DIFF(timestamp) TIMESTAMP_ADD_INT(date64) TIMESTAMP_ADD_INT(timestamp) +// timestampaddDay for microsecond timestamps +ADD_TIMESTAMP_INT32_FIXEDUNITS(timestamp, timestampaddDay_micro, MICROS_IN_DAY) +ADD_TIMESTAMP_INT64_FIXEDUNITS(timestamp, timestampaddDay_micro, MICROS_IN_DAY) + +// timestampaddDay for nanosecond timestamps +ADD_TIMESTAMP_INT32_FIXEDUNITS(timestamp, timestampaddDay_nano, NANOS_IN_DAY) +ADD_TIMESTAMP_INT64_FIXEDUNITS(timestamp, timestampaddDay_nano, NANOS_IN_DAY) + // add gdv_int32 to timestamp ADD_INT32_TO_TIMESTAMP_FIXED_UNITS(date64, date_add, MILLIS_IN_DAY) ADD_INT32_TO_TIMESTAMP_FIXED_UNITS(date64, add, MILLIS_IN_DAY) diff --git a/cpp/src/gandiva/precompiled/types.h b/cpp/src/gandiva/precompiled/types.h index c93b694fc777..3542d73343d0 100644 --- a/cpp/src/gandiva/precompiled/types.h +++ b/cpp/src/gandiva/precompiled/types.h @@ -114,6 +114,32 @@ gdv_int64 timestampaddMonth_timestamp_int64(gdv_timestamp, gdv_int64); gdv_int64 timestampaddQuarter_timestamp_int64(gdv_timestamp, gdv_int64); gdv_int64 timestampaddYear_timestamp_int64(gdv_timestamp, gdv_int64); +// timestampaddDay for microsecond timestamps +gdv_int64 timestampaddDay_micro_int32_timestamp(gdv_int32, gdv_timestamp); +gdv_int64 timestampaddDay_micro_timestamp_int32(gdv_timestamp, gdv_int32); +gdv_int64 timestampaddDay_micro_int64_timestamp(gdv_int64, gdv_timestamp); +gdv_int64 timestampaddDay_micro_timestamp_int64(gdv_timestamp, gdv_int64); + +// timestampaddDay for nanosecond timestamps +gdv_int64 timestampaddDay_nano_int32_timestamp(gdv_int32, gdv_timestamp); +gdv_int64 timestampaddDay_nano_timestamp_int32(gdv_timestamp, gdv_int32); +gdv_int64 timestampaddDay_nano_int64_timestamp(gdv_int64, gdv_timestamp); +gdv_int64 timestampaddDay_nano_timestamp_int64(gdv_timestamp, gdv_int64); + +// timestampdiff for microsecond timestamps +gdv_int32 timestampdiffSecond_micro_timestamp_timestamp(gdv_timestamp, gdv_timestamp); +gdv_int32 timestampdiffMinute_micro_timestamp_timestamp(gdv_timestamp, gdv_timestamp); +gdv_int32 timestampdiffHour_micro_timestamp_timestamp(gdv_timestamp, gdv_timestamp); +gdv_int32 timestampdiffDay_micro_timestamp_timestamp(gdv_timestamp, gdv_timestamp); +gdv_int32 timestampdiffWeek_micro_timestamp_timestamp(gdv_timestamp, gdv_timestamp); + +// timestampdiff for nanosecond timestamps +gdv_int32 timestampdiffSecond_nano_timestamp_timestamp(gdv_timestamp, gdv_timestamp); +gdv_int32 timestampdiffMinute_nano_timestamp_timestamp(gdv_timestamp, gdv_timestamp); +gdv_int32 timestampdiffHour_nano_timestamp_timestamp(gdv_timestamp, gdv_timestamp); +gdv_int32 timestampdiffDay_nano_timestamp_timestamp(gdv_timestamp, gdv_timestamp); +gdv_int32 timestampdiffWeek_nano_timestamp_timestamp(gdv_timestamp, gdv_timestamp); + gdv_boolean isnull_day_time_interval(gdv_day_time_interval in, gdv_boolean is_valid); gdv_boolean istrue_boolean(gdv_boolean in, gdv_boolean isvalid);