feat: support to_timestamp/to_char fix comments
This commit is contained in:
parent
f299a28109
commit
70850697a4
|
@ -486,7 +486,7 @@ return_timestamp: {
|
||||||
#### TO_CHAR
|
#### TO_CHAR
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
TO_CHAR(ts, str_literal)
|
TO_CHAR(ts, format_str_literal)
|
||||||
```
|
```
|
||||||
|
|
||||||
**Description**: Convert a ts column to string as the format specified
|
**Description**: Convert a ts column to string as the format specified
|
||||||
|
@ -539,11 +539,12 @@ TO_CHAR(ts, str_literal)
|
||||||
- When `ms`,`us`,`ns` are used in `to_char`, like `to_char(ts, 'yyyy-mm-dd hh:mi:ss.ms.us.ns')`, The time of `ms`,`us`,`ns` corresponds to the same fraction seconds. When ts is `1697182085123`, the output of `ms` is `123`, `us` is `123000`, `ns` is `123000000`.
|
- When `ms`,`us`,`ns` are used in `to_char`, like `to_char(ts, 'yyyy-mm-dd hh:mi:ss.ms.us.ns')`, The time of `ms`,`us`,`ns` corresponds to the same fraction seconds. When ts is `1697182085123`, the output of `ms` is `123`, `us` is `123000`, `ns` is `123000000`.
|
||||||
- If we want to output some characters of format without converting, surround it with double quotes. `to_char(ts, 'yyyy-mm-dd "is formated by yyyy-mm-dd"')`. If want to output double quotes, add a back slash before double quote, like `to_char(ts, '\"yyyy-mm-dd\"')` will output `"2023-10-10"`.
|
- If we want to output some characters of format without converting, surround it with double quotes. `to_char(ts, 'yyyy-mm-dd "is formated by yyyy-mm-dd"')`. If want to output double quotes, add a back slash before double quote, like `to_char(ts, '\"yyyy-mm-dd\"')` will output `"2023-10-10"`.
|
||||||
- For formats that output digits, the uppercase and lowercase formats are the same.
|
- For formats that output digits, the uppercase and lowercase formats are the same.
|
||||||
|
- The local time zone will be used to convert the timestamp.
|
||||||
|
|
||||||
#### TO_TIMESTAMP
|
#### TO_TIMESTAMP
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
TO_TIMESTAMP(str_literal, str_literal)
|
TO_TIMESTAMP(ts_str_literal, format_str_literal)
|
||||||
```
|
```
|
||||||
|
|
||||||
**Description**: Convert a formated timestamp string to a timestamp
|
**Description**: Convert a formated timestamp string to a timestamp
|
||||||
|
|
|
@ -486,7 +486,7 @@ return_timestamp: {
|
||||||
#### TO_CHAR
|
#### TO_CHAR
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
TO_CHAR(ts, str_literal)
|
TO_CHAR(ts, format_str_literal)
|
||||||
```
|
```
|
||||||
|
|
||||||
**功能说明**: 将timestamp类型按照指定格式转换为字符串
|
**功能说明**: 将timestamp类型按照指定格式转换为字符串
|
||||||
|
@ -504,7 +504,7 @@ TO_CHAR(ts, str_literal)
|
||||||
| **格式** | **说明**| **例子** |
|
| **格式** | **说明**| **例子** |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
|AM,am,PM,pm| 无点分隔的上午下午 | 07:00:00am|
|
|AM,am,PM,pm| 无点分隔的上午下午 | 07:00:00am|
|
||||||
|A.M.,a.m.,P.M.,p.m.| 有点分割的上午下午| 07:00:00a.m.|
|
|A.M.,a.m.,P.M.,p.m.| 有点分隔的上午下午| 07:00:00a.m.|
|
||||||
|YYYY,yyyy|年, 4个及以上数字| 2023-10-10|
|
|YYYY,yyyy|年, 4个及以上数字| 2023-10-10|
|
||||||
|YYY,yyy| 年, 最后3位数字| 023-10-10|
|
|YYY,yyy| 年, 最后3位数字| 023-10-10|
|
||||||
|YY,yy| 年, 最后2位数字| 23-10-10|
|
|YY,yy| 年, 最后2位数字| 23-10-10|
|
||||||
|
@ -537,13 +537,14 @@ TO_CHAR(ts, str_literal)
|
||||||
**使用说明**:
|
**使用说明**:
|
||||||
- `Month`, `Day`等的输出格式是左对齐的, 右侧添加空格, 如`2023-OCTOBER -01`, `2023-SEPTEMBER-01`, 9月是月份中英文字母数最长的, 因此9月没有空格. 星期类似.
|
- `Month`, `Day`等的输出格式是左对齐的, 右侧添加空格, 如`2023-OCTOBER -01`, `2023-SEPTEMBER-01`, 9月是月份中英文字母数最长的, 因此9月没有空格. 星期类似.
|
||||||
- 使用`ms`, `us`, `ns`时, 以上三种格式的输出只在精度上不同, 比如ts为 `1697182085123`, `ms` 的输出为 `123`, `us` 的输出为 `123000`, `ns` 的输出为 `123000000`.
|
- 使用`ms`, `us`, `ns`时, 以上三种格式的输出只在精度上不同, 比如ts为 `1697182085123`, `ms` 的输出为 `123`, `us` 的输出为 `123000`, `ns` 的输出为 `123000000`.
|
||||||
- 如果想要在格式串中指定某些部分不做转换, 可以使用双引号, 如`to_char(ts, 'yyyy-mm-dd "is formated by yyyy-mm-dd"')`. 如果想要输出双引号, 那么在双引号之前加一个反斜杠, 如 `to_char(ts, '\"yyyy-mm-dd\"')` 将会输出 `"2023-10-10"`.
|
- 时间格式中无法匹配规则的内容会直接输出. 如果想要在格式串中指定某些能够匹配规则的部分不做转换, 可以使用双引号, 如`to_char(ts, 'yyyy-mm-dd "is formated by yyyy-mm-dd"')`. 如果想要输出双引号, 那么在双引号之前加一个反斜杠, 如 `to_char(ts, '\"yyyy-mm-dd\"')` 将会输出 `"2023-10-10"`.
|
||||||
- 那些输出是数字的格式, 如`YYYY`, `DD`, 大写与小写意义相同, 即`yyyy` 和 `YYYY` 可以互换.
|
- 那些输出是数字的格式, 如`YYYY`, `DD`, 大写与小写意义相同, 即`yyyy` 和 `YYYY` 可以互换.
|
||||||
|
- 默认输出的时间为本地时区的时间.
|
||||||
|
|
||||||
#### TO_TIMESTAMP
|
#### TO_TIMESTAMP
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
TO_TIMESTAMP(str_literal, str_literal)
|
TO_TIMESTAMP(ts_str_literal, format_str_literal)
|
||||||
```
|
```
|
||||||
|
|
||||||
**功能说明**: 将字符串按照指定格式转化为时间戳.
|
**功能说明**: 将字符串按照指定格式转化为时间戳.
|
||||||
|
|
|
@ -100,15 +100,22 @@ int32_t taosTm2Ts(struct STm* tm, int64_t* ts, int32_t precision);
|
||||||
|
|
||||||
/// @brief convert a timestamp to a formatted string
|
/// @brief convert a timestamp to a formatted string
|
||||||
/// @param format the timestamp format, must null terminated
|
/// @param format the timestamp format, must null terminated
|
||||||
void taosTs2Char(const char* format, int64_t ts, int32_t precision, char* out);
|
/// @param [in,out] formats the formats array pointer generated. Shouldn't be NULL.
|
||||||
|
/// If (*formats == NULL), [format] will be used and [formats] will be updated to the new generated
|
||||||
|
/// 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
|
||||||
|
void taosTs2Char(const char* format, SArray** formats, int64_t ts, int32_t precision, char* out, int32_t outLen);
|
||||||
/// @brief convert a formatted timestamp string to a timestamp
|
/// @brief convert a formatted timestamp string to a timestamp
|
||||||
/// @param format must null terminated
|
/// @param format must null terminated
|
||||||
|
/// @param [in, out] formats, see taosTs2Char
|
||||||
/// @param tsStr must null terminated
|
/// @param tsStr must null terminated
|
||||||
/// @retval 0 for success, otherwise error occured
|
/// @retval 0 for success, otherwise error occured
|
||||||
int32_t taosChar2Ts(const char* format, const char* tsStr, int64_t* ts, int32_t precision, char* errMsg,
|
/// @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);
|
||||||
|
|
||||||
void TEST_ts2char(const char* format, int64_t ts, int32_t precision, char* out);
|
void 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);
|
int32_t TEST_char2ts(const char* format, int64_t* ts, int32_t precision, const char* tsStr);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
@ -1008,7 +1008,6 @@ typedef enum {
|
||||||
TSFKW_Day, // Sunday, Monday
|
TSFKW_Day, // Sunday, Monday
|
||||||
TSFKW_DY, // MON, TUE
|
TSFKW_DY, // MON, TUE
|
||||||
TSFKW_Dy, // Mon, Tue
|
TSFKW_Dy, // Mon, Tue
|
||||||
TSFKW_dy, // mon, tue
|
|
||||||
TSFKW_D, // 1-7 -> Sunday(1) -> Saturday(7)
|
TSFKW_D, // 1-7 -> Sunday(1) -> Saturday(7)
|
||||||
TSFKW_HH24,
|
TSFKW_HH24,
|
||||||
TSFKW_HH12,
|
TSFKW_HH12,
|
||||||
|
@ -1021,12 +1020,12 @@ typedef enum {
|
||||||
TSFKW_Mon,
|
TSFKW_Mon,
|
||||||
TSFKW_MS,
|
TSFKW_MS,
|
||||||
TSFKW_NS,
|
TSFKW_NS,
|
||||||
TSFKW_OF,
|
//TSFKW_OF,
|
||||||
TSFKW_PM,
|
TSFKW_PM,
|
||||||
TSFKW_P_M,
|
TSFKW_P_M,
|
||||||
TSFKW_SS,
|
TSFKW_SS,
|
||||||
// TSFKW_TZM,
|
|
||||||
TSFKW_TZH,
|
TSFKW_TZH,
|
||||||
|
// TSFKW_TZM,
|
||||||
// TSFKW_TZ,
|
// TSFKW_TZ,
|
||||||
TSFKW_US,
|
TSFKW_US,
|
||||||
TSFKW_YYYY,
|
TSFKW_YYYY,
|
||||||
|
@ -1039,13 +1038,15 @@ typedef enum {
|
||||||
TSFKW_a_m,
|
TSFKW_a_m,
|
||||||
// TSFKW_b_c,
|
// TSFKW_b_c,
|
||||||
// TSFKW_bc,
|
// TSFKW_bc,
|
||||||
TSFKW_d,
|
|
||||||
TSFKW_day,
|
TSFKW_day,
|
||||||
TSFKW_ddd,
|
TSFKW_ddd,
|
||||||
TSFKW_dd,
|
TSFKW_dd,
|
||||||
|
TSFKW_dy, // mon, tue
|
||||||
|
TSFKW_d,
|
||||||
TSFKW_hh24,
|
TSFKW_hh24,
|
||||||
TSFKW_hh12,
|
TSFKW_hh12,
|
||||||
TSFKW_hh,
|
TSFKW_hh,
|
||||||
|
TSFKW_mi,
|
||||||
TSFKW_mm,
|
TSFKW_mm,
|
||||||
TSFKW_month,
|
TSFKW_month,
|
||||||
TSFKW_mon,
|
TSFKW_mon,
|
||||||
|
@ -1067,17 +1068,17 @@ typedef enum {
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static const TSFormatKeyWord formatKeyWords[] = {
|
static const TSFormatKeyWord formatKeyWords[] = {
|
||||||
//{"A.D.", 4, TSFKW_A_D},
|
|
||||||
{"A.M.", 4, TSFKW_A_M, false},
|
|
||||||
//{"AD", 2, TSFKW_AD, false},
|
//{"AD", 2, TSFKW_AD, false},
|
||||||
|
//{"A.D.", 4, TSFKW_A_D},
|
||||||
{"AM", 2, TSFKW_AM, false},
|
{"AM", 2, TSFKW_AM, false},
|
||||||
//{"B.C.", 4, TSFKW_B_C, false},
|
{"A.M.", 4, TSFKW_A_M, false},
|
||||||
//{"BC", 2, TSFKW_BC, false},
|
//{"BC", 2, TSFKW_BC, false},
|
||||||
|
//{"B.C.", 4, TSFKW_B_C, false},
|
||||||
{"DAY", 3, TSFKW_DAY, false},
|
{"DAY", 3, TSFKW_DAY, false},
|
||||||
{"DDD", 3, TSFKW_DDD, true},
|
{"DDD", 3, TSFKW_DDD, true},
|
||||||
{"DD", 2, TSFKW_DD, true},
|
{"DD", 2, TSFKW_DD, true},
|
||||||
{"DY", 2, TSFKW_DY, false},
|
|
||||||
{"Day", 3, TSFKW_Day, false},
|
{"Day", 3, TSFKW_Day, false},
|
||||||
|
{"DY", 2, TSFKW_DY, false},
|
||||||
{"Dy", 2, TSFKW_Dy, false},
|
{"Dy", 2, TSFKW_Dy, false},
|
||||||
{"D", 1, TSFKW_D, true},
|
{"D", 1, TSFKW_D, true},
|
||||||
{"HH24", 4, TSFKW_HH24, true},
|
{"HH24", 4, TSFKW_HH24, true},
|
||||||
|
@ -1087,13 +1088,13 @@ static const TSFormatKeyWord formatKeyWords[] = {
|
||||||
{"MM", 2, TSFKW_MM, true},
|
{"MM", 2, TSFKW_MM, true},
|
||||||
{"MONTH", 5, TSFKW_MONTH, false},
|
{"MONTH", 5, TSFKW_MONTH, false},
|
||||||
{"MON", 3, TSFKW_MON, false},
|
{"MON", 3, TSFKW_MON, false},
|
||||||
{"MS", 2, TSFKW_MS, true},
|
|
||||||
{"Month", 5, TSFKW_Month, false},
|
{"Month", 5, TSFKW_Month, false},
|
||||||
{"Mon", 3, TSFKW_Mon, false},
|
{"Mon", 3, TSFKW_Mon, false},
|
||||||
|
{"MS", 2, TSFKW_MS, true},
|
||||||
{"NS", 2, TSFKW_NS, true},
|
{"NS", 2, TSFKW_NS, true},
|
||||||
//{"OF", 2, TSFKW_OF, false},
|
//{"OF", 2, TSFKW_OF, false},
|
||||||
{"P.M.", 4, TSFKW_P_M, false},
|
|
||||||
{"PM", 2, TSFKW_PM, false},
|
{"PM", 2, TSFKW_PM, false},
|
||||||
|
{"P.M.", 4, TSFKW_P_M, false},
|
||||||
{"SS", 2, TSFKW_SS, true},
|
{"SS", 2, TSFKW_SS, true},
|
||||||
{"TZH", 3, TSFKW_TZH, false},
|
{"TZH", 3, TSFKW_TZH, false},
|
||||||
//{"TZM", 3, TSFKW_TZM},
|
//{"TZM", 3, TSFKW_TZM},
|
||||||
|
@ -1104,9 +1105,9 @@ static const TSFormatKeyWord formatKeyWords[] = {
|
||||||
{"YY", 2, TSFKW_YY, true},
|
{"YY", 2, TSFKW_YY, true},
|
||||||
{"Y", 1, TSFKW_Y, true},
|
{"Y", 1, TSFKW_Y, true},
|
||||||
//{"a.d.", 4, TSFKW_a_d, false},
|
//{"a.d.", 4, TSFKW_a_d, false},
|
||||||
{"a.m.", 4, TSFKW_a_m, false},
|
|
||||||
//{"ad", 2, TSFKW_ad, false},
|
//{"ad", 2, TSFKW_ad, false},
|
||||||
{"am", 2, TSFKW_am, false},
|
{"am", 2, TSFKW_am, false},
|
||||||
|
{"a.m.", 4, TSFKW_a_m, false},
|
||||||
//{"b.c.", 4, TSFKW_b_c, false},
|
//{"b.c.", 4, TSFKW_b_c, false},
|
||||||
//{"bc", 2, TSFKW_bc, false},
|
//{"bc", 2, TSFKW_bc, false},
|
||||||
{"day", 3, TSFKW_day, false},
|
{"day", 3, TSFKW_day, false},
|
||||||
|
@ -1124,8 +1125,8 @@ static const TSFormatKeyWord formatKeyWords[] = {
|
||||||
{"ms", 2, TSFKW_MS, true},
|
{"ms", 2, TSFKW_MS, true},
|
||||||
{"ns", 2, TSFKW_NS, true},
|
{"ns", 2, TSFKW_NS, true},
|
||||||
//{"of", 2, TSFKW_OF, false},
|
//{"of", 2, TSFKW_OF, false},
|
||||||
{"p.m.", 4, TSFKW_p_m, false},
|
|
||||||
{"pm", 2, TSFKW_pm, false},
|
{"pm", 2, TSFKW_pm, false},
|
||||||
|
{"p.m.", 4, TSFKW_p_m, false},
|
||||||
{"ss", 2, TSFKW_SS, true},
|
{"ss", 2, TSFKW_SS, true},
|
||||||
{"tzh", 3, TSFKW_TZH, false},
|
{"tzh", 3, TSFKW_TZH, false},
|
||||||
//{"tzm", 3, TSFKW_TZM},
|
//{"tzm", 3, TSFKW_TZM},
|
||||||
|
@ -1139,9 +1140,34 @@ static const TSFormatKeyWord formatKeyWords[] = {
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
|
#define TS_FROMAT_KEYWORD_INDEX_SIZE ('z' - 'A' + 1)
|
||||||
|
static const int TSFormatKeywordIndex[TS_FROMAT_KEYWORD_INDEX_SIZE] = {
|
||||||
|
/*A*/ TSFKW_AM, -1, -1,
|
||||||
|
/*D*/ TSFKW_DAY, -1, -1, -1,
|
||||||
|
/*H*/ TSFKW_HH24, -1, -1, -1, -1,
|
||||||
|
/*M*/ TSFKW_MI,
|
||||||
|
/*N*/ TSFKW_NS, -1,
|
||||||
|
/*P*/ TSFKW_PM, -1, -1,
|
||||||
|
/*S*/ TSFKW_SS,
|
||||||
|
/*T*/ TSFKW_TZH,
|
||||||
|
/*U*/ TSFKW_US, -1, -1, -1,
|
||||||
|
/*Y*/ TSFKW_YYYY, -1,
|
||||||
|
/*[ \ ] ^ _ `*/ -1, -1, -1, -1, -1, -1,
|
||||||
|
/*a*/ TSFKW_am, -1, -1,
|
||||||
|
/*d*/ TSFKW_day, -1, -1, -1,
|
||||||
|
/*h*/ TSFKW_hh24, -1, -1, -1, -1,
|
||||||
|
/*m*/ TSFKW_mi,
|
||||||
|
/*n*/ TSFKW_ns, -1,
|
||||||
|
/*p*/ TSFKW_pm, -1, -1,
|
||||||
|
/*s*/ TSFKW_ss,
|
||||||
|
/*t*/ TSFKW_tzh,
|
||||||
|
/*u*/ TSFKW_us, -1, -1, -1,
|
||||||
|
/*y*/ TSFKW_yyyy, -1};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
char c[2];
|
const char* c;
|
||||||
|
int32_t len;
|
||||||
const TSFormatKeyWord* key;
|
const TSFormatKeyWord* key;
|
||||||
} TSFormatNode;
|
} TSFormatNode;
|
||||||
|
|
||||||
|
@ -1169,9 +1195,10 @@ static const char* const long_apms[] = {A_M_STR, P_M_STR, a_m_str, p_m_str, NULL
|
||||||
|
|
||||||
static const TSFormatKeyWord* keywordSearch(const char* str) {
|
static const TSFormatKeyWord* keywordSearch(const char* str) {
|
||||||
if (*str < 'A' || *str > 'z' || (*str > 'Z' && *str < 'a')) return NULL;
|
if (*str < 'A' || *str > 'z' || (*str > 'Z' && *str < 'a')) return NULL;
|
||||||
int32_t idx = 0;
|
int32_t idx = TSFormatKeywordIndex[str[0] - 'A'];
|
||||||
|
if (idx < 0) return NULL;
|
||||||
const TSFormatKeyWord* key = &formatKeyWords[idx++];
|
const TSFormatKeyWord* key = &formatKeyWords[idx++];
|
||||||
while (key->name) {
|
while (key->name && str[0] == key->name[0]) {
|
||||||
if (0 == strncmp(key->name, str, key->len)) {
|
if (0 == strncmp(key->name, str, key->len)) {
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
@ -1184,74 +1211,110 @@ static bool isSeperatorChar(char c) {
|
||||||
return (c > 0x20 && c < 0x7F && !(c >= 'A' && c <= 'Z') && !(c >= 'a' && c <= 'z') && !(c >= '0' && c <= '9'));
|
return (c > 0x20 && c < 0x7F && !(c >= 'A' && c <= 'Z') && !(c >= 'a' && c <= 'z') && !(c >= '0' && c <= '9'));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void parseTsFormat(const char* format_str, SArray* formats) {
|
static void parseTsFormat(const char* formatStr, SArray* formats) {
|
||||||
while (*format_str) {
|
TSFormatNode* lastOtherFormat = NULL;
|
||||||
const TSFormatKeyWord* key = keywordSearch(format_str);
|
while (*formatStr) {
|
||||||
|
const TSFormatKeyWord* key = keywordSearch(formatStr);
|
||||||
if (key) {
|
if (key) {
|
||||||
TSFormatNode format = {.key = key, .type = TS_FORMAT_NODE_TYPE_KEYWORD};
|
TSFormatNode format = {.key = key, .type = TS_FORMAT_NODE_TYPE_KEYWORD};
|
||||||
taosArrayPush(formats, &format);
|
taosArrayPush(formats, &format);
|
||||||
format_str += key->len;
|
formatStr += key->len;
|
||||||
|
lastOtherFormat = NULL;
|
||||||
} else {
|
} else {
|
||||||
if (*format_str == '"') {
|
if (*formatStr == '"') {
|
||||||
|
lastOtherFormat = NULL;
|
||||||
// for double quoted string
|
// for double quoted string
|
||||||
format_str++;
|
formatStr++;
|
||||||
while (*format_str) {
|
TSFormatNode* last = NULL;
|
||||||
if (*format_str == '"') {
|
while (*formatStr) {
|
||||||
format_str++;
|
if (*formatStr == '"') {
|
||||||
|
formatStr++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (*format_str == '\\' && *(format_str + 1)) format_str++;
|
if (*formatStr == '\\' && *(formatStr + 1)) {
|
||||||
|
formatStr++;
|
||||||
|
last = NULL; // stop expanding last format, create new format
|
||||||
|
}
|
||||||
|
if (last) {
|
||||||
|
// expand
|
||||||
|
assert(last->type == TS_FORMAT_NODE_TYPE_CHAR);
|
||||||
|
last->len++;
|
||||||
|
formatStr++;
|
||||||
|
} else {
|
||||||
|
// create new
|
||||||
TSFormatNode format = {.type = TS_FORMAT_NODE_TYPE_CHAR, .key = NULL};
|
TSFormatNode format = {.type = TS_FORMAT_NODE_TYPE_CHAR, .key = NULL};
|
||||||
format.c[0] = *format_str;
|
format.c = formatStr;
|
||||||
format.c[1] = '\0';
|
format.len = 1;
|
||||||
taosArrayPush(formats, &format);
|
taosArrayPush(formats, &format);
|
||||||
format_str++;
|
formatStr++;
|
||||||
|
last = taosArrayGetLast(formats);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// for other strings
|
// for other strings
|
||||||
if (*format_str == '\\' && *(format_str + 1)) format_str++;
|
if (*formatStr == '\\' && *(formatStr + 1)) {
|
||||||
|
formatStr++;
|
||||||
|
lastOtherFormat = NULL; // stop expanding
|
||||||
|
} else {
|
||||||
|
if (lastOtherFormat && !isSeperatorChar(*formatStr)) {
|
||||||
|
// expanding
|
||||||
|
} else {
|
||||||
|
// create new
|
||||||
|
lastOtherFormat = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (lastOtherFormat) {
|
||||||
|
assert(lastOtherFormat->type == TS_FORMAT_NODE_TYPE_CHAR);
|
||||||
|
lastOtherFormat->len++;
|
||||||
|
formatStr++;
|
||||||
|
} else {
|
||||||
TSFormatNode format = {
|
TSFormatNode format = {
|
||||||
.type = isSeperatorChar(*format_str) ? TS_FORMAT_NODE_TYPE_SEPARATOR : TS_FORMAT_NODE_TYPE_CHAR,
|
.type = isSeperatorChar(*formatStr) ? TS_FORMAT_NODE_TYPE_SEPARATOR : TS_FORMAT_NODE_TYPE_CHAR,
|
||||||
.key = NULL};
|
.key = NULL};
|
||||||
format.c[0] = *format_str;
|
format.c = formatStr;
|
||||||
format.c[1] = '\0';
|
format.len = 1;
|
||||||
taosArrayPush(formats, &format);
|
taosArrayPush(formats, &format);
|
||||||
format_str++;
|
formatStr++;
|
||||||
|
if (format.type == TS_FORMAT_NODE_TYPE_CHAR) lastOtherFormat = taosArrayGetLast(formats);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tm2char(const SArray* formats, const struct STm* tm, char* s) {
|
static void tm2char(const SArray* formats, const struct STm* tm, char* s, int32_t outLen) {
|
||||||
int32_t size = taosArrayGetSize(formats);
|
int32_t size = taosArrayGetSize(formats);
|
||||||
|
const char* start = s;
|
||||||
for (int32_t i = 0; i < size; ++i) {
|
for (int32_t i = 0; i < size; ++i) {
|
||||||
TSFormatNode* format = taosArrayGet(formats, i);
|
TSFormatNode* format = taosArrayGet(formats, i);
|
||||||
if (format->type != TS_FORMAT_NODE_TYPE_KEYWORD) {
|
if (format->type != TS_FORMAT_NODE_TYPE_KEYWORD) {
|
||||||
strcpy(s, format->c);
|
if (s - start + format->len + 1 > outLen) break;
|
||||||
s += strlen(s);
|
strncpy(s, format->c, format->len);
|
||||||
|
s += format->len;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (s - start + 16 > outLen) break;
|
||||||
|
|
||||||
switch (format->key->id) {
|
switch (format->key->id) {
|
||||||
case TSFKW_AM:
|
case TSFKW_AM:
|
||||||
case TSFKW_PM:
|
case TSFKW_PM:
|
||||||
sprintf(s, tm->tm.tm_hour % 24 >= 12 ? "PM" : "AM");
|
sprintf(s, tm->tm.tm_hour % 24 >= 12 ? "PM" : "AM");
|
||||||
s += strlen(s);
|
s += 2;
|
||||||
break;
|
break;
|
||||||
case TSFKW_A_M:
|
case TSFKW_A_M:
|
||||||
case TSFKW_P_M:
|
case TSFKW_P_M:
|
||||||
sprintf(s, tm->tm.tm_hour % 24 >= 12 ? "P.M." : "A.M.");
|
sprintf(s, tm->tm.tm_hour % 24 >= 12 ? "P.M." : "A.M.");
|
||||||
s += strlen(s);
|
s += 4;
|
||||||
break;
|
break;
|
||||||
case TSFKW_am:
|
case TSFKW_am:
|
||||||
case TSFKW_pm:
|
case TSFKW_pm:
|
||||||
sprintf(s, tm->tm.tm_hour % 24 >= 12 ? "pm" : "am");
|
sprintf(s, tm->tm.tm_hour % 24 >= 12 ? "pm" : "am");
|
||||||
s += strlen(s);
|
s += 2;
|
||||||
break;
|
break;
|
||||||
case TSFKW_a_m:
|
case TSFKW_a_m:
|
||||||
case TSFKW_p_m:
|
case TSFKW_p_m:
|
||||||
sprintf(s, tm->tm.tm_hour % 24 >= 12 ? "p.m." : "a.m.");
|
sprintf(s, tm->tm.tm_hour % 24 >= 12 ? "p.m." : "a.m.");
|
||||||
s += strlen(s);
|
s += 4;
|
||||||
break;
|
break;
|
||||||
case TSFKW_DDD:
|
case TSFKW_DDD:
|
||||||
sprintf(s, "%d", tm->tm.tm_yday);
|
sprintf(s, "%d", tm->tm.tm_yday);
|
||||||
|
@ -1259,11 +1322,11 @@ static void tm2char(const SArray* formats, const struct STm* tm, char* s) {
|
||||||
break;
|
break;
|
||||||
case TSFKW_DD:
|
case TSFKW_DD:
|
||||||
sprintf(s, "%02d", tm->tm.tm_mday);
|
sprintf(s, "%02d", tm->tm.tm_mday);
|
||||||
s += strlen(s);
|
s += 2;
|
||||||
break;
|
break;
|
||||||
case TSFKW_D:
|
case TSFKW_D:
|
||||||
sprintf(s, "%d", tm->tm.tm_wday + 1);
|
sprintf(s, "%d", tm->tm.tm_wday + 1);
|
||||||
s += strlen(s);
|
s += 1;
|
||||||
break;
|
break;
|
||||||
case TSFKW_DAY: {
|
case TSFKW_DAY: {
|
||||||
// MONDAY, TUESDAY...
|
// MONDAY, TUESDAY...
|
||||||
|
@ -1293,13 +1356,13 @@ static void tm2char(const SArray* formats, const struct STm* tm, char* s) {
|
||||||
char buf[8] = {0};
|
char buf[8] = {0};
|
||||||
for (int32_t i = 0; i < strlen(wd); ++i) buf[i] = toupper(wd[i]);
|
for (int32_t i = 0; i < strlen(wd); ++i) buf[i] = toupper(wd[i]);
|
||||||
sprintf(s, "%3s", buf);
|
sprintf(s, "%3s", buf);
|
||||||
s += strlen(s);
|
s += 3;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TSFKW_Dy:
|
case TSFKW_Dy:
|
||||||
// Mon, Tue
|
// Mon, Tue
|
||||||
sprintf(s, "%3s", shortWeekDays[tm->tm.tm_wday]);
|
sprintf(s, "%3s", shortWeekDays[tm->tm.tm_wday]);
|
||||||
s += strlen(s);
|
s += 3;
|
||||||
break;
|
break;
|
||||||
case TSFKW_dy: {
|
case TSFKW_dy: {
|
||||||
// mon, tue
|
// mon, tue
|
||||||
|
@ -1307,26 +1370,26 @@ static void tm2char(const SArray* formats, const struct STm* tm, char* s) {
|
||||||
char buf[8] = {0};
|
char buf[8] = {0};
|
||||||
for (int32_t i = 0; i < strlen(wd); ++i) buf[i] = tolower(wd[i]);
|
for (int32_t i = 0; i < strlen(wd); ++i) buf[i] = tolower(wd[i]);
|
||||||
sprintf(s, "%3s", buf);
|
sprintf(s, "%3s", buf);
|
||||||
s += strlen(s);
|
s += 3;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TSFKW_HH24:
|
case TSFKW_HH24:
|
||||||
sprintf(s, "%02d", tm->tm.tm_hour);
|
sprintf(s, "%02d", tm->tm.tm_hour);
|
||||||
s += strlen(s);
|
s += 2;
|
||||||
break;
|
break;
|
||||||
case TSFKW_HH:
|
case TSFKW_HH:
|
||||||
case TSFKW_HH12:
|
case TSFKW_HH12:
|
||||||
// 0 or 12 o'clock in 24H coresponds to 12 o'clock (AM/PM) in 12H
|
// 0 or 12 o'clock in 24H coresponds to 12 o'clock (AM/PM) in 12H
|
||||||
sprintf(s, "%02d", tm->tm.tm_hour % 12 == 0 ? 12 : tm->tm.tm_hour % 12);
|
sprintf(s, "%02d", tm->tm.tm_hour % 12 == 0 ? 12 : tm->tm.tm_hour % 12);
|
||||||
s += strlen(s);
|
s += 2;
|
||||||
break;
|
break;
|
||||||
case TSFKW_MI:
|
case TSFKW_MI:
|
||||||
sprintf(s, "%02d", tm->tm.tm_min);
|
sprintf(s, "%02d", tm->tm.tm_min);
|
||||||
s += strlen(s);
|
s += 2;
|
||||||
break;
|
break;
|
||||||
case TSFKW_MM:
|
case TSFKW_MM:
|
||||||
sprintf(s, "%02d", tm->tm.tm_mon + 1);
|
sprintf(s, "%02d", tm->tm.tm_mon + 1);
|
||||||
s += strlen(s);
|
s += 2;
|
||||||
break;
|
break;
|
||||||
case TSFKW_MONTH: {
|
case TSFKW_MONTH: {
|
||||||
const char* mon = fullMonths[tm->tm.tm_mon];
|
const char* mon = fullMonths[tm->tm.tm_mon];
|
||||||
|
@ -1370,19 +1433,19 @@ static void tm2char(const SArray* formats, const struct STm* tm, char* s) {
|
||||||
}
|
}
|
||||||
case TSFKW_SS:
|
case TSFKW_SS:
|
||||||
sprintf(s, "%02d", tm->tm.tm_sec);
|
sprintf(s, "%02d", tm->tm.tm_sec);
|
||||||
s += strlen(s);
|
s += 2;
|
||||||
break;
|
break;
|
||||||
case TSFKW_MS:
|
case TSFKW_MS:
|
||||||
sprintf(s, "%03" PRId64, tm->fsec / 1000000L);
|
sprintf(s, "%03" PRId64, tm->fsec / 1000000L);
|
||||||
s += strlen(s);
|
s += 3;
|
||||||
break;
|
break;
|
||||||
case TSFKW_US:
|
case TSFKW_US:
|
||||||
sprintf(s, "%06" PRId64, tm->fsec / 1000L);
|
sprintf(s, "%06" PRId64, tm->fsec / 1000L);
|
||||||
s += strlen(s);
|
s += 6;
|
||||||
break;
|
break;
|
||||||
case TSFKW_NS:
|
case TSFKW_NS:
|
||||||
sprintf(s, "%09" PRId64, tm->fsec);
|
sprintf(s, "%09" PRId64, tm->fsec);
|
||||||
s += strlen(s);
|
s += 9;
|
||||||
break;
|
break;
|
||||||
case TSFKW_TZH:
|
case TSFKW_TZH:
|
||||||
sprintf(s, "%s%02d", tsTimezone < 0 ? "-" : "+", tsTimezone);
|
sprintf(s, "%s%02d", tsTimezone < 0 ? "-" : "+", tsTimezone);
|
||||||
|
@ -1429,6 +1492,7 @@ static const char* tsFormatStr2Int32(int32_t* dest, const char* str, int32_t len
|
||||||
char* last;
|
char* last;
|
||||||
int64_t res;
|
int64_t res;
|
||||||
const char* s = str;
|
const char* s = str;
|
||||||
|
if ('\0' == str[0]) return NULL;
|
||||||
if (len <= 0) {
|
if (len <= 0) {
|
||||||
res = taosStr2Int64(s, &last, 10);
|
res = taosStr2Int64(s, &last, 10);
|
||||||
s = last;
|
s = last;
|
||||||
|
@ -1523,18 +1587,27 @@ static int32_t char2ts(const char* s, SArray* formats, int64_t* ts, int32_t prec
|
||||||
int32_t tzSign = 1, tz = tsTimezone;
|
int32_t tzSign = 1, tz = tsTimezone;
|
||||||
int32_t err = 0;
|
int32_t err = 0;
|
||||||
|
|
||||||
for (int32_t i = 0; i < size; ++i) {
|
for (int32_t i = 0; i < size && *s != '\0'; ++i) {
|
||||||
while (isspace(*s)) {
|
while (isspace(*s) && *s != '\0') {
|
||||||
s++;
|
s++;
|
||||||
}
|
}
|
||||||
|
if (!s) break;
|
||||||
TSFormatNode* node = taosArrayGet(formats, i);
|
TSFormatNode* node = taosArrayGet(formats, i);
|
||||||
if (node->type == TS_FORMAT_NODE_TYPE_SEPARATOR) {
|
if (node->type == TS_FORMAT_NODE_TYPE_SEPARATOR) {
|
||||||
// separator matches any character
|
// separator matches any character
|
||||||
if (isSeperatorChar(s[0])) s += strlen(node->c);
|
if (isSeperatorChar(s[0])) s += node->len;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (node->type == TS_FORMAT_NODE_TYPE_CHAR) {
|
if (node->type == TS_FORMAT_NODE_TYPE_CHAR) {
|
||||||
if (!isspace(node->c[0])) s += strlen(node->c);
|
int32_t pos = 0;
|
||||||
|
// skip leading spaces
|
||||||
|
while (isspace(node->c[pos]) && node->len > 0) pos++;
|
||||||
|
while (pos < node->len && *s != '\0') {
|
||||||
|
if (!isspace(node->c[pos++])) {
|
||||||
|
while (isspace(*s) && *s != '\0') s++;
|
||||||
|
if (*s != '\0') s++; // forward together
|
||||||
|
}
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
assert(node->type == TS_FORMAT_NODE_TYPE_KEYWORD);
|
assert(node->type == TS_FORMAT_NODE_TYPE_KEYWORD);
|
||||||
|
@ -1545,7 +1618,7 @@ static int32_t char2ts(const char* s, SArray* formats, int64_t* ts, int32_t prec
|
||||||
case TSFKW_p_m: {
|
case TSFKW_p_m: {
|
||||||
int32_t idx = strArrayCaseSearch(long_apms, s);
|
int32_t idx = strArrayCaseSearch(long_apms, s);
|
||||||
if (idx >= 0) {
|
if (idx >= 0) {
|
||||||
s += strlen(long_apms[idx]);
|
s += 4;
|
||||||
pm = idx % 2;
|
pm = idx % 2;
|
||||||
hour12 = 1;
|
hour12 = 1;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1558,7 +1631,7 @@ static int32_t char2ts(const char* s, SArray* formats, int64_t* ts, int32_t prec
|
||||||
case TSFKW_pm: {
|
case TSFKW_pm: {
|
||||||
int32_t idx = strArrayCaseSearch(apms, s);
|
int32_t idx = strArrayCaseSearch(apms, s);
|
||||||
if (idx >= 0) {
|
if (idx >= 0) {
|
||||||
s += strlen(apms[idx]);
|
s += 2;
|
||||||
pm = idx % 2;
|
pm = idx % 2;
|
||||||
hour12 = 1;
|
hour12 = 1;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1793,39 +1866,41 @@ static int32_t char2ts(const char* s, SArray* formats, int64_t* ts, int32_t prec
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void taosTs2Char(const char* format, int64_t ts, int32_t precision, char* out) {
|
void taosTs2Char(const char* format, SArray** formats, int64_t ts, int32_t precision, char* out, int32_t outLen) {
|
||||||
SArray* formats = taosArrayInit(8, sizeof(TSFormatNode));
|
if (!*formats) {
|
||||||
parseTsFormat(format, formats);
|
*formats = taosArrayInit(8, sizeof(TSFormatNode));
|
||||||
|
parseTsFormat(format, *formats);
|
||||||
|
}
|
||||||
struct STm tm;
|
struct STm tm;
|
||||||
taosTs2Tm(ts, precision, &tm);
|
taosTs2Tm(ts, precision, &tm);
|
||||||
tm2char(formats, &tm, out);
|
tm2char(*formats, &tm, out, outLen);
|
||||||
taosArrayDestroy(formats);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t taosChar2Ts(const char* format, const char* tsStr, int64_t* ts, int32_t precision, char* errMsg,
|
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) {
|
||||||
const char* sErrPos;
|
const char* sErrPos;
|
||||||
int32_t fErrIdx;
|
int32_t fErrIdx;
|
||||||
SArray* formats = taosArrayInit(4, sizeof(TSFormatNode));
|
if (!*formats) {
|
||||||
parseTsFormat(format, formats);
|
*formats = taosArrayInit(4, sizeof(TSFormatNode));
|
||||||
int32_t code = char2ts(tsStr, formats, ts, precision, &sErrPos, &fErrIdx);
|
parseTsFormat(format, *formats);
|
||||||
|
}
|
||||||
|
int32_t code = char2ts(tsStr, *formats, ts, precision, &sErrPos, &fErrIdx);
|
||||||
if (code == -1) {
|
if (code == -1) {
|
||||||
TSFormatNode* fNode = (taosArrayGet(formats, fErrIdx));
|
TSFormatNode* fNode = (taosArrayGet(*formats, fErrIdx));
|
||||||
snprintf(errMsg, errMsgLen, "mismatch format for: %s and %s", sErrPos,
|
snprintf(errMsg, errMsgLen, "mismatch format for: %s and %s", sErrPos,
|
||||||
fErrIdx < taosArrayGetSize(formats) ? ((TSFormatNode*)taosArrayGet(formats, fErrIdx))->key->name : "");
|
fErrIdx < taosArrayGetSize(*formats) ? ((TSFormatNode*)taosArrayGet(*formats, fErrIdx))->key->name : "");
|
||||||
} else if (code == -2) {
|
} else if (code == -2) {
|
||||||
snprintf(errMsg, errMsgLen, "timestamp format error: %s -> %s", tsStr, format);
|
snprintf(errMsg, errMsgLen, "timestamp format error: %s -> %s", tsStr, format);
|
||||||
}
|
}
|
||||||
taosArrayDestroy(formats);
|
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TEST_ts2char(const char* format, int64_t ts, int32_t precision, char* out) {
|
void TEST_ts2char(const char* format, int64_t ts, int32_t precision, char* out, int32_t outLen) {
|
||||||
SArray* formats = taosArrayInit(4, sizeof(TSFormatNode));
|
SArray* formats = taosArrayInit(4, sizeof(TSFormatNode));
|
||||||
parseTsFormat(format, formats);
|
parseTsFormat(format, formats);
|
||||||
struct STm tm;
|
struct STm tm;
|
||||||
taosTs2Tm(ts, precision, &tm);
|
taosTs2Tm(ts, precision, &tm);
|
||||||
tm2char(formats, &tm, out);
|
tm2char(formats, &tm, out, outLen);
|
||||||
taosArrayDestroy(formats);
|
taosArrayDestroy(formats);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -316,8 +316,8 @@ TEST(timeTest, timestamp2tm) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_ts2char(int64_t ts, const char* format, int32_t precison, const char* expected) {
|
void test_ts2char(int64_t ts, const char* format, int32_t precison, const char* expected) {
|
||||||
char buf[128] = {0};
|
char buf[256] = {0};
|
||||||
TEST_ts2char(format, ts, precison, buf);
|
TEST_ts2char(format, ts, precison, buf, 256);
|
||||||
printf("ts: %ld format: %s res: [%s], expected: [%s]\n", ts, format, buf, expected);
|
printf("ts: %ld format: %s res: [%s], expected: [%s]\n", ts, format, buf, expected);
|
||||||
ASSERT_STREQ(expected, buf);
|
ASSERT_STREQ(expected, buf);
|
||||||
}
|
}
|
||||||
|
@ -408,8 +408,8 @@ TEST(timeTest, char2ts) {
|
||||||
|
|
||||||
#ifndef WINDOWS
|
#ifndef WINDOWS
|
||||||
// 2023-1-1 21:10:10.120450780
|
// 2023-1-1 21:10:10.120450780
|
||||||
ASSERT_EQ(0, TEST_char2ts("yy \"年\"-MM 月-dd \"日\" HH24:MI:ss.ms.us.ns TZH", &ts, TSDB_TIME_PRECISION_NANO,
|
ASSERT_EQ(0, TEST_char2ts("yy \"年\"-MM 月-dd \"日 子\" HH24:MI:ss.ms.us.ns TZH", &ts, TSDB_TIME_PRECISION_NANO,
|
||||||
" 23 年 - 1 月 - 01 日 \t 21:10:10 . 12 . \t 00045 . 00000078 \t+08"));
|
" 23 年 - 1 月 - 01 日 子 \t 21:10:10 . 12 . \t 00045 . 00000078 \t+08"));
|
||||||
ASSERT_EQ(ts, 1672578610120450780LL);
|
ASSERT_EQ(ts, 1672578610120450780LL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -437,7 +437,7 @@ TEST(timeTest, char2ts) {
|
||||||
"2100/january/01 FRIDAY 11:10:10.124456+08"));
|
"2100/january/01 FRIDAY 11:10:10.124456+08"));
|
||||||
ASSERT_EQ(ts, 4102456210124456LL);
|
ASSERT_EQ(ts, 4102456210124456LL);
|
||||||
ASSERT_EQ(0, TEST_char2ts("yyyy/Month/dd Dy HH24:MI:ss.usTZH", &ts, TSDB_TIME_PRECISION_MICRO,
|
ASSERT_EQ(0, TEST_char2ts("yyyy/Month/dd Dy HH24:MI:ss.usTZH", &ts, TSDB_TIME_PRECISION_MICRO,
|
||||||
"2100/january/01 Fri 11:10:10.124456+08"));
|
"2100/january/01 Fri 11:10:10.124456+08:00"));
|
||||||
ASSERT_EQ(ts, 4102456210124456LL);
|
ASSERT_EQ(ts, 4102456210124456LL);
|
||||||
|
|
||||||
ASSERT_EQ(0, TEST_char2ts("yyyy/month/dd day HH24:MI:ss.usTZH", &ts, TSDB_TIME_PRECISION_MICRO,
|
ASSERT_EQ(0, TEST_char2ts("yyyy/month/dd day HH24:MI:ss.usTZH", &ts, TSDB_TIME_PRECISION_MICRO,
|
||||||
|
@ -461,7 +461,8 @@ TEST(timeTest, char2ts) {
|
||||||
// '/' cannot convert to MM
|
// '/' cannot convert to MM
|
||||||
ASSERT_EQ(-1, TEST_char2ts("yyyyMMdd ", &ts, TSDB_TIME_PRECISION_MICRO, "2100/2/1"));
|
ASSERT_EQ(-1, TEST_char2ts("yyyyMMdd ", &ts, TSDB_TIME_PRECISION_MICRO, "2100/2/1"));
|
||||||
// nothing to be converted to dd
|
// nothing to be converted to dd
|
||||||
ASSERT_EQ(-1, TEST_char2ts("yyyyMMdd ", &ts, TSDB_TIME_PRECISION_MICRO, "210012"));
|
ASSERT_EQ(0, TEST_char2ts("yyyyMMdd ", &ts, TSDB_TIME_PRECISION_MICRO, "210012"));
|
||||||
|
ASSERT_EQ(ts, 4131273600000000LL); // 2100-12-1
|
||||||
ASSERT_EQ(-1, TEST_char2ts("yyyyMMdd ", &ts, TSDB_TIME_PRECISION_MICRO, "21001"));
|
ASSERT_EQ(-1, TEST_char2ts("yyyyMMdd ", &ts, TSDB_TIME_PRECISION_MICRO, "21001"));
|
||||||
ASSERT_EQ(-1, TEST_char2ts("yyyyMM-dd ", &ts, TSDB_TIME_PRECISION_MICRO, "23a1-1"));
|
ASSERT_EQ(-1, TEST_char2ts("yyyyMM-dd ", &ts, TSDB_TIME_PRECISION_MICRO, "23a1-1"));
|
||||||
|
|
||||||
|
@ -481,6 +482,13 @@ TEST(timeTest, char2ts) {
|
||||||
ASSERT_EQ(-1, TEST_char2ts("HH12:MI:SS", &ts, TSDB_TIME_PRECISION_MICRO, "21:12:12"));
|
ASSERT_EQ(-1, TEST_char2ts("HH12:MI:SS", &ts, TSDB_TIME_PRECISION_MICRO, "21:12:12"));
|
||||||
ASSERT_EQ(-1, TEST_char2ts("yyyy/MM1/dd ", &ts, TSDB_TIME_PRECISION_MICRO, "2100111111111/11/2"));
|
ASSERT_EQ(-1, TEST_char2ts("yyyy/MM1/dd ", &ts, TSDB_TIME_PRECISION_MICRO, "2100111111111/11/2"));
|
||||||
ASSERT_EQ(-2, TEST_char2ts("yyyy/MM1/ddTZH", &ts, TSDB_TIME_PRECISION_MICRO, "23/11/2-13"));
|
ASSERT_EQ(-2, TEST_char2ts("yyyy/MM1/ddTZH", &ts, TSDB_TIME_PRECISION_MICRO, "23/11/2-13"));
|
||||||
|
ASSERT_EQ(0, TEST_char2ts("yyyy年 MM/ddTZH", &ts, TSDB_TIME_PRECISION_MICRO, "1970年1/1+0"));
|
||||||
|
ASSERT_EQ(ts, 0);
|
||||||
|
ASSERT_EQ(-1, TEST_char2ts("yyyy年a MM/dd", &ts, TSDB_TIME_PRECISION_MICRO, "2023年1/2"));
|
||||||
|
ASSERT_EQ(0, TEST_char2ts("yyyy年 MM/ddTZH", &ts, TSDB_TIME_PRECISION_MICRO, "1970年 1/1+0"));
|
||||||
|
ASSERT_EQ(ts, 0);
|
||||||
|
ASSERT_EQ(0, TEST_char2ts("yyyy年 a a a MM/ddTZH", &ts, TSDB_TIME_PRECISION_MICRO, "1970年 a a a 1/1+0"));
|
||||||
|
ASSERT_EQ(0, TEST_char2ts("yyyy年 a a a a a a a a a a a a a a a MM/ddTZH", &ts, TSDB_TIME_PRECISION_MICRO, "1970年 a "));
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
|
|
|
@ -2107,7 +2107,7 @@ static int32_t translateToChar(SFunctionNode* pFunc, char* pErrBuf, int32_t len)
|
||||||
if (!IS_STR_DATA_TYPE(para2Type) || !IS_TIMESTAMP_TYPE(para1Type)) {
|
if (!IS_STR_DATA_TYPE(para2Type) || !IS_TIMESTAMP_TYPE(para1Type)) {
|
||||||
return invaildFuncParaTypeErrMsg(pErrBuf, len, pFunc->functionName);
|
return invaildFuncParaTypeErrMsg(pErrBuf, len, pFunc->functionName);
|
||||||
}
|
}
|
||||||
pFunc->node.resType = (SDataType){.bytes = tDataTypes[TSDB_DATA_TYPE_VARCHAR].bytes, .type = TSDB_DATA_TYPE_VARCHAR};
|
pFunc->node.resType = (SDataType){.bytes = 4096, .type = TSDB_DATA_TYPE_VARCHAR};
|
||||||
return TSDB_CODE_SUCCESS;
|
return TSDB_CODE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1203,9 +1203,13 @@ int32_t toTimestampFunction(SScalarParam* pInput, int32_t inputNum, SScalarParam
|
||||||
char * tsStr = taosMemoryMalloc(TS_FORMAT_MAX_LEN);
|
char * tsStr = taosMemoryMalloc(TS_FORMAT_MAX_LEN);
|
||||||
char * format = taosMemoryMalloc(TS_FORMAT_MAX_LEN);
|
char * format = taosMemoryMalloc(TS_FORMAT_MAX_LEN);
|
||||||
int32_t len, code = TSDB_CODE_SUCCESS;
|
int32_t len, code = TSDB_CODE_SUCCESS;
|
||||||
|
SArray *formats = NULL;
|
||||||
|
|
||||||
for (int32_t i = 0; i < pInput[0].numOfRows; ++i) {
|
for (int32_t i = 0; i < pInput[0].numOfRows; ++i) {
|
||||||
if (colDataIsNull_s(pInput[1].columnData, i) || colDataIsNull_s(pInput[0].columnData, i))
|
if (colDataIsNull_s(pInput[1].columnData, i) || colDataIsNull_s(pInput[0].columnData, i)) {
|
||||||
colDataSetNULL(pOutput->columnData, i);
|
colDataSetNULL(pOutput->columnData, i);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
char *tsData = colDataGetData(pInput[0].columnData, i);
|
char *tsData = colDataGetData(pInput[0].columnData, i);
|
||||||
char *formatData = colDataGetData(pInput[1].columnData, pInput[1].numOfRows > 1 ? i : 0);
|
char *formatData = colDataGetData(pInput[1].columnData, pInput[1].numOfRows > 1 ? i : 0);
|
||||||
|
@ -1213,11 +1217,17 @@ int32_t toTimestampFunction(SScalarParam* pInput, int32_t inputNum, SScalarParam
|
||||||
strncpy(tsStr, varDataVal(tsData), len);
|
strncpy(tsStr, varDataVal(tsData), len);
|
||||||
tsStr[len] = '\0';
|
tsStr[len] = '\0';
|
||||||
len = TMIN(TS_FORMAT_MAX_LEN - 1, varDataLen(formatData));
|
len = TMIN(TS_FORMAT_MAX_LEN - 1, varDataLen(formatData));
|
||||||
|
if (pInput[1].numOfRows > 1 || i == 0) {
|
||||||
strncpy(format, varDataVal(formatData), len);
|
strncpy(format, varDataVal(formatData), len);
|
||||||
format[len] = '\0';
|
format[len] = '\0';
|
||||||
|
if (formats) {
|
||||||
|
taosArrayDestroy(formats);
|
||||||
|
formats = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
int32_t precision = pOutput->columnData->info.precision;
|
int32_t precision = pOutput->columnData->info.precision;
|
||||||
char errMsg[128] = {0};
|
char errMsg[128] = {0};
|
||||||
code = taosChar2Ts(format, tsStr, &ts, precision, errMsg, 128);
|
code = taosChar2Ts(format, &formats, tsStr, &ts, precision, errMsg, 128);
|
||||||
if (code) {
|
if (code) {
|
||||||
qError("func to_timestamp failed %s", errMsg);
|
qError("func to_timestamp failed %s", errMsg);
|
||||||
code = TSDB_CODE_FUNC_TO_TIMESTAMP_FAILED;
|
code = TSDB_CODE_FUNC_TO_TIMESTAMP_FAILED;
|
||||||
|
@ -1225,6 +1235,7 @@ int32_t toTimestampFunction(SScalarParam* pInput, int32_t inputNum, SScalarParam
|
||||||
}
|
}
|
||||||
colDataSetVal(pOutput->columnData, i, (char *)&ts, false);
|
colDataSetVal(pOutput->columnData, i, (char *)&ts, false);
|
||||||
}
|
}
|
||||||
|
if (formats) taosArrayDestroy(formats);
|
||||||
taosMemoryFree(tsStr);
|
taosMemoryFree(tsStr);
|
||||||
taosMemoryFree(format);
|
taosMemoryFree(format);
|
||||||
return code;
|
return code;
|
||||||
|
@ -1232,22 +1243,32 @@ int32_t toTimestampFunction(SScalarParam* pInput, int32_t inputNum, SScalarParam
|
||||||
|
|
||||||
int32_t toCharFunction(SScalarParam* pInput, int32_t inputNum, SScalarParam* pOutput) {
|
int32_t toCharFunction(SScalarParam* pInput, int32_t inputNum, SScalarParam* pOutput) {
|
||||||
char * format = taosMemoryMalloc(TS_FORMAT_MAX_LEN);
|
char * format = taosMemoryMalloc(TS_FORMAT_MAX_LEN);
|
||||||
char * out = taosMemoryMalloc(TS_FORMAT_MAX_LEN * 2);
|
char * out = taosMemoryCalloc(1, TS_FORMAT_MAX_LEN + VARSTR_HEADER_SIZE);
|
||||||
int32_t len;
|
int32_t len;
|
||||||
|
SArray *formats = NULL;
|
||||||
for (int32_t i = 0; i < pInput[0].numOfRows; ++i) {
|
for (int32_t i = 0; i < pInput[0].numOfRows; ++i) {
|
||||||
if (colDataIsNull_s(pInput[1].columnData, i) || colDataIsNull_s(pInput[0].columnData, i))
|
if (colDataIsNull_s(pInput[1].columnData, i) || colDataIsNull_s(pInput[0].columnData, i)) {
|
||||||
colDataSetNULL(pOutput->columnData, i);
|
colDataSetNULL(pOutput->columnData, i);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
char *ts = colDataGetData(pInput[0].columnData, i);
|
char *ts = colDataGetData(pInput[0].columnData, i);
|
||||||
char *formatData = colDataGetData(pInput[1].columnData, pInput[1].numOfRows > 1 ? i : 0);
|
char *formatData = colDataGetData(pInput[1].columnData, pInput[1].numOfRows > 1 ? i : 0);
|
||||||
len = TMIN(TS_FORMAT_MAX_LEN - 1, varDataLen(formatData));
|
len = TMIN(TS_FORMAT_MAX_LEN - 1, varDataLen(formatData));
|
||||||
|
if (pInput[1].numOfRows > 1 || i == 0) {
|
||||||
strncpy(format, varDataVal(formatData), len);
|
strncpy(format, varDataVal(formatData), len);
|
||||||
format[len] = '\0';
|
format[len] = '\0';
|
||||||
|
if (formats) {
|
||||||
|
taosArrayDestroy(formats);
|
||||||
|
formats = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
int32_t precision = pInput[0].columnData->info.precision;
|
int32_t precision = pInput[0].columnData->info.precision;
|
||||||
taosTs2Char(format, *(int64_t *)ts, precision, varDataVal(out));
|
taosTs2Char(format, &formats, *(int64_t *)ts, precision, varDataVal(out), TS_FORMAT_MAX_LEN);
|
||||||
varDataSetLen(out, strlen(varDataVal(out)));
|
varDataSetLen(out, strlen(varDataVal(out)));
|
||||||
colDataSetVal(pOutput->columnData, i, out, false);
|
colDataSetVal(pOutput->columnData, i, out, false);
|
||||||
}
|
}
|
||||||
|
if (formats) taosArrayDestroy(formats);
|
||||||
taosMemoryFree(format);
|
taosMemoryFree(format);
|
||||||
taosMemoryFree(out);
|
taosMemoryFree(out);
|
||||||
return TSDB_CODE_SUCCESS;
|
return TSDB_CODE_SUCCESS;
|
||||||
|
|
|
@ -60,10 +60,15 @@ class TDTestCase:
|
||||||
rowsBatched = 0
|
rowsBatched = 0
|
||||||
sql += " %s%d values "%(ctbPrefix,i)
|
sql += " %s%d values "%(ctbPrefix,i)
|
||||||
for j in range(rowsPerTbl):
|
for j in range(rowsPerTbl):
|
||||||
if (i < ctbNum/2):
|
if i % 3 == 0:
|
||||||
sql += "(%d, %d, %d, %d,%d,%d,%d,true,'binary%d', 'nchar%d') "%(startTs + j*tsStep, j%10, j%10, j%10, j%10, j%10, j%10, j%10, j%10)
|
ts_format = 'NULL'
|
||||||
else:
|
else:
|
||||||
sql += "(%d, %d, NULL, %d,NULL,%d,%d,true,'binary%d', 'nchar%d') "%(startTs + j*tsStep, j%10, j%10, j%10, j%10, j%10, j%10)
|
ts_format = "'yyyy-mm-dd hh24:mi:ss'"
|
||||||
|
|
||||||
|
if (i < ctbNum/2):
|
||||||
|
sql += "(%d, %d, %d, %d,%d,%d,%d,true,'2023-11-01 10:10:%d', %s, 'nchar%d') "%(startTs + j*tsStep, j%10, j%10, j%10, j%10, j%10, j%10, j%10, ts_format, j%10)
|
||||||
|
else:
|
||||||
|
sql += "(%d, %d, NULL, %d,NULL,%d,%d,true,NULL , %s, 'nchar%d') "%(startTs + j*tsStep, j%10, j%10, j%10, j%10, ts_format, j%10)
|
||||||
rowsBatched += 1
|
rowsBatched += 1
|
||||||
if ((rowsBatched == batchNum) or (j == rowsPerTbl - 1)):
|
if ((rowsBatched == batchNum) or (j == rowsPerTbl - 1)):
|
||||||
tsql.execute(sql)
|
tsql.execute(sql)
|
||||||
|
@ -85,7 +90,7 @@ class TDTestCase:
|
||||||
'stbName': 'meters',
|
'stbName': 'meters',
|
||||||
'colPrefix': 'c',
|
'colPrefix': 'c',
|
||||||
'tagPrefix': 't',
|
'tagPrefix': 't',
|
||||||
'colSchema': [{'type': 'INT', 'count':1},{'type': 'BIGINT', 'count':1},{'type': 'FLOAT', 'count':1},{'type': 'DOUBLE', 'count':1},{'type': 'smallint', 'count':1},{'type': 'tinyint', 'count':1},{'type': 'bool', 'count':1},{'type': 'binary', 'len':10, 'count':1},{'type': 'nchar', 'len':10, 'count':1}],
|
'colSchema': [{'type': 'INT', 'count':1},{'type': 'BIGINT', 'count':1},{'type': 'FLOAT', 'count':1},{'type': 'DOUBLE', 'count':1},{'type': 'smallint', 'count':1},{'type': 'tinyint', 'count':1},{'type': 'bool', 'count':1},{'type': 'varchar', 'len':1024, 'count':2},{'type': 'nchar', 'len':10, 'count':1}],
|
||||||
'tagSchema': [{'type': 'INT', 'count':1},{'type': 'nchar', 'len':20, 'count':1},{'type': 'binary', 'len':20, 'count':1},{'type': 'BIGINT', 'count':1},{'type': 'smallint', 'count':1},{'type': 'DOUBLE', 'count':1}],
|
'tagSchema': [{'type': 'INT', 'count':1},{'type': 'nchar', 'len':20, 'count':1},{'type': 'binary', 'len':20, 'count':1},{'type': 'BIGINT', 'count':1},{'type': 'smallint', 'count':1},{'type': 'DOUBLE', 'count':1}],
|
||||||
'ctbPrefix': 't',
|
'ctbPrefix': 't',
|
||||||
'ctbStartIdx': 0,
|
'ctbStartIdx': 0,
|
||||||
|
@ -146,6 +151,18 @@ class TDTestCase:
|
||||||
tdSql.query("select to_char(ts, 'yy-mon-dd hh24:mi:ss.msa.m.TZH Day') from meters where to_timestamp(to_char(ts, 'yy-mon-dd hh24:mi:ss dy'), 'yy-mon-dd hh24:mi:ss dy') != ts")
|
tdSql.query("select to_char(ts, 'yy-mon-dd hh24:mi:ss.msa.m.TZH Day') from meters where to_timestamp(to_char(ts, 'yy-mon-dd hh24:mi:ss dy'), 'yy-mon-dd hh24:mi:ss dy') != ts")
|
||||||
tdSql.checkRows(0)
|
tdSql.checkRows(0)
|
||||||
|
|
||||||
|
tdSql.query("select to_timestamp(c8, 'YYYY-MM-DD hh24:mi:ss') from meters")
|
||||||
|
tdSql.query("select to_timestamp(c8, c9) from meters")
|
||||||
|
|
||||||
|
format = "YYYY-MM-DD HH:MI:SS"
|
||||||
|
for i in range(500):
|
||||||
|
format = format + "1234567890"
|
||||||
|
tdSql.query("select to_char(ts, '%s') from meters" % (format), queryTimes=1)
|
||||||
|
time_str = '2023-11-11 10:10:10'
|
||||||
|
for i in range(500):
|
||||||
|
time_str = time_str + "1234567890"
|
||||||
|
tdSql.query("select to_timestamp('%s', '%s')" % (time_str, format))
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
self.prepareTestEnv()
|
self.prepareTestEnv()
|
||||||
self.test_to_timestamp()
|
self.test_to_timestamp()
|
||||||
|
|
Loading…
Reference in New Issue