Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions velox/functions/prestosql/DateTimeFunctions.h
Original file line number Diff line number Diff line change
Expand Up @@ -1902,6 +1902,38 @@ struct AtTimezoneFunction : public TimestampWithTimezoneSupport<T> {
}
};

template <typename T>
struct AtTimezoneTimeFunction : public TimestampWithTimezoneSupport<T> {
VELOX_DEFINE_FUNCTION_TYPES(T);

std::optional<int64_t> targetTimezoneID_;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This need only be an int16_t type..


FOLLY_ALWAYS_INLINE void initialize(
const std::vector<TypePtr>& /*inputTypes*/,
const core::QueryConfig& config,
const arg_type<TimeWithTimezone>* /*timeWithTz*/,
const arg_type<Varchar>* timezone) {
if (timezone) {
targetTimezoneID_ = tz::getTimeZoneID(
std::string_view(timezone->data(), timezone->size()));
}
}

FOLLY_ALWAYS_INLINE void call(
out_type<TimeWithTimezone>& result,
const arg_type<TimeWithTimezone>& timeWithTz,
const arg_type<Varchar>& timezone) {
const auto inputMs = unpackMillisUtc(*timeWithTz);
const auto targetTimezoneID = targetTimezoneID_.has_value()
? targetTimezoneID_.value()
: tz::getTimeZoneID(std::string_view(timezone.data(), timezone.size()));

// Similar to timestamp version - only timezone ID changes, not the time
// value.
result = pack(inputMs, targetTimezoneID);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you need to call the time equivalent of time with timezone else you will create invalid time types.

}
};

template <typename TExec>
struct ToMillisecondFunction {
VELOX_DEFINE_FUNCTION_TYPES(TExec);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "velox/functions/Registerer.h"
#include "velox/functions/prestosql/DateTimeFunctions.h"
#include "velox/functions/prestosql/types/TimeWithTimezoneRegistration.h"
#include "velox/functions/prestosql/types/TimeWithTimezoneType.h"
#include "velox/functions/prestosql/types/TimestampWithTimeZoneRegistration.h"

namespace facebook::velox::functions {
Expand Down Expand Up @@ -318,6 +319,12 @@ void registerSimpleFunctions(const std::string& prefix) {
TimestampWithTimezone,
Varchar>({prefix + "at_timezone"});

registerFunction<
AtTimezoneTimeFunction,
TimeWithTimezone,
TimeWithTimezone,
Varchar>({prefix + "at_timezone"});

registerFunction<ToMillisecondFunction, int64_t, IntervalDayTime>(
{prefix + "to_milliseconds"});

Expand Down
118 changes: 118 additions & 0 deletions velox/functions/prestosql/tests/DateTimeFunctionsTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "velox/common/base/tests/GTestUtils.h"
#include "velox/external/tzdb/zoned_time.h"
#include "velox/functions/prestosql/tests/utils/FunctionBaseTest.h"
#include "velox/functions/prestosql/types/TimeWithTimezoneType.h"
#include "velox/functions/prestosql/types/TimestampWithTimeZoneType.h"
#include "velox/type/tz/TimeZoneMap.h"

Expand Down Expand Up @@ -6135,6 +6136,123 @@ TEST_F(DateTimeFunctionsTest, atTimezoneTest) {
EXPECT_EQ(at_timezone(std::nullopt, "Pacific/Fiji"), std::nullopt);
}

TEST_F(DateTimeFunctionsTest, atTimezoneTimeTest) {
const auto at_timezone_time = [&](std::optional<int64_t> timeWithTimezone,
std::optional<std::string> targetTimezone) {
return evaluateOnce<int64_t>(
"at_timezone(c0, c1)",
{TIME_WITH_TIME_ZONE(), VARCHAR()},
timeWithTimezone,
targetTimezone);
};

const int64_t millisTenOClockWarsawWinter = 9 * 60 * 60 * 1000;

EXPECT_EQ(
at_timezone_time(
pack(millisTenOClockWarsawWinter, tz::getTimeZoneID("Europe/Warsaw")),
"UTC"),
pack(millisTenOClockWarsawWinter, tz::getTimeZoneID("UTC")));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isnt right, timewithtimezone supports bias encoding of offset minutes, not IANA timezone id's.


EXPECT_EQ(
at_timezone_time(
pack(millisTenOClockWarsawWinter, tz::getTimeZoneID("Europe/Warsaw")),
"+00:45"),
pack(millisTenOClockWarsawWinter, tz::getTimeZoneID("+00:45")));

EXPECT_EQ(
at_timezone_time(
pack(millisTenOClockWarsawWinter, tz::getTimeZoneID("Europe/Warsaw")),
"America/New_York"),
pack(millisTenOClockWarsawWinter, tz::getTimeZoneID("America/New_York")));

EXPECT_EQ(
at_timezone_time(
pack(millisTenOClockWarsawWinter, tz::getTimeZoneID("Europe/Warsaw")),
"Europe/Berlin"),
pack(millisTenOClockWarsawWinter, tz::getTimeZoneID("Europe/Berlin")));

const int64_t millisTenOClockUTC = 10 * 60 * 60 * 1000;
EXPECT_EQ(
at_timezone_time(
pack(millisTenOClockUTC, tz::getTimeZoneID("UTC")), "UTC"),
pack(millisTenOClockUTC, tz::getTimeZoneID("UTC")));

EXPECT_EQ(
at_timezone_time(
pack(millisTenOClockWarsawWinter, tz::getTimeZoneID("Europe/Warsaw")),
"Europe/Warsaw"),
pack(millisTenOClockWarsawWinter, tz::getTimeZoneID("Europe/Warsaw")));

const int64_t millisTwoOClockWarsawWinter = 1 * 60 * 60 * 1000;
const int64_t millisTwentyOClockNewYork = 20 * 60 * 60 * 1000;
EXPECT_EQ(
at_timezone_time(
pack(millisTwoOClockWarsawWinter, tz::getTimeZoneID("Europe/Warsaw")),
"America/New_York"),
pack(millisTwentyOClockNewYork, tz::getTimeZoneID("America/New_York")));

const int64_t millisTwentyTwoOClockNewYork = 22 * 60 * 60 * 1000;
const int64_t millisFourOClockWarsaw = 4 * 60 * 60 * 1000;
EXPECT_EQ(
at_timezone_time(
pack(
millisTwentyTwoOClockNewYork,
tz::getTimeZoneID("America/New_York")),
"Europe/Warsaw"),
pack(millisFourOClockWarsaw, tz::getTimeZoneID("Europe/Warsaw")));

const int64_t millisMidnight = 0;
const int64_t millisTwentyThreeOClock = 23 * 60 * 60 * 1000;
EXPECT_EQ(
at_timezone_time(
pack(millisMidnight, tz::getTimeZoneID("+14:00")), "+13:00"),
pack(millisTwentyThreeOClock, tz::getTimeZoneID("+13:00")));

const int64_t millisTwentyOClock = 20 * 60 * 60 * 1000;
EXPECT_EQ(
at_timezone_time(
pack(millisMidnight, tz::getTimeZoneID("+14:00")), "-14:00"),
pack(millisTwentyOClock, tz::getTimeZoneID("-14:00")));

const int64_t millisMaxTime =
23 * 60 * 60 * 1000 + 59 * 60 * 1000 + 59 * 1000 + 999;
const int64_t millisTwentyTwoFiftyNine =
22 * 60 * 60 * 1000 + 59 * 60 * 1000 + 59 * 1000 + 999;
EXPECT_EQ(
at_timezone_time(
pack(millisMaxTime, tz::getTimeZoneID("+14:00")), "+13:00"),
pack(millisTwentyTwoFiftyNine, tz::getTimeZoneID("+13:00")));

const int64_t millisNineteenFiftyNine =
19 * 60 * 60 * 1000 + 59 * 60 * 1000 + 59 * 1000 + 999;
EXPECT_EQ(
at_timezone_time(
pack(millisMaxTime, tz::getTimeZoneID("+14:00")), "-14:00"),
pack(millisNineteenFiftyNine, tz::getTimeZoneID("-14:00")));

const int64_t millisTenOClockKathmandu = 10 * 60 * 60 * 1000;
const int64_t millisFourFifteenUTC = 4 * 60 * 60 * 1000 + 15 * 60 * 1000;
EXPECT_EQ(
at_timezone_time(
pack(millisFourFifteenUTC, tz::getTimeZoneID("Asia/Kathmandu")),
"UTC"),
pack(millisFourFifteenUTC, tz::getTimeZoneID("UTC")));

EXPECT_EQ(
at_timezone_time(
pack(millisTenOClockKathmandu, tz::getTimeZoneID("Asia/Kabul")),
"Asia/Kabul"),
pack(millisTenOClockKathmandu, tz::getTimeZoneID("Asia/Kabul")));

EXPECT_EQ(
at_timezone_time(
pack(millisTenOClockUTC, tz::getTimeZoneID("UTC")), std::nullopt),
std::nullopt);

EXPECT_EQ(at_timezone_time(std::nullopt, "UTC"), std::nullopt);
}

TEST_F(DateTimeFunctionsTest, toMilliseconds) {
EXPECT_EQ(
123,
Expand Down
Loading