diff --git a/src/common/function/FunctionManager.cpp b/src/common/function/FunctionManager.cpp index f73053cdc1f..ef5af9050f3 100644 --- a/src/common/function/FunctionManager.cpp +++ b/src/common/function/FunctionManager.cpp @@ -1712,9 +1712,14 @@ FunctionManager::FunctionManager() { if (args[0].get().isStr()) { auto result = time::TimeUtils::parseTime(args[0].get().getStr()); if (!result.ok()) { + DLOG(ERROR) << "DEBUG POINT: " << result.status(); return Value::kNullBadData; } - return time::TimeUtils::timeToUTC(result.value()); + if (result.value().withTimeZone) { + return result.value().t; + } else { + return time::TimeUtils::timeToUTC(result.value().t); + } } else if (args[0].get().isMap()) { auto result = time::TimeUtils::timeFromMap(args[0].get().getMap()); if (!result.ok()) { @@ -1749,7 +1754,11 @@ FunctionManager::FunctionManager() { if (!result.ok()) { return Value::kNullBadData; } - return time::TimeUtils::dateTimeToUTC(result.value()); + if (result.value().withTimeZone) { + return result.value().dt; + } else { + return time::TimeUtils::dateTimeToUTC(result.value().dt); + } } else if (args[0].get().isMap()) { auto result = time::TimeUtils::dateTimeFromMap(args[0].get().getMap()); if (!result.ok()) { diff --git a/src/common/function/test/CMakeLists.txt b/src/common/function/test/CMakeLists.txt index b8517314dfe..ab547cf44a6 100644 --- a/src/common/function/test/CMakeLists.txt +++ b/src/common/function/test/CMakeLists.txt @@ -21,6 +21,24 @@ nebula_add_test( gtest_main ) +nebula_add_test( + NAME + twice_timezone_conversion_test + SOURCES + TwiceTimezoneConversionTest.cpp + OBJECTS + $ + $ + $ + $ + $ + $ + $ + $ + LIBRARIES + gtest +) + nebula_add_test( NAME agg_function_manager_test diff --git a/src/common/function/test/TwiceTimezoneConversionTest.cpp b/src/common/function/test/TwiceTimezoneConversionTest.cpp new file mode 100644 index 00000000000..c5e983043c5 --- /dev/null +++ b/src/common/function/test/TwiceTimezoneConversionTest.cpp @@ -0,0 +1,62 @@ +// Copyright (c) 2022 vesoft inc. All rights reserved. +// +// This source code is licensed under Apache 2.0 License. + +#include + +#include "common/datatypes/Date.h" +#include "common/function/FunctionManager.h" +#include "common/time/TimezoneInfo.h" + +DECLARE_string(timezone_name); + +// #4432 +TEST(DatetimeFunction, TwiceTimezoneConversion) { + // date + { + auto result = nebula::FunctionManager::get("date", 1); + ASSERT_TRUE(result.ok()); + nebula::Value arg = nebula::Value("2019-01-01"); + auto res = std::move(result).value()({arg}); + ASSERT_EQ(res.type(), nebula::Value::Type::DATE); + EXPECT_EQ(res.getDate(), nebula::Date(2019, 1, 1)); + } + + // time + { + auto result = nebula::FunctionManager::get("time", 1); + ASSERT_TRUE(result.ok()); + nebula::Value arg = nebula::Value("23:04:05+08:00"); + auto res = std::move(result).value()({arg}); + ASSERT_EQ(res.type(), nebula::Value::Type::TIME); + EXPECT_EQ(res.getTime(), nebula::Time(15, 4, 5, 0)); + } + + // datetime + { + auto result = nebula::FunctionManager::get("datetime", 1); + ASSERT_TRUE(result.ok()); + nebula::Value arg = nebula::Value("2019-01-01T23:04:05+08:00"); + auto res = std::move(result).value()({arg}); + ASSERT_EQ(res.type(), nebula::Value::Type::DATETIME); + EXPECT_EQ(res.getDateTime(), nebula::DateTime(2019, 1, 1, 15, 4, 5, 0)); + } +} + +int main(int argc, char **argv) { + testing::InitGoogleTest(&argc, argv); + folly::init(&argc, &argv, true); + google::SetStderrLogging(google::INFO); + + FLAGS_timezone_name = "UTC+08:00"; + + auto result = nebula::time::Timezone::initializeGlobalTimezone(); + if (!result.ok()) { + LOG(FATAL) << result; + } + + DLOG(INFO) << "Timezone: " << nebula::time::Timezone::getGlobalTimezone().stdZoneName(); + DLOG(INFO) << "Timezone offset: " << nebula::time::Timezone::getGlobalTimezone().utcOffsetSecs(); + + return RUN_ALL_TESTS(); +} diff --git a/src/common/time/TimeUtils.cpp b/src/common/time/TimeUtils.cpp index 4b1c1630700..16ccea8455d 100644 --- a/src/common/time/TimeUtils.cpp +++ b/src/common/time/TimeUtils.cpp @@ -154,7 +154,8 @@ StatusOr TimeUtils::toTimestamp(const Value &val) { if (!status.ok()) { return status.status(); } - auto dateTime = std::move(status).value(); + auto result = std::move(status).value(); + auto dateTime = result.withTimeZone ? result.dt : dateTimeToUTC(result.dt); if (dateTime.microsec != 0) { return Status::Error("The timestamp only supports seconds unit."); } @@ -206,7 +207,7 @@ StatusOr TimeUtils::toTimestamp(const Value &val) { return d; } -/*static*/ StatusOr TimeUtils::parseDateTime(const std::string &str) { +/*static*/ StatusOr TimeUtils::parseDateTime(const std::string &str) { auto p = DatetimeReader(); auto result = p.readDatetime(str); NG_RETURN_IF_ERROR(result); @@ -220,7 +221,7 @@ StatusOr TimeUtils::toTimestamp(const Value &val) { return result.value(); } -/*static*/ StatusOr