diff --git a/include/os/osTimezone.h b/include/os/osTimezone.h index c9cb55207c..82f4b7b30b 100644 --- a/include/os/osTimezone.h +++ b/include/os/osTimezone.h @@ -26,7 +26,7 @@ extern "C" { extern void* pTimezoneNameMap; #ifdef WINDOWS -typedef struct void *timezone_t; +typedef void *timezone_t; #else typedef struct state *timezone_t; struct tm *localtime_rz(timezone_t , time_t const *, struct tm *); diff --git a/include/util/taoserror.h b/include/util/taoserror.h index 73a38ac38f..9b1e0d7320 100644 --- a/include/util/taoserror.h +++ b/include/util/taoserror.h @@ -1027,7 +1027,7 @@ int32_t taosGetErrSize(); #define TSDB_CODE_AUDIT_FAIL_GENERATE_JSON TAOS_DEF_ERROR_CODE(0, 0x6102) //TIMEZONE -#define TSDB_CODE_INVALID_TIMEZONE TAOS_DEF_ERROR_CODE(0, 0x6200) +#define TSDB_CODE_NOT_SUPPORTTED_IN_WINDOWS TAOS_DEF_ERROR_CODE(0, 0x6200) #ifdef __cplusplus } diff --git a/source/client/src/clientMain.c b/source/client/src/clientMain.c index d87f43dd2b..13cf39f924 100644 --- a/source/client/src/clientMain.c +++ b/source/client/src/clientMain.c @@ -56,6 +56,12 @@ int taos_options(TSDB_OPTION option, const void *arg, ...) { return ret; } +#ifndef WINDOWS +static void freeTz(void *p){ + timezone_t tz = *(timezone_t *)p; + tzfree(tz); +} + static timezone_t setConnnectionTz(const char* val){ timezone_t tz = NULL; static int32_t lock_c = 0; @@ -73,7 +79,7 @@ static timezone_t setConnnectionTz(const char* val){ atomic_store_32(&lock_c, 0); goto END; } - taosHashSetFreeFp(pTimezoneMap, (_hash_free_fn_t)tzfree); + taosHashSetFreeFp(pTimezoneMap, freeTz); } if (pTimezoneNameMap == NULL){ @@ -94,10 +100,9 @@ static timezone_t setConnnectionTz(const char* val){ tz = tzalloc(val); if (tz == NULL) { tscWarn("%s unknown timezone %s change to UTC", __func__, val); - val = "UTC"; - tz = tzalloc(val); + tz = tzalloc("UTC"); if (tz == NULL) { - tscError("%s set timezone %s error", __func__, val); + tscError("%s set timezone UTC error", __func__); terrno = TAOS_SYSTEM_ERROR(errno); goto END; } @@ -120,11 +125,19 @@ END: atomic_store_32(&lock_c, 0); return tz; } +#endif + static int32_t setConnectionOption(TAOS *taos, TSDB_OPTION_CONNECTION option, const char* val){ if (taos == NULL) { return TSDB_CODE_INVALID_PARA; } +#ifdef WINDOWS + if (option == TSDB_OPTION_CONNECTION_TIMEZONE){ + return TSDB_CODE_NOT_SUPPORTTED_IN_WINDOWS; + } +#endif + if (option < TSDB_OPTION_CONNECTION_CLEAR || option >= TSDB_MAX_OPTIONS_CONNECTION){ return TSDB_CODE_INVALID_PARA; } @@ -163,7 +176,11 @@ static int32_t setConnectionOption(TAOS *taos, TSDB_OPTION_CONNECTION option, co } if (option == TSDB_OPTION_CONNECTION_TIMEZONE || option == TSDB_OPTION_CONNECTION_CLEAR) { +#ifndef WINDOWS if (val != NULL){ + if (val[0] == 0){ + val = "UTC"; + } timezone_t tz = setConnnectionTz(val); if (tz == NULL){ code = terrno; @@ -173,6 +190,7 @@ static int32_t setConnectionOption(TAOS *taos, TSDB_OPTION_CONNECTION option, co } else { pObj->optionInfo.timezone = NULL; } +#endif } if (option == TSDB_OPTION_CONNECTION_USER_APP || option == TSDB_OPTION_CONNECTION_CLEAR) { diff --git a/source/client/test/timezoneTest.cpp b/source/client/test/timezoneTest.cpp index 84ee53452a..382b28e275 100644 --- a/source/client/test/timezoneTest.cpp +++ b/source/client/test/timezoneTest.cpp @@ -225,7 +225,9 @@ TEST(timezoneCase, setConnectionOption_Test) { // test timezone code = taos_options_connection(pConn, TSDB_OPTION_CONNECTION_TIMEZONE, ""); - ASSERT(code != 0); + ASSERT(code == 0); + CHECK_TAOS_OPTION_POINTER(pConn, timezone, false); + check_sql_result(pConn, "select timezone()", "UTC (UTC, +0000)"); code = taos_options_connection(pConn, TSDB_OPTION_CONNECTION_TIMEZONE, NULL); ASSERT(code == 0); @@ -243,7 +245,9 @@ TEST(timezoneCase, setConnectionOption_Test) { check_sql_result(pConn, "select timezone()", "Asia/Kolkata (IST, +0530)"); code = taos_options_connection(pConn, TSDB_OPTION_CONNECTION_TIMEZONE, "adbc"); - ASSERT(code != 0); + ASSERT(code == 0); + CHECK_TAOS_OPTION_POINTER(pConn, timezone, false); + check_sql_result(pConn, "select timezone()", "adbc (UTC, +0000)"); // test user APP code = taos_options_connection(pConn, TSDB_OPTION_CONNECTION_USER_APP, ""); @@ -593,6 +597,19 @@ TEST(timezoneCase, func_timezone_Test) { execQuery(pConn, "insert into db1.ntb1 values(1704070200000, '2023-12-31 23:50:00', 11)"); // 2023-12-31 23:50:00-0100 checkRows(pConn, "select a.ts,b.ts from db1.ntb a join db1.ntb1 b on timetruncate(a.ts, 1d) = timetruncate(b.ts, 1d)", 1); + // operator +1n +1y + check_sql_result(pConn, "select TO_ISO8601(CAST('2023-01-31T00:00:00.000-01' as timestamp) + 1n)", "2023-02-28T00:00:00.000-0100"); + check_sql_result(pConn, "select TO_ISO8601(CAST('2024-01-31T00:00:00.000-01' as timestamp) + 1n)", "2024-02-29T00:00:00.000-0100"); + check_sql_result(pConn, "select TO_ISO8601(CAST('2024-02-29T00:00:00.000-01' as timestamp) + 1y)", "2025-02-28T00:00:00.000-0100"); + check_sql_result(pConn, "select TO_ISO8601(CAST('2024-01-31T00:00:00.000-01' as timestamp) + 1y)", "2025-01-31T00:00:00.000-0100"); + + check_sql_result(pConn, "select TO_ISO8601(CAST('2024-01-01T00:00:00.000+01' as timestamp) + 1n)", "2024-01-31T22:00:00.000-0100"); + check_sql_result(pConn, "select TO_ISO8601(CAST('2024-01-01T00:00:00.000+01' as timestamp) + 1y)", "2024-12-31T22:00:00.000-0100"); + + // case when + check_sql_result_integer(pConn, "select case CAST('2024-01-01T00:00:00.000+01' as timestamp) when 1704063600000 then 1 end", 1); + check_sql_result_integer(pConn, "select case CAST('2024-01-01T00:00:00.000' as timestamp) when 1704070800000 then 1 end", 1); + taos_close(pConn); } diff --git a/source/common/src/ttime.c b/source/common/src/ttime.c index 45b5ab6564..db3f7fec32 100644 --- a/source/common/src/ttime.c +++ b/source/common/src/ttime.c @@ -1408,11 +1408,17 @@ static int32_t tm2char(const SArray* formats, const struct STm* tm, char* s, int (void)sprintf(s, "%09" PRId64, tm->fsec); s += 9; break; - case TSFKW_TZH: - (void)sprintf(s, "%c%02d", (tm->tm.tm_gmtoff >= 0) ? '+' : '-', - abs((int) tm->tm.tm_gmtoff) / 3600); + case TSFKW_TZH:{ +#ifdef WINDOWS + int32_t gmtoff = -_timezone; +#else + int32_t gmtoff = tm->tm.tm_gmtoff; +#endif + (void)sprintf(s, "%c%02d", (gmtoff >= 0) ? '+' : '-', + abs(gmtoff) / 3600); s += strlen(s); break; + } case TSFKW_YYYY: (void)sprintf(s, "%04d", tm->tm.tm_year + 1900); s += strlen(s); @@ -1832,7 +1838,12 @@ static int32_t char2ts(const char* s, SArray* formats, int64_t* ts, int32_t prec tm.fsec = ms * 1000000 + us * 1000 + ns; int32_t ret = taosTm2Ts(&tm, ts, precision, tz); if (tzHour != 0) { - *ts += (tm.tm.tm_gmtoff - tzHour * 3600) * TICK_PER_SECOND[precision]; +#ifdef WINDOWS + int32_t gmtoff = -_timezone; +#else + int32_t gmtoff = tm.tm.tm_gmtoff; +#endif + *ts += (gmtoff - tzHour * 3600) * TICK_PER_SECOND[precision]; } return ret; } diff --git a/source/os/src/osTime.c b/source/os/src/osTime.c index f25631f932..2720eab56e 100644 --- a/source/os/src/osTime.c +++ b/source/os/src/osTime.c @@ -422,56 +422,18 @@ int64_t user_mktime64(const uint32_t year, const uint32_t mon, const uint32_t da time_t taosMktime(struct tm *timep, timezone_t tz) { #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 + int64_t tzw = 0; + #ifdef _MSC_VER + #if _MSC_VER >= 1900 + tzw = _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 + timep->tm_sec, tzw); #else time_t r = tz != NULL ? mktime_z(tz, timep) : mktime(timep); if (r == (time_t)-1) { @@ -486,56 +448,7 @@ struct tm *taosGmTimeR(const time_t *timep, struct tm *result){ 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; - } - } + return gmtime_s(result, timep); #else return gmtime_r(timep, result); #endif @@ -545,7 +458,11 @@ time_t taosTimeGm(struct tm *tmp){ if (tmp == NULL) { return -1; } +#ifdef WINDOWS + return _mkgmtime(tmp); +#else return timegm(tmp); +#endif } struct tm *taosLocalTime(const time_t *timep, struct tm *result, char *buf, int32_t bufSize, timezone_t tz) { diff --git a/source/os/src/osTimezone.c b/source/os/src/osTimezone.c index a5a839ea35..d47c0ac663 100644 --- a/source/os/src/osTimezone.c +++ b/source/os/src/osTimezone.c @@ -790,7 +790,11 @@ int32_t taosGetLocalTimezoneOffset() { uError("%s failed to get local time: code:%d", __FUNCTION__, errno); return TSDB_CODE_TIME_ERROR; } +#ifdef WINDOWS + return -_timezone; +#else return (int32_t)(tm1.tm_gmtoff); +#endif } int32_t taosFormatTimezoneStr(time_t t, const char* tz, timezone_t sp, char *outTimezoneStr){ diff --git a/source/util/src/terror.c b/source/util/src/terror.c index a3cb3e80bf..ca498a9c75 100644 --- a/source/util/src/terror.c +++ b/source/util/src/terror.c @@ -871,7 +871,7 @@ TAOS_DEFINE_ERROR(TSDB_CODE_AUDIT_FAIL_SEND_AUDIT_RECORD, "Failed to send out TAOS_DEFINE_ERROR(TSDB_CODE_AUDIT_FAIL_GENERATE_JSON, "Failed to generate json") //TIMEZONE -TAOS_DEFINE_ERROR(TSDB_CODE_INVALID_TIMEZONE, "Invalid timezone") +TAOS_DEFINE_ERROR(TSDB_CODE_NOT_SUPPORTTED_IN_WINDOWS,"Operation not supported in windows") #ifdef TAOS_ERROR_C }; #endif diff --git a/tests/system-test/0-others/information_schema.py b/tests/system-test/0-others/information_schema.py index 538aa1ad63..f5378b189e 100644 --- a/tests/system-test/0-others/information_schema.py +++ b/tests/system-test/0-others/information_schema.py @@ -225,7 +225,7 @@ class TDTestCase: tdSql.checkEqual(True, len(tdSql.queryResult) in range(282, 283)) tdSql.query("select * from information_schema.ins_columns where db_name ='performance_schema'") - tdSql.checkEqual(56, len(tdSql.queryResult)) + tdSql.checkEqual(60, len(tdSql.queryResult)) def ins_dnodes_check(self): tdSql.execute('drop database if exists db2') diff --git a/tests/system-test/2-query/timezone.py b/tests/system-test/2-query/timezone.py index 88c16fb163..e08e85dcf5 100644 --- a/tests/system-test/2-query/timezone.py +++ b/tests/system-test/2-query/timezone.py @@ -142,9 +142,7 @@ class TDTestCase: tdSql.query(f"select ts from {self.dbname}.d5") tdSql.checkData(0, 0, "2021-07-01 20:00:00.000") - tdSql.execute(f"insert into {self.dbname}.d6 using {self.dbname}.stb tags (1) values ('2021-07-01T00:00:00.000-115',1)") - tdSql.query(f"select ts from {self.dbname}.d6") - tdSql.checkData(0, 0, "2021-07-01 19:05:00.000") + tdSql.error(f"insert into {self.dbname}.d6 using {self.dbname}.stb tags (1) values ('2021-07-01T00:00:00.000-115',1)") tdSql.execute(f"insert into {self.dbname}.d7 using {self.dbname}.stb tags (1) values ('2021-07-01T00:00:00.000-1105',1)") tdSql.query(f"select ts from {self.dbname}.d7")