diff --git a/CMakeLists.txt b/CMakeLists.txt index 05fe56e0351..da676c5716f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -79,6 +79,7 @@ macro(nebula_add_library name type) # hbase_thrift_generator parser_target wkt_parser_target + datetime_parser_target ) endmacro() diff --git a/src/codec/test/CMakeLists.txt b/src/codec/test/CMakeLists.txt index 1d761a12d88..f529f16431e 100644 --- a/src/codec/test/CMakeLists.txt +++ b/src/codec/test/CMakeLists.txt @@ -31,6 +31,7 @@ set(CODEC_TEST_LIBS $ $ $ + $ $ $ ) diff --git a/src/common/datatypes/Date.cpp b/src/common/datatypes/Date.cpp index 6252588ec7e..7c2fd9861a6 100644 --- a/src/common/datatypes/Date.cpp +++ b/src/common/datatypes/Date.cpp @@ -12,6 +12,11 @@ namespace nebula { +static inline std::string decimal(const std::string& number) { + auto find = std::find(number.begin(), number.end(), '.'); + return std::string(find, number.end()); +} + const int64_t kDaysSoFar[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}; const int64_t kLeapDaysSoFar[] = {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}; @@ -98,22 +103,26 @@ std::string Date::toString() const { } std::string Time::toString() const { + auto microsecStr = folly::stringPrintf("%.9f", static_cast(microsec) / 1000000.0); + auto decimalPart = decimal(microsecStr); // It's in current timezone already - return folly::stringPrintf("%02d:%02d:%02d.%06d", hour, minute, sec, microsec); + return folly::stringPrintf("%02d:%02d:%02d%s", hour, minute, sec, decimalPart.c_str()); } std::string DateTime::toString() const { + auto microsecStr = folly::stringPrintf("%.9f", static_cast(microsec) / 1000000.0); + auto decimalPart = decimal(microsecStr); // It's in current timezone already return folly::stringPrintf( "%hd-%02hhu-%02hhu" - "T%02hhu:%02hhu:%02hhu.%u", + "T%02hhu:%02hhu:%02hhu%s", static_cast(year), static_cast(month), static_cast(day), static_cast(hour), static_cast(minute), static_cast(sec), - static_cast(microsec)); + decimalPart.c_str()); } } // namespace nebula diff --git a/src/common/datatypes/Date.h b/src/common/datatypes/Date.h index 80b58243bb6..a7bd42e0c48 100644 --- a/src/common/datatypes/Date.h +++ b/src/common/datatypes/Date.h @@ -164,6 +164,19 @@ struct DateTime { sec = 0; microsec = 0; } + explicit DateTime(const Date& date, const Time& time) { + year = date.year; + month = date.month; + day = date.day; + hour = time.hour; + minute = time.minute; + sec = time.sec; + microsec = time.microsec; + } + + Date date() const { return Date(year, month, day); } + + Time time() const { return Time(hour, minute, sec, microsec); } void clear() { year = 0; diff --git a/src/common/datatypes/test/CMakeLists.txt b/src/common/datatypes/test/CMakeLists.txt index e2feb822850..beff0176017 100644 --- a/src/common/datatypes/test/CMakeLists.txt +++ b/src/common/datatypes/test/CMakeLists.txt @@ -44,6 +44,7 @@ nebula_add_test( $ $ $ + $ $ $ LIBRARIES @@ -65,6 +66,7 @@ nebula_add_test( $ $ $ + $ $ LIBRARIES gtest @@ -110,6 +112,7 @@ nebula_add_test( $ $ $ + $ $ $ LIBRARIES diff --git a/src/common/datatypes/test/ValueToJsonTest.cpp b/src/common/datatypes/test/ValueToJsonTest.cpp index a35220fc78a..457b666051d 100644 --- a/src/common/datatypes/test/ValueToJsonTest.cpp +++ b/src/common/datatypes/test/ValueToJsonTest.cpp @@ -136,7 +136,7 @@ TEST(ValueToJson, list) { Time(13, 30, 15, 0), // time DateTime(2021, 12, 21, 13, 30, 15, 0)})); // datetime dynamic expectedListJsonObj = dynamic::array( - 2, 2.33, true, "str", "2021-12-21", "13:30:15.000000Z", "2021-12-21T13:30:15.0Z"); + 2, 2.33, true, "str", "2021-12-21", "13:30:15.000000000Z", "2021-12-21T13:30:15.000000000Z"); ASSERT_EQ(expectedListJsonObj, list1.toJson()); dynamic expectedListMetaObj = dynamic::array(nullptr, @@ -158,7 +158,7 @@ TEST(ValueToJson, Set) { Time(13, 30, 15, 0), // time DateTime(2021, 12, 21, 13, 30, 15, 0)})); // datetime dynamic expectedSetJsonObj = dynamic::array( - 2, 2.33, true, "str", "2021-12-21", "13:30:15.000000Z", "2021-12-21T13:30:15.0Z"); + 2, 2.33, true, "str", "2021-12-21", "13:30:15.000000000Z", "2021-12-21T13:30:15.000000000Z"); // The underlying data structure is unordered_set, so sort before the comparison auto actualJson = set.toJson(); std::sort(actualJson.begin(), actualJson.end()); @@ -179,7 +179,7 @@ TEST(ValueToJson, map) { {"key7", DateTime(2021, 12, 21, 13, 30, 15, 0)}})); // datetime dynamic expectedMapJsonObj = dynamic::object("key1", 2)("key2", 2.33)("key3", true)("key4", "str")("key5", "2021-12-21")( - "key6", "13:30:15.000000Z")("key7", "2021-12-21T13:30:15.0Z"); + "key6", "13:30:15.000000000Z")("key7", "2021-12-21T13:30:15.000000000Z"); ASSERT_EQ(expectedMapJsonObj, map.toJson()); // Skip meta json comparison since nested dynamic objects cannot be sorted. i.g. dynamic::object // inside dynamic::array @@ -194,18 +194,23 @@ TEST(ValueToJson, dataset) { Date(2021, 12, 21), // date Time(13, 30, 15, 0), // time DateTime(2021, 12, 21, 13, 30, 15, 0)})); - dynamic expectedDatasetJsonObj = dynamic::array(dynamic::object( - "row", - dynamic::array( - 2, 2.33, true, "str", "2021-12-21", "13:30:15.000000Z", "2021-12-21T13:30:15.0Z"))( - "meta", - dynamic::array(nullptr, - nullptr, - nullptr, - nullptr, - dynamic::object("type", "date"), - dynamic::object("type", "time"), - dynamic::object("type", "datetime")))); + dynamic expectedDatasetJsonObj = + dynamic::array(dynamic::object("row", + dynamic::array(2, + 2.33, + true, + "str", + "2021-12-21", + "13:30:15.000000000Z", + "2021-12-21T13:30:15.000000000Z"))( + "meta", + dynamic::array(nullptr, + nullptr, + nullptr, + nullptr, + dynamic::object("type", "date"), + dynamic::object("type", "time"), + dynamic::object("type", "datetime")))); ASSERT_EQ(expectedDatasetJsonObj, dataset.toJson()); } diff --git a/src/common/expression/test/CMakeLists.txt b/src/common/expression/test/CMakeLists.txt index 1cda6272cd3..4457d468103 100644 --- a/src/common/expression/test/CMakeLists.txt +++ b/src/common/expression/test/CMakeLists.txt @@ -11,6 +11,7 @@ set(expression_test_common_libs $ $ $ + $ $ $ $ @@ -113,6 +114,7 @@ nebula_add_executable( $ $ $ + $ $ $ LIBRARIES @@ -136,6 +138,7 @@ nebula_add_executable( $ $ $ + $ $ LIBRARIES follybenchmark diff --git a/src/common/function/test/CMakeLists.txt b/src/common/function/test/CMakeLists.txt index a1e5366cc08..b8517314dfe 100644 --- a/src/common/function/test/CMakeLists.txt +++ b/src/common/function/test/CMakeLists.txt @@ -13,6 +13,7 @@ nebula_add_test( $ $ $ + $ $ $ LIBRARIES diff --git a/src/common/function/test/FunctionManagerTest.cpp b/src/common/function/test/FunctionManagerTest.cpp index a34a88e0d06..0bcc1f133d7 100644 --- a/src/common/function/test/FunctionManagerTest.cpp +++ b/src/common/function/test/FunctionManagerTest.cpp @@ -318,7 +318,7 @@ TEST_F(FunctionManagerTest, functionCall) { TEST_FUNCTION(toString, args_["toString_bool"], "true"); TEST_FUNCTION(toString, args_["string"], "AbcDeFG"); TEST_FUNCTION(toString, args_["date"], "1984-10-11"); - TEST_FUNCTION(toString, args_["datetime"], "1984-10-11T12:31:14.341"); + TEST_FUNCTION(toString, args_["datetime"], "1984-10-11T12:31:14.000341000"); TEST_FUNCTION(toString, args_["nullvalue"], Value::kNullValue); } { @@ -327,8 +327,9 @@ TEST_F(FunctionManagerTest, functionCall) { DateTime dateTime(2021, 10, 31, 8, 5, 34, 29); TEST_FUNCTION(concat, std::vector({"hello", 1, "world"}), "hello1world"); TEST_FUNCTION(concat, std::vector({true, 2, date}), "true22021-10-31"); - TEST_FUNCTION(concat, std::vector({true, dateTime}), "true2021-10-31T08:05:34.29"); - TEST_FUNCTION(concat, std::vector({2.3, time}), "2.309:39:21.000012"); + TEST_FUNCTION( + concat, std::vector({true, dateTime}), "true2021-10-31T08:05:34.000029000"); + TEST_FUNCTION(concat, std::vector({2.3, time}), "2.309:39:21.000012000"); TEST_FUNCTION(concat, args_["two"], "24"); TEST_FUNCTION(concat_ws, std::vector({",", 1}), "1"); TEST_FUNCTION(concat_ws, std::vector({"@", 1, "world"}), "1@world"); @@ -337,7 +338,7 @@ TEST_F(FunctionManagerTest, functionCall) { "1ABtrueABworld"); TEST_FUNCTION(concat_ws, std::vector({".", 1, true, Value::kNullValue, "world", time}), - "1.true.world.09:39:21.000012"); + "1.true.world.09:39:21.000012000"); } { TEST_FUNCTION(toBoolean, args_["int"], Value::kNullBadType); diff --git a/src/common/geo/test/CMakeLists.txt b/src/common/geo/test/CMakeLists.txt index e1455c56154..932fffb14e6 100644 --- a/src/common/geo/test/CMakeLists.txt +++ b/src/common/geo/test/CMakeLists.txt @@ -13,6 +13,7 @@ nebula_add_test( $ $ $ + $ $ LIBRARIES gtest diff --git a/src/common/time/CMakeLists.txt b/src/common/time/CMakeLists.txt index f1f239a3150..5fef0592a4c 100644 --- a/src/common/time/CMakeLists.txt +++ b/src/common/time/CMakeLists.txt @@ -16,4 +16,6 @@ nebula_add_library( TimeConversion.cpp ) +nebula_add_subdirectory(parser) + nebula_add_subdirectory(test) diff --git a/src/common/time/TimeUtils.cpp b/src/common/time/TimeUtils.cpp index e9e65fb6361..5733fa72be1 100644 --- a/src/common/time/TimeUtils.cpp +++ b/src/common/time/TimeUtils.cpp @@ -9,6 +9,7 @@ #include "common/fs/FileUtils.h" #include "common/time/TimezoneInfo.h" +#include "common/time/parser/DatetimeReader.h" namespace nebula { namespace time { @@ -170,5 +171,24 @@ StatusOr TimeUtils::toTimestamp(const Value &val) { return timestamp; } +/*static*/ StatusOr TimeUtils::parseDateTime(const std::string &str) { + auto p = DatetimeReader::makeDateTimeReader(); + auto result = p.readDatetime(str); + NG_RETURN_IF_ERROR(result); + return result.value(); +} + +/*static*/ StatusOr TimeUtils::parseDate(const std::string &str) { + auto p = DatetimeReader::makeDateReader(); + auto result = p.readDate(str); + NG_RETURN_IF_ERROR(result); + return result.value(); +} + +/*static*/ StatusOr