From 69da972796b6279b3ddfa2df01a1986e74e04ec4 Mon Sep 17 00:00:00 2001 From: wangmm0220 Date: Fri, 22 Nov 2024 18:31:51 +0800 Subject: [PATCH] feat:[TD-32642] add timezone logic --- include/common/ttime.h | 27 +- include/libs/function/function.h | 1 + include/libs/nodes/querynodes.h | 9 +- include/libs/parser/parser.h | 1 + include/os/osTime.h | 11 +- source/client/src/clientImpl.c | 3 +- source/client/src/clientMain.c | 3 +- source/client/test/CMakeLists.txt | 4 +- source/client/test/clientTests.cpp | 433 +++++++++---- source/common/src/tdatablock.c | 2 +- source/common/src/tglobal.c | 4 +- source/common/src/tmisce.c | 5 +- source/common/src/tname.c | 67 -- source/common/src/ttime.c | 172 +++--- source/common/test/commonTests.cpp | 10 +- source/dnode/mgmt/mgmt_dnode/src/dmHandle.c | 2 +- source/dnode/mnode/impl/src/mndMain.c | 2 +- source/libs/function/src/builtins.c | 8 +- source/libs/parser/inc/parUtil.h | 2 +- source/libs/parser/src/parAstCreater.c | 3 + source/libs/parser/src/parInsertSql.c | 30 +- source/libs/parser/src/parTranslater.c | 14 +- source/libs/scalar/src/filter.c | 36 -- source/libs/scalar/src/scalar.c | 8 +- source/libs/scalar/src/sclfunc.c | 55 +- source/libs/scalar/src/sclvector.c | 7 +- source/os/src/osTime.c | 302 +++------ source/os/src/osTimezone.c | 643 +++++++++++++++++++- source/os/test/osTimeTests.cpp | 23 +- source/util/src/tconfig.c | 16 +- source/util/src/tlog.c | 27 +- tests/system-test/2-query/timezone.py | 37 +- tests/system-test/2-query/timezone_conf.py | 34 ++ tools/shell/src/shellEngine.c | 2 +- utils/test/c/CMakeLists.txt | 9 + utils/test/c/timezone_test.c | 97 +++ utils/test/c/tmqDemo.c | 2 +- utils/test/c/tmqSim.c | 4 +- utils/tsim/src/simExe.c | 2 +- 39 files changed, 1438 insertions(+), 679 deletions(-) create mode 100644 tests/system-test/2-query/timezone_conf.py create mode 100644 utils/test/c/timezone_test.c diff --git a/include/common/ttime.h b/include/common/ttime.h index 65cbc34fc3..41dd0bf6be 100644 --- a/include/common/ttime.h +++ b/include/common/ttime.h @@ -58,19 +58,7 @@ static FORCE_INLINE int64_t taosGetTimestamp(int32_t precision) { * precision == TSDB_TIME_PRECISION_MILLI, it returns timestamp in millisecond. * precision == TSDB_TIME_PRECISION_NANO, it returns timestamp in nanosecond. */ -static FORCE_INLINE int64_t taosGetTimestampToday(int32_t precision) { - int64_t factor = (precision == TSDB_TIME_PRECISION_MILLI) ? 1000 - : (precision == TSDB_TIME_PRECISION_MICRO) ? 1000000 - : 1000000000; - time_t t = taosTime(NULL); - struct tm tm; - (void) taosLocalTime(&t, &tm, NULL, 0); //tztodo - tm.tm_hour = 0; - tm.tm_min = 0; - tm.tm_sec = 0; - - return (int64_t)taosMktime(&tm) * factor; -} +int64_t taosGetTimestampToday(int32_t precision, timezone_t tz); int64_t taosTimeAdd(int64_t t, int64_t duration, char unit, int32_t precision); @@ -81,13 +69,12 @@ int32_t taosTimeCountIntervalForFill(int64_t skey, int64_t ekey, int64_t interva int32_t parseAbsoluteDuration(const char* token, int32_t tokenlen, int64_t* ts, char* unit, int32_t timePrecision); int32_t parseNatualDuration(const char* token, int32_t tokenLen, int64_t* duration, char* unit, int32_t timePrecision, bool negativeAllow); -int32_t taosParseTime(const char* timestr, int64_t* pTime, int32_t len, int32_t timePrec); -void deltaToUtcInitOnce(); +int32_t taosParseTime(const char* timestr, int64_t* pTime, int32_t len, int32_t timePrec, timezone_t tz); char getPrecisionUnit(int32_t precision); int64_t convertTimePrecision(int64_t ts, int32_t fromPrecision, int32_t toPrecision); int32_t convertTimeFromPrecisionToUnit(int64_t time, int32_t fromPrecision, char toUnit, int64_t* pRes); -int32_t convertStringToTimestamp(int16_t type, char* inputData, int64_t timePrec, int64_t* timeVal); +int32_t convertStringToTimestamp(int16_t type, char* inputData, int64_t timePrec, int64_t* timeVal, timezone_t tz); int32_t getDuration(int64_t val, char unit, int64_t* result, int32_t timePrecision); int32_t taosFormatUtcTime(char* buf, int32_t bufLen, int64_t ts, int32_t precision); @@ -97,8 +84,8 @@ struct STm { int64_t fsec; // in NANOSECOND }; -int32_t taosTs2Tm(int64_t ts, int32_t precision, struct STm* tm); -int32_t taosTm2Ts(struct STm* tm, int64_t* ts, int32_t precision); +int32_t taosTs2Tm(int64_t ts, int32_t precision, struct STm* tm, timezone_t tz); +int32_t taosTm2Ts(struct STm* tm, int64_t* ts, int32_t precision, timezone_t tz); /// @brief convert a timestamp to a formatted string /// @param format the timestamp format, must null terminated @@ -107,7 +94,7 @@ int32_t taosTm2Ts(struct STm* tm, int64_t* ts, int32_t precision); /// formats array; If not NULL, [formats] will be used instead of [format] to skip parse formats again. /// @param out output buffer, should be initialized by memset /// @notes remember to free the generated formats -int32_t taosTs2Char(const char* format, SArray** formats, int64_t ts, int32_t precision, char* out, int32_t outLen); +int32_t taosTs2Char(const char* format, SArray** formats, int64_t ts, int32_t precision, char* out, int32_t outLen, timezone_t tz); /// @brief convert a formatted timestamp string to a timestamp /// @param format must null terminated /// @param [in, out] formats, see taosTs2Char @@ -115,7 +102,7 @@ int32_t taosTs2Char(const char* format, SArray** formats, int64_t ts, int32_t pr /// @retval 0 for success, otherwise error occured /// @notes remember to free the generated formats even when error occured int32_t taosChar2Ts(const char* format, SArray** formats, const char* tsStr, int64_t* ts, int32_t precision, char* errMsg, - int32_t errMsgLen); + int32_t errMsgLen, timezone_t tz); int32_t TEST_ts2char(const char* format, int64_t ts, int32_t precision, char* out, int32_t outLen); int32_t TEST_char2ts(const char* format, int64_t* ts, int32_t precision, const char* tsStr); diff --git a/include/libs/function/function.h b/include/libs/function/function.h index 51d9e752a4..cd3ad7597e 100644 --- a/include/libs/function/function.h +++ b/include/libs/function/function.h @@ -292,6 +292,7 @@ struct SScalarParam { void *param; // other parameter, such as meta handle from vnode, to extract table name/tag value int32_t numOfRows; int32_t numOfQualified; // number of qualified elements in the final results + timezone_t tz; }; #define cleanupResultRowEntry(p) p->initialized = false diff --git a/include/libs/nodes/querynodes.h b/include/libs/nodes/querynodes.h index 4763077ed9..c6d0869404 100644 --- a/include/libs/nodes/querynodes.h +++ b/include/libs/nodes/querynodes.h @@ -129,8 +129,9 @@ typedef struct SValueNode { double d; char* p; } datum; - int64_t typeData; - int8_t unit; + int64_t typeData; + int8_t unit; + timezone_t tz; } SValueNode; typedef struct SLeftValueNode { @@ -159,6 +160,7 @@ typedef struct SOperatorNode { EOperatorType opType; SNode* pLeft; SNode* pRight; + timezone_t tz; } SOperatorNode; typedef struct SLogicConditionNode { @@ -191,6 +193,8 @@ typedef struct SFunctionNode { int32_t originalFuncId; ETrimType trimType; bool dual; // whether select stmt without from stmt, true for without. +// char timezone[TD_TIMEZONE_LEN]; + timezone_t tz; } SFunctionNode; typedef struct STableNode { @@ -399,6 +403,7 @@ typedef struct SCaseWhenNode { SNode* pCase; SNode* pElse; SNodeList* pWhenThenList; + timezone_t tz; } SCaseWhenNode; typedef struct SWindowOffsetNode { diff --git a/include/libs/parser/parser.h b/include/libs/parser/parser.h index 832e4f8863..bfea9dbbe7 100644 --- a/include/libs/parser/parser.h +++ b/include/libs/parser/parser.h @@ -101,6 +101,7 @@ typedef struct SParseContext { int8_t biMode; SArray* pSubMetaList; setQueryFn setQueryFp; + timezone_t timezone; } SParseContext; int32_t qParseSql(SParseContext* pCxt, SQuery** pQuery); diff --git a/include/os/osTime.h b/include/os/osTime.h index 6142edcfa7..8367926dd6 100644 --- a/include/os/osTime.h +++ b/include/os/osTime.h @@ -92,15 +92,16 @@ static FORCE_INLINE int64_t taosGetMonoTimestampMs() { } char *taosStrpTime(const char *buf, const char *fmt, struct tm *tm); -struct tm *taosLocalTime(const time_t *timep, struct tm *result, char *buf, int32_t bufSize); -struct tm *taosLocalTimeNolock(struct tm *result, const time_t *timep, int dst); +struct tm *taosLocalTime(const time_t *timep, struct tm *result, char *buf, int32_t bufSize, timezone_t tz); +struct tm *taosGmTimeR(const time_t *timep, struct tm *result); +time_t taosTimeGm(struct tm *tmp); time_t taosTime(time_t *t); -time_t taosMktime(struct tm *timep); +time_t taosMktime(struct tm *timep, timezone_t tz); int64_t user_mktime64(const uint32_t year, const uint32_t mon, const uint32_t day, const uint32_t hour, const uint32_t min, const uint32_t sec, int64_t time_zone); -struct tm *taosLocalTimeRz(timezone_t state, const time_t *timep, struct tm *result); -time_t taosMktimeRz(timezone_t state, struct tm *timep); +//struct tm *taosLocalTimeRz(timezone_t state, const time_t *timep, struct tm *result); +//time_t taosMktimeRz(timezone_t state, struct tm *timep); #ifdef __cplusplus } #endif diff --git a/source/client/src/clientImpl.c b/source/client/src/clientImpl.c index 74fd4e13a7..f6ebc1f809 100644 --- a/source/client/src/clientImpl.c +++ b/source/client/src/clientImpl.c @@ -300,7 +300,8 @@ int32_t parseSql(SRequestObj* pRequest, bool topicQuery, SQuery** pQuery, SStmtC .svrVer = pTscObj->sVer, .nodeOffline = (pTscObj->pAppInfo->onlineDnodes < pTscObj->pAppInfo->totalDnodes), .isStmtBind = pRequest->isStmtBind, - .setQueryFp = setQueryRequest}; + .setQueryFp = setQueryRequest, + .timezone = pTscObj->optionInfo.timezone,}; cxt.mgmtEpSet = getEpSet_s(&pTscObj->pAppInfo->mgmtEp); int32_t code = catalogGetHandle(pTscObj->pAppInfo->clusterId, &cxt.pCatalog); diff --git a/source/client/src/clientMain.c b/source/client/src/clientMain.c index 2ee094bc18..c9e571b91b 100644 --- a/source/client/src/clientMain.c +++ b/source/client/src/clientMain.c @@ -1342,7 +1342,8 @@ int32_t createParseContext(const SRequestObj *pRequest, SParseContext **pCxt, SS .allocatorId = pRequest->allocatorRefId, .parseSqlFp = clientParseSql, .parseSqlParam = pWrapper, - .setQueryFp = setQueryRequest}; + .setQueryFp = setQueryRequest, + .timezone = pTscObj->optionInfo.timezone}; int8_t biMode = atomic_load_8(&((STscObj *)pTscObj)->biMode); (*pCxt)->biMode = biMode; return TSDB_CODE_SUCCESS; diff --git a/source/client/test/CMakeLists.txt b/source/client/test/CMakeLists.txt index 054b5af2b9..82c12653af 100644 --- a/source/client/test/CMakeLists.txt +++ b/source/client/test/CMakeLists.txt @@ -35,12 +35,12 @@ TARGET_INCLUDE_DIRECTORIES( PRIVATE "${TD_SOURCE_DIR}/source/client/inc" ) -IF(${TD_LINUX}) +#IF(${TD_LINUX}) add_test( NAME clientTest COMMAND clientTest ) -ENDIF () +#ENDIF () TARGET_INCLUDE_DIRECTORIES( tmqTest diff --git a/source/client/test/clientTests.cpp b/source/client/test/clientTests.cpp index 125df8f6b0..97d863b330 100644 --- a/source/client/test/clientTests.cpp +++ b/source/client/test/clientTests.cpp @@ -1489,127 +1489,352 @@ TEST(clientCase, sub_tb_mt_test) { } } -TEST(clientCase, timezone_Test) { - { - // taos_options( TSDB_OPTION_TIMEZONE, "UTC-8"); - int code = taos_options(TSDB_OPTION_TIMEZONE, "UTC-8"); - ASSERT_TRUE(code == 0); - TAOS* pConn = taos_connect("localhost", "root", "taosdata", NULL, 0); - ASSERT_NE(pConn, nullptr); +TAOS* getConnWithGlobalOption(const char *tz){ + int code = taos_options(TSDB_OPTION_TIMEZONE, tz); + ASSERT(code == 0); + TAOS* pConn = taos_connect("localhost", "root", "taosdata", NULL, 0); + ASSERT(pConn != nullptr); + return pConn; +} - TAOS_RES* pRes = taos_query(pConn, "drop database if exists db1"); - ASSERT_EQ(taos_errno(pRes), TSDB_CODE_SUCCESS); - taos_free_result(pRes); +TAOS* getConnWithOption(const char *tz){ + TAOS* pConn = taos_connect("localhost", "root", "taosdata", NULL, 0); + ASSERT(pConn != nullptr); + if (tz != NULL){ + int code = taos_options_connection(pConn, TSDB_OPTION_CONNECTION_TIMEZONE, tz); + ASSERT(code == 0); + } + return pConn; +} - pRes = taos_query(pConn, "create database db1"); - ASSERT_EQ(taos_errno(pRes), TSDB_CODE_SUCCESS); - taos_free_result(pRes); +void execQuery(TAOS* pConn, const char *sql){ + TAOS_RES* pRes = taos_query(pConn, sql); + ASSERT(taos_errno(pRes) == TSDB_CODE_SUCCESS); + taos_free_result(pRes); +} - pRes = taos_query(pConn, "create table db1.t1 (ts timestamp, v int)"); - ASSERT_EQ(taos_errno(pRes), TSDB_CODE_SUCCESS); - taos_free_result(pRes); +void execQueryFail(TAOS* pConn, const char *sql){ + TAOS_RES* pRes = taos_query(pConn, sql); + ASSERT(taos_errno(pRes) != TSDB_CODE_SUCCESS); + taos_free_result(pRes); +} - char sql[256] = {0}; - (void)sprintf(sql, "insert into db1.t1 values('2023-09-16 17:00:00', 1)"); - pRes = taos_query(pConn, sql); - ASSERT_EQ(taos_errno(pRes), TSDB_CODE_SUCCESS); - taos_free_result(pRes); +void checkRows(TAOS* pConn, const char *sql, int32_t expectedRows){ + TAOS_RES* pRes = taos_query(pConn, sql); + ASSERT(taos_errno(pRes) == TSDB_CODE_SUCCESS); + TAOS_ROW pRow = NULL; + int rows = 0; + while ((pRow = taos_fetch_row(pRes)) != NULL) { + rows++; + } + ASSERT(rows == expectedRows); + taos_free_result(pRes); +} - pRes = taos_query(pConn, "select * from db1.t1 where ts == '2023-09-16 17:00:00'"); - ASSERT_EQ(taos_errno(pRes), TSDB_CODE_SUCCESS); - - TAOS_ROW pRow = NULL; - TAOS_FIELD* pFields = taos_fetch_fields(pRes); - int32_t numOfFields = taos_num_fields(pRes); - - char str[512] = {0}; - int rows = 0; - while ((pRow = taos_fetch_row(pRes)) != NULL) { - rows++; +void check_timezone(TAOS* pConn, const char *sql, const char* tz){ + TAOS_RES *pRes = taos_query(pConn, sql); + ASSERT(taos_errno(pRes) == 0); + TAOS_ROW row = NULL; + while ((row = taos_fetch_row(pRes)) != NULL) { + if (strcmp((const char*)row[0], "timezone") == 0){ + ASSERT(strstr((const char*)row[1], tz) != NULL); } - ASSERT_TRUE(rows == 1); + } + taos_free_result(pRes); +} - taos_free_result(pRes); +void check_sql_result_partial(TAOS* pConn, const char *sql, const char* result){ + TAOS_RES *pRes = taos_query(pConn, sql); + ASSERT(taos_errno(pRes) == 0); + TAOS_ROW row = NULL; + while ((row = taos_fetch_row(pRes)) != NULL) { + ASSERT(strstr((const char*)row[0], result) != NULL); + } + taos_free_result(pRes); +} + +int64_t get_sql_result(TAOS* pConn, const char *sql){ + int64_t ts = 0; + TAOS_RES *pRes = taos_query(pConn, sql); + ASSERT(taos_errno(pRes) == 0); + TAOS_ROW row = NULL; + while ((row = taos_fetch_row(pRes)) != NULL) { + ts = *(int64_t*)row[0]; + } + taos_free_result(pRes); + return ts; +} + +void check_sql_result(TAOS* pConn, const char *sql, const char* result){ + TAOS_RES *pRes = taos_query(pConn, sql); + ASSERT(taos_errno(pRes) == 0); + TAOS_ROW row = NULL; + while ((row = taos_fetch_row(pRes)) != NULL) { + ASSERT (strcmp((const char*)row[0], result) == 0); + } + taos_free_result(pRes); +} + +void check_sql_result_integer(TAOS* pConn, const char *sql, int64_t result){ + TAOS_RES *pRes = taos_query(pConn, sql); + ASSERT(taos_errno(pRes) == 0); + TAOS_ROW row = NULL; + while ((row = taos_fetch_row(pRes)) != NULL) { + ASSERT (*(int64_t*)row[0] == result); + } + taos_free_result(pRes); +} + +void check_set_timezone(TAOS* optionFunc(const char *tz)){ + { + TAOS* pConn = optionFunc("UTC-8"); + check_timezone(pConn, "show local variables", "UTC-8"); + + execQuery(pConn, "drop database if exists db1"); + execQuery(pConn, "create database db1"); + execQuery(pConn, "create table db1.t1 (ts timestamp, v int)"); + + execQuery(pConn, "insert into db1.t1 values('2023-09-16 17:00:00', 1)"); + checkRows(pConn, "select * from db1.t1 where ts == '2023-09-16 17:00:00'", 1); taos_close(pConn); } { - // taos_options( TSDB_OPTION_TIMEZONE, "UTC+8"); - int code = taos_options(TSDB_OPTION_TIMEZONE, "UTC+8"); - ASSERT_TRUE(code == 0); - TAOS* pConn = taos_connect("localhost", "root", "taosdata", NULL, 0); - ASSERT_NE(pConn, nullptr); - - TAOS_RES* pRes = taos_query(pConn, "select * from db1.t1 where ts == '2023-09-16 01:00:00'"); - ASSERT_EQ(taos_errno(pRes), TSDB_CODE_SUCCESS); - - TAOS_ROW pRow = NULL; - TAOS_FIELD* pFields = taos_fetch_fields(pRes); - int32_t numOfFields = taos_num_fields(pRes); - - int rows = 0; - char str[512] = {0}; - while ((pRow = taos_fetch_row(pRes)) != NULL) { - rows++; - } - ASSERT_TRUE(rows == 1); - - taos_free_result(pRes); - - char sql[256] = {0}; - (void)sprintf(sql, "insert into db1.t1 values('2023-09-16 17:00:01', 1)"); - pRes = taos_query(pConn, sql); - ASSERT_EQ(taos_errno(pRes), TSDB_CODE_SUCCESS); - - taos_free_result(pRes); + TAOS* pConn = optionFunc("UTC+8"); + check_timezone(pConn, "show local variables", "UTC+8"); + checkRows(pConn, "select * from db1.t1 where ts == '2023-09-16 01:00:00'", 1); + execQuery(pConn, "insert into db1.t1 values('2023-09-16 17:00:01', 1)"); taos_close(pConn); } { - // taos_options( TSDB_OPTION_TIMEZONE, "UTC+0"); - int code = taos_options(TSDB_OPTION_TIMEZONE, "UTC+0"); - ASSERT_TRUE(code == 0); - TAOS* pConn = taos_connect("localhost", "root", "taosdata", NULL, 0); - ASSERT_NE(pConn, nullptr); - - TAOS_RES* pRes = taos_query(pConn, "select * from db1.t1 where ts == '2023-09-16 09:00:00'"); - ASSERT_EQ(taos_errno(pRes), TSDB_CODE_SUCCESS); - - TAOS_ROW pRow = NULL; - TAOS_FIELD* pFields = taos_fetch_fields(pRes); - int32_t numOfFields = taos_num_fields(pRes); - - int rows = 0; - char str[512] = {0}; - while ((pRow = taos_fetch_row(pRes)) != NULL) { - rows++; - } - ASSERT_TRUE(rows == 1); - taos_free_result(pRes); - - { - TAOS_RES* pRes = taos_query(pConn, "select * from db1.t1 where ts == '2023-09-17 01:00:01'"); - ASSERT_EQ(taos_errno(pRes), TSDB_CODE_SUCCESS); - - TAOS_ROW pRow = NULL; - TAOS_FIELD* pFields = taos_fetch_fields(pRes); - int32_t numOfFields = taos_num_fields(pRes); - - int rows = 0; - char str[512] = {0}; - while ((pRow = taos_fetch_row(pRes)) != NULL) { - rows++; - } - ASSERT_TRUE(rows == 1); - taos_free_result(pRes); - } + TAOS* pConn = optionFunc("UTC+0"); + check_timezone(pConn, "show local variables", "UTC+0"); + checkRows(pConn, "select * from db1.t1 where ts == '2023-09-16 09:00:00'", 1); + checkRows(pConn, "select * from db1.t1 where ts == '2023-09-17 01:00:01'", 1); taos_close(pConn); } } +TEST(clientCase, set_timezone_Test) { + check_set_timezone(getConnWithGlobalOption); + check_set_timezone(getConnWithOption); +} + +TEST(clientCase, alter_timezone_Test) { + TAOS* pConn = getConnWithGlobalOption("UTC-8"); + check_timezone(pConn, "show local variables", "UTC-8"); + + execQuery(pConn, "alter local 'timezone Asia/Kolkata'"); + check_timezone(pConn, "show local variables", "Asia/Kolkata"); + + execQueryFail(pConn, "alter dnode 1 'timezone Asia/Kolkata'"); +} + +struct insert_params +{ + const char *tz; + const char *tbname; + const char *t1; + const char *t2; +}; + +struct insert_params params1[] = { + {"UTC", "ntb", "2023-09-16 17:00:00", "2023-09-16 17:00:00+08:00"}, + {"UTC", "ctb1", "2023-09-16 17:00:00", "2023-09-16 17:00:00+08:00"}, +}; + +struct insert_params params2[] = { + {"UTC+9", "ntb", "2023-09-16 08:00:00", "2023-09-16 08:00:00-01:00"}, + {"UTC+9", "ctb1", "2023-09-16 08:00:00", "2023-09-16 11:00:00+02:00"}, +}; + +void do_insert(struct insert_params params){ + TAOS* pConn = getConnWithOption(params.tz); + char sql[1024] = {0}; + (void)snprintf(sql, sizeof(sql), "insert into db1.%s values('%s', '%s', 1)", params.tbname, params.t1, params.t2); + execQuery(pConn, sql); + taos_close(pConn); +} + +void do_select(struct insert_params params){ + TAOS* pConn = getConnWithOption(params.tz); + char sql[1024] = {0}; + (void)snprintf(sql, sizeof(sql), "select * from db1.%s where ts == '%s' and c1 == '%s'", params.tbname, params.t1, params.t2); + checkRows(pConn, sql, 1); + taos_close(pConn); +} + +// test insert string and integer to timestamp both normal table and child table(and tag) +TEST(clientCase, insert_with_timezone_Test) { + /* + * 1. prepare data, create db and tables + */ + TAOS* pConn1 = getConnWithOption("UTC+2"); + execQuery(pConn1, "drop database if exists db1"); + execQuery(pConn1, "create database db1"); + execQuery(pConn1, "create table db1.ntb (ts timestamp, c1 timestamp, c2 int)"); + execQuery(pConn1, "create table db1.stb (ts timestamp, c1 timestamp, c2 int) tags(t1 timestamp, t2 timestamp, t3 int)"); + execQuery(pConn1, "create table db1.ctb1 using db1.stb tags(\"2023-09-16 17:00:00+05:00\", \"2023-09-16 17:00:00\", 1)"); + execQuery(pConn1, "create table db1.ctb2 using db1.stb tags(1732178775000, 1732178775000, 1)"); + execQuery(pConn1, "insert into db1.ntb values(1732178775133, 1732178775133, 1)"); + execQuery(pConn1, "insert into db1.ctb1 values(1732178775133, 1732178775133, 1)"); + execQuery(pConn1, "insert into db1.ctb2 values(1732178775133, 1732178775133, 1)"); + + /* + * 2. test tag and timestamp with integer format + */ + TAOS* pConn2 = getConnWithOption("UTC-2"); + checkRows(pConn2, "select * from db1.stb where t1 == '2023-09-16 17:00:00+05:00' and t2 == '2023-09-16 21:00:00'", 1); + checkRows(pConn2, "select * from db1.stb where t1 == '2024-11-21 16:46:15+08:00' and t2 == '2024-11-21 09:46:15+01:00'", 1); + checkRows(pConn2, "select * from db1.ntb where ts == '2024-11-21 09:46:15.133+01:00' and c1 == '2024-11-21 10:46:15.133'", 1); + checkRows(pConn2, "select * from db1.ctb1 where ts == '2024-11-21 09:46:15.133+01:00' and c1 == '2024-11-21 10:46:15.133'", 1); + + check_sql_result(pConn2, "select TO_ISO8601(ts) from db1.ctb1", "2024-11-21T10:46:15.133+0200"); // 2024-01-01 23:00:00+0200 + + + /* + * 3. test timestamp with string format + */ + for (unsigned int i = 0; i < sizeof (params1) / sizeof (params1[0]); ++i){ + do_insert(params1[i]); + do_select(params1[i]); + do_select(params2[i]); + } + + /* + * 4. test NULL timezone, use default timezone UTC-8 + */ + TAOS* pConn3 = getConnWithOption(NULL); + checkRows(pConn3, "select * from db1.stb where t1 == '2023-09-16 20:00:00' and t2 == '2023-09-17 03:00:00'", 2); + checkRows(pConn3, "select * from db1.stb where t1 == 1732178775000 and t2 == 1732178775000", 1); + checkRows(pConn3, "select * from db1.ntb where ts == '2024-11-21 16:46:15.133' and c1 == '2024-11-21 16:46:15.133'", 1); + checkRows(pConn3, "select * from db1.ctb1 where ts == '2023-09-17 01:00:00' and c1 == '2023-09-16 17:00:00'", 1); + + /* + * 5. test multi connection with different timezone + */ + checkRows(pConn2, "select * from db1.ctb1 where ts == '2024-11-21 09:46:15.133+01:00' and c1 == '2024-11-21 10:46:15.133'", 1); + checkRows(pConn1, "select * from db1.ctb1 where ts == '2024-11-21 09:46:15.133+01:00' and c1 == '2024-11-21 06:46:15.133'", 1); + + taos_close(pConn1); + taos_close(pConn2); + taos_close(pConn3); +} + +TEST(clientCase, func_timezone_Test) { + TAOS* pConn = getConnWithGlobalOption("UTC+8"); + check_sql_result(pConn, "select timezone()", "UTC+8 (UTC, -0800)"); + taos_close(pConn); + + pConn = getConnWithOption("UTC-2"); + + execQuery(pConn, "drop database if exists db1"); + execQuery(pConn, "create database db1"); + execQuery(pConn, "create table db1.ntb (ts timestamp, c1 binary(32), c2 int)"); + execQuery(pConn, "insert into db1.ntb values(1704142800000, '2024-01-01 23:00:00', 1)"); // 2024-01-01 23:00:00+0200 + + // test timezone + check_sql_result(pConn, "select timezone()", "UTC-test (UTC, +0200)"); + + // test timetruncate + check_sql_result(pConn, "select TO_ISO8601(TIMETRUNCATE('2024-01-01 23:00:00', 1d, 0))", "2024-01-01T02:00:00.000+0200"); + check_sql_result(pConn, "select TO_ISO8601(TIMETRUNCATE('2024-01-01 01:00:00', 1d, 0))", "2023-12-31T02:00:00.000+0200"); + check_sql_result(pConn, "select TO_ISO8601(TIMETRUNCATE('2024-01-01 01:00:00+0300', 1d, 0))", "2023-12-31T02:00:00.000+0200"); + check_sql_result(pConn, "select TO_ISO8601(TIMETRUNCATE('2024-01-01 01:00:00-0300', 1d, 0))", "2024-01-01T02:00:00.000+0200"); + + check_sql_result(pConn, "select TO_ISO8601(TIMETRUNCATE('2024-01-04 23:00:00', 1w, 0))", "2024-01-04T02:00:00.000+0200"); + check_sql_result(pConn, "select TO_ISO8601(TIMETRUNCATE('2024-01-04 01:00:00', 1w, 0))", "2023-12-28T02:00:00.000+0200"); + check_sql_result(pConn, "select TO_ISO8601(TIMETRUNCATE('2024-01-04 01:00:00+0300', 1w, 0))", "2023-12-28T02:00:00.000+0200"); + check_sql_result(pConn, "select TO_ISO8601(TIMETRUNCATE('2024-01-04 01:00:00-0300', 1w, 0))", "2024-01-04T02:00:00.000+0200"); + + check_sql_result(pConn, "select TO_ISO8601(TIMETRUNCATE('2024-01-01 23:00:00', 1d, 1))", "2024-01-01T00:00:00.000+0200"); + check_sql_result(pConn, "select TO_ISO8601(TIMETRUNCATE('2024-01-01 01:00:00', 1d, 1))", "2024-01-01T00:00:00.000+0200"); + check_sql_result(pConn, "select TO_ISO8601(TIMETRUNCATE('2024-01-01 01:00:00+0500', 1d, 1))", "2023-12-31T00:00:00.000+0200"); + check_sql_result(pConn, "select TO_ISO8601(TIMETRUNCATE('2024-01-01 01:00:00-0300', 1d, 1))", "2024-01-01T00:00:00.000+0200"); + + check_sql_result(pConn, "select TO_ISO8601(TIMETRUNCATE('2024-01-04 23:00:00', 1w, 1))", "2024-01-04T00:00:00.000+0200"); + check_sql_result(pConn, "select TO_ISO8601(TIMETRUNCATE('2024-01-04 01:00:00', 1w, 1))", "2024-01-04T00:00:00.000+0200"); + check_sql_result(pConn, "select TO_ISO8601(TIMETRUNCATE('2024-01-04 01:00:00+0500', 1w, 1))", "2023-12-28T00:00:00.000+0200"); + check_sql_result(pConn, "select TO_ISO8601(TIMETRUNCATE('2024-01-04 01:00:00-0300', 1w, 1))", "2024-01-04T00:00:00.000+0200"); + + check_sql_result(pConn, "select TO_ISO8601(TIMETRUNCATE(1704142800000, 1d, 0))", "2024-01-01T02:00:00.000+0200"); // 2024-01-01 23:00:00+0200 + check_sql_result(pConn, "select TO_ISO8601(TIMETRUNCATE(ts, 1w, 1)) from db1.ntb", "2023-12-28T00:00:00.000+0200"); // 2024-01-01 23:00:00+0200 + +// int64_t now = get_sql_result(pConn, "select now(),now() + 2d"); +// int64_t locationNow = now + 2 * 3600; +// check_sql_result_partial(pConn, "select TO_ISO8601(today())", "T00:00:00.000+0200"); // 2024-01-01 23:00:00+0200 +// check_sql_result_partial(pConn, "select TO_ISO8601(now())", "+0200"); // 2024-01-01 23:00:00+0200 + + // WEEKDAY + check_sql_result_integer(pConn, "select WEEKDAY('2024-01-01')", 0); + check_sql_result_integer(pConn, "select WEEKDAY('2024-01-01 03:00:00')", 0); + check_sql_result_integer(pConn, "select WEEKDAY('2024-01-01 23:00:00+0200')", 0); + check_sql_result_integer(pConn, "select WEEKDAY('2024-01-01 23:00:00-1100')", 1); + check_sql_result_integer(pConn, "select WEEKDAY(1704142800000)", 0); + check_sql_result_integer(pConn, "select WEEKDAY(ts) from db1.ntb", 1); + + // DAYOFWEEK + check_sql_result_integer(pConn, "select DAYOFWEEK('2024-01-01')", 2); + check_sql_result_integer(pConn, "select DAYOFWEEK('2024-01-01 03:00:00')", 2); + check_sql_result_integer(pConn, "select DAYOFWEEK('2024-01-01 23:00:00+0200')", 2); + check_sql_result_integer(pConn, "select DAYOFWEEK('2024-01-01 23:00:00-1100')", 3); + check_sql_result_integer(pConn, "select DAYOFWEEK(1704142800000)", 2); + check_sql_result_integer(pConn, "select DAYOFWEEK(ts) from db1.ntb", 3); + + // WEEK + check_sql_result_integer(pConn, "select WEEK('2024-01-07')", 1); + check_sql_result_integer(pConn, "select WEEK('2024-01-07 02:00:00')", 1); + check_sql_result_integer(pConn, "select WEEK('2024-01-07 02:00:00+0200')", 1); + check_sql_result_integer(pConn, "select WEEK('2024-01-07 02:00:00+1100')", 0); + check_sql_result_integer(pConn, "select WEEK(1704142800000)", 0); // 2024-01-01 23:00:00+0200 + check_sql_result_integer(pConn, "select WEEK(ts) from db1.ntb", 0); // 2024-01-01 23:00:00+0200 + + check_sql_result_integer(pConn, "select WEEK('2024-01-07', 3)", 1); + check_sql_result_integer(pConn, "select WEEK('2024-01-07 02:00:00', 3)", 1); + check_sql_result_integer(pConn, "select WEEK('2024-01-07 02:00:00+0200', 3)", 1); + check_sql_result_integer(pConn, "select WEEK('2024-01-01 02:00:00+1100', 3)", 52); + check_sql_result_integer(pConn, "select WEEK(1704142800000, 3)", 1); // 2024-01-01 23:00:00+0200 + check_sql_result_integer(pConn, "select WEEK(ts, 3) from db1.ntb", 1); // 2024-01-01 23:00:00+0200 + + // WEEKOFYEAR + check_sql_result_integer(pConn, "select WEEKOFYEAR('2024-01-07')", 1); + check_sql_result_integer(pConn, "select WEEKOFYEAR('2024-01-07 02:00:00')", 1); + check_sql_result_integer(pConn, "select WEEKOFYEAR('2024-01-07 02:00:00+0200')", 1); + check_sql_result_integer(pConn, "select WEEKOFYEAR('2024-01-01 02:00:00+1100')", 52); + check_sql_result_integer(pConn, "select WEEKOFYEAR(1704142800000)", 1); // 2024-01-01 23:00:00+0200 + check_sql_result_integer(pConn, "select WEEKOFYEAR(ts) from db1.ntb", 1); // 2024-01-01 23:00:00+0200 + + // TO_ISO8601 + check_sql_result(pConn, "select TO_ISO8601(ts) from db1.ntb", "2024-01-01T23:00:00.000+0200"); + check_sql_result(pConn, "select TO_ISO8601(ts,'-08') from db1.ntb", "2024-01-01T13:00:00.000-08"); + check_sql_result(pConn, "select TO_ISO8601(1)", "1970-01-01T02:00:00.001+0200"); + check_sql_result(pConn, "select TO_ISO8601(1,'+0800')", "1970-01-01T08:00:00.001+0800"); + + // TO_UNIXTIMESTAMP + check_sql_result_integer(pConn, "select TO_UNIXTIMESTAMP(c1) from db1.ntb", 1704121200000); // use timezone in server UTC-8 + check_sql_result_integer(pConn, "select TO_UNIXTIMESTAMP('2024-01-01T23:00:00.000+0200')", 1704142800000); + check_sql_result_integer(pConn, "select TO_UNIXTIMESTAMP('2024-01-01T13:00:00.000-08')", 1704142800000); + check_sql_result_integer(pConn, "select TO_UNIXTIMESTAMP('2024-01-01T23:00:00.001')", 1704142800001); + + // TO_TIMESTAMP + check_sql_result_integer(pConn, "select TO_TIMESTAMP(c1,'yyyy-mm-dd hh24:mi:ss') from db1.ntb", 1704121200000); // use timezone in server UTC-8 + check_sql_result_integer(pConn, "select TO_TIMESTAMP('2024-01-01 23:00:00+02:00', 'yyyy-mm-dd hh24:mi:ss tzh')", 1704142800000); + check_sql_result_integer(pConn, "select TO_TIMESTAMP('2024-01-01T13:00:00-08', 'yyyy-mm-ddThh24:mi:ss tzh')", 1704142800000); + check_sql_result_integer(pConn, "select TO_TIMESTAMP('2024/01/01 23:00:00', 'yyyy/mm/dd hh24:mi:ss')", 1704142800000); + + // TO_CHAR + check_sql_result(pConn, "select TO_CHAR(ts,'yyyy-mm-dd hh24:mi:ss') from db1.ntb", "2024-01-02 05:00:00"); // use timezone in server UTC-8 + check_sql_result(pConn, "select TO_CHAR(cast(1704142800000 as timestamp), 'yyyy-mm-dd hh24:mi:ss tzh')", "2024-01-01 23:00:00 +02"); + check_sql_result(pConn, "select TO_CHAR(cast(1704142800000 as timestamp), 'yyyy-mm-dd hh24:mi:ss')", "2024-01-01 23:00:00"); + + taos_close(pConn); + +} + time_t time_winter = 1731323281; // 2024-11-11 19:08:01+0800 time_t time_summer = 1731323281 - 120 * 24 * 60 * 60; @@ -1697,7 +1922,7 @@ TEST(clientCase, mktime_Test){ for (unsigned int i = 0; i < sizeof (test_mk) / sizeof (test_mk[0]); ++i) { setenv ("TZ", test_mk[i].env, 1); - t = taosMktime (&tm); + t = taosMktime (&tm, NULL); ASSERT (t == test_mk[i].expected); } } @@ -1719,7 +1944,7 @@ TEST(clientCase, mktime_rz_Test){ { timezone_t tz = tzalloc(test_mk[i].env); ASSERT(tz); - t = taosMktimeRz(tz, &tm); + t = taosMktime(&tm, tz); ASSERT (t == test_mk[i].expected); tzfree(tz); } @@ -1739,13 +1964,12 @@ TEST(testCase, localtime_performance_Test) { for (int j = 0; j < cnt; ++j) { time_t t = time_winter - j; struct tm tm1; - ASSERT (taosLocalTime(&t, &tm1, NULL, 0)); + ASSERT (taosLocalTime(&t, &tm1, NULL, 0, NULL)); } int64_t tmp = taosGetTimestampNs() - t1; printf("localtime cost:%" PRId64 " ns, run %" PRId64 " times", tmp, cnt); time_localtime += tmp/cnt; - timezone; printf("\n"); @@ -1754,7 +1978,7 @@ TEST(testCase, localtime_performance_Test) { for (int j = 0; j < cnt; ++j) { time_t t = time_winter - j; struct tm tm1; - ASSERT (taosLocalTimeRz(sp, &t, &tm1)); + ASSERT (taosLocalTime(&t, &tm1, NULL, 0, sp)); } tmp = taosGetTimestampNs() - t2; printf("localtime_rz cost:%" PRId64 " ns, run %" PRId64 " times", tmp, cnt); @@ -1765,4 +1989,5 @@ TEST(testCase, localtime_performance_Test) { tzfree(sp); } + #pragma GCC diagnostic pop diff --git a/source/common/src/tdatablock.c b/source/common/src/tdatablock.c index 60d1f34cf7..d0f02835e8 100644 --- a/source/common/src/tdatablock.c +++ b/source/common/src/tdatablock.c @@ -2473,7 +2473,7 @@ static int32_t formatTimestamp(char* buf, size_t cap, int64_t val, int precision } } struct tm ptm = {0}; - if (taosLocalTime(&tt, &ptm, buf, cap) == NULL) { + if (taosLocalTime(&tt, &ptm, buf, cap, NULL) == NULL) { code = TSDB_CODE_INTERNAL_ERROR; TSDB_CHECK_CODE(code, lino, _end); } diff --git a/source/common/src/tglobal.c b/source/common/src/tglobal.c index 57b3a7d67c..3641f3232c 100644 --- a/source/common/src/tglobal.c +++ b/source/common/src/tglobal.c @@ -2231,7 +2231,9 @@ static int32_t taosCfgDynamicOptionsForClient(SConfig *pCfg, const char *name) { break; } case 't': { - if (strcasecmp("tempDir", name) == 0) { + if (strcasecmp("timezone", name) == 0) { + matched = true; + } else if (strcasecmp("tempDir", name) == 0) { uInfo("%s set from %s to %s", name, tsTempDir, pItem->str); tstrncpy(tsTempDir, pItem->str, PATH_MAX); TAOS_CHECK_GOTO(taosExpandDir(tsTempDir, tsTempDir, PATH_MAX), &lino, _out); diff --git a/source/common/src/tmisce.c b/source/common/src/tmisce.c index 10375ba857..03918ff6f8 100644 --- a/source/common/src/tmisce.c +++ b/source/common/src/tmisce.c @@ -292,7 +292,10 @@ int32_t dumpConfToDataBlock(SSDataBlock* pBlock, int32_t startCol) { char value[TSDB_CONFIG_VALUE_LEN + VARSTR_HEADER_SIZE] = {0}; int32_t valueLen = 0; - TAOS_CHECK_GOTO(cfgDumpItemValue(pItem, &value[VARSTR_HEADER_SIZE], TSDB_CONFIG_VALUE_LEN, &valueLen), NULL, _exit); + if (pItem->dtype == CFG_DTYPE_TIMEZONE){ + + } + TAOS_CHECK_GOTO(cfgDumpItemValue(pItem, varDataVal(value), TSDB_CONFIG_VALUE_LEN, &valueLen), NULL, _exit); varDataSetLen(value, valueLen); pColInfo = taosArrayGet(pBlock->pDataBlock, col++); diff --git a/source/common/src/tname.c b/source/common/src/tname.c index 964741e2c4..9ced37eb38 100644 --- a/source/common/src/tname.c +++ b/source/common/src/tname.c @@ -20,73 +20,6 @@ #define VALID_NAME_TYPE(x) ((x) == TSDB_DB_NAME_T || (x) == TSDB_TABLE_NAME_T) -#if 0 -int64_t taosGetIntervalStartTimestamp(int64_t startTime, int64_t slidingTime, int64_t intervalTime, char timeUnit, int16_t precision) { - if (slidingTime == 0) { - return startTime; - } - int64_t start = startTime; - if (timeUnit == 'n' || timeUnit == 'y') { - start /= 1000; - if (precision == TSDB_TIME_PRECISION_MICRO) { - start /= 1000; - } - struct tm tm; - time_t t = (time_t)start; - taosLocalTime(&t, &tm, NULL, 0); - tm.tm_sec = 0; - tm.tm_min = 0; - tm.tm_hour = 0; - tm.tm_mday = 1; - - if (timeUnit == 'y') { - tm.tm_mon = 0; - tm.tm_year = (int)(tm.tm_year / slidingTime * slidingTime); - } else { - int mon = tm.tm_year * 12 + tm.tm_mon; - mon = (int)(mon / slidingTime * slidingTime); - tm.tm_year = mon / 12; - tm.tm_mon = mon % 12; - } - - start = mktime(&tm) * 1000L; - if (precision == TSDB_TIME_PRECISION_MICRO) { - start *= 1000L; - } - } else { - int64_t delta = startTime - intervalTime; - int32_t factor = delta > 0? 1:-1; - - start = (delta / slidingTime + factor) * slidingTime; - - if (timeUnit == 'd' || timeUnit == 'w') { - /* - * here we revised the start time of day according to the local time zone, - * but in case of DST, the start time of one day need to be dynamically decided. - */ - // todo refactor to extract function that is available for Linux/Windows/Mac platform -#if defined(WINDOWS) && _MSC_VER >= 1900 - // see https://docs.microsoft.com/en-us/cpp/c-runtime-library/daylight-dstbias-timezone-and-tzname?view=vs-2019 - int64_t timezone = _timezone; - int32_t daylight = _daylight; - char** tzname = _tzname; -#endif - - int64_t t = (precision == TSDB_TIME_PRECISION_MILLI) ? MILLISECOND_PER_SECOND : MILLISECOND_PER_SECOND * 1000L; - start += timezone * t; - } - - int64_t end = start + intervalTime - 1; - if (end < startTime) { - start += slidingTime; - } - } - - return start; -} - -#endif - void toName(int32_t acctId, const char* pDbName, const char* pTableName, SName* pName) { if (pName == NULL){ return; diff --git a/source/common/src/ttime.c b/source/common/src/ttime.c index c18ac32e46..574b2d2fce 100644 --- a/source/common/src/ttime.c +++ b/source/common/src/ttime.c @@ -27,28 +27,24 @@ static int32_t parseFraction(char* str, char** end, int32_t timePrec, int64_t* pFraction); static int32_t parseTimeWithTz(const char* timestr, int64_t* time, int32_t timePrec, char delim); -static int32_t parseLocaltime(char* timestr, int32_t len, int64_t* utime, int32_t timePrec, char delim); -static int32_t parseLocaltimeDst(char* timestr, int32_t len, int64_t* utime, int32_t timePrec, char delim); +static int32_t parseLocaltimeDst(char* timestr, int32_t len, int64_t* utime, int32_t timePrec, char delim, timezone_t tz); static char* forwardToTimeStringEnd(char* str); static bool checkTzPresent(const char* str, int32_t len); static int32_t parseTimezone(char* str, int64_t* tzOffset); -static int32_t (*parseLocaltimeFp[])(char* timestr, int32_t len, int64_t* utime, int32_t timePrec, char delim) = { - parseLocaltime, parseLocaltimeDst}; - -int32_t taosParseTime(const char* timestr, int64_t* utime, int32_t len, int32_t timePrec) { +int32_t taosParseTime(const char* timestr, int64_t* utime, int32_t len, int32_t timePrec, timezone_t tz) { /* parse datatime string in with tz */ if (strnchr(timestr, 'T', len, false) != NULL) { if (checkTzPresent(timestr, len)) { return parseTimeWithTz(timestr, utime, timePrec, 'T'); } else { - return parseLocaltimeDst((char*)timestr, len, utime, timePrec, 'T'); + return parseLocaltimeDst((char*)timestr, len, utime, timePrec, 'T', tz); } } else { if (checkTzPresent(timestr, len)) { return parseTimeWithTz(timestr, utime, timePrec, 0); } else { - return parseLocaltimeDst((char*)timestr, len, utime, timePrec, 0); + return parseLocaltimeDst((char*)timestr, len, utime, timePrec, 0, tz); } } } @@ -165,7 +161,7 @@ int32_t parseTimezone(char* str, int64_t* tzOffset) { i += 2; } - if (hour > 12 || hour < 0) { + if (hour > 13 || hour < 0) { TAOS_RETURN(TSDB_CODE_INVALID_PARA); } @@ -176,7 +172,7 @@ int32_t parseTimezone(char* str, int64_t* tzOffset) { } int64_t minute = strnatoi(&str[i], 2); - if (minute > 59 || (hour == 12 && minute > 0)) { + if (minute > 59 || minute < 0) { TAOS_RETURN(TSDB_CODE_INVALID_PARA); } @@ -233,7 +229,10 @@ int32_t parseTimeWithTz(const char* timestr, int64_t* time, int32_t timePrec, ch int64_t seconds = user_mktime64(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, 0); // int64_t seconds = gmtime(&tm); #else - int64_t seconds = timegm(&tm); + int64_t seconds = taosTimeGm(&tm); + if (seconds == -1){ + TAOS_RETURN(TAOS_SYSTEM_ERROR(errno)); + } #endif int64_t fraction = 0; @@ -298,48 +297,7 @@ static FORCE_INLINE bool validateTm(struct tm* pTm) { return true; } -int32_t parseLocaltime(char* timestr, int32_t len, int64_t* utime, int32_t timePrec, char delim) { - *utime = 0; - struct tm tm = {0}; - - char* str; - if (delim == 'T') { - str = taosStrpTime(timestr, "%Y-%m-%dT%H:%M:%S", &tm); - } else if (delim == 0) { - str = taosStrpTime(timestr, "%Y-%m-%d %H:%M:%S", &tm); - } else { - str = NULL; - } - - if (str == NULL || (((str - timestr) < len) && (*str != '.')) || !validateTm(&tm)) { - // if parse failed, try "%Y-%m-%d" format - str = taosStrpTime(timestr, "%Y-%m-%d", &tm); - if (str == NULL || (((str - timestr) < len) && (*str != '.')) || !validateTm(&tm)) { - TAOS_RETURN(TSDB_CODE_INVALID_PARA); - } - } - -#ifdef _MSC_VER -#if _MSC_VER >= 1900 - int64_t timezone = _timezone; -#endif -#endif - - int64_t seconds = - user_mktime64(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, timezone); - - int64_t fraction = 0; - - if (*str == '.') { - /* parse the second fraction part */ - TAOS_CHECK_RETURN(parseFraction(str + 1, &str, timePrec, &fraction)); - } - - *utime = TSDB_TICK_PER_SECOND(timePrec) * seconds + fraction; - TAOS_RETURN(TSDB_CODE_SUCCESS); -} - -int32_t parseLocaltimeDst(char* timestr, int32_t len, int64_t* utime, int32_t timePrec, char delim) { +int32_t parseLocaltimeDst(char* timestr, int32_t len, int64_t* utime, int32_t timePrec, char delim, timezone_t tz) { *utime = 0; struct tm tm = {0}; tm.tm_isdst = -1; @@ -361,8 +319,7 @@ int32_t parseLocaltimeDst(char* timestr, int32_t len, int64_t* utime, int32_t ti } } - /* mktime will be affected by TZ, set by using taos_options */ - int64_t seconds = taosMktime(&tm); //tztodo + int64_t seconds = taosMktime(&tm, tz); int64_t fraction = 0; if (*str == '.') { @@ -523,7 +480,7 @@ int32_t convertTimeFromPrecisionToUnit(int64_t time, int32_t fromPrecision, char TAOS_RETURN(TSDB_CODE_SUCCESS); } -int32_t convertStringToTimestamp(int16_t type, char* inputData, int64_t timePrec, int64_t* timeVal) { +int32_t convertStringToTimestamp(int16_t type, char* inputData, int64_t timePrec, int64_t* timeVal, timezone_t tz) { int32_t charLen = varDataLen(inputData); char* newColData; if (type == TSDB_DATA_TYPE_BINARY || type == TSDB_DATA_TYPE_VARBINARY) { @@ -532,7 +489,7 @@ int32_t convertStringToTimestamp(int16_t type, char* inputData, int64_t timePrec TAOS_RETURN(terrno); } (void)memcpy(newColData, varDataVal(inputData), charLen); - int32_t ret = taosParseTime(newColData, timeVal, charLen, (int32_t)timePrec); + int32_t ret = taosParseTime(newColData, timeVal, charLen, (int32_t)timePrec, tz); if (ret != TSDB_CODE_SUCCESS) { taosMemoryFree(newColData); TAOS_RETURN(TSDB_CODE_INVALID_TIMESTAMP); @@ -549,7 +506,7 @@ int32_t convertStringToTimestamp(int16_t type, char* inputData, int64_t timePrec TAOS_RETURN(TSDB_CODE_FAILED); } newColData[len] = 0; - int32_t ret = taosParseTime(newColData, timeVal, len, (int32_t)timePrec); + int32_t ret = taosParseTime(newColData, timeVal, len, (int32_t)timePrec, tz); if (ret != TSDB_CODE_SUCCESS) { taosMemoryFree(newColData); TAOS_RETURN(ret); @@ -681,7 +638,10 @@ int64_t taosTimeAdd(int64_t t, int64_t duration, char unit, int32_t precision) { struct tm tm; time_t tt = (time_t)(t / TSDB_TICK_PER_SECOND(precision)); - struct tm* ptm = taosLocalTime(&tt, &tm, NULL, 0); + if(taosGmTimeR(&tt, &tm) == NULL) { + uError("failed to convert time to gm time, code:%d", errno); + return t; + } int32_t mon = tm.tm_year * 12 + tm.tm_mon + (int32_t)numOfMonth; tm.tm_year = mon / 12; tm.tm_mon = mon % 12; @@ -692,7 +652,12 @@ int64_t taosTimeAdd(int64_t t, int64_t duration, char unit, int32_t precision) { if (tm.tm_mday > daysOfMonth[tm.tm_mon]) { tm.tm_mday = daysOfMonth[tm.tm_mon]; } - return (int64_t)(taosMktime(&tm) * TSDB_TICK_PER_SECOND(precision) + fraction); + tt = taosTimeGm(&tm); + if (tt == -1){ + uError("failed to convert gm time to time, code:%d", errno); + return t; + } + return (int64_t)(tt * TSDB_TICK_PER_SECOND(precision) + fraction); } /** @@ -731,7 +696,7 @@ int32_t taosTimeCountIntervalForFill(int64_t skey, int64_t ekey, int64_t interva ekey = skey; skey = tmp; } - int32_t ret; + int32_t ret = 0; if (unit != 'n' && unit != 'y') { ret = (int32_t)((ekey - skey) / interval); @@ -742,11 +707,17 @@ int32_t taosTimeCountIntervalForFill(int64_t skey, int64_t ekey, int64_t interva struct tm tm; time_t t = (time_t)skey; - struct tm* ptm = taosLocalTime(&t, &tm, NULL, 0); + if (taosLocalTime(&t, &tm, NULL, 0, NULL) == NULL) { + uError("%s failed to convert time to local time, code:%d", __FUNCTION__, errno); + return ret; + } int32_t smon = tm.tm_year * 12 + tm.tm_mon; t = (time_t)ekey; - ptm = taosLocalTime(&t, &tm, NULL, 0); + if (taosLocalTime(&t, &tm, NULL, 0, NULL) == NULL) { + uError("%s failed to convert time to local time, code:%d", __FUNCTION__, errno); + return ret; + } int32_t emon = tm.tm_year * 12 + tm.tm_mon; if (unit == 'y') { @@ -770,7 +741,10 @@ int64_t taosTimeTruncate(int64_t ts, const SInterval* pInterval) { start /= (int64_t)(TSDB_TICK_PER_SECOND(precision)); struct tm tm; time_t tt = (time_t)start; - struct tm* ptm = taosLocalTime(&tt, &tm, NULL, 0); + if (taosLocalTime(&tt, &tm, NULL, 0, NULL) == NULL){ + uError("%s failed to convert time to local time, code:%d", __FUNCTION__, errno); + return ts; + } tm.tm_sec = 0; tm.tm_min = 0; tm.tm_hour = 0; @@ -786,7 +760,12 @@ int64_t taosTimeTruncate(int64_t ts, const SInterval* pInterval) { tm.tm_mon = mon % 12; } - start = (int64_t)(taosMktime(&tm) * TSDB_TICK_PER_SECOND(precision)); + tt = taosMktime(&tm, NULL); + if (tt == -1){ + uError("%s failed to convert local time to time, code:%d", __FUNCTION__, errno); + return ts; + } + start = (int64_t)(tt * TSDB_TICK_PER_SECOND(precision)); } else { if (IS_CALENDAR_TIME_DURATION(pInterval->intervalUnit)) { int64_t news = (ts / pInterval->sliding) * pInterval->sliding; @@ -931,7 +910,7 @@ int32_t taosFormatUtcTime(char* buf, int32_t bufLen, int64_t t, int32_t precisio TAOS_RETURN(TSDB_CODE_INVALID_PARA); } - if (NULL == taosLocalTime(", &ptm, buf, bufLen)) { + if (NULL == taosLocalTime(", &ptm, buf, bufLen, NULL)) { TAOS_RETURN(TAOS_SYSTEM_ERROR(errno)); } int32_t length = (int32_t)strftime(ts, 40, "%Y-%m-%dT%H:%M:%S", &ptm); @@ -942,17 +921,17 @@ int32_t taosFormatUtcTime(char* buf, int32_t bufLen, int64_t t, int32_t precisio TAOS_RETURN(TSDB_CODE_SUCCESS); } -int32_t taosTs2Tm(int64_t ts, int32_t precision, struct STm* tm) { +int32_t taosTs2Tm(int64_t ts, int32_t precision, struct STm* tm, timezone_t tz) { tm->fsec = ts % TICK_PER_SECOND[precision] * (TICK_PER_SECOND[TSDB_TIME_PRECISION_NANO] / TICK_PER_SECOND[precision]); time_t t = ts / TICK_PER_SECOND[precision]; - if (NULL == taosLocalTime(&t, &tm->tm, NULL, 0)) { //tztodo + if (NULL == taosLocalTime(&t, &tm->tm, NULL, 0, tz)) { TAOS_RETURN(TAOS_SYSTEM_ERROR(errno)); } return TSDB_CODE_SUCCESS; } -int32_t taosTm2Ts(struct STm* tm, int64_t* ts, int32_t precision) { - *ts = taosMktime(&tm->tm); //tztodo +int32_t taosTm2Ts(struct STm* tm, int64_t* ts, int32_t precision, timezone_t tz) { + *ts = taosMktime(&tm->tm, tz); *ts *= TICK_PER_SECOND[precision]; *ts += tm->fsec / (TICK_PER_SECOND[TSDB_TIME_PRECISION_NANO] / TICK_PER_SECOND[precision]); return TSDB_CODE_SUCCESS; @@ -1420,7 +1399,8 @@ static int32_t tm2char(const SArray* formats, const struct STm* tm, char* s, int s += 9; break; case TSFKW_TZH: - (void)sprintf(s, "%s%02d", tsTimezone < 0 ? "-" : "+", tsTimezone); + (void)sprintf(s, "%c%02d", (tm->tm.tm_gmtoff >= 0) ? '+' : '-', + abs((int) tm->tm.tm_gmtoff) / 3600); s += strlen(s); break; case TSFKW_YYYY: @@ -1552,13 +1532,13 @@ static bool needMoreDigits(SArray* formats, int32_t curIdx) { /// @retval -2 if datetime err, like 2023-13-32 25:61:69 /// @retval -3 if not supported static int32_t char2ts(const char* s, SArray* formats, int64_t* ts, int32_t precision, const char** sErrPos, - int32_t* fErrIdx) { + int32_t* fErrIdx, timezone_t tz) { int32_t size = taosArrayGetSize(formats); int32_t pm = 0; // default am int32_t hour12 = 0; // default HH24 int32_t year = 0, mon = 0, yd = 0, md = 1, wd = 0; int32_t hour = 0, min = 0, sec = 0, us = 0, ms = 0, ns = 0; - int32_t tzSign = 1, tz = tsTimezone; + int32_t tzHour = 0; int32_t err = 0; bool withYD = false, withMD = false; @@ -1685,8 +1665,7 @@ static int32_t char2ts(const char* s, SArray* formats, int64_t* ts, int32_t prec } } break; case TSFKW_TZH: { - tzSign = *s == '-' ? -1 : 1; - const char* newPos = tsFormatStr2Int32(&tz, s, -1, needMoreDigits(formats, i)); + const char* newPos = tsFormatStr2Int32(&tzHour, s, -1, needMoreDigits(formats, i)); if (NULL == newPos) err = -1; else { @@ -1839,14 +1818,16 @@ static int32_t char2ts(const char* s, SArray* formats, int64_t* ts, int32_t prec tm.tm.tm_min = min; tm.tm.tm_sec = sec; if (!checkTm(&tm.tm)) return -2; - if (tz < -12 || tz > 12) return -2; + if (tzHour < -13 || tzHour > 13) return -2; tm.fsec = ms * 1000000 + us * 1000 + ns; - int32_t ret = taosTm2Ts(&tm, ts, precision); - *ts += 60 * 60 * (tsTimezone - tz) * TICK_PER_SECOND[precision]; + int32_t ret = taosTm2Ts(&tm, ts, precision, tz); + if (tzHour != 0) { + *ts += (tm.tm.tm_gmtoff - tzHour * 3600) * TICK_PER_SECOND[precision]; + } return ret; } -int32_t taosTs2Char(const char* format, SArray** formats, int64_t ts, int32_t precision, char* out, int32_t outLen) { +int32_t taosTs2Char(const char* format, SArray** formats, int64_t ts, int32_t precision, char* out, int32_t outLen, timezone_t tz) { if (!*formats) { *formats = taosArrayInit(8, sizeof(TSFormatNode)); if (!*formats) { @@ -1855,12 +1836,12 @@ int32_t taosTs2Char(const char* format, SArray** formats, int64_t ts, int32_t pr TAOS_CHECK_RETURN(parseTsFormat(format, *formats)); } struct STm tm; - TAOS_CHECK_RETURN(taosTs2Tm(ts, precision, &tm)); + TAOS_CHECK_RETURN(taosTs2Tm(ts, precision, &tm, tz)); return tm2char(*formats, &tm, out, outLen); } int32_t taosChar2Ts(const char* format, SArray** formats, const char* tsStr, int64_t* ts, int32_t precision, - char* errMsg, int32_t errMsgLen) { + char* errMsg, int32_t errMsgLen, timezone_t tz) { const char* sErrPos; int32_t fErrIdx; if (!*formats) { @@ -1870,7 +1851,7 @@ int32_t taosChar2Ts(const char* format, SArray** formats, const char* tsStr, int } TAOS_CHECK_RETURN(parseTsFormat(format, *formats)); } - int32_t code = char2ts(tsStr, *formats, ts, precision, &sErrPos, &fErrIdx); + int32_t code = char2ts(tsStr, *formats, ts, precision, &sErrPos, &fErrIdx, tz); if (code == -1) { TSFormatNode* fNode = (taosArrayGet(*formats, fErrIdx)); snprintf(errMsg, errMsgLen, "mismatch format for: %s and %s", sErrPos, @@ -1895,7 +1876,7 @@ int32_t TEST_ts2char(const char* format, int64_t ts, int32_t precision, char* ou } TAOS_CHECK_RETURN(parseTsFormat(format, formats)); struct STm tm; - TAOS_CHECK_GOTO(taosTs2Tm(ts, precision, &tm), NULL, _exit); + TAOS_CHECK_GOTO(taosTs2Tm(ts, precision, &tm, NULL), NULL, _exit); TAOS_CHECK_GOTO(tm2char(formats, &tm, out, outLen), NULL, _exit); _exit: @@ -1908,7 +1889,7 @@ int32_t TEST_char2ts(const char* format, int64_t* ts, int32_t precision, const c int32_t fErrIdx; SArray* formats = taosArrayInit(4, sizeof(TSFormatNode)); TAOS_CHECK_RETURN(parseTsFormat(format, formats)); - int32_t code = char2ts(tsStr, formats, ts, precision, &sErrPos, &fErrIdx); + int32_t code = char2ts(tsStr, formats, ts, precision, &sErrPos, &fErrIdx, NULL); if (code == -1) { (void)printf("failed position: %s\n", sErrPos); (void)printf("failed format: %s\n", ((TSFormatNode*)taosArrayGet(formats, fErrIdx))->key->name); @@ -2024,3 +2005,26 @@ bool checkRecursiveTsmaInterval(int64_t baseInterval, int8_t baseUnit, int64_t i } return true; } + +int64_t taosGetTimestampToday(int32_t precision, timezone_t tz) { + int64_t factor = (precision == TSDB_TIME_PRECISION_SECONDS) ? 1 + : (precision == TSDB_TIME_PRECISION_MILLI) ? 1000 + : (precision == TSDB_TIME_PRECISION_MICRO) ? 1000000 + : 1000000000; + time_t t = taosTime(NULL); + struct tm tm; + if (taosLocalTime(&t, &tm, NULL, 0, tz) == NULL){ + uError("%s failed to get local time, code:%d", __FUNCTION__, errno); + return t; + } + tm.tm_hour = 0; + tm.tm_min = 0; + tm.tm_sec = 0; + + time_t tmp = taosMktime(&tm, tz); + if (tmp == (time_t)-1) { + uError("%s failed to get timestamp of today, code:%d", __FUNCTION__, errno); + return t; + } + return (int64_t)tmp * factor; +} \ No newline at end of file diff --git a/source/common/test/commonTests.cpp b/source/common/test/commonTests.cpp index 054c3d5f58..19fe6b00d3 100644 --- a/source/common/test/commonTests.cpp +++ b/source/common/test/commonTests.cpp @@ -429,9 +429,9 @@ void test_timestamp_tm_conversion(int64_t ts, int32_t precision, int32_t y, int3 struct STm tm; taosFormatUtcTime(buf, 128, ts, precision); printf("formated ts of %ld, precision: %d is: %s\n", ts, precision, buf); - taosTs2Tm(ts, precision, &tm); + taosTs2Tm(ts, precision, &tm, NULL); check_tm(&tm, y, mon, d, h, m, s, fsec); - taosTm2Ts(&tm, &ts_tmp, precision); + taosTm2Ts(&tm, &ts_tmp, precision, NULL); ASSERT_EQ(ts, ts_tmp); } @@ -442,15 +442,15 @@ TEST(timeTest, timestamp2tm) { int64_t ts, tmp_ts = 0; struct STm tm; - ASSERT_EQ(TSDB_CODE_SUCCESS, taosParseTime(ts_str_ns, &ts, strlen(ts_str_ns), TSDB_TIME_PRECISION_NANO)); + ASSERT_EQ(TSDB_CODE_SUCCESS, taosParseTime(ts_str_ns, &ts, strlen(ts_str_ns), TSDB_TIME_PRECISION_NANO, NULL)); test_timestamp_tm_conversion(ts, TSDB_TIME_PRECISION_NANO, 2023 - 1900, 9 /* mon start from 0*/, 12, 11, 29, 0, 775726171L); - ASSERT_EQ(TSDB_CODE_SUCCESS, taosParseTime(ts_str_us, &ts, strlen(ts_str_us), TSDB_TIME_PRECISION_MICRO)); + ASSERT_EQ(TSDB_CODE_SUCCESS, taosParseTime(ts_str_us, &ts, strlen(ts_str_us), TSDB_TIME_PRECISION_MICRO, NULL)); test_timestamp_tm_conversion(ts, TSDB_TIME_PRECISION_MICRO, 2023 - 1900, 9 /* mon start from 0*/, 12, 11, 29, 0, 775726000L); - ASSERT_EQ(TSDB_CODE_SUCCESS, taosParseTime(ts_str_ms, &ts, strlen(ts_str_ms), TSDB_TIME_PRECISION_MILLI)); + ASSERT_EQ(TSDB_CODE_SUCCESS, taosParseTime(ts_str_ms, &ts, strlen(ts_str_ms), TSDB_TIME_PRECISION_MILLI, NULL)); test_timestamp_tm_conversion(ts, TSDB_TIME_PRECISION_MILLI, 2023 - 1900, 9 /* mon start from 0*/, 12, 11, 29, 0, 775000000L); diff --git a/source/dnode/mgmt/mgmt_dnode/src/dmHandle.c b/source/dnode/mgmt/mgmt_dnode/src/dmHandle.c index f65fe290a2..756caad9ad 100644 --- a/source/dnode/mgmt/mgmt_dnode/src/dmHandle.c +++ b/source/dnode/mgmt/mgmt_dnode/src/dmHandle.c @@ -198,7 +198,7 @@ void dmSendStatusReq(SDnodeMgmt *pMgmt) { req.clusterCfg.monitorParas.tsSlowLogThresholdTest = tsSlowLogThresholdTest; tstrncpy(req.clusterCfg.monitorParas.tsSlowLogExceptDb, tsSlowLogExceptDb, TSDB_DB_NAME_LEN); char timestr[32] = "1970-01-01 00:00:00.00"; - if (taosParseTime(timestr, &req.clusterCfg.checkTime, (int32_t)strlen(timestr), TSDB_TIME_PRECISION_MILLI) != 0) { + if (taosParseTime(timestr, &req.clusterCfg.checkTime, (int32_t)strlen(timestr), TSDB_TIME_PRECISION_MILLI, NULL) != 0) { dError("failed to parse time since %s", tstrerror(code)); } memcpy(req.clusterCfg.timezone, tsTimezoneStr, TD_TIMEZONE_LEN); diff --git a/source/dnode/mnode/impl/src/mndMain.c b/source/dnode/mnode/impl/src/mndMain.c index c2edf6d6d8..def57a87c5 100644 --- a/source/dnode/mnode/impl/src/mndMain.c +++ b/source/dnode/mnode/impl/src/mndMain.c @@ -713,7 +713,7 @@ SMnode *mndOpen(const char *path, const SMnodeOpt *pOption) { } char timestr[24] = "1970-01-01 00:00:00.00"; - code = taosParseTime(timestr, &pMnode->checkTime, (int32_t)strlen(timestr), TSDB_TIME_PRECISION_MILLI); + code = taosParseTime(timestr, &pMnode->checkTime, (int32_t)strlen(timestr), TSDB_TIME_PRECISION_MILLI, NULL); if (code < 0) { mError("failed to parse time since %s", tstrerror(code)); (void)taosThreadRwlockDestroy(&pMnode->lock); diff --git a/source/libs/function/src/builtins.c b/source/libs/function/src/builtins.c index 6837ecbf20..4248f8a393 100644 --- a/source/libs/function/src/builtins.c +++ b/source/libs/function/src/builtins.c @@ -186,11 +186,11 @@ static int32_t countTrailingSpaces(const SValueNode* pVal, bool isLtrim) { return numOfSpaces; } -static int32_t addTimezoneParam(SNodeList* pList) { +static int32_t addTimezoneParam(SNodeList* pList, timezone_t tz) { char buf[TD_TIME_STR_LEN] = {0}; time_t t = taosTime(NULL); struct tm tmInfo; - if (taosLocalTime(&t, &tmInfo, buf, sizeof(buf)) != NULL) { + if (taosLocalTime(&t, &tmInfo, buf, sizeof(buf), tz) != NULL) { (void)strftime(buf, sizeof(buf), "%z", &tmInfo); } int32_t len = (int32_t)strlen(buf); @@ -1446,7 +1446,7 @@ static int32_t translateToIso8601(SFunctionNode* pFunc, char* pErrBuf, int32_t l return buildFuncErrMsg(pErrBuf, len, TSDB_CODE_FUNC_FUNTION_ERROR, "Invalid timzone format"); } } else { // add default client timezone - int32_t code = addTimezoneParam(pFunc->pParameterList); + int32_t code = addTimezoneParam(pFunc->pParameterList, pFunc->tz); if (code != TSDB_CODE_SUCCESS) { return code; } @@ -1501,7 +1501,7 @@ static int32_t translateTimeTruncate(SFunctionNode* pFunc, char* pErrBuf, int32_ } // add client timezone as param - code = addTimezoneParam(pFunc->pParameterList); + code = addTimezoneParam(pFunc->pParameterList, pFunc->tz); if (code != TSDB_CODE_SUCCESS) { return code; } diff --git a/source/libs/parser/inc/parUtil.h b/source/libs/parser/inc/parUtil.h index 857c7604a9..89628ea97e 100644 --- a/source/libs/parser/inc/parUtil.h +++ b/source/libs/parser/inc/parUtil.h @@ -135,7 +135,7 @@ int32_t trimString(const char* src, int32_t len, char* dst, int32_t dlen); int32_t getVnodeSysTableTargetName(int32_t acctId, SNode* pWhere, SName* pName); int32_t checkAndTrimValue(SToken* pToken, char* tmpTokenBuf, SMsgBuf* pMsgBuf, int8_t type); int32_t parseTagValue(SMsgBuf* pMsgBuf, const char** pSql, uint8_t precision, SSchema* pTagSchema, SToken* pToken, - SArray* pTagName, SArray* pTagVals, STag** pTag); + SArray* pTagName, SArray* pTagVals, STag** pTag, timezone_t tz); int32_t parseTbnameToken(SMsgBuf* pMsgBuf, char* tname, SToken* pToken, bool* pFoundCtbName); int32_t buildCatalogReq(const SParseMetaCache* pMetaCache, SCatalogReq* pCatalogReq); diff --git a/source/libs/parser/src/parAstCreater.c b/source/libs/parser/src/parAstCreater.c index 269e9e4a04..cceebd627e 100644 --- a/source/libs/parser/src/parAstCreater.c +++ b/source/libs/parser/src/parAstCreater.c @@ -420,6 +420,7 @@ SNode* createValueNode(SAstCreateContext* pCxt, int32_t dataType, const SToken* val->node.resType.precision = TSDB_TIME_PRECISION_MILLI; } val->translate = false; + val->tz = pCxt->pQueryCxt->timezone; return (SNode*)val; _err: return NULL; @@ -1041,6 +1042,7 @@ SNode* createFunctionNode(SAstCreateContext* pCxt, const SToken* pFuncName, SNod CHECK_MAKE_NODE(func); COPY_STRING_FORM_ID_TOKEN(func->functionName, pFuncName); func->pParameterList = pParameterList; + func->tz = pCxt->pQueryCxt->timezone; return (SNode*)func; _err: nodesDestroyList(pParameterList); @@ -1497,6 +1499,7 @@ SNode* createCaseWhenNode(SAstCreateContext* pCxt, SNode* pCase, SNodeList* pWhe pCaseWhen->pCase = pCase; pCaseWhen->pWhenThenList = pWhenThenList; pCaseWhen->pElse = pElse; + pCaseWhen->tz = pCxt->pQueryCxt->timezone; return (SNode*)pCaseWhen; _err: nodesDestroyNode(pCase); diff --git a/source/libs/parser/src/parInsertSql.c b/source/libs/parser/src/parInsertSql.c index 81deefcaf1..c89735472d 100644 --- a/source/libs/parser/src/parInsertSql.c +++ b/source/libs/parser/src/parInsertSql.c @@ -247,13 +247,13 @@ static int32_t parseBoundColumns(SInsertParseContext* pCxt, const char** pSql, E } static int parseTimestampOrInterval(const char** end, SToken* pToken, int16_t timePrec, int64_t* ts, int64_t* interval, - SMsgBuf* pMsgBuf, bool* isTs) { + SMsgBuf* pMsgBuf, bool* isTs, timezone_t tz) { if (pToken->type == TK_NOW) { *isTs = true; *ts = taosGetTimestamp(timePrec); } else if (pToken->type == TK_TODAY) { *isTs = true; - *ts = taosGetTimestampToday(timePrec); + *ts = taosGetTimestampToday(timePrec, tz); } else if (pToken->type == TK_NK_INTEGER) { *isTs = true; if (TSDB_CODE_SUCCESS != toInteger(pToken->z, pToken->n, 10, ts)) { @@ -267,7 +267,7 @@ static int parseTimestampOrInterval(const char** end, SToken* pToken, int16_t ti } } else { // parse the RFC-3339/ISO-8601 timestamp format string *isTs = true; - if (taosParseTime(pToken->z, ts, pToken->n, timePrec) != TSDB_CODE_SUCCESS) { + if (taosParseTime(pToken->z, ts, pToken->n, timePrec, tz) != TSDB_CODE_SUCCESS) { if ((pToken->n == 0) || (pToken->type != TK_NK_STRING && pToken->type != TK_NK_HEX && pToken->type != TK_NK_BIN)) { return buildSyntaxErrMsg(pMsgBuf, "invalid timestamp format", pToken->z); @@ -277,7 +277,7 @@ static int parseTimestampOrInterval(const char** end, SToken* pToken, int16_t ti *ts = taosGetTimestamp(timePrec); } else if (IS_TODAY_STR(pToken->z, pToken->n)) { *isTs = true; - *ts = taosGetTimestampToday(timePrec); + *ts = taosGetTimestampToday(timePrec, tz); } else if (TSDB_CODE_SUCCESS == toIntegerPure(pToken->z, pToken->n, 10, ts)) { *isTs = true; } else { @@ -289,7 +289,7 @@ static int parseTimestampOrInterval(const char** end, SToken* pToken, int16_t ti return TSDB_CODE_SUCCESS; } -static int parseTime(const char** end, SToken* pToken, int16_t timePrec, int64_t* time, SMsgBuf* pMsgBuf) { +static int parseTime(const char** end, SToken* pToken, int16_t timePrec, int64_t* time, SMsgBuf* pMsgBuf, timezone_t tz) { int32_t index = 0, i = 0; int64_t interval = 0, tempInterval = 0; int64_t ts = 0, tempTs = 0; @@ -297,7 +297,7 @@ static int parseTime(const char** end, SToken* pToken, int16_t timePrec, int64_t const char* pTokenEnd = *end; if (TSDB_CODE_SUCCESS != - parseTimestampOrInterval(&pTokenEnd, pToken, timePrec, &ts, &interval, pMsgBuf, &firstIsTS)) { + parseTimestampOrInterval(&pTokenEnd, pToken, timePrec, &ts, &interval, pMsgBuf, &firstIsTS, tz)) { return buildSyntaxErrMsg(pMsgBuf, "invalid timestamp format", pToken->z); } @@ -371,7 +371,7 @@ static int parseTime(const char** end, SToken* pToken, int16_t timePrec, int64_t } if (TSDB_CODE_SUCCESS != - parseTimestampOrInterval(&pTokenEnd, &valueToken, timePrec, &tempTs, &tempInterval, pMsgBuf, &secondIsTs)) { + parseTimestampOrInterval(&pTokenEnd, &valueToken, timePrec, &tempTs, &tempInterval, pMsgBuf, &secondIsTs, tz)) { return buildSyntaxErrMsg(pMsgBuf, "invalid timestamp format", pToken->z); } @@ -477,7 +477,7 @@ static int32_t parseVarbinary(SToken* pToken, uint8_t** pData, uint32_t* nData, } static int32_t parseTagToken(const char** end, SToken* pToken, SSchema* pSchema, int16_t timePrec, STagVal* val, - SMsgBuf* pMsgBuf) { + SMsgBuf* pMsgBuf, timezone_t tz) { int64_t iv; uint64_t uv; char* endptr = NULL; @@ -700,7 +700,7 @@ static int32_t parseTagToken(const char** end, SToken* pToken, SSchema* pSchema, break; } case TSDB_DATA_TYPE_TIMESTAMP: { - if (parseTime(end, pToken, timePrec, &iv, pMsgBuf) != TSDB_CODE_SUCCESS) { + if (parseTime(end, pToken, timePrec, &iv, pMsgBuf, tz) != TSDB_CODE_SUCCESS) { return buildSyntaxErrMsg(pMsgBuf, "invalid timestamp", pToken->z); } @@ -732,7 +732,7 @@ static int32_t parseBoundTagsClause(SInsertParseContext* pCxt, SVnodeModifyOpStm } int32_t parseTagValue(SMsgBuf* pMsgBuf, const char** pSql, uint8_t precision, SSchema* pTagSchema, SToken* pToken, - SArray* pTagName, SArray* pTagVals, STag** pTag) { + SArray* pTagName, SArray* pTagVals, STag** pTag, timezone_t tz) { bool isNull = isNullValue(pTagSchema->type, pToken); if (!isNull && pTagName) { if (NULL == taosArrayPush(pTagName, pTagSchema->name)) { @@ -755,7 +755,7 @@ int32_t parseTagValue(SMsgBuf* pMsgBuf, const char** pSql, uint8_t precision, SS if (isNull) return 0; STagVal val = {0}; - int32_t code = parseTagToken(pSql, pToken, pTagSchema, precision, &val, pMsgBuf); + int32_t code = parseTagToken(pSql, pToken, pTagSchema, precision, &val, pMsgBuf, tz); if (TSDB_CODE_SUCCESS == code) { if (NULL == taosArrayPush(pTagVals, &val)){ code = terrno; @@ -975,7 +975,7 @@ static int32_t parseTagsClauseImpl(SInsertParseContext* pCxt, SVnodeModifyOpStmt code = buildSyntaxErrMsg(&pCxt->msg, "not expected tags values ", token.z); } if (TSDB_CODE_SUCCESS == code) { - code = parseTagValue(&pCxt->msg, &pStmt->pSql, precision, pTagSchema, &token, pTagName, pTagVals, &pTag); + code = parseTagValue(&pCxt->msg, &pStmt->pSql, precision, pTagSchema, &token, pTagName, pTagVals, &pTag, pCxt->pComCxt->timezone); } } @@ -1672,7 +1672,7 @@ static int32_t parseValueTokenImpl(SInsertParseContext* pCxt, const char** pSql, break; } case TSDB_DATA_TYPE_TIMESTAMP: { - if (parseTime(pSql, pToken, timePrec, &pVal->value.val, &pCxt->msg) != TSDB_CODE_SUCCESS) { + if (parseTime(pSql, pToken, timePrec, &pVal->value.val, &pCxt->msg, pCxt->pComCxt->timezone) != TSDB_CODE_SUCCESS) { return buildSyntaxErrMsg(&pCxt->msg, "invalid timestamp", pToken->z); } break; @@ -1785,7 +1785,7 @@ static int32_t processCtbTagsAfterCtbName(SInsertParseContext* pCxt, SVnodeModif if (code == TSDB_CODE_SUCCESS) { code = parseTagValue(&pCxt->msg, NULL, precision, pTagSchema, pTagToken, pStbRowsCxt->aTagNames, - pStbRowsCxt->aTagVals, &pStbRowsCxt->pTag); + pStbRowsCxt->aTagVals, &pStbRowsCxt->pTag, pCxt->pComCxt->timezone); } } if (code == TSDB_CODE_SUCCESS && !pStbRowsCxt->isJsonTag) { @@ -1844,7 +1844,7 @@ static int32_t doGetStbRowValues(SInsertParseContext* pCxt, SVnodeModifyOpStmt* } if (code == TSDB_CODE_SUCCESS) { code = parseTagValue(&pCxt->msg, ppSql, precision, (SSchema*)pTagSchema, pToken, pTagNames, pTagVals, - &pStbRowsCxt->pTag); + &pStbRowsCxt->pTag, pCxt->pComCxt->timezone); } } } else if (pCols->pColIndex[i] == tbnameIdx) { diff --git a/source/libs/parser/src/parTranslater.c b/source/libs/parser/src/parTranslater.c index 824764a9f6..b73adfe256 100755 --- a/source/libs/parser/src/parTranslater.c +++ b/source/libs/parser/src/parTranslater.c @@ -1949,7 +1949,7 @@ static int32_t parseTimeFromValueNode(STranslateContext* pCxt, SValueNode* pVal) return TSDB_CODE_SUCCESS; } else if (IS_VAR_DATA_TYPE(pVal->node.resType.type) || TSDB_DATA_TYPE_TIMESTAMP == pVal->node.resType.type) { if (TSDB_CODE_SUCCESS == taosParseTime(pVal->literal, &pVal->datum.i, pVal->node.resType.bytes, - pVal->node.resType.precision)) { + pVal->node.resType.precision, pVal->tz)) { return TSDB_CODE_SUCCESS; } char* pEnd = NULL; @@ -14008,7 +14008,7 @@ static int32_t buildKVRowForBindTags(STranslateContext* pCxt, SCreateSubTableCla if (pSchema->type == TSDB_DATA_TYPE_JSON) { isJson = true; } - code = parseTagValue(&pCxt->msgBuf, &tagStr, precision, pSchema, &token, tagName, pTagArray, ppTag); + code = parseTagValue(&pCxt->msgBuf, &tagStr, precision, pSchema, &token, tagName, pTagArray, ppTag, pCxt->pParseCxt->timezone); } if (TSDB_CODE_SUCCESS == code) { @@ -14069,7 +14069,7 @@ static int32_t buildKVRowForAllTags(STranslateContext* pCxt, SCreateSubTableClau if (pTagSchema->type == TSDB_DATA_TYPE_JSON) { isJson = true; } - code = parseTagValue(&pCxt->msgBuf, &tagStr, precision, pTagSchema, &token, tagName, pTagArray, ppTag); + code = parseTagValue(&pCxt->msgBuf, &tagStr, precision, pTagSchema, &token, tagName, pTagArray, ppTag, pCxt->pParseCxt->timezone); } if (TSDB_CODE_SUCCESS == code) { @@ -14265,7 +14265,7 @@ static int32_t fillVgroupInfo(SParseContext* pParseCxt, const SName* pName, SVgr return code; } -static int32_t parseOneStbRow(SMsgBuf* pMsgBuf, SParseFileContext* pParFileCxt) { +static int32_t parseOneStbRow(SMsgBuf* pMsgBuf, SParseFileContext* pParFileCxt, timezone_t tz) { int32_t code = TSDB_CODE_SUCCESS; int sz = taosArrayGetSize(pParFileCxt->aTagIndexs); int32_t numOfTags = getNumOfTags(pParFileCxt->pStbMeta); @@ -14297,7 +14297,7 @@ static int32_t parseOneStbRow(SMsgBuf* pMsgBuf, SParseFileContext* pParFileCxt) if (TSDB_CODE_SUCCESS == code) { SArray* aTagNames = pParFileCxt->tagNameFilled ? NULL : pParFileCxt->aTagNames; code = parseTagValue(pMsgBuf, &pParFileCxt->pSql, precision, (SSchema*)pTagSchema, &token, aTagNames, - pParFileCxt->aTagVals, &pParFileCxt->pTag); + pParFileCxt->aTagVals, &pParFileCxt->pTag, tz); } } else { // parse tbname @@ -14363,7 +14363,7 @@ static int32_t parseCsvFile(SMsgBuf* pMsgBuf, SParseContext* pParseCxt, SParseFi (void)strtolower(pLine, pLine); pParFileCxt->pSql = pLine; - code = parseOneStbRow(pMsgBuf, pParFileCxt); + code = parseOneStbRow(pMsgBuf, pParFileCxt, pParseCxt->timezone); if (TSDB_CODE_SUCCESS == code) { code = fillVgroupInfo(pParseCxt, &pParFileCxt->ctbName, &pParFileCxt->vg); @@ -15064,7 +15064,7 @@ static int32_t buildUpdateTagValReq(STranslateContext* pCxt, SAlterTableStmt* pS if (TSDB_CODE_SUCCESS == code) { code = parseTagValue(&pCxt->msgBuf, &tagStr, pTableMeta->tableInfo.precision, pSchema, &token, NULL, - pReq->pTagArray, &pTag); + pReq->pTagArray, &pTag, pCxt->pParseCxt->timezone); if (pSchema->type == TSDB_DATA_TYPE_JSON && token.type == TK_NULL && code == TSDB_CODE_SUCCESS) { pReq->tagFree = true; } diff --git a/source/libs/scalar/src/filter.c b/source/libs/scalar/src/filter.c index d8622d93ee..cb08851196 100644 --- a/source/libs/scalar/src/filter.c +++ b/source/libs/scalar/src/filter.c @@ -4694,33 +4694,6 @@ EDealRes fltReviseRewriter(SNode **pNode, void *pContext) { stat->scalarMode = true; return DEAL_RES_CONTINUE; } - - /* - if (!FILTER_GET_FLAG(stat->info->options, FLT_OPTION_TIMESTAMP)) { - return DEAL_RES_CONTINUE; - } - - if (TSDB_DATA_TYPE_BINARY != valueNode->node.resType.type && TSDB_DATA_TYPE_NCHAR != - valueNode->node.resType.type && - TSDB_DATA_TYPE_GEOMETRY != valueNode->node.resType.type) { return DEAL_RES_CONTINUE; - } - - if (stat->precision < 0) { - int32_t code = fltAddValueNodeToConverList(stat, valueNode); - if (code) { - stat->code = code; - return DEAL_RES_ERROR; - } - - return DEAL_RES_CONTINUE; - } - - int32_t code = sclConvertToTsValueNode(stat->precision, valueNode); - if (code) { - stat->code = code; - return DEAL_RES_ERROR; - } - */ return DEAL_RES_CONTINUE; } @@ -4887,15 +4860,6 @@ int32_t fltReviseNodes(SFilterInfo *pInfo, SNode **pNode, SFltTreeStat *pStat) { FLT_ERR_JRET(pStat->code); - /* - int32_t nodeNum = taosArrayGetSize(pStat->nodeList); - for (int32_t i = 0; i < nodeNum; ++i) { - SValueNode *valueNode = *(SValueNode **)taosArrayGet(pStat->nodeList, i); - - FLT_ERR_JRET(sclConvertToTsValueNode(pStat->precision, valueNode)); - } - */ - _return: taosArrayDestroy(pStat->nodeList); diff --git a/source/libs/scalar/src/scalar.c b/source/libs/scalar/src/scalar.c index 209110b014..d533eba74e 100644 --- a/source/libs/scalar/src/scalar.c +++ b/source/libs/scalar/src/scalar.c @@ -24,7 +24,7 @@ int32_t scalarGetOperatorParamNum(EOperatorType type) { int32_t sclConvertToTsValueNode(int8_t precision, SValueNode *valueNode) { char *timeStr = valueNode->datum.p; int64_t value = 0; - int32_t code = convertStringToTimestamp(valueNode->node.resType.type, valueNode->datum.p, precision, &value); + int32_t code = convertStringToTimestamp(valueNode->node.resType.type, valueNode->datum.p, precision, &value, valueNode->tz); //todo tz if (code != TSDB_CODE_SUCCESS) { return code; } @@ -81,6 +81,8 @@ int32_t sclConvertValueToSclParam(SValueNode *pValueNode, SScalarParam *out, int goto _exit; } + in.tz = pValueNode->tz; + out->tz = pValueNode->tz; code = vectorConvertSingleColImpl(&in, out, overflow, -1, -1); _exit: @@ -586,6 +588,7 @@ int32_t sclInitOperatorParams(SScalarParam **pParams, SOperatorNode *node, SScal SCL_ERR_JRET(sclSetOperatorValueType(node, ctx)); SCL_ERR_JRET(sclInitParam(node->pLeft, ¶mList[0], ctx, rowNum)); + paramList[0].tz = node->tz; if (paramNum > 1) { TSWAP(ctx->type.selfType, ctx->type.peerType); SCL_ERR_JRET(sclInitParam(node->pRight, ¶mList[1], ctx, rowNum)); @@ -756,6 +759,7 @@ int32_t sclExecFunction(SFunctionNode *node, SScalarCtx *ctx, SScalarParam *outp int32_t paramNum = 0; int32_t code = 0; SCL_ERR_RET(sclInitParamList(¶ms, node->pParameterList, ctx, ¶mNum, &rowNum)); + params->tz = node->tz; if (fmIsUserDefinedFunc(node->funcId)) { code = callUdfScalarFunc(node->functionName, params, paramNum, output); @@ -942,7 +946,7 @@ int32_t sclExecCaseWhen(SCaseWhenNode *node, SScalarCtx *ctx, SScalarParam *outp SCL_ERR_JRET(sclGetNodeRes(node->pCase, ctx, &pCase)); SCL_ERR_JRET(sclGetNodeRes(node->pElse, ctx, &pElse)); - + pCase->tz = node->tz; SDataType compType = {0}; compType.type = TSDB_DATA_TYPE_BOOL; compType.bytes = tDataTypes[compType.type].bytes; diff --git a/source/libs/scalar/src/sclfunc.c b/source/libs/scalar/src/sclfunc.c index 9e75abcfe8..1ddf74eb2d 100644 --- a/source/libs/scalar/src/sclfunc.c +++ b/source/libs/scalar/src/sclfunc.c @@ -2053,7 +2053,7 @@ int32_t castFunction(SScalarParam *pInput, int32_t inputNum, SScalarParam *pOutp if (inputType == TSDB_DATA_TYPE_BINARY || inputType == TSDB_DATA_TYPE_NCHAR) { int64_t timePrec; GET_TYPED_DATA(timePrec, int64_t, GET_PARAM_TYPE(&pInput[1]), pInput[1].columnData->pData); - int32_t ret = convertStringToTimestamp(inputType, input, timePrec, &timeVal); + int32_t ret = convertStringToTimestamp(inputType, input, timePrec, &timeVal, pInput->tz); if (ret != TSDB_CODE_SUCCESS) { *(int64_t *)output = 0; } else { @@ -2240,17 +2240,14 @@ int32_t toISO8601Function(SScalarParam *pInput, int32_t inputNum, SScalarParam * if (0 != offsetOfTimezone(tz, &offset)) { goto _end; } - quot -= offset + 3600 * ((int64_t)tsTimezone); + quot -= offset; struct tm tmInfo; - int32_t len = 0; - - if (taosLocalTime((const time_t *)", &tmInfo, buf, sizeof(buf)) == NULL) { - len = (int32_t)strlen(buf); + if (taosGmTimeR((const time_t *)", &tmInfo) == NULL) { goto _end; } - len = (int32_t)strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S", &tmInfo); + int32_t len = (int32_t)strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S", &tmInfo); len += tsnprintf(buf + len, fractionLen, format, mod); @@ -2286,7 +2283,7 @@ int32_t toUnixtimestampFunction(SScalarParam *pInput, int32_t inputNum, SScalarP char *input = colDataGetData(pInput[0].columnData, i); int64_t timeVal = 0; - int32_t ret = convertStringToTimestamp(type, input, timePrec, &timeVal); + int32_t ret = convertStringToTimestamp(type, input, timePrec, &timeVal, pInput->tz); if (ret != TSDB_CODE_SUCCESS) { colDataSetNULL(pOutput->columnData, i); } else { @@ -2381,7 +2378,7 @@ int32_t toTimestampFunction(SScalarParam* pInput, int32_t inputNum, SScalarParam } int32_t precision = pOutput->columnData->info.precision; char errMsg[128] = {0}; - code = taosChar2Ts(format, &formats, tsStr, &ts, precision, errMsg, 128); + code = taosChar2Ts(format, &formats, tsStr, &ts, precision, errMsg, 128, pInput->tz); if (code) { qError("func to_timestamp failed %s", errMsg); SCL_ERR_JRET(code); @@ -2424,7 +2421,7 @@ int32_t toCharFunction(SScalarParam* pInput, int32_t inputNum, SScalarParam* pOu } } int32_t precision = pInput[0].columnData->info.precision; - SCL_ERR_JRET(taosTs2Char(format, &formats, *(int64_t *)ts, precision, varDataVal(out), TS_FORMAT_MAX_LEN)); + SCL_ERR_JRET(taosTs2Char(format, &formats, *(int64_t *)ts, precision, varDataVal(out), TS_FORMAT_MAX_LEN, pInput->tz)); varDataSetLen(out, strlen(varDataVal(out))); SCL_ERR_JRET(colDataSetVal(pOutput->columnData, i, out, false)); } @@ -2437,11 +2434,11 @@ _return: } /** Time functions **/ -int64_t offsetFromTz(char *timezone, int64_t factor) { - char *minStr = &timezone[3]; +int64_t offsetFromTz(char *timezoneStr, int64_t factor) { + char *minStr = &timezoneStr[3]; int64_t minutes = taosStr2Int64(minStr, NULL, 10); (void)memset(minStr, 0, strlen(minStr)); - int64_t hours = taosStr2Int64(timezone, NULL, 10); + int64_t hours = taosStr2Int64(timezoneStr, NULL, 10); int64_t seconds = hours * 3600 + minutes * 60; return seconds * factor; @@ -2453,7 +2450,7 @@ int32_t timeTruncateFunction(SScalarParam *pInput, int32_t inputNum, SScalarPara int64_t timeUnit, timePrec, timeVal = 0; bool ignoreTz = true; - char timezone[20] = {0}; + char timezoneStr[20] = {0}; GET_TYPED_DATA(timeUnit, int64_t, GET_PARAM_TYPE(&pInput[1]), pInput[1].columnData->pData); @@ -2465,7 +2462,7 @@ int32_t timeTruncateFunction(SScalarParam *pInput, int32_t inputNum, SScalarPara } GET_TYPED_DATA(timePrec, int64_t, GET_PARAM_TYPE(&pInput[timePrecIdx]), pInput[timePrecIdx].columnData->pData); - (void)memcpy(timezone, varDataVal(pInput[timeZoneIdx].columnData->pData), varDataLen(pInput[timeZoneIdx].columnData->pData)); + (void)memcpy(timezoneStr, varDataVal(pInput[timeZoneIdx].columnData->pData), varDataLen(pInput[timeZoneIdx].columnData->pData)); for (int32_t i = 0; i < pInput[0].numOfRows; ++i) { if (colDataIsNull_s(pInput[0].columnData, i)) { @@ -2476,7 +2473,7 @@ int32_t timeTruncateFunction(SScalarParam *pInput, int32_t inputNum, SScalarPara char *input = colDataGetData(pInput[0].columnData, i); if (IS_VAR_DATA_TYPE(type)) { /* datetime format strings */ - int32_t ret = convertStringToTimestamp(type, input, timePrec, &timeVal); + int32_t ret = convertStringToTimestamp(type, input, timePrec, &timeVal, pInput->tz); if (ret != TSDB_CODE_SUCCESS) { colDataSetNULL(pOutput->columnData, i); continue; @@ -2493,7 +2490,7 @@ int32_t timeTruncateFunction(SScalarParam *pInput, int32_t inputNum, SScalarPara // truncate the timestamp to time_unit precision int64_t seconds = timeUnit / TSDB_TICK_PER_SECOND(timePrec); if (ignoreTz && (seconds == 604800 || seconds == 86400)) { - timeVal = timeVal - (timeVal + offsetFromTz(timezone, TSDB_TICK_PER_SECOND(timePrec))) % timeUnit; + timeVal = timeVal - (timeVal + offsetFromTz(timezoneStr, TSDB_TICK_PER_SECOND(timePrec))) % timeUnit; } else { timeVal = timeVal / timeUnit * timeUnit; } @@ -2536,7 +2533,7 @@ int32_t timeDiffFunction(SScalarParam *pInput, int32_t inputNum, SScalarParam *p int32_t type = GET_PARAM_TYPE(&pInput[k]); if (IS_VAR_DATA_TYPE(type)) { /* datetime format strings */ - int32_t ret = convertStringToTimestamp(type, input[k], TSDB_TIME_PRECISION_NANO, &timeVal[k]); + int32_t ret = convertStringToTimestamp(type, input[k], TSDB_TIME_PRECISION_NANO, &timeVal[k], pInput->tz); if (ret != TSDB_CODE_SUCCESS) { hasNull = true; break; @@ -2655,7 +2652,7 @@ int32_t todayFunction(SScalarParam *pInput, int32_t inputNum, SScalarParam *pOut int64_t timePrec; GET_TYPED_DATA(timePrec, int64_t, GET_PARAM_TYPE(&pInput[0]), pInput[0].columnData->pData); - int64_t ts = taosGetTimestampToday(timePrec); + int64_t ts = taosGetTimestampToday(timePrec, pInput->tz); for (int32_t i = 0; i < pInput->numOfRows; ++i) { colDataSetInt64(pOutput->columnData, i, &ts); } @@ -2665,8 +2662,16 @@ int32_t todayFunction(SScalarParam *pInput, int32_t inputNum, SScalarParam *pOut int32_t timezoneFunction(SScalarParam *pInput, int32_t inputNum, SScalarParam *pOutput) { char output[TD_TIMEZONE_LEN + VARSTR_HEADER_SIZE] = {0}; - (void)memcpy(varDataVal(output), tsTimezoneStr, TD_TIMEZONE_LEN); - varDataSetLen(output, strlen(tsTimezoneStr)); + // pInput->tz todo tz + char* tmp = NULL; + if (pInput->tz == NULL) { + (void)memcpy(varDataVal(output), tsTimezoneStr, TD_TIMEZONE_LEN); + } else{ + time_t tx1 = taosGetTimestampSec(); + SCL_ERR_RET(taosFormatTimezoneStr(tx1, "UTC-test", pInput->tz, varDataVal(output))); + } + + varDataSetLen(output, strlen(varDataVal(output))); for (int32_t i = 0; i < pInput->numOfRows; ++i) { SCL_ERR_RET(colDataSetVal(pOutput->columnData, i, output, false)); } @@ -2690,7 +2695,7 @@ int32_t weekdayFunctionImpl(SScalarParam *pInput, int32_t inputNum, SScalarParam char *input = colDataGetData(pInput[0].columnData, i); if (IS_VAR_DATA_TYPE(type)) { /* datetime format strings */ - int32_t ret = convertStringToTimestamp(type, input, timePrec, &timeVal); + int32_t ret = convertStringToTimestamp(type, input, timePrec, &timeVal, pInput->tz); if (ret != TSDB_CODE_SUCCESS) { colDataSetNULL(pOutput->columnData, i); continue; @@ -2701,7 +2706,7 @@ int32_t weekdayFunctionImpl(SScalarParam *pInput, int32_t inputNum, SScalarParam GET_TYPED_DATA(timeVal, int64_t, type, input); } struct STm tm; - TAOS_CHECK_RETURN(taosTs2Tm(timeVal, timePrec, &tm)); + TAOS_CHECK_RETURN(taosTs2Tm(timeVal, timePrec, &tm, pInput->tz)); int64_t ret = startFromZero ? (tm.tm.tm_wday + 6) % 7 : tm.tm.tm_wday + 1; colDataSetInt64(pOutput->columnData, i, &ret); } @@ -2800,7 +2805,7 @@ int32_t weekFunctionImpl(SScalarParam *pInput, int32_t inputNum, SScalarParam *p char *input = colDataGetData(pInput[0].columnData, i); if (IS_VAR_DATA_TYPE(type)) { /* datetime format strings */ - int32_t ret = convertStringToTimestamp(type, input, prec, &timeVal); + int32_t ret = convertStringToTimestamp(type, input, prec, &timeVal, pInput->tz); if (ret != TSDB_CODE_SUCCESS) { colDataSetNULL(pOutput->columnData, i); continue; @@ -2811,7 +2816,7 @@ int32_t weekFunctionImpl(SScalarParam *pInput, int32_t inputNum, SScalarParam *p GET_TYPED_DATA(timeVal, int64_t, type, input); } struct STm tm; - SCL_ERR_RET(taosTs2Tm(timeVal, prec, &tm)); + SCL_ERR_RET(taosTs2Tm(timeVal, prec, &tm, pInput->tz)); int64_t ret = calculateWeekNum(tm.tm, weekMode(mode)); colDataSetInt64(pOutput->columnData, i, &ret); } diff --git a/source/libs/scalar/src/sclvector.c b/source/libs/scalar/src/sclvector.c index 7e37d00bfe..d9becf199a 100644 --- a/source/libs/scalar/src/sclvector.c +++ b/source/libs/scalar/src/sclvector.c @@ -242,7 +242,7 @@ int32_t getVectorBigintValueFn(int32_t srcType, _getBigintValue_fn_t *p) { static FORCE_INLINE int32_t varToTimestamp(char *buf, SScalarParam *pOut, int32_t rowIndex, int32_t *overflow) { int64_t value = 0; int32_t code = TSDB_CODE_SUCCESS; - if (taosParseTime(buf, &value, strlen(buf), pOut->columnData->info.precision) != TSDB_CODE_SUCCESS) { + if (taosParseTime(buf, &value, strlen(buf), pOut->columnData->info.precision, pOut->tz) != TSDB_CODE_SUCCESS) { value = 0; code = TSDB_CODE_SCALAR_CONVERT_ERROR; } @@ -2042,6 +2042,9 @@ int32_t vectorCompareImpl(SScalarParam *pLeft, SScalarParam *pRight, SScalarPara SScalarParam *param1 = NULL; SScalarParam *param2 = NULL; int32_t code = TSDB_CODE_SUCCESS; + pRight->tz = pLeft->tz; + pLeftOut.tz = pLeft->tz; + pRightOut.tz = pRight->tz; if (noConvertBeforeCompare(GET_PARAM_TYPE(pLeft), GET_PARAM_TYPE(pRight), optr)) { param1 = pLeft; param2 = pRight; @@ -2125,6 +2128,7 @@ int32_t vectorIsNull(SScalarParam *pLeft, SScalarParam *pRight, SScalarParam *pO } int32_t vectorNotNull(SScalarParam *pLeft, SScalarParam *pRight, SScalarParam *pOut, int32_t _ord) { + pRight->tz = pLeft->tz; for (int32_t i = 0; i < pLeft->numOfRows; ++i) { int8_t v = IS_HELPER_NULL(pLeft->columnData, i) ? 0 : 1; if (v) { @@ -2138,6 +2142,7 @@ int32_t vectorNotNull(SScalarParam *pLeft, SScalarParam *pRight, SScalarParam *p } int32_t vectorIsTrue(SScalarParam *pLeft, SScalarParam *pRight, SScalarParam *pOut, int32_t _ord) { + pRight->tz = pLeft->tz; SCL_ERR_RET(vectorConvertSingleColImpl(pLeft, pOut, NULL, -1, -1)); for (int32_t i = 0; i < pOut->numOfRows; ++i) { if (colDataIsNull_s(pOut->columnData, i)) { diff --git a/source/os/src/osTime.c b/source/os/src/osTime.c index 3798a96e9d..3d026b3ccc 100644 --- a/source/os/src/osTime.c +++ b/source/os/src/osTime.c @@ -413,7 +413,7 @@ int64_t user_mktime64(const uint32_t year, const uint32_t mon, const uint32_t da return _res + time_zone; } -time_t taosMktime(struct tm *timep) { +time_t taosMktime(struct tm *timep, timezone_t tz) { #ifdef WINDOWS #if 0 struct tm tm1 = {0}; @@ -466,7 +466,7 @@ time_t taosMktime(struct tm *timep) { timep->tm_sec, tz); #endif #else - time_t r = mktime(timep); + time_t r = tz != NULL ? mktime_z(tz, timep) : mktime(timep); if (r == (time_t)-1) { terrno = TAOS_SYSTEM_ERROR(errno); } @@ -474,7 +474,74 @@ time_t taosMktime(struct tm *timep) { #endif } -struct tm *taosLocalTime(const time_t *timep, struct tm *result, char *buf, int32_t bufSize) { +struct tm *taosGmTimeR(const time_t *timep, struct tm *result){ + if (timep == NULL || result == NULL) { + return NULL; + } +#ifdef WINDOWS + if (*timep < -2208988800LL) { + if (buf != NULL) { + snprintf(buf, bufSize, "NaN"); + } + return NULL; + } else if (*timep < 0) { + SYSTEMTIME ss, s; + FILETIME ff, f; + + LARGE_INTEGER offset; + struct tm tm1; + time_t tt = 0; + if (localtime_s(&tm1, &tt) != 0) { + if (buf != NULL) { + snprintf(buf, bufSize, "NaN"); + } + return NULL; + } + ss.wYear = tm1.tm_year + 1900; + ss.wMonth = tm1.tm_mon + 1; + ss.wDay = tm1.tm_mday; + ss.wHour = tm1.tm_hour; + ss.wMinute = tm1.tm_min; + ss.wSecond = tm1.tm_sec; + ss.wMilliseconds = 0; + SystemTimeToFileTime(&ss, &ff); + offset.QuadPart = ff.dwHighDateTime; + offset.QuadPart <<= 32; + offset.QuadPart |= ff.dwLowDateTime; + offset.QuadPart += *timep * 10000000; + f.dwLowDateTime = offset.QuadPart & 0xffffffff; + f.dwHighDateTime = (offset.QuadPart >> 32) & 0xffffffff; + FileTimeToSystemTime(&f, &s); + result->tm_sec = s.wSecond; + result->tm_min = s.wMinute; + result->tm_hour = s.wHour; + result->tm_mday = s.wDay; + result->tm_mon = s.wMonth - 1; + result->tm_year = s.wYear - 1900; + result->tm_wday = s.wDayOfWeek; + result->tm_yday = 0; + result->tm_isdst = 0; + } else { + if (localtime_s(result, timep) != 0) { + if (buf != NULL) { + snprintf(buf, bufSize, "NaN"); + } + return NULL; + } + } +#else + return gmtime_r(timep, result); +#endif +} + +time_t taosTimeGm(struct tm *tmp){ + if (tmp == NULL) { + return -1; + } + return timegm(tmp); +} + +struct tm *taosLocalTime(const time_t *timep, struct tm *result, char *buf, int32_t bufSize, timezone_t tz) { struct tm *res = NULL; if (timep == NULL || result == NULL) { return NULL; @@ -531,7 +598,7 @@ struct tm *taosLocalTime(const time_t *timep, struct tm *result, char *buf, int3 } } #else - res = localtime_r(timep, result); + res = tz != NULL ? localtime_rz(tz, timep, result): localtime_r(timep, result); if (res == NULL && buf != NULL) { (void)snprintf(buf, bufSize, "NaN"); } @@ -539,233 +606,6 @@ struct tm *taosLocalTime(const time_t *timep, struct tm *result, char *buf, int3 return result; } -time_t taosMktimeRz(timezone_t state, struct tm *timep) { -#ifdef WINDOWS - #if 0 - struct tm tm1 = {0}; - LARGE_INTEGER t; - FILETIME f; - SYSTEMTIME s; - FILETIME ff; - SYSTEMTIME ss; - LARGE_INTEGER offset; - - time_t tt = 0; - localtime_s(&tm1, &tt); - ss.wYear = tm1.tm_year + 1900; - ss.wMonth = tm1.tm_mon + 1; - ss.wDay = tm1.tm_mday; - ss.wHour = tm1.tm_hour; - ss.wMinute = tm1.tm_min; - ss.wSecond = tm1.tm_sec; - ss.wMilliseconds = 0; - SystemTimeToFileTime(&ss, &ff); - offset.QuadPart = ff.dwHighDateTime; - offset.QuadPart <<= 32; - offset.QuadPart |= ff.dwLowDateTime; - - s.wYear = timep->tm_year + 1900; - s.wMonth = timep->tm_mon + 1; - s.wDay = timep->tm_mday; - s.wHour = timep->tm_hour; - s.wMinute = timep->tm_min; - s.wSecond = timep->tm_sec; - s.wMilliseconds = 0; - SystemTimeToFileTime(&s, &f); - t.QuadPart = f.dwHighDateTime; - t.QuadPart <<= 32; - t.QuadPart |= f.dwLowDateTime; - - t.QuadPart -= offset.QuadPart; - return (time_t)(t.QuadPart / 10000000); -#else - time_t result = mktime(timep); - if (result != -1) { - return result; - } -#ifdef _MSC_VER -#if _MSC_VER >= 1900 - int64_t tz = _timezone; -#endif -#endif - return user_mktime64(timep->tm_year + 1900, timep->tm_mon + 1, timep->tm_mday, timep->tm_hour, timep->tm_min, - timep->tm_sec, tz); -#endif -#else - time_t r = mktime_z(state, timep); - if (r == (time_t)-1) { - terrno = TAOS_SYSTEM_ERROR(errno); - } - return r; -#endif -} - -struct tm *taosLocalTimeRz(timezone_t state, const time_t *timep, struct tm *result) { - struct tm *res = NULL; - if (timep == NULL || result == NULL) { - return NULL; - } -#ifdef WINDOWS - if (*timep < -2208988800LL) { - if (buf != NULL) { - snprintf(buf, bufSize, "NaN"); - } - return NULL; - } else if (*timep < 0) { - SYSTEMTIME ss, s; - FILETIME ff, f; - - LARGE_INTEGER offset; - struct tm tm1; - time_t tt = 0; - if (localtime_s(&tm1, &tt) != 0) { - if (buf != NULL) { - snprintf(buf, bufSize, "NaN"); - } - return NULL; - } - ss.wYear = tm1.tm_year + 1900; - ss.wMonth = tm1.tm_mon + 1; - ss.wDay = tm1.tm_mday; - ss.wHour = tm1.tm_hour; - ss.wMinute = tm1.tm_min; - ss.wSecond = tm1.tm_sec; - ss.wMilliseconds = 0; - SystemTimeToFileTime(&ss, &ff); - offset.QuadPart = ff.dwHighDateTime; - offset.QuadPart <<= 32; - offset.QuadPart |= ff.dwLowDateTime; - offset.QuadPart += *timep * 10000000; - f.dwLowDateTime = offset.QuadPart & 0xffffffff; - f.dwHighDateTime = (offset.QuadPart >> 32) & 0xffffffff; - FileTimeToSystemTime(&f, &s); - result->tm_sec = s.wSecond; - result->tm_min = s.wMinute; - result->tm_hour = s.wHour; - result->tm_mday = s.wDay; - result->tm_mon = s.wMonth - 1; - result->tm_year = s.wYear - 1900; - result->tm_wday = s.wDayOfWeek; - result->tm_yday = 0; - result->tm_isdst = 0; - } else { - if (localtime_s(result, timep) != 0) { - if (buf != NULL) { - snprintf(buf, bufSize, "NaN"); - } - return NULL; - } - } -#else - return localtime_rz(state, timep, result); -#endif -} - -static int isLeapYear(time_t year) { - if (year % 4) - return 0; - else if (year % 100) - return 1; - else if (year % 400) - return 0; - else - return 1; -} - -struct tm *taosLocalTimeNolock(struct tm *result, const time_t *timep, int dst) { - if (result == NULL) { - return NULL; - } -#ifdef WINDOWS - if (*timep < 0) { - return NULL; - // TODO: bugs in following code - SYSTEMTIME ss, s; - FILETIME ff, f; - LARGE_INTEGER offset; - struct tm tm1; - time_t tt = 0; - if (localtime_s(&tm1, &tt) != 0) { - return NULL; - } - ss.wYear = tm1.tm_year + 1900; - ss.wMonth = tm1.tm_mon + 1; - ss.wDay = tm1.tm_mday; - ss.wHour = tm1.tm_hour; - ss.wMinute = tm1.tm_min; - ss.wSecond = tm1.tm_sec; - ss.wMilliseconds = 0; - SystemTimeToFileTime(&ss, &ff); - offset.QuadPart = ff.dwHighDateTime; - offset.QuadPart <<= 32; - offset.QuadPart |= ff.dwLowDateTime; - offset.QuadPart += *timep * 10000000; - f.dwLowDateTime = offset.QuadPart & 0xffffffff; - f.dwHighDateTime = (offset.QuadPart >> 32) & 0xffffffff; - FileTimeToSystemTime(&f, &s); - result->tm_sec = s.wSecond; - result->tm_min = s.wMinute; - result->tm_hour = s.wHour; - result->tm_mday = s.wDay; - result->tm_mon = s.wMonth - 1; - result->tm_year = s.wYear - 1900; - result->tm_wday = s.wDayOfWeek; - result->tm_yday = 0; - result->tm_isdst = 0; - } else { - if (localtime_s(result, timep) != 0) { - return NULL; - } - } -#elif defined(LINUX) - time_t secsMin = 60, secsHour = 3600, secsDay = 3600 * 24; - long tz = timezone; - - time_t t = *timep; - t -= tz; /* Adjust for timezone. */ - t += 3600 * dst; /* Adjust for daylight time. */ - time_t days = t / secsDay; /* Days passed since epoch. */ - time_t seconds = t % secsDay; /* Remaining seconds. */ - - result->tm_isdst = dst; - result->tm_hour = seconds / secsHour; - result->tm_min = (seconds % secsHour) / secsMin; - result->tm_sec = (seconds % secsHour) % secsMin; - - /* 1/1/1970 was a Thursday, that is, day 4 from the POV of the tm structure - * where sunday = 0, so to calculate the day of the week we have to add 4 - * and take the modulo by 7. */ - result->tm_wday = (days + 4) % 7; - - /* Calculate the current year. */ - result->tm_year = 1970; - while (1) { - /* Leap years have one day more. */ - time_t daysOfYear = 365 + isLeapYear(result->tm_year); - if (daysOfYear > days) break; - days -= daysOfYear; - result->tm_year++; - } - result->tm_yday = days; /* Number of day of the current year. */ - /* We need to calculate in which month and day of the month we are. To do - * so we need to skip days according to how many days there are in each - * month, and adjust for the leap year that has one more day in February. */ - int mdays[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; - mdays[1] += isLeapYear(result->tm_year); - result->tm_mon = 0; - while (days >= mdays[result->tm_mon]) { - days -= mdays[result->tm_mon]; - result->tm_mon++; - } - - result->tm_mday = days + 1; /* Add 1 since our 'days' is zero-based. */ - result->tm_year -= 1900; /* Surprisingly tm_year is year-1900. */ -#else - localtime_r(timep, result); -#endif - return result; -} - int32_t taosGetTimestampSec() { return (int32_t)time(NULL); } int32_t taosClockGetTime(int clock_id, struct timespec *pTS) { diff --git a/source/os/src/osTimezone.c b/source/os/src/osTimezone.c index 1b54f3a42c..83100d4327 100644 --- a/source/os/src/osTimezone.c +++ b/source/os/src/osTimezone.c @@ -764,7 +764,7 @@ int32_t taosSetGlobalTimezone(const char *tz) { return terrno; } int32_t code = TSDB_CODE_SUCCESS; - + uDebug("[tz]set timezone to %s", tz) #ifdef WINDOWS char winStr[TD_LOCALE_LEN * 2]; memset(winStr, 0, sizeof(winStr)); @@ -830,16 +830,9 @@ int32_t taosSetGlobalTimezone(const char *tz) { int32_t taosFormatTimezoneStr(time_t t, const char* tz, timezone_t sp, char *outTimezoneStr){ struct tm tm1; - if (sp == NULL) { - if (taosLocalTime(&t, &tm1, NULL, 0) == NULL) { - uError("failed to get local time"); - return TSDB_CODE_TIME_ERROR; - } - } else { - if (taosLocalTimeRz(sp, &t, &tm1) == NULL) { - uError("failed to get rz time"); - return TSDB_CODE_TIME_ERROR; - } + if (taosLocalTime(&t, &tm1, NULL, 0, sp) == NULL) { + uError("%s failed to get local time: code:%d", __FUNCTION__, errno); + return TSDB_CODE_TIME_ERROR; } /* @@ -862,12 +855,13 @@ int32_t taosFormatTimezoneStr(time_t t, const char* tz, timezone_t sp, char *out return TSDB_CODE_TIME_ERROR; } (void)snprintf(outTimezoneStr, TD_TIMEZONE_LEN, "%s (%s, %s)", tz, str1, str2); + uDebug("[tz] system timezone:%s", outTimezoneStr); return 0; } void getTimezoneStr(char *tz) { do { - int n = readlink("/r/localtime", tz, TD_TIMEZONE_LEN - 1); + int n = readlink("/etc/localtime", tz, TD_TIMEZONE_LEN - 1); if (n < 0) { uWarn("[tz] failed to readlink /etc/localtime, reason:%s", strerror(errno)); break; @@ -903,6 +897,7 @@ END: if (tz[0] == '\0') { memcpy(tz, "n/a", sizeof("n/a")); } + uDebug("[tz] system timezone:%s", tz); } int32_t taosGetSystemTimezone(char *outTimezoneStr) { @@ -3211,3 +3206,627 @@ leapcorr(struct state const *sp, time_t t) } return 0; } + + +/* + * ************************************************************************** + * The code from here to the end of the file is the code for the + * strftime() function. + * ***************** + */ + + +#ifndef DEPRECATE_TWO_DIGIT_YEARS +# define DEPRECATE_TWO_DIGIT_YEARS false +#endif + +struct lc_time_T { + const char * mon[MONSPERYEAR]; + const char * month[MONSPERYEAR]; + const char * wday[DAYSPERWEEK]; + const char * weekday[DAYSPERWEEK]; + const char * X_fmt; + const char * x_fmt; + const char * c_fmt; + const char * am; + const char * pm; + const char * date_fmt; +}; + +static const struct lc_time_T C_time_locale = { + { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" + }, { + "January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December" + }, { + "Sun", "Mon", "Tue", "Wed", + "Thu", "Fri", "Sat" + }, { + "Sunday", "Monday", "Tuesday", "Wednesday", + "Thursday", "Friday", "Saturday" + }, + + /* X_fmt */ + "%H:%M:%S", + + /* + ** x_fmt + ** C99 and later require this format. + ** Using just numbers (as here) makes Quakers happier; + ** it's also compatible with SVR4. + */ + "%m/%d/%y", + + /* + ** c_fmt + ** C99 and later require this format. + ** Previously this code used "%D %X", but we now conform to C99. + ** Note that + ** "%a %b %d %H:%M:%S %Y" + ** is used by Solaris 2.3. + */ + "%a %b %e %T %Y", + + /* am */ + "AM", + + /* pm */ + "PM", + + /* date_fmt */ + "%a %b %e %H:%M:%S %Z %Y" +}; + +enum warn { IN_NONE, IN_SOME, IN_THIS, IN_ALL }; + +static char * _add(const char *, char *, const char *); +static char * _conv(int, const char *, char *, const char *); +static char * _fmt(const char *, const struct tm *, char *, const char *, + enum warn *); +static char * _yconv(int, int, bool, bool, char *, char const *); + +#ifndef YEAR_2000_NAME +# define YEAR_2000_NAME "CHECK_STRFTIME_FORMATS_FOR_TWO_DIGIT_YEARS" +#endif /* !defined YEAR_2000_NAME */ + +#if HAVE_STRFTIME_L +size_t +strftime_l(char *restrict s, size_t maxsize, char const *restrict format, + struct tm const *restrict t, + ATTRIBUTE_MAYBE_UNUSED locale_t locale) +{ + /* Just call strftime, as only the C locale is supported. */ + return strftime(s, maxsize, format, t); +} +#endif + +size_t +strftime(char *restrict s, size_t maxsize, char const *restrict format, + struct tm const *restrict t) +{ + char * p; + int saved_errno = errno; + enum warn warn = IN_NONE; + + tzset(); + p = _fmt(format, t, s, s + maxsize, &warn); + if (DEPRECATE_TWO_DIGIT_YEARS + && warn != IN_NONE && getenv(YEAR_2000_NAME)) { + fprintf(stderr, "\n"); + fprintf(stderr, "strftime format \"%s\" ", format); + fprintf(stderr, "yields only two digits of years in "); + if (warn == IN_SOME) + fprintf(stderr, "some locales"); + else if (warn == IN_THIS) + fprintf(stderr, "the current locale"); + else fprintf(stderr, "all locales"); + fprintf(stderr, "\n"); + } + if (p == s + maxsize) { + errno = ERANGE; + return 0; + } + *p = '\0'; + errno = saved_errno; + return p - s; +} + +static char * +_fmt(const char *format, const struct tm *t, char *pt, + const char *ptlim, enum warn *warnp) +{ + struct lc_time_T const *Locale = &C_time_locale; + + for ( ; *format; ++format) { + if (*format == '%') { + label: + switch (*++format) { + default: + /* Output unknown conversion specifiers as-is, + to aid debugging. This includes '%' at + format end. This conforms to C23 section + 7.29.3.5 paragraph 6, which says behavior + is undefined here. */ + --format; + break; + case 'A': + pt = _add((t->tm_wday < 0 || + t->tm_wday >= DAYSPERWEEK) ? + "?" : Locale->weekday[t->tm_wday], + pt, ptlim); + continue; + case 'a': + pt = _add((t->tm_wday < 0 || + t->tm_wday >= DAYSPERWEEK) ? + "?" : Locale->wday[t->tm_wday], + pt, ptlim); + continue; + case 'B': + pt = _add((t->tm_mon < 0 || + t->tm_mon >= MONSPERYEAR) ? + "?" : Locale->month[t->tm_mon], + pt, ptlim); + continue; + case 'b': + case 'h': + pt = _add((t->tm_mon < 0 || + t->tm_mon >= MONSPERYEAR) ? + "?" : Locale->mon[t->tm_mon], + pt, ptlim); + continue; + case 'C': + /* + ** %C used to do a... + ** _fmt("%a %b %e %X %Y", t); + ** ...whereas now POSIX 1003.2 calls for + ** something completely different. + ** (ado, 1993-05-24) + */ + pt = _yconv(t->tm_year, TM_YEAR_BASE, + true, false, pt, ptlim); + continue; + case 'c': + { + enum warn warn2 = IN_SOME; + + pt = _fmt(Locale->c_fmt, t, pt, ptlim, &warn2); + if (warn2 == IN_ALL) + warn2 = IN_THIS; + if (warn2 > *warnp) + *warnp = warn2; + } + continue; + case 'D': + pt = _fmt("%m/%d/%y", t, pt, ptlim, warnp); + continue; + case 'd': + pt = _conv(t->tm_mday, "%02d", pt, ptlim); + continue; + case 'E': + case 'O': + /* + ** Locale modifiers of C99 and later. + ** The sequences + ** %Ec %EC %Ex %EX %Ey %EY + ** %Od %oe %OH %OI %Om %OM + ** %OS %Ou %OU %OV %Ow %OW %Oy + ** are supposed to provide alternative + ** representations. + */ + goto label; + case 'e': + pt = _conv(t->tm_mday, "%2d", pt, ptlim); + continue; + case 'F': + pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp); + continue; + case 'H': + pt = _conv(t->tm_hour, "%02d", pt, ptlim); + continue; + case 'I': + pt = _conv((t->tm_hour % 12) ? + (t->tm_hour % 12) : 12, + "%02d", pt, ptlim); + continue; + case 'j': + pt = _conv(t->tm_yday + 1, "%03d", pt, ptlim); + continue; + case 'k': + /* + ** This used to be... + ** _conv(t->tm_hour % 12 ? + ** t->tm_hour % 12 : 12, 2, ' '); + ** ...and has been changed to the below to + ** match SunOS 4.1.1 and Arnold Robbins' + ** strftime version 3.0. That is, "%k" and + ** "%l" have been swapped. + ** (ado, 1993-05-24) + */ + pt = _conv(t->tm_hour, "%2d", pt, ptlim); + continue; +#ifdef KITCHEN_SINK + case 'K': + /* + ** After all this time, still unclaimed! + */ + pt = _add("kitchen sink", pt, ptlim); + continue; +#endif /* defined KITCHEN_SINK */ + case 'l': + /* + ** This used to be... + ** _conv(t->tm_hour, 2, ' '); + ** ...and has been changed to the below to + ** match SunOS 4.1.1 and Arnold Robbin's + ** strftime version 3.0. That is, "%k" and + ** "%l" have been swapped. + ** (ado, 1993-05-24) + */ + pt = _conv((t->tm_hour % 12) ? + (t->tm_hour % 12) : 12, + "%2d", pt, ptlim); + continue; + case 'M': + pt = _conv(t->tm_min, "%02d", pt, ptlim); + continue; + case 'm': + pt = _conv(t->tm_mon + 1, "%02d", pt, ptlim); + continue; + case 'n': + pt = _add("\n", pt, ptlim); + continue; + case 'p': + pt = _add((t->tm_hour >= (HOURSPERDAY / 2)) ? + Locale->pm : + Locale->am, + pt, ptlim); + continue; + case 'R': + pt = _fmt("%H:%M", t, pt, ptlim, warnp); + continue; + case 'r': + pt = _fmt("%I:%M:%S %p", t, pt, ptlim, warnp); + continue; + case 'S': + pt = _conv(t->tm_sec, "%02d", pt, ptlim); + continue; + case 's': + { + struct tm tm; + char buf[INT_STRLEN_MAXIMUM( + time_t) + 1]; + time_t mkt; + + tm.tm_sec = t->tm_sec; + tm.tm_min = t->tm_min; + tm.tm_hour = t->tm_hour; + tm.tm_mday = t->tm_mday; + tm.tm_mon = t->tm_mon; + tm.tm_year = t->tm_year; +#ifdef TM_GMTOFF + mkt = timeoff(&tm, t->TM_GMTOFF); +#else + tm.tm_isdst = t->tm_isdst; + mkt = mktime(&tm); +#endif + /* If mktime fails, %s expands to the + value of (time_t) -1 as a failure + marker; this is better in practice + than strftime failing. */ + if (TYPE_SIGNED(time_t)) { + intmax_t n = mkt; + sprintf(buf, "%"PRIdMAX, n); + } else { + uintmax_t n = mkt; + sprintf(buf, "%"PRIuMAX, n); + } + pt = _add(buf, pt, ptlim); + } + continue; + case 'T': + pt = _fmt("%H:%M:%S", t, pt, ptlim, warnp); + continue; + case 't': + pt = _add("\t", pt, ptlim); + continue; + case 'U': + pt = _conv((t->tm_yday + DAYSPERWEEK - + t->tm_wday) / DAYSPERWEEK, + "%02d", pt, ptlim); + continue; + case 'u': + /* + ** From Arnold Robbins' strftime version 3.0: + ** "ISO 8601: Weekday as a decimal number + ** [1 (Monday) - 7]" + ** (ado, 1993-05-24) + */ + pt = _conv((t->tm_wday == 0) ? + DAYSPERWEEK : t->tm_wday, + "%d", pt, ptlim); + continue; + case 'V': /* ISO 8601 week number */ + case 'G': /* ISO 8601 year (four digits) */ + case 'g': /* ISO 8601 year (two digits) */ +/* +** From Arnold Robbins' strftime version 3.0: "the week number of the +** year (the first Monday as the first day of week 1) as a decimal number +** (01-53)." +** (ado, 1993-05-24) +** +** From by Markus Kuhn: +** "Week 01 of a year is per definition the first week which has the +** Thursday in this year, which is equivalent to the week which contains +** the fourth day of January. In other words, the first week of a new year +** is the week which has the majority of its days in the new year. Week 01 +** might also contain days from the previous year and the week before week +** 01 of a year is the last week (52 or 53) of the previous year even if +** it contains days from the new year. A week starts with Monday (day 1) +** and ends with Sunday (day 7). For example, the first week of the year +** 1997 lasts from 1996-12-30 to 1997-01-05..." +** (ado, 1996-01-02) +*/ + { + int year; + int base; + int yday; + int wday; + int w; + + year = t->tm_year; + base = TM_YEAR_BASE; + yday = t->tm_yday; + wday = t->tm_wday; + for ( ; ; ) { + int len; + int bot; + int top; + + len = isleap_sum(year, base) ? + DAYSPERLYEAR : + DAYSPERNYEAR; + /* + ** What yday (-3 ... 3) does + ** the ISO year begin on? + */ + bot = ((yday + 11 - wday) % + DAYSPERWEEK) - 3; + /* + ** What yday does the NEXT + ** ISO year begin on? + */ + top = bot - + (len % DAYSPERWEEK); + if (top < -3) + top += DAYSPERWEEK; + top += len; + if (yday >= top) { + ++base; + w = 1; + break; + } + if (yday >= bot) { + w = 1 + ((yday - bot) / + DAYSPERWEEK); + break; + } + --base; + yday += isleap_sum(year, base) ? + DAYSPERLYEAR : + DAYSPERNYEAR; + } +#ifdef XPG4_1994_04_09 + if ((w == 52 && + t->tm_mon == TM_JANUARY) || + (w == 1 && + t->tm_mon == TM_DECEMBER)) + w = 53; +#endif /* defined XPG4_1994_04_09 */ + if (*format == 'V') + pt = _conv(w, "%02d", + pt, ptlim); + else if (*format == 'g') { + *warnp = IN_ALL; + pt = _yconv(year, base, + false, true, + pt, ptlim); + } else pt = _yconv(year, base, + true, true, + pt, ptlim); + } + continue; + case 'v': + /* + ** From Arnold Robbins' strftime version 3.0: + ** "date as dd-bbb-YYYY" + ** (ado, 1993-05-24) + */ + pt = _fmt("%e-%b-%Y", t, pt, ptlim, warnp); + continue; + case 'W': + pt = _conv((t->tm_yday + DAYSPERWEEK - + (t->tm_wday ? + (t->tm_wday - 1) : + (DAYSPERWEEK - 1))) / DAYSPERWEEK, + "%02d", pt, ptlim); + continue; + case 'w': + pt = _conv(t->tm_wday, "%d", pt, ptlim); + continue; + case 'X': + pt = _fmt(Locale->X_fmt, t, pt, ptlim, warnp); + continue; + case 'x': + { + enum warn warn2 = IN_SOME; + + pt = _fmt(Locale->x_fmt, t, pt, ptlim, &warn2); + if (warn2 == IN_ALL) + warn2 = IN_THIS; + if (warn2 > *warnp) + *warnp = warn2; + } + continue; + case 'y': + *warnp = IN_ALL; + pt = _yconv(t->tm_year, TM_YEAR_BASE, + false, true, + pt, ptlim); + continue; + case 'Y': + pt = _yconv(t->tm_year, TM_YEAR_BASE, + true, true, + pt, ptlim); + continue; + case 'Z': +#ifdef TM_ZONE + pt = _add(t->TM_ZONE, pt, ptlim); +#elif HAVE_TZNAME + if (t->tm_isdst >= 0) + pt = _add(tzname[t->tm_isdst != 0], + pt, ptlim); +#endif + /* + ** C99 and later say that %Z must be + ** replaced by the empty string if the + ** time zone abbreviation is not + ** determinable. + */ + continue; + case 'z': +#if defined TM_GMTOFF || USG_COMPAT || ALTZONE + { + long diff; + char const * sign; + bool negative; + +# ifdef TM_GMTOFF + diff = t->TM_GMTOFF; +# else + /* + ** C99 and later say that the UT offset must + ** be computed by looking only at + ** tm_isdst. This requirement is + ** incorrect, since it means the code + ** must rely on magic (in this case + ** altzone and timezone), and the + ** magic might not have the correct + ** offset. Doing things correctly is + ** tricky and requires disobeying the standard; + ** see GNU C strftime for details. + ** For now, punt and conform to the + ** standard, even though it's incorrect. + ** + ** C99 and later say that %z must be replaced by + ** the empty string if the time zone is not + ** determinable, so output nothing if the + ** appropriate variables are not available. + */ + if (t->tm_isdst < 0) + continue; + if (t->tm_isdst == 0) +# if USG_COMPAT + diff = -timezone; +# else + continue; +# endif + else +# if ALTZONE + diff = -altzone; +# else + continue; +# endif +# endif + negative = diff < 0; + if (diff == 0) { +# ifdef TM_ZONE + negative = t->TM_ZONE[0] == '-'; +# else + negative = t->tm_isdst < 0; +# if HAVE_TZNAME + if (tzname[t->tm_isdst != 0][0] == '-') + negative = true; +# endif +# endif + } + if (negative) { + sign = "-"; + diff = -diff; + } else sign = "+"; + pt = _add(sign, pt, ptlim); + diff /= SECSPERMIN; + diff = (diff / MINSPERHOUR) * 100 + + (diff % MINSPERHOUR); + pt = _conv(diff, "%04d", pt, ptlim); + } +#endif + continue; + case '+': + pt = _fmt(Locale->date_fmt, t, pt, ptlim, + warnp); + continue; + case '%': + break; + } + } + if (pt == ptlim) + break; + *pt++ = *format; + } + return pt; +} + +static char * +_conv(int n, const char *format, char *pt, const char *ptlim) +{ + char buf[INT_STRLEN_MAXIMUM(int) + 1]; + + sprintf(buf, format, n); + return _add(buf, pt, ptlim); +} + +static char * +_add(const char *str, char *pt, const char *ptlim) +{ + while (pt < ptlim && (*pt = *str++) != '\0') + ++pt; + return pt; +} + +/* +** POSIX and the C Standard are unclear or inconsistent about +** what %C and %y do if the year is negative or exceeds 9999. +** Use the convention that %C concatenated with %y yields the +** same output as %Y, and that %Y contains at least 4 bytes, +** with more only if necessary. +*/ + +static char * +_yconv(int a, int b, bool convert_top, bool convert_yy, + char *pt, const char *ptlim) +{ + register int lead; + register int trail; + + int DIVISOR = 100; + trail = a % DIVISOR + b % DIVISOR; + lead = a / DIVISOR + b / DIVISOR + trail / DIVISOR; + trail %= DIVISOR; + if (trail < 0 && lead > 0) { + trail += DIVISOR; + --lead; + } else if (lead < 0 && trail > 0) { + trail -= DIVISOR; + ++lead; + } + if (convert_top) { + if (lead == 0 && trail < 0) + pt = _add("-0", pt, ptlim); + else pt = _conv(lead, "%02d", pt, ptlim); + } + if (convert_yy) + pt = _conv(((trail < 0) ? -trail : trail), "%02d", pt, ptlim); + return pt; +} \ No newline at end of file diff --git a/source/os/test/osTimeTests.cpp b/source/os/test/osTimeTests.cpp index 42837cc537..501502f7e6 100644 --- a/source/os/test/osTimeTests.cpp +++ b/source/os/test/osTimeTests.cpp @@ -29,30 +29,11 @@ #include "os.h" #include "tlog.h" -TEST(osTimeTests, taosLocalTimeNolock) { - time_t currentTime; - // Test when result is not NULL - struct tm expectedTime; - struct tm* result = taosLocalTimeNolock(&expectedTime, ¤tTime, 1); - if (result) { - EXPECT_EQ(expectedTime.tm_year, result->tm_year); - EXPECT_EQ(expectedTime.tm_mon, result->tm_mon); - EXPECT_EQ(expectedTime.tm_mday, result->tm_mday); - EXPECT_EQ(expectedTime.tm_hour, result->tm_hour); - EXPECT_EQ(expectedTime.tm_min, result->tm_min); - EXPECT_EQ(expectedTime.tm_sec, result->tm_sec); - EXPECT_EQ(expectedTime.tm_wday, result->tm_wday); - EXPECT_EQ(expectedTime.tm_yday, result->tm_yday); - EXPECT_EQ(expectedTime.tm_isdst, result->tm_isdst); - } -} - - TEST(osTimeTests, taosLocalTime) { // Test 1: Test when both timep and result are not NULL time_t timep = 1617531000; // 2021-04-04 18:10:00 struct tm result; - struct tm* local_time = taosLocalTime(&timep, &result, NULL, 0); + struct tm* local_time = taosLocalTime(&timep, &result, NULL, 0, NULL); ASSERT_NE(local_time, nullptr); ASSERT_EQ(local_time->tm_year, 121); ASSERT_EQ(local_time->tm_mon, 3); @@ -62,7 +43,7 @@ TEST(osTimeTests, taosLocalTime) { ASSERT_EQ(local_time->tm_sec, 00); // Test 2: Test when timep is NULL - local_time = taosLocalTime(NULL, &result, NULL, 0); + local_time = taosLocalTime(NULL, &result, NULL, 0, NULL); ASSERT_EQ(local_time, nullptr); // Test 4: Test when timep is negative on Windows diff --git a/source/util/src/tconfig.c b/source/util/src/tconfig.c index 96056e3678..a4fc223c90 100644 --- a/source/util/src/tconfig.c +++ b/source/util/src/tconfig.c @@ -254,14 +254,14 @@ static int32_t cfgSetTimezone(SConfigItem *pItem, const char *value, ECfgSrcType uError("invalid timezone:%s", value); TAOS_RETURN(TSDB_CODE_INVALID_TIMEZONE); } - TAOS_CHECK_RETURN(osSetTimezone(value)); - - TAOS_CHECK_RETURN(doSetConf(pItem, value, stype)); if (strlen(value) == 0) { uError("cfg:%s, type:%s src:%s, value:%s, skip to set timezone", pItem->name, cfgDtypeStr(pItem->dtype), cfgStypeStr(stype), value); TAOS_RETURN(TSDB_CODE_SUCCESS); } + TAOS_CHECK_RETURN(osSetTimezone(value)); + + TAOS_CHECK_RETURN(doSetConf(pItem, tsTimezoneStr, stype)); TAOS_RETURN(TSDB_CODE_SUCCESS); } @@ -698,11 +698,19 @@ int32_t cfgDumpItemValue(SConfigItem *pItem, char *buf, int32_t bufSize, int32_t case CFG_DTYPE_DOUBLE: len = tsnprintf(buf, bufSize, "%f", pItem->fval); break; + case CFG_DTYPE_TIMEZONE:{ +// char str1[TD_TIMEZONE_LEN] = {0}; +// time_t tx1 = taosGetTimestampSec(); +// if (taosFormatTimezoneStr(tx1, buf, NULL, str1) != 0) { +// tstrncpy(str1, "tz error", sizeof(str1)); +// } +// len = tsnprintf(buf, bufSize, "%s", str1); +// break; + } case CFG_DTYPE_STRING: case CFG_DTYPE_DIR: case CFG_DTYPE_LOCALE: case CFG_DTYPE_CHARSET: - case CFG_DTYPE_TIMEZONE: case CFG_DTYPE_NONE: len = tsnprintf(buf, bufSize, "%s", pItem->str); break; diff --git a/source/util/src/tlog.c b/source/util/src/tlog.c index 76d0139521..9e6d946637 100644 --- a/source/util/src/tlog.c +++ b/source/util/src/tlog.c @@ -20,6 +20,7 @@ #include "tglobal.h" #include "tjson.h" #include "tutil.h" +#include "ttime.h" #define LOG_MAX_LINE_SIZE (10024) #define LOG_MAX_LINE_BUFFER_SIZE (LOG_MAX_LINE_SIZE + 3) @@ -157,24 +158,11 @@ static int32_t taosStartLog() { static void getDay(char *buf, int32_t bufSize) { time_t t = taosTime(NULL); struct tm tmInfo; - if (taosLocalTime(&t, &tmInfo, buf, bufSize) != NULL) { + if (taosLocalTime(&t, &tmInfo, buf, bufSize, NULL) != NULL) { TAOS_UNUSED(strftime(buf, bufSize, "%Y-%m-%d", &tmInfo)); } } -static int64_t getTimestampToday() { - time_t t = taosTime(NULL); - struct tm tm; - if (taosLocalTime(&t, &tm, NULL, 0) == NULL) { - return 0; - } - tm.tm_hour = 0; - tm.tm_min = 0; - tm.tm_sec = 0; - - return (int64_t)taosMktime(&tm); -} - static void getFullPathName(char *fullName, const char *logName) { if (strlen(tsLogDir) != 0) { char lastC = tsLogDir[strlen(tsLogDir) - 1]; @@ -206,7 +194,7 @@ int32_t taosInitSlowLog() { getDay(day, sizeof(day)); (void)snprintf(name, PATH_MAX + TD_TIME_STR_LEN, "%s.%s", tsLogObj.slowLogName, day); - tsLogObj.timestampToday = getTimestampToday(); + tsLogObj.timestampToday = taosGetTimestampToday(TSDB_TIME_PRECISION_SECONDS, NULL); tsLogObj.slowHandle = taosLogBuffNew(LOG_SLOW_BUF_SIZE); if (tsLogObj.slowHandle == NULL) return terrno; @@ -448,7 +436,7 @@ static void taosOpenNewSlowLogFile() { TdFilePtr pOldFile = tsLogObj.slowHandle->pFile; tsLogObj.slowHandle->pFile = pFile; (void)taosCloseFile(&pOldFile); - tsLogObj.timestampToday = getTimestampToday(); + tsLogObj.timestampToday = taosGetTimestampToday(TSDB_TIME_PRECISION_SECONDS, NULL); (void)taosThreadMutexUnlock(&tsLogObj.logMutex); } @@ -634,8 +622,11 @@ static inline int32_t taosBuildLogHead(char *buffer, const char *flags) { TAOS_UNUSED(taosGetTimeOfDay(&timeSecs)); time_t curTime = timeSecs.tv_sec; - ptm = taosLocalTime(&curTime, &Tm, NULL, 0); - + ptm = taosLocalTime(&curTime, &Tm, NULL, 0, NULL); + if (ptm == NULL){ + uError("%s failed to get local time, code:%d", __FUNCTION__ , errno); + return 0; + } return sprintf(buffer, "%02d/%02d %02d:%02d:%02d.%06d %08" PRId64 " %s %s", ptm->tm_mon + 1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec, (int32_t)timeSecs.tv_usec, taosGetSelfPthreadId(), LOG_EDITION_FLG, flags); diff --git a/tests/system-test/2-query/timezone.py b/tests/system-test/2-query/timezone.py index 33bcb16595..4b1509a2b5 100644 --- a/tests/system-test/2-query/timezone.py +++ b/tests/system-test/2-query/timezone.py @@ -159,9 +159,44 @@ class TDTestCase: tdSql.execute(f'drop database {self.dbname}') + # def timezone_check(self, cursor, timezone): + # cursor.execute("show local variables") + # res = cursor.fetchall() + # for i in range(cursor.rowcount): + # if res[i][0] == "timezone" : + # if res[i][1].find(timezone) == -1: + # tdLog.exit("show timezone:%s != %s"%(res[i][1],timezone)) + # + # def timezone_check_set_options(self): + # buildPath = tdCom.getBuildPath() + # cmdStr = '%s/build/bin/timezone_test'%(buildPath) + # print("cmdStr:", cmdStr) + # tdLog.info(cmdStr) + # ret = os.system(cmdStr) + # if ret != 0: + # tdLog.exit("timezone_test error") + # + # def timezone_check_conf(self, timezone): + # updateCfgDict = ({"clientCfg" : {'timezone': 'UTC'} },) + # tdDnodes.sim.deploy(updateCfgDict) + # conn = taos.connect(config=tdDnodes.getSimCfgPath()) + # cursor = conn.cursor() + # self.timezone_check(cursor, 'UTC') + # cursor.close() + def timezone_check(self, sql, timezone): + tdSql.query(sql) + rows = tdSql.getRows() + for i in range(rows): + if tdSql.getData(i, 0) == "timezone" : + if tdSql.getData(i, 1).find(timezone) == -1: + tdLog.exit("show timezone:%s != %s"%(tdSql.getData(i, 1),timezone)) def run(self): # sourcery skip: extract-duplicate-method - timezone = self.get_system_timezone() + # timezone = self.get_system_timezone() + timezone = "Asia/Shanghai" + self.timezone_check("show local variables", timezone) + self.timezone_check("show dnode 1 variables", timezone) + self.timezone_check_ntb(timezone) self.timezone_check_stb(timezone) self.timezone_format_test() diff --git a/tests/system-test/2-query/timezone_conf.py b/tests/system-test/2-query/timezone_conf.py new file mode 100644 index 0000000000..2a54114a6b --- /dev/null +++ b/tests/system-test/2-query/timezone_conf.py @@ -0,0 +1,34 @@ + +from util.log import * +from util.sql import * +from util.cases import * +from util.sqlset import * +from util.cluster import * + +class TDTestCase: + updateCfgDict = {"clientCfg" : {'timezone': 'UTC'} , 'timezone': 'UTC-8'} + + def init(self, conn, logSql, replicaVar=1): + self.replicaVar = int(replicaVar) + tdLog.debug(f"start to excute {__file__}") + tdSql.init(conn.cursor()) + + def timezone_check(self, timezone, sql): + tdSql.execute(sql) + rows = tdSql.getRows() + for i in range(rows): + if tdSql.getData(i, 0) == "timezone" : + if tdSql.getData(i, 1).find(timezone) == -1: + tdLog.exit("show timezone:%s != %s"%(tdSql.getData(i, 1),timezone)) + + def run(self): + self.timezone_check('UTC', "show local variables") + self.timezone_check('UTC-8', "show dnode 1 variables") + + def stop(self): + tdSql.close() + tdLog.success(f"{__file__} successfully executed") + + +tdCases.addLinux(__file__, TDTestCase()) +tdCases.addWindows(__file__, TDTestCase()) diff --git a/tools/shell/src/shellEngine.c b/tools/shell/src/shellEngine.c index 50a7fe8119..e8a1a38e30 100644 --- a/tools/shell/src/shellEngine.c +++ b/tools/shell/src/shellEngine.c @@ -337,7 +337,7 @@ char *shellFormatTimestamp(char *buf, int32_t bufSize, int64_t val, int32_t prec } struct tm ptm = {0}; - if (taosLocalTime(&tt, &ptm, buf, bufSize) == NULL) { + if (taosLocalTime(&tt, &ptm, buf, bufSize, NULL) == NULL) { return buf; } size_t pos = strftime(buf, 35, "%Y-%m-%d %H:%M:%S", &ptm); diff --git a/utils/test/c/CMakeLists.txt b/utils/test/c/CMakeLists.txt index 7589d11840..15a4424185 100644 --- a/utils/test/c/CMakeLists.txt +++ b/utils/test/c/CMakeLists.txt @@ -15,6 +15,7 @@ add_executable(tmq_multi_thread_test tmq_multi_thread_test.c) add_executable(tmq_offset_test tmq_offset_test.c) add_executable(varbinary_test varbinary_test.c) add_executable(replay_test replay_test.c) +add_executable(timezone_test timezone_test.c) if(${TD_LINUX}) add_executable(tsz_test tsz_test.c) @@ -142,6 +143,14 @@ target_link_libraries( PUBLIC os ) +target_link_libraries( + timezone_test + PUBLIC taos + PUBLIC util + PUBLIC common + PUBLIC os +) + if(${TD_LINUX}) target_link_libraries( tsz_test diff --git a/utils/test/c/timezone_test.c b/utils/test/c/timezone_test.c new file mode 100644 index 0000000000..f8bedc62cc --- /dev/null +++ b/utils/test/c/timezone_test.c @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include "taos.h" +#include "types.h" +#include "tlog.h" + +char* timezone_name = "America/New_York"; +void check_timezone(const char* tzName){ + TAOS* pConn = taos_connect("localhost", "root", "taosdata", NULL, 0); + ASSERT(pConn != NULL); + TAOS_RES *pRes = taos_query(pConn, "show local variables"); + ASSERT(taos_errno(pRes) == 0); + TAOS_ROW row = NULL; + while ((row = taos_fetch_row(pRes)) != NULL) { + if (strcmp(row[0], "timezone") == 0){ + ASSERT(strstr(row[1], tzName) != NULL); + } + } + taos_free_result(pRes); + taos_close(pConn); +} + +void timezone_set_options_test(){ + taos_options(TSDB_OPTION_TIMEZONE, timezone_name); + check_timezone(timezone_name); +} + +void timezone_insert_test(){ + TAOS *taos = taos_connect("localhost", "root", "taosdata", NULL, 0); + + TAOS_RES *pRes = taos_query(taos, "drop database if exists tz_db"); + taos_free_result(pRes); + + pRes = taos_query(taos, "create database if not exists tz_db"); + taos_free_result(pRes); + + pRes = taos_query(taos, "use tz_db"); + int code = taos_errno(pRes); + taos_free_result(pRes); + ASSERT(code == 0); + + pRes = taos_query(taos, "create stable stb (ts timestamp, c1 int) tags (t1 timestamp, t2 binary(32))"); + taos_free_result(pRes); + + pRes = taos_query(taos, "create table ntb (ts timestamp, c1 int)"); + taos_free_result(pRes); + + pRes = taos_query(taos, "insert into tb1 using stb tags (1, 'test') values (1, 2)"); + taos_free_result(pRes); + + pRes = taos_query(taos, "insert into tb1 using stb tags ('2013-04-12T10:52:01', 'test') values ('2013-04-12T10:52:01', 2)"); + taos_free_result(pRes); + + pRes = taos_query(taos, "insert into ntb values ('2013-04-12T10:52:01', 2)"); + taos_free_result(pRes); + + pRes = taos_query(taos, "insert into ntb values (1, 2)"); + taos_free_result(pRes); + + + /* + select today(); + select cast(1 as timestamp) + '2013-04-12T10:52:01'; + tsConver.sim + "COMPACT DATABASE test START WITH '2023-03-07 14:01:23' END WITH '2023-03-08 14:01:23'" + TK_TIMEZONE + + ts > c1('2013-04-12T10:52:01') + in ('2013-04-12T10:52:01') + + offsetFromTz hash join + */ +} + +int main(int argc, char *argv[]) { + int ret = 0; + timezone_set_options_test(); + return ret; +} diff --git a/utils/test/c/tmqDemo.c b/utils/test/c/tmqDemo.c index 40ed98132c..550613ee9a 100644 --- a/utils/test/c/tmqDemo.c +++ b/utils/test/c/tmqDemo.c @@ -597,7 +597,7 @@ void printParaIntoFile() { time_t tTime = taosGetTimestampSec(); struct tm tm; - taosLocalTime(&tTime, &tm, NULL, 0); + taosLocalTime(&tTime, &tm, NULL, 0, NULL); taosFprintfFile(pFile, "###################################################################\n"); taosFprintfFile(pFile, "# configDir: %s\n", configDir); diff --git a/utils/test/c/tmqSim.c b/utils/test/c/tmqSim.c index c045629d1f..bb0d813ace 100644 --- a/utils/test/c/tmqSim.c +++ b/utils/test/c/tmqSim.c @@ -166,7 +166,7 @@ static void printHelp() { char* getCurrentTimeString(char* timeString) { time_t tTime = taosGetTimestampSec(); struct tm tm; - taosLocalTime(&tTime, &tm, NULL, 0); + taosLocalTime(&tTime, &tm, NULL, 0, NULL); sprintf(timeString, "%d-%02d-%02d %02d:%02d:%02d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); @@ -472,7 +472,7 @@ static char* shellFormatTimestamp(char* buf, int32_t bufSize, int64_t val, int32 } struct tm ptm; - if (taosLocalTime(&tt, &ptm, buf, bufSize) == NULL) { + if (taosLocalTime(&tt, &ptm, buf, bufSize, NULL) == NULL) { return buf; } size_t pos = strftime(buf, 35, "%Y-%m-%d %H:%M:%S", &ptm); diff --git a/utils/tsim/src/simExe.c b/utils/tsim/src/simExe.c index c7cec64dec..2d269bdea2 100644 --- a/utils/tsim/src/simExe.c +++ b/utils/tsim/src/simExe.c @@ -797,7 +797,7 @@ bool simExecuteNativeSqlCommand(SScript *script, char *rest, bool isSlow) { tt = (*(int64_t *)row[i]) / 1000000000; } - if (taosLocalTime(&tt, &tp, timeStr, sizeof(timeStr)) == NULL) { + if (taosLocalTime(&tt, &tp, timeStr, sizeof(timeStr), NULL) == NULL) { break; } strftime(timeStr, 64, "%y-%m-%d %H:%M:%S", &tp);