diff --git a/deps/oblib/src/lib/timezone/ob_time_convert.cpp b/deps/oblib/src/lib/timezone/ob_time_convert.cpp index 97056cbfdb..687d935314 100644 --- a/deps/oblib/src/lib/timezone/ob_time_convert.cpp +++ b/deps/oblib/src/lib/timezone/ob_time_convert.cpp @@ -625,6 +625,47 @@ int ObTimeConverter::str_to_scn_value(const ObString &str, return ret; } +int ObTimeConverter::scn_to_str(const uint64_t scn_val, + const ObTimeZoneInfo *sys_tz_info, + char *buf, int64_t buf_len, int64_t &pos) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(sys_tz_info) || OB_ISNULL(buf) || OB_UNLIKELY(buf_len <= 0)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid arguments", KP(sys_tz_info), KP(buf), K(buf_len)); + } else { + const int64_t utc_timestamp = scn_val / 1000; + int64_t dt_value = 0; + if (OB_FAIL(ObTimeConverter::timestamp_to_datetime(utc_timestamp, + sys_tz_info, + dt_value))) { + LOG_WARN("failed to convert timestamp to datetime", K(ret)); + } else if (OB_UNLIKELY(dt_value > DATETIME_MAX_VAL || dt_value < DATETIME_MIN_VAL)) { + ret = OB_OPERATE_OVERFLOW; + LOG_WARN("overflow", K(utc_timestamp), K(dt_value), K(scn_val), K(sys_tz_info)); + } else { + const int32_t value_ns = scn_val % 1000; + ObOTimestampData ot_data; + ot_data.time_us_ = dt_value; + ot_data.time_ctx_.tail_nsec_ = value_ns; + const int16_t MAX_NS_SCALE = 9; + const ObObjType type = ObTimestampNanoType; + ObString otimestamp_format("YYYY-MM-DD HH24:MI:SS.FF9"); + const ObDataTypeCastParams dtc_params(sys_tz_info/*not used during otimestamp_to_str with ObTimestampNanoType*/, + DEFAULT_NLS_DATE_FORMAT, + otimestamp_format, + DEFAULT_NLS_TIMESTAMP_TZ_FORMAT, + CS_TYPE_INVALID, + CS_TYPE_INVALID, + CS_TYPE_UTF8MB4_GENERAL_CI); + if (OB_FAIL(otimestamp_to_str(ot_data, dtc_params, MAX_NS_SCALE, type, buf, buf_len, pos))) { + LOG_WARN("fail to cast otimestamp to str", K(utc_timestamp), K(dt_value), K(scn_val), K(sys_tz_info)); + } + } + } + return ret; +} + /** * @brief calcs tz offset value by time zone name from the input ob_time, fills the result back to ob_time * @param in: cvrt_ctx diff --git a/deps/oblib/src/lib/timezone/ob_time_convert.h b/deps/oblib/src/lib/timezone/ob_time_convert.h index 562561015e..8cadc64857 100644 --- a/deps/oblib/src/lib/timezone/ob_time_convert.h +++ b/deps/oblib/src/lib/timezone/ob_time_convert.h @@ -400,6 +400,11 @@ public: const ObString &nlf_format, const bool is_oracle_mode, uint64_t &scn_value); + //convert a scn to timestamp str with ns + //invoker need to gurantee scn_val is valid + static int scn_to_str(const uint64_t scn_val, + const ObTimeZoneInfo *sys_tz_info, + char *buf, int64_t buf_len, int64_t &pos); //ob_time store local time static int str_to_tz_offset(const ObTimeConvertCtx &cvrt_ctx, ObTime &ob_time); //ob_time store local time diff --git a/deps/oblib/unittest/lib/timezone/test_ob_time_convert.cpp b/deps/oblib/unittest/lib/timezone/test_ob_time_convert.cpp index ea8ec2cf1d..bcd77e449b 100644 --- a/deps/oblib/unittest/lib/timezone/test_ob_time_convert.cpp +++ b/deps/oblib/unittest/lib/timezone/test_ob_time_convert.cpp @@ -3200,8 +3200,51 @@ TEST(ObTimeConvertTest, interval) } +TEST(ObTimeConvertTest, scn_to_str) +{ + // timezone with offset only. + ObString tz_str; + ObTimeZoneInfo tz_info; + char tz_buf[50] = {0}; + tz_str.assign_buffer(tz_buf, 50); + strcpy(tz_buf, "+8:00"); + tz_str.set_length(static_cast(strlen(tz_buf))); + tz_info.set_timezone(tz_str); + + const int64_t BUF_LEN = 100; + char buf[BUF_LEN] = {0}; + int64_t pos = 0; + uint64_t scn_val = 9223372036854775808UL; + + ASSERT_EQ(OB_INVALID_ARGUMENT, ObTimeConverter::scn_to_str(scn_val, NULL, buf, BUF_LEN, pos)); + ASSERT_EQ(OB_INVALID_ARGUMENT, ObTimeConverter::scn_to_str(scn_val, &tz_info, NULL, BUF_LEN, pos)); + ASSERT_EQ(OB_INVALID_ARGUMENT, ObTimeConverter::scn_to_str(scn_val, &tz_info, buf, 0, pos)); + + ASSERT_EQ(OB_SUCCESS, ObTimeConverter::scn_to_str(scn_val, &tz_info, buf, BUF_LEN, pos)); + OB_LOG(INFO, "YYY +8:00", K(scn_val), K(tz_buf), K(buf)); + + pos= 0; + scn_val = 1687780338123456789; + ASSERT_EQ(OB_SUCCESS, ObTimeConverter::scn_to_str(scn_val, &tz_info, buf, BUF_LEN, pos)); + OB_LOG(INFO, "YYY +8:00", K(scn_val), K(tz_buf), K(buf)); + ASSERT_TRUE(0 == strcmp(buf, "2023-06-26 19:52:18.123456789")); + + + strcpy(tz_buf, "-08:00"); + tz_str.assign(tz_buf, static_cast(strlen(tz_buf))); + tz_info.set_timezone(tz_str); + + pos= 0; + ASSERT_EQ(OB_SUCCESS, ObTimeConverter::scn_to_str(scn_val, &tz_info, buf, BUF_LEN, pos)); + OB_LOG(INFO, "YYY -08:00", K(scn_val), K(tz_buf), K(buf)); + ASSERT_TRUE(0 == strcmp(buf, "2023-06-26 03:52:18.123456789")); + +} + int main(int argc, char **argv) { + system("rm -f test_time_convert.log"); + OB_LOGGER.set_file_name("test_time_convert.log", true); OB_LOGGER.set_log_level("INFO"); ::testing::InitGoogleTest(&argc,argv); return RUN_ALL_TESTS();