• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

taosdata / TDengine / #4933

20 Jan 2026 10:44AM UTC coverage: 66.671% (+0.03%) from 66.646%
#4933

push

travis-ci

web-flow
merge: from main to 3.0 #34340

73 of 178 new or added lines in 9 files covered. (41.01%)

1199 existing lines in 124 files now uncovered.

203121 of 304663 relevant lines covered (66.67%)

132228377.94 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

79.02
/source/common/src/ttime.c
1
/*
2
 * Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
3
 *
4
 * This program is free software: you can use, redistribute, and/or modify
5
 * it under the terms of the GNU Affero General Public License, version 3
6
 * or later ("AGPL"), as published by the Free Software Foundation.
7
 *
8
 * This program is distributed in the hope that it will be useful, but WITHOUT
9
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10
 * FITNESS FOR A PARTICULAR PURPOSE.
11
 *
12
 * You should have received a copy of the GNU Affero General Public License
13
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14
 */
15

16
#ifdef DARWIN
17
#define _XOPEN_SOURCE
18
#else
19
#define _XOPEN_SOURCE 500
20
#endif
21

22
#define _BSD_SOURCE
23
#define _DEFAULT_SOURCE
24
#include "ttime.h"
25

26
#include "tlog.h"
27

28
static int32_t parseFraction(char* str, char** end, int32_t timePrec, int64_t* pFraction);
29
static int32_t parseTimeWithTz(const char* timestr, int64_t* time, int32_t timePrec, char delim);
30
static int32_t parseLocaltimeDst(char* timestr, int32_t len, int64_t* utime, int32_t timePrec, char delim, timezone_t tz);
31
static char*   forwardToTimeStringEnd(char* str);
32
static bool    checkTzPresent(const char* str, int32_t len);
33
static int32_t parseTimezone(char* str, int64_t* tzOffset);
34

35
int32_t taosParseTime(const char* timestr, int64_t* utime, int32_t len, int32_t timePrec, timezone_t tz) {
2,147,483,647✔
36
  /* parse datatime string in with tz */
37
  if (strnchr(timestr, 'T', len, false) != NULL) {
2,147,483,647✔
38
    if (checkTzPresent(timestr, len)) {
112,082,100✔
39
      return parseTimeWithTz(timestr, utime, timePrec, 'T');
97,989,330✔
40
    } else {
41
      return parseLocaltimeDst((char*)timestr, len, utime, timePrec, 'T', tz);
14,092,770✔
42
    }
43
  } else {
44
    if (checkTzPresent(timestr, len)) {
2,147,483,647✔
45
      return parseTimeWithTz(timestr, utime, timePrec, 0);
2,580✔
46
    } else {
47
      return parseLocaltimeDst((char*)timestr, len, utime, timePrec, 0, tz);
2,147,483,647✔
48
    }
49
  }
50
}
51

52
bool checkTzPresent(const char* str, int32_t len) {
2,147,483,647✔
53
  char*   seg = forwardToTimeStringEnd((char*)str);
2,147,483,647✔
54
  int32_t seg_len = len - (int32_t)(seg - str);
2,147,483,647✔
55

56
  char* c = &seg[seg_len - 1];
2,147,483,647✔
57
  for (int32_t i = 0; i < seg_len; ++i) {
2,147,483,647✔
58
    if (0 == *c) {
2,147,483,647✔
59
      break;
×
60
    }
61
    if (*c == 'Z' || *c == 'z' || *c == '+' || *c == '-') {
2,147,483,647✔
62
      return true;
97,991,910✔
63
    }
64
    c--;
2,147,483,647✔
65
  }
66

67
  return false;
2,147,483,647✔
68
}
69

70
char* forwardToTimeStringEnd(char* str) {
2,147,483,647✔
71
  int32_t i = 0;
2,147,483,647✔
72
  int32_t numOfSep = 0;
2,147,483,647✔
73

74
  while (str[i] != 0 && numOfSep < 2) {
2,147,483,647✔
75
    if (str[i++] == ':') {
2,147,483,647✔
76
      numOfSep++;
2,147,483,647✔
77
    }
78
  }
79

80
  while (str[i] >= '0' && str[i] <= '9') {
2,147,483,647✔
81
    i++;
2,147,483,647✔
82
  }
83

84
  return &str[i];
2,147,483,647✔
85
}
86

87
int32_t parseFraction(char* str, char** end, int32_t timePrec, int64_t* pFraction) {
2,147,483,647✔
88
  int32_t i = 0;
2,147,483,647✔
89
  int64_t fraction = 0;
2,147,483,647✔
90

91
  const int32_t MILLI_SEC_FRACTION_LEN = 3;
2,147,483,647✔
92
  const int32_t MICRO_SEC_FRACTION_LEN = 6;
2,147,483,647✔
93
  const int32_t NANO_SEC_FRACTION_LEN = 9;
2,147,483,647✔
94

95
  int32_t factor[9] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000};
2,147,483,647✔
96
  int32_t times = 1;
2,147,483,647✔
97

98
  while (str[i] >= '0' && str[i] <= '9') {
2,147,483,647✔
99
    i++;
2,147,483,647✔
100
  }
101

102
  int32_t totalLen = i;
2,147,483,647✔
103
  if (totalLen <= 0) {
2,147,483,647✔
104
    TAOS_RETURN(TSDB_CODE_INVALID_PARA);
×
105
  }
106

107
  /* parse the fraction */
108
  if (timePrec == TSDB_TIME_PRECISION_MILLI) {
2,147,483,647✔
109
    /* only use the initial 3 bits */
110
    if (i >= MILLI_SEC_FRACTION_LEN) {
2,147,483,647✔
111
      i = MILLI_SEC_FRACTION_LEN;
2,147,483,647✔
112
    }
113

114
    times = MILLI_SEC_FRACTION_LEN - i;
2,147,483,647✔
115
  } else if (timePrec == TSDB_TIME_PRECISION_MICRO) {
66,363✔
116
    if (i >= MICRO_SEC_FRACTION_LEN) {
44,053✔
117
      i = MICRO_SEC_FRACTION_LEN;
27,981✔
118
    }
119
    times = MICRO_SEC_FRACTION_LEN - i;
44,053✔
120
  } else if (timePrec == TSDB_TIME_PRECISION_NANO) {
22,310✔
121
    if (i >= NANO_SEC_FRACTION_LEN) {
22,310✔
122
      i = NANO_SEC_FRACTION_LEN;
10,188✔
123
    }
124
    times = NANO_SEC_FRACTION_LEN - i;
22,310✔
125
  } else {
126
    TAOS_RETURN(TSDB_CODE_INVALID_PARA);
×
127
  }
128

129
  fraction = strnatoi(str, i) * factor[times];
2,147,483,647✔
130
  *end = str + totalLen;
2,147,483,647✔
131
  *pFraction = fraction;
2,147,483,647✔
132

133
  TAOS_RETURN(TSDB_CODE_SUCCESS);
2,147,483,647✔
134
}
135

136
#define PARSE(str,len,result) \
137
  if (len != 2) {\
138
    TAOS_RETURN(TSDB_CODE_INVALID_PARA);\
139
  }\
140
  result = strnatoi(str, len);
141

142
int32_t parseTimezone(char* str, int64_t* tzOffset) {
276,820,748✔
143
  int64_t hour = 0;
276,820,748✔
144
  int64_t minute = 0;
276,820,748✔
145

146
  int32_t i = 0;
276,820,748✔
147
  if (str[i] != '+' && str[i] != '-') {
276,820,748✔
148
    TAOS_RETURN(TSDB_CODE_INVALID_PARA);
×
149
  }
150

151
  i++;
276,821,114✔
152

153
  int32_t j = i;
276,821,114✔
154
  while (str[j]) {
1,384,156,498✔
155
    if ((str[j] >= '0' && str[j] <= '9') || str[j] == ':') {
1,107,335,981✔
156
      ++j;
1,107,335,384✔
157
      continue;
1,107,335,384✔
158
    }
159

160
    TAOS_RETURN(TSDB_CODE_INVALID_PARA);
2,061✔
161
  }
162

163
  char* sep = strchr(&str[i], ':');
276,820,151✔
164
  if (sep != NULL) {
276,820,151✔
165
    int32_t hourSize = (int32_t)(sep - &str[i]);
65,792✔
166
    PARSE(&str[i], hourSize, hour);
65,792✔
167

168
    i += hourSize + 1;
65,792✔
169
    size_t minSize = strlen(&str[i]);
65,792✔
170
    PARSE(&str[i], minSize, minute);
65,792✔
171
  } else {
172
    size_t hourSize = strlen(&str[i]);
276,754,359✔
173
    if (hourSize > 2){
276,755,457✔
174
      hourSize = 2;
276,752,559✔
175
    }
176
    PARSE(&str[i], hourSize, hour)
276,755,457✔
177
    i += hourSize;
276,755,457✔
178
    size_t minSize = strlen(&str[i]);
276,755,457✔
179
    if (minSize > 0){
276,755,457✔
180
      PARSE(&str[i], minSize, minute);
276,752,559✔
181
    }
182
  }
183

184
  if (hour > 13 || hour < 0) {
276,820,791✔
185
    TAOS_RETURN(TSDB_CODE_INVALID_PARA);
×
186
  }
187
  if (minute > 59 || minute < 0) {
276,820,791✔
188
    TAOS_RETURN(TSDB_CODE_INVALID_PARA);
×
189
  }
190

191
  if (str[0] == '+') {
276,820,791✔
192
    *tzOffset = -(hour * 3600 + minute * 60);
276,813,326✔
193
  } else {
194
    *tzOffset = hour * 3600 + minute * 60;
7,465✔
195
  }
196

197
  TAOS_RETURN(TSDB_CODE_SUCCESS);
276,820,791✔
198
}
199

200
int32_t offsetOfTimezone(char* tzStr, int64_t* offset) {
184,248,274✔
201
  if (tzStr && (tzStr[0] == 'z' || tzStr[0] == 'Z')) {
184,248,274✔
202
    *offset = 0;
1,990✔
203
    return TSDB_CODE_SUCCESS;
1,990✔
204
  }
205
  return parseTimezone(tzStr, offset);
184,246,284✔
206
}
207

208
/*
209
 * rfc3339 format:
210
 * 2013-04-12T15:52:01+08:00
211
 * 2013-04-12T15:52:01.123+08:00
212
 *
213
 * 2013-04-12T15:52:01Z
214
 * 2013-04-12T15:52:01.123Z
215
 *
216
 * iso-8601 format:
217
 * 2013-04-12T15:52:01+0800
218
 * 2013-04-12T15:52:01.123+0800
219
 */
220
int32_t parseTimeWithTz(const char* timestr, int64_t* time, int32_t timePrec, char delim) {
97,991,910✔
221
  int64_t factor = TSDB_TICK_PER_SECOND(timePrec);
97,991,910✔
222
  int64_t tzOffset = 0;
97,991,910✔
223

224
  struct tm tm = {0};
97,991,910✔
225

226
  char* str;
97,991,784✔
227
  if (delim == 'T') {
97,991,910✔
228
    str = taosStrpTime(timestr, "%Y-%m-%dT%H:%M:%S", &tm);
97,989,330✔
229
  } else if (delim == 0) {
2,580✔
230
    str = taosStrpTime(timestr, "%Y-%m-%d %H:%M:%S", &tm);
2,580✔
231
  } else {
232
    str = NULL;
×
233
  }
234

235
  if (str == NULL) {
97,991,910✔
236
    TAOS_RETURN(TSDB_CODE_INVALID_PARA);
5,329,860✔
237
  }
238

239
/* mktime will be affected by TZ, set by using taos_options */
240
#if defined(WINDOWS) || defined(TD_ASTRA) 
241
  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);
242
  // int64_t seconds = gmtime(&tm);
243
#else
244
  int64_t seconds = taosTimeGm(&tm);
92,662,050✔
245
  if (seconds == -1){
92,662,050✔
246
    TAOS_RETURN(TAOS_SYSTEM_ERROR(ERRNO));
×
247
  }
248
#endif
249

250
  int64_t fraction = 0;
92,662,050✔
251
  str = forwardToTimeStringEnd((char*)timestr);
92,662,050✔
252

253
  if ((str[0] == 'Z' || str[0] == 'z') && str[1] == '\0') {
92,662,050✔
254
    /* utc time, no millisecond, return directly*/
255
    *time = seconds * factor;
84,206✔
256
  } else if (str[0] == '.') {
92,577,844✔
257
    str += 1;
92,514,546✔
258
    TAOS_CHECK_RETURN(parseFraction(str, &str, timePrec, &fraction));
92,514,546✔
259

260
    *time = seconds * factor + fraction;
92,514,546✔
261

262
    char seg = str[0];
92,514,546✔
263
    if (seg != 'Z' && seg != 'z' && seg != '+' && seg != '-') {
92,514,546✔
264
      TAOS_RETURN(TSDB_CODE_INVALID_PARA);
×
265
    } else if ((seg == 'Z' || seg == 'z') && str[1] != '\0') {
92,514,546✔
266
      TAOS_RETURN(TSDB_CODE_INVALID_PARA);
×
267
    } else if (seg == '+' || seg == '-') {
92,514,546✔
268
      // parse the timezone
269
      TAOS_CHECK_RETURN(parseTimezone(str, &tzOffset));
92,511,166✔
270

271
      *time += tzOffset * factor;
92,508,647✔
272
    }
273

274
  } else if (str[0] == '+' || str[0] == '-') {
63,298✔
275
    *time = seconds * factor + fraction;
63,298✔
276

277
    // parse the timezone
278
    TAOS_CHECK_RETURN(parseTimezone(str, &tzOffset));
63,298✔
279

280
    *time += tzOffset * factor;
63,298✔
281
  } else {
282
    TAOS_RETURN(TSDB_CODE_INVALID_PARA);
×
283
  }
284

285
  TAOS_RETURN(TSDB_CODE_SUCCESS);
92,659,531✔
286
}
287

288
static FORCE_INLINE bool validateTm(struct tm* pTm) {
289
  if (pTm == NULL) {
2,147,483,647✔
290
    return false;
×
291
  }
292

293
  int32_t dayOfMonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
2,147,483,647✔
294

295
  int32_t leapYearMonthDay = 29;
2,147,483,647✔
296
  int32_t year = pTm->tm_year + 1900;
2,147,483,647✔
297
  bool    isLeapYear = ((year % 100) == 0) ? ((year % 400) == 0) : ((year % 4) == 0);
2,147,483,647✔
298

299
  if (isLeapYear && (pTm->tm_mon == 1)) {
2,147,483,647✔
300
    if (pTm->tm_mday > leapYearMonthDay) {
3,607,989✔
301
      return false;
×
302
    }
303
  } else {
304
    if (pTm->tm_mday > dayOfMonth[pTm->tm_mon]) {
2,147,483,647✔
305
      return false;
×
306
    }
307
  }
308

309
  return true;
2,147,483,647✔
310
}
311

312
int32_t parseLocaltimeDst(char* timestr, int32_t len, int64_t* utime, int32_t timePrec, char delim, timezone_t tz) {
2,147,483,647✔
313
  *utime = 0;
2,147,483,647✔
314
  struct tm tm = {0};
2,147,483,647✔
315
  tm.tm_isdst = -1;
2,147,483,647✔
316

317
  char* str;
2,147,483,647✔
318
  if (delim == 'T') {
2,147,483,647✔
319
    str = taosStrpTime(timestr, "%Y-%m-%dT%H:%M:%S", &tm);
14,093,136✔
320
  } else if (delim == 0) {
2,147,483,647✔
321
    str = taosStrpTime(timestr, "%Y-%m-%d %H:%M:%S", &tm);
2,147,483,647✔
322
  } else {
323
    str = NULL;
×
324
  }
325

326
  if (str == NULL || (((str - timestr) < len) && (*str != '.')) || !validateTm(&tm)) {
2,147,483,647✔
327
    // if parse failed, try "%Y-%m-%d" format
328
    str = taosStrpTime(timestr, "%Y-%m-%d", &tm);
62,163,094✔
329
    if (str == NULL || (((str - timestr) < len) && (*str != '.')) || !validateTm(&tm)) {
62,279,994✔
330
      TAOS_RETURN(TSDB_CODE_INVALID_PARA);
62,040,442✔
331
    }
332
  }
333

334
  int64_t seconds = taosMktime(&tm, tz);
2,147,483,647✔
335

336
  int64_t fraction = 0;
2,147,483,647✔
337
  if (*str == '.') {
2,147,483,647✔
338
    /* parse the second fraction part */
339
    TAOS_CHECK_RETURN(parseFraction(str + 1, &str, timePrec, &fraction));
2,147,483,647✔
340
  }
341

342
  *utime = TSDB_TICK_PER_SECOND(timePrec) * seconds + fraction;
2,147,483,647✔
343
  TAOS_RETURN(TSDB_CODE_SUCCESS);
2,147,483,647✔
344
}
345

346
char getPrecisionUnit(int32_t precision) {
4,469,709✔
347
  static char units[3] = {TIME_UNIT_MILLISECOND, TIME_UNIT_MICROSECOND, TIME_UNIT_NANOSECOND};
348
  switch (precision) {
4,469,709✔
349
    case TSDB_TIME_PRECISION_MILLI:
4,469,709✔
350
    case TSDB_TIME_PRECISION_MICRO:
351
    case TSDB_TIME_PRECISION_NANO:
352
      return units[precision];
4,469,709✔
353
    default:
×
354
      return 0;
×
355
  }
356
}
357

358
int64_t convertTimePrecision(int64_t utime, int32_t fromPrecision, int32_t toPrecision) {
2,147,483,647✔
359
  switch (fromPrecision) {
2,147,483,647✔
360
    case TSDB_TIME_PRECISION_MILLI: {
2,147,483,647✔
361
      switch (toPrecision) {
2,147,483,647✔
362
        case TSDB_TIME_PRECISION_MILLI:
2,147,483,647✔
363
          return utime;
2,147,483,647✔
364
        case TSDB_TIME_PRECISION_MICRO:
386,200✔
365
          if (utime > INT64_MAX / 1000) {
386,200✔
366
            return INT64_MAX;
×
367
          }
368
          return utime * 1000;
386,200✔
369
        case TSDB_TIME_PRECISION_NANO:
5,936,809✔
370
          if (utime > INT64_MAX / 1000000) {
5,936,809✔
371
            return INT64_MAX;
×
372
          }
373
          return utime * 1000000;
5,936,809✔
UNCOV
374
        default:
×
UNCOV
375
          return utime;
×
376
      }
377
    }  // end from milli
378
    case TSDB_TIME_PRECISION_MICRO: {
180,360✔
379
      switch (toPrecision) {
180,360✔
380
        case TSDB_TIME_PRECISION_MILLI:
63,973✔
381
          return utime / 1000;
63,973✔
382
        case TSDB_TIME_PRECISION_MICRO:
57,748✔
383
          return utime;
57,748✔
384
        case TSDB_TIME_PRECISION_NANO:
58,639✔
385
          if (utime > INT64_MAX / 1000) {
58,639✔
386
            return INT64_MAX;
×
387
          }
388
          return utime * 1000;
58,639✔
389
        default:
×
390
          return utime;
×
391
      }
392
    }  // end from micro
393
    case TSDB_TIME_PRECISION_NANO: {
6,062,940✔
394
      switch (toPrecision) {
6,062,940✔
395
        case TSDB_TIME_PRECISION_MILLI:
5,188,036✔
396
          return utime / 1000000;
5,188,036✔
397
        case TSDB_TIME_PRECISION_MICRO:
26,083✔
398
          return utime / 1000;
26,083✔
399
        case TSDB_TIME_PRECISION_NANO:
846,929✔
400
          return utime;
846,929✔
401
        default:
1,892✔
402
          return utime;
1,892✔
403
      }
404
    }  // end from nano
405
    default: {
×
406
      return utime;  // only to pass windows compilation
×
407
    }
408
  }  // end switch fromPrecision
409

410
  return utime;
411
}
412

413
// !!!!notice:there are precision problems, double lose precison if time is too large, for example:
414
// 1626006833631000000*1.0 = double = 1626006833631000064
415
// int64_t convertTimePrecision(int64_t time, int32_t fromPrecision, int32_t toPrecision) {
416
//  static double factors[3][3] = {{1., 1000., 1000000.}, {1.0 / 1000, 1., 1000.}, {1.0 / 1000000, 1.0 / 1000, 1.}};
417
//  ((double)time * factors[fromPrecision][toPrecision]);
418
//}
419

420
// !!!!notice: double lose precison if time is too large, for example: 1626006833631000000*1.0 = double =
421
// 1626006833631000064
422
int32_t convertTimeFromPrecisionToUnit(int64_t time, int32_t fromPrecision, char toUnit, int64_t* pRes) {
8,579,996✔
423
  if (fromPrecision != TSDB_TIME_PRECISION_MILLI && fromPrecision != TSDB_TIME_PRECISION_MICRO &&
8,579,996✔
424
      fromPrecision != TSDB_TIME_PRECISION_NANO) {
425
    TAOS_RETURN(TSDB_CODE_INVALID_PARA);
×
426
  }
427

428
  int64_t factors[3] = {NANOSECOND_PER_MSEC, NANOSECOND_PER_USEC, 1};
8,579,996✔
429
  double  tmp = time;
8,579,996✔
430
  switch (toUnit) {
8,579,996✔
431
    case 's': {
942,568✔
432
      time /= (NANOSECOND_PER_SEC / factors[fromPrecision]);
942,568✔
433
      tmp = (double)time;
942,568✔
434
      break;
942,568✔
435
    }
436
    case 'm':
1,223,040✔
437
      time /= (NANOSECOND_PER_MINUTE / factors[fromPrecision]);
1,223,040✔
438
      tmp = (double)time;
1,223,040✔
439
      break;
1,223,040✔
440
    case 'h':
6,262✔
441
      time /= (NANOSECOND_PER_HOUR / factors[fromPrecision]);
6,262✔
442
      tmp = (double)time;
6,262✔
443
      break;
6,262✔
444
    case 'd':
5,554,974✔
445
      time /= (NANOSECOND_PER_DAY / factors[fromPrecision]);
5,554,974✔
446
      tmp = (double)time;
5,554,974✔
447
      break;
5,554,974✔
448
    case 'w':
×
449
      time /= (NANOSECOND_PER_WEEK / factors[fromPrecision]);
×
450
      tmp = (double)time;
×
451
      break;
×
452
    case 'a':
844,392✔
453
      time /= (NANOSECOND_PER_MSEC / factors[fromPrecision]);
844,392✔
454
      tmp = (double)time;
844,392✔
455
      break;
844,392✔
456
    case 'u':
6,570✔
457
      // the result of (NANOSECOND_PER_USEC/(double)factors[fromPrecision]) maybe a double
458
      switch (fromPrecision) {
459
        case TSDB_TIME_PRECISION_MILLI: {
×
460
          tmp *= 1000;
×
461
          time *= 1000;
×
462
          break;
×
463
        }
464
        case TSDB_TIME_PRECISION_MICRO: {
4,380✔
465
          time /= 1;
4,380✔
466
          tmp = (double)time;
4,380✔
467
          break;
4,380✔
468
        }
469
        case TSDB_TIME_PRECISION_NANO: {
2,190✔
470
          time /= 1000;
2,190✔
471
          tmp = (double)time;
2,190✔
472
          break;
2,190✔
473
        }
474
      }
475
      break;
6,570✔
476
    case 'b':
2,190✔
477
      tmp *= factors[fromPrecision];
2,190✔
478
      time *= factors[fromPrecision];
2,190✔
479
      break;
2,190✔
480
    default: {
×
481
      TAOS_RETURN(TSDB_CODE_INVALID_PARA);
×
482
    }
483
  }
484
  if (tmp >= (double)INT64_MAX) {
8,579,996✔
485
    *pRes = INT64_MAX;
×
486
  } else if (tmp <= (double)INT64_MIN) {
8,579,996✔
487
    *pRes = INT64_MIN;
×
488
  } else {
489
    *pRes = time;
8,579,996✔
490
  }
491

492
  TAOS_RETURN(TSDB_CODE_SUCCESS);
8,579,996✔
493
}
494

495
int32_t convertStringToTimestamp(int16_t type, char* inputData, int64_t timePrec, int64_t* timeVal, timezone_t tz, void* charsetCxt) {
178,243,017✔
496
  int32_t charLen = varDataLen(inputData);
178,243,017✔
497
  char*   newColData;
498
  if (type == TSDB_DATA_TYPE_BINARY || type == TSDB_DATA_TYPE_VARBINARY) {
299,017,789✔
499
    newColData = taosMemoryCalloc(1, charLen + 1);
173,150,780✔
500
    if (NULL == newColData) {
173,134,359✔
501
      TAOS_RETURN(terrno);
×
502
    }
503
    (void)memcpy(newColData, varDataVal(inputData), charLen);
173,134,359✔
504
    int32_t ret = taosParseTime(newColData, timeVal, charLen, (int32_t)timePrec, tz);
173,133,355✔
505
    if (ret != TSDB_CODE_SUCCESS) {
173,146,210✔
506
      taosMemoryFree(newColData);
52,373,404✔
507
      TAOS_RETURN(TSDB_CODE_INVALID_TIMESTAMP);
52,372,860✔
508
    }
509
    taosMemoryFree(newColData);
120,772,806✔
510
  } else if (type == TSDB_DATA_TYPE_NCHAR) {
5,092,237✔
511
    newColData = taosMemoryCalloc(1, charLen + TSDB_NCHAR_SIZE);
5,092,237✔
512
    if (NULL == newColData) {
5,092,237✔
513
      TAOS_RETURN(terrno);
×
514
    }
515
    int len = taosUcs4ToMbs((TdUcs4*)varDataVal(inputData), charLen, newColData, charsetCxt);
5,092,237✔
516
    if (len < 0) {
5,092,237✔
517
      taosMemoryFree(newColData);
×
518
      TAOS_RETURN(TSDB_CODE_FAILED);
×
519
    }
520
    newColData[len] = 0;
5,092,237✔
521
    int32_t ret = taosParseTime(newColData, timeVal, len, (int32_t)timePrec, tz);
5,092,237✔
522
    if (ret != TSDB_CODE_SUCCESS) {
5,092,237✔
523
      taosMemoryFree(newColData);
5,092,237✔
524
      TAOS_RETURN(ret);
5,092,237✔
525
    }
526
    taosMemoryFree(newColData);
×
527
  } else {
528
    TAOS_RETURN(TSDB_CODE_FAILED);
×
529
  }
530
  TAOS_RETURN(TSDB_CODE_SUCCESS);
120,774,772✔
531
}
532

533
int32_t getDuration(int64_t val, char unit, int64_t* result, int32_t timePrecision) {
2,147,483,647✔
534
  switch (unit) {
2,147,483,647✔
535
    case 's':
2,147,483,647✔
536
      if (val > INT64_MAX / MILLISECOND_PER_SECOND) {
2,147,483,647✔
537
        TAOS_RETURN(TSDB_CODE_OUT_OF_RANGE);
×
538
      }
539
      (*result) = convertTimePrecision(val * MILLISECOND_PER_SECOND, TSDB_TIME_PRECISION_MILLI, timePrecision);
2,147,483,647✔
540
      break;
2,147,483,647✔
541
    case 'm':
10,818,293✔
542
      if (val > INT64_MAX / MILLISECOND_PER_MINUTE) {
10,818,293✔
543
        TAOS_RETURN(TSDB_CODE_OUT_OF_RANGE);
×
544
      }
545
      (*result) = convertTimePrecision(val * MILLISECOND_PER_MINUTE, TSDB_TIME_PRECISION_MILLI, timePrecision);
10,818,293✔
546
      break;
10,818,293✔
547
    case 'h':
2,567,799✔
548
      if (val > INT64_MAX / MILLISECOND_PER_MINUTE) {
2,567,799✔
549
        TAOS_RETURN(TSDB_CODE_OUT_OF_RANGE);
×
550
      }
551
      (*result) = convertTimePrecision(val * MILLISECOND_PER_HOUR, TSDB_TIME_PRECISION_MILLI, timePrecision);
2,567,799✔
552
      break;
2,567,799✔
553
    case 'd':
69,391,061✔
554
      if (val > INT64_MAX / MILLISECOND_PER_DAY) {
69,391,061✔
555
        TAOS_RETURN(TSDB_CODE_OUT_OF_RANGE);
×
556
      }
557
      (*result) = convertTimePrecision(val * MILLISECOND_PER_DAY, TSDB_TIME_PRECISION_MILLI, timePrecision);
69,391,061✔
558
      break;
69,391,061✔
559
    case 'w':
661,991✔
560
      if (val > INT64_MAX / MILLISECOND_PER_WEEK) {
661,991✔
561
        TAOS_RETURN(TSDB_CODE_OUT_OF_RANGE);
×
562
      }
563
      (*result) = convertTimePrecision(val * MILLISECOND_PER_WEEK, TSDB_TIME_PRECISION_MILLI, timePrecision);
661,991✔
564
      break;
661,991✔
565
    case 'a':
4,193,816✔
566
      (*result) = convertTimePrecision(val, TSDB_TIME_PRECISION_MILLI, timePrecision);
4,193,816✔
567
      break;
4,193,816✔
568
    case 'u':
178,755✔
569
      (*result) = convertTimePrecision(val, TSDB_TIME_PRECISION_MICRO, timePrecision);
178,755✔
570
      break;
178,755✔
571
    case 'b':
513,270✔
572
      (*result) = convertTimePrecision(val, TSDB_TIME_PRECISION_NANO, timePrecision);
513,270✔
573
      break;
513,270✔
UNCOV
574
    default: {
×
UNCOV
575
      TAOS_RETURN(TSDB_CODE_OUT_OF_RANGE);
×
576
    }
577
  }
578
  TAOS_RETURN(TSDB_CODE_SUCCESS);
2,147,483,647✔
579
}
580

581
/*
582
 * n - months
583
 * y - Years
584
 * is not allowed, since the duration of month or year are both variable.
585
 *
586
 * b - nanoseconds;
587
 * u - microseconds;
588
 * a - Millionseconds
589
 * s - Seconds
590
 * m - Minutes
591
 * h - Hours
592
 * d - Days (24 hours)
593
 * w - Weeks (7 days)
594
 */
595
int32_t parseAbsoluteDuration(const char* token, int32_t tokenlen, int64_t* duration, char* unit,
2,147,483,647✔
596
                              int32_t timePrecision) {
597
  SET_ERRNO(0);
2,147,483,647✔
598
  char* endPtr = NULL;
2,147,483,647✔
599

600
  /* get the basic numeric value */
601
  int64_t timestamp = taosStr2Int64(token, &endPtr, 10);
2,147,483,647✔
602
  if ((timestamp == 0 && token[0] != '0') || ERRNO != 0) {
2,147,483,647✔
603
    TAOS_RETURN(TAOS_SYSTEM_ERROR(ERRNO));
×
604
  }
605

606
  /* natual month/year are not allowed in absolute duration */
607
  *unit = token[tokenlen - 1];
2,147,483,647✔
608
  if (*unit == 'n' || *unit == 'y') {
2,147,483,647✔
609
    TAOS_RETURN(TSDB_CODE_INVALID_PARA);
4,989✔
610
  }
611

612
  return getDuration(timestamp, *unit, duration, timePrecision);
2,147,483,647✔
613
}
614

615
int32_t parseNatualDuration(const char* token, int32_t tokenLen, int64_t* duration, char* unit, int32_t timePrecision,
86,208,674✔
616
                            bool negativeAllow) {
617
  SET_ERRNO(0);
86,208,674✔
618

619
  /* get the basic numeric value */
620
  *duration = taosStr2Int64(token, NULL, 10);
86,208,674✔
621
  if ((*duration < 0 && !negativeAllow) || ERRNO != 0) {
86,208,674✔
622
    TAOS_RETURN(TAOS_SYSTEM_ERROR(ERRNO));
1,482✔
623
  }
624

625
  *unit = token[tokenLen - 1];
86,207,192✔
626
  if (*unit == 'n' || *unit == 'y') {
86,207,192✔
627
    TAOS_RETURN(TSDB_CODE_SUCCESS);
209,697✔
628
  }
629
  if (isdigit(*unit)) {
85,997,495✔
630
    *unit = getPrecisionUnit(timePrecision);
9,496✔
631
  }
632

633
  return getDuration(*duration, *unit, duration, timePrecision);
85,997,893✔
634
}
635

636
static bool taosIsLeapYear(int32_t year) { return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)); }
4,875,686✔
637

638
int64_t taosTimeAdd(int64_t t, int64_t duration, char unit, int32_t precision, timezone_t tz) {
2,147,483,647✔
639
  if (duration == 0) {
2,147,483,647✔
640
    return t;
2,147,483,647✔
641
  }
642

643
  if (!IS_CALENDAR_TIME_DURATION(unit)) {
2,147,483,647✔
644
    double tmp = t;
2,147,483,647✔
645
    if (tmp + duration >= (double)INT64_MAX || tmp + duration <= (double)INT64_MIN) {
2,147,483,647✔
646
      uError("time overflow, t:%" PRId64 ", duration:%" PRId64 ", unit:%c, precision:%d", t, duration, unit, precision);
×
647
      return t;
2,031✔
648
    } else {
649
      return t + duration;
2,147,483,647✔
650
    }
651
  }
652

653
  // The following code handles the y/n time duration
654
  int64_t numOfMonth = (unit == 'y') ? duration * 12 : duration;
×
655
  int64_t fraction = t % TSDB_TICK_PER_SECOND(precision);
×
656

657
  struct tm  tm;
×
658
  time_t     tt = (time_t)(t / TSDB_TICK_PER_SECOND(precision));
4,874,905✔
659
  if(taosLocalTime(&tt, &tm, NULL, 0, tz) == NULL) {
4,874,905✔
UNCOV
660
    uError("failed to convert time to gm time, code:%d", ERRNO);
×
661
    return t;
×
662
  }
663
  int32_t    mon = tm.tm_year * 12 + tm.tm_mon + (int32_t)numOfMonth;
4,875,686✔
664
  tm.tm_year = mon / 12;
4,875,686✔
665
  tm.tm_mon = mon % 12;
4,875,686✔
666
  int daysOfMonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4,875,686✔
667
  if (taosIsLeapYear(1900 + tm.tm_year)) {
4,875,686✔
668
    daysOfMonth[1] = 29;
3,690,566✔
669
  }
670
  if (tm.tm_mday > daysOfMonth[tm.tm_mon]) {
4,875,686✔
671
    tm.tm_mday = daysOfMonth[tm.tm_mon];
54,640✔
672
  }
673

674
  tt = taosMktime(&tm, tz);
4,875,686✔
675
  if (tt == -1){
4,875,686✔
UNCOV
676
    uError("failed to convert gm time to time, code:%d", ERRNO);
×
677
    return t;
×
678
  }
679
  return (int64_t)(tt * TSDB_TICK_PER_SECOND(precision) + fraction);
4,875,686✔
680
}
681

682
/**
683
 * @brief calc how many windows after filling between skey and ekey
684
 * @notes for asc order
685
 *     skey      --->       ekey
686
 *      ^                    ^
687
 * _____!_____.........._____|_____..
688
 *      |__1__)
689
 *            |__2__)...-->|_ret+1_)
690
 *      skey + ret * interval <= ekey
691
 *      skey + ret * interval + interval > ekey
692
 * ======> (ekey - skey - interval) / interval < ret <= (ekey - skey) / interval
693
 * For keys from blocks which do not need filling, skey + ret * interval == ekey.
694
 * For keys need filling, skey + ret * interval <= ekey.
695
 * Total num of windows is ret + 1(the last window)
696
 *
697
 *        for desc order
698
 *     skey       <---      ekey
699
 *      ^                    ^
700
 * _____|____..........______!____...
701
 *                           |_first_)
702
 *                     |__1__)
703
 *  |_ret_)<--...|__2__)
704
 *      skey >= ekey - ret * interval
705
 *      skey < ekey - ret * interval + interval
706
 *=======> (ekey - skey) / interval <= ret < (ekey - skey + interval) / interval
707
 * For keys from blocks which do not need filling, skey == ekey - ret * interval.
708
 * For keys need filling, skey >= ekey - ret * interval.
709
 * Total num of windows is ret + 1(the first window)
710
 */
711
int32_t taosTimeCountIntervalForFill(int64_t skey, int64_t ekey, int64_t interval, char unit, int32_t precision,
251,268✔
712
                                     int32_t order) {
713
  if (ekey < skey) {
251,268✔
714
    int64_t tmp = ekey;
177,393✔
715
    ekey = skey;
177,393✔
716
    skey = tmp;
177,393✔
717
  }
718
  int32_t ret = 0;
251,268✔
719

720
  if (unit != 'n' && unit != 'y') {
251,268✔
721
    ret = (int32_t)((ekey - skey) / interval);
251,268✔
722
    if (order == TSDB_ORDER_DESC && ret * interval < (ekey - skey)) ret += 1;
251,268✔
723
  } else {
724
    skey /= (int64_t)(TSDB_TICK_PER_SECOND(precision));
×
725
    ekey /= (int64_t)(TSDB_TICK_PER_SECOND(precision));
×
726

727
    struct tm  tm;
×
728
    time_t     t = (time_t)skey;
×
729
    if (taosLocalTime(&t, &tm, NULL, 0, NULL) == NULL) {
×
730
      uError("%s failed to convert time to local time, code:%d", __FUNCTION__, ERRNO);
×
731
      return ret;
×
732
    }
733
    int32_t    smon = tm.tm_year * 12 + tm.tm_mon;
×
734

735
    t = (time_t)ekey;
×
736
    if (taosLocalTime(&t, &tm, NULL, 0, NULL) == NULL) {
×
737
      uError("%s failed to convert time to local time, code:%d", __FUNCTION__, ERRNO);
×
738
      return ret;
×
739
    }
740
    int32_t emon = tm.tm_year * 12 + tm.tm_mon;
×
741

742
    if (unit == 'y') {
×
743
      interval *= 12;
×
744
    }
745
    ret = (emon - smon) / (int32_t)interval;
×
746
    if (order == TSDB_ORDER_DESC && ret * interval < (smon - emon)) ret += 1;
×
747
  }
748
  return ret + 1;
251,268✔
749
}
750

751
int64_t taosTimeTruncate(int64_t ts, const SInterval* pInterval) {
2,147,483,647✔
752
  if (ts <= INT64_MIN || ts >= INT64_MAX) {
2,147,483,647✔
753
    return ts;
×
754
  }
755
  if (pInterval->sliding == 0) {
2,147,483,647✔
756
    return ts;
×
757
  }
758

759
  int64_t start = ts;
2,147,483,647✔
760
  int32_t precision = pInterval->precision;
2,147,483,647✔
761

762
  if (IS_CALENDAR_TIME_DURATION(pInterval->slidingUnit)) {
2,147,483,647✔
763
    start /= (int64_t)(TSDB_TICK_PER_SECOND(precision));
452,137✔
764
    struct tm  tm;
452,137✔
765
    time_t     tt = (time_t)start;
451,746✔
766
    if (taosLocalTime(&tt, &tm, NULL, 0, pInterval->timezone) == NULL){
451,746✔
767
      uError("%s failed to convert time to local time, code:%d", __FUNCTION__, ERRNO);
×
768
      return ts;
×
769
    }
770
    tm.tm_sec = 0;
452,136✔
771
    tm.tm_min = 0;
452,136✔
772
    tm.tm_hour = 0;
452,136✔
773
    tm.tm_mday = 1;
452,136✔
774

775
    if (pInterval->slidingUnit == 'y') {
452,136✔
776
      tm.tm_mon = 0;
96,585✔
777
      tm.tm_year = (int32_t)(tm.tm_year / pInterval->sliding * pInterval->sliding);
96,585✔
778
    } else {
779
      int32_t mon = tm.tm_year * 12 + tm.tm_mon;
355,551✔
780
      mon = (int32_t)(mon / pInterval->sliding * pInterval->sliding);
355,551✔
781
      tm.tm_year = mon / 12;
355,551✔
782
      tm.tm_mon = mon % 12;
355,551✔
783
    }
784

785
    tt = taosMktime(&tm, pInterval->timezone);
452,136✔
786
    if (tt == -1){
452,527✔
787
      uError("%s failed to convert local time to time, code:%d", __FUNCTION__, ERRNO);
×
788
      return ts;
×
789
    }
790
    start = (int64_t)(tt * TSDB_TICK_PER_SECOND(precision));
452,527✔
791
  } else {
792
    if (IS_CALENDAR_TIME_DURATION(pInterval->intervalUnit)) {
2,147,483,647✔
793
      int64_t news = (ts / pInterval->sliding) * pInterval->sliding;
2,186,411✔
794
      if (pInterval->slidingUnit == 'd' || pInterval->slidingUnit == 'w') {
334,033✔
795
#if defined(WINDOWS) && _MSC_VER >= 1900
796
        int64_t timezone = _timezone;
797
#endif
798
        news += (int64_t)(timezone * TSDB_TICK_PER_SECOND(precision));
334,033✔
799
      }
800

801
      start = news;
334,033✔
802
      if (news <= ts) {
334,033✔
803
        int64_t prev = news;
334,033✔
804
        int64_t newe = taosTimeAdd(news, pInterval->interval, pInterval->intervalUnit, precision, pInterval->timezone) - 1;
334,033✔
805

806
        if (newe < ts) {  // move towards the greater endpoint
334,033✔
807
          while (newe < ts && news < ts) {
×
808
            news += pInterval->sliding;
×
809
            newe = taosTimeAdd(news, pInterval->interval, pInterval->intervalUnit, precision, pInterval->timezone) - 1;
×
810
          }
811

812
          prev = news;
×
813
        } else {
814
          while (newe >= ts) {
1,279,960✔
815
            prev = news;
945,927✔
816
            news -= pInterval->sliding;
945,927✔
817
            newe = taosTimeAdd(news, pInterval->interval, pInterval->intervalUnit, precision, pInterval->timezone) - 1;
945,927✔
818
          }
819
        }
820

821
        start = prev;
334,033✔
822
      }
823
    } else {
824
      int64_t delta = ts - pInterval->interval;
2,147,483,647✔
825
      int32_t factor = (delta >= 0) ? 1 : -1;
2,147,483,647✔
826

827
      start = (delta / pInterval->sliding + factor) * pInterval->sliding;
2,147,483,647✔
828

829
      if (pInterval->intervalUnit == 'd' || pInterval->intervalUnit == 'w') {
2,147,483,647✔
830
        /*
831
         * here we revised the start time of day according to the local time zone,
832
         * but in case of DST, the start time of one day need to be dynamically decided.
833
         */
834
        // todo refactor to extract function that is available for Linux/Windows/Mac platform
835
#if defined(WINDOWS) && _MSC_VER >= 1900
836
        // see
837
        // https://docs.microsoft.com/en-us/cpp/c-runtime-library/daylight-dstbias-timezone-and-tzname?view=vs-2019
838
        int64_t timezone = _timezone;
839
#endif
840

841
        start += (int64_t)(timezone * TSDB_TICK_PER_SECOND(precision));
1,245,479,958✔
842
      }
843

844
      int64_t end = 0;
2,147,483,647✔
845

846
      // not enough time range
847
      if (start < 0 || INT64_MAX - start > pInterval->interval - 1) {
2,147,483,647✔
848
        end = taosTimeAdd(start, pInterval->interval, pInterval->intervalUnit, precision, pInterval->timezone) - 1;
2,147,483,647✔
849
        while (end < ts) {  // move forward to the correct time window
2,147,483,647✔
850
          start += pInterval->sliding;
430,261,638✔
851

852
          if (start < 0 || INT64_MAX - start > pInterval->interval - 1) {
430,255,016✔
853
            end = start + pInterval->interval - 1;
430,237,392✔
854
          } else {
855
            end = INT64_MAX;
×
856
            break;
×
857
          }
858
        }
859
      } else {
860
        end = INT64_MAX;
1,037✔
861
      }
862
    }
863
  }
864

865
  if (pInterval->offset > 0) {
2,147,483,647✔
866
    // try to move current window to the left-hande-side, due to the offset effect.
867
    int64_t newe = taosTimeAdd(start, pInterval->interval, pInterval->intervalUnit, precision, pInterval->timezone) - 1;
2,247,504✔
868
    int64_t slidingStart = start;
2,247,504✔
869
    while (newe >= ts) {
6,153,940✔
870
      start = slidingStart;
3,906,436✔
871
      slidingStart = taosTimeAdd(slidingStart, -pInterval->sliding, pInterval->slidingUnit, precision, pInterval->timezone);
3,906,436✔
872
      int64_t news = taosTimeAdd(slidingStart, pInterval->offset, pInterval->offsetUnit, precision, pInterval->timezone);
3,906,436✔
873
      newe = taosTimeAdd(news, pInterval->interval, pInterval->intervalUnit, precision, pInterval->timezone) - 1;
3,906,436✔
874
    }
875
    start = taosTimeAdd(start, pInterval->offset, pInterval->offsetUnit, precision, pInterval->timezone);
2,247,504✔
876
  }
877

878
  return start;
2,147,483,647✔
879
}
880

881
// used together with taosTimeTruncate. when offset is great than zero, slide-start/slide-end is the anchor point
882
int64_t taosTimeGetIntervalEnd(int64_t intervalStart, const SInterval* pInterval) {
2,147,483,647✔
883
  return taosTimeAdd(intervalStart, pInterval->interval, pInterval->intervalUnit, pInterval->precision, pInterval->timezone) - 1;
2,147,483,647✔
884
}
885

886
void calcIntervalAutoOffset(SInterval* interval) {
317,622,091✔
887
  if (!interval || interval->offset != AUTO_DURATION_VALUE) {
317,622,091✔
888
    return;
317,173,401✔
889
  }
890

891
  interval->offset = 0;
559,368✔
892

893
  if (interval->timeRange.skey == INT64_MIN) {
559,758✔
894
    return;
×
895
  }
896

897
  TSKEY skey = interval->timeRange.skey;
559,368✔
898
  TSKEY start = taosTimeTruncate(skey, interval);
559,758✔
899
  TSKEY news = start;
559,758✔
900
  while (news <= skey) {
1,514,801✔
901
    start = news;
955,043✔
902
    news = taosTimeAdd(start, interval->sliding, interval->slidingUnit, interval->precision, interval->timezone);
955,043✔
903
    if (news < start) {
955,043✔
904
      // overflow happens
905
      uError("%s failed and skip, skey [%" PRId64 "], inter[%" PRId64 "(%c)], slid[%" PRId64 "(%c)], precision[%d]",
×
906
             __func__, skey, interval->interval, interval->intervalUnit, interval->sliding, interval->slidingUnit,
907
             interval->precision);
908
      return;
×
909
    }
910
  }
911
  interval->offset = skey - start;
559,758✔
912
}
913

914
// internal function, when program is paused in debugger,
915
// one can call this function from debugger to print a
916
// timestamp as human readable string, for example (gdb):
917
//     p fmtts(1593769722)
918
// outputs:
919
//     2020-07-03 17:48:42
920
// and the parameter can also be a variable.
921
const char* fmtts(int64_t ts) {
×
922
  static char buf[TD_TIME_STR_LEN] = {0};
923
  size_t      pos = 0;
×
924
  struct tm   tm;
×
925

926
  if (ts > -62135625943 && ts < 32503651200) {
×
927
    time_t t = (time_t)ts;
×
928
    if (taosLocalTime(&t, &tm, buf, sizeof(buf), NULL) == NULL) {
×
929
      return buf;
×
930
    }
931
    pos += taosStrfTime(buf + pos, sizeof(buf), "s=%Y-%m-%d %H:%M:%S", &tm);
×
932
  }
933

934
  if (ts > -62135625943000 && ts < 32503651200000) {
×
935
    time_t t = (time_t)(ts / 1000);
×
936
    if (taosLocalTime(&t, &tm, buf, sizeof(buf), NULL) == NULL) {
×
937
      return buf;
×
938
    }
939
    if (pos > 0) {
×
940
      buf[pos++] = ' ';
×
941
      buf[pos++] = '|';
×
942
      buf[pos++] = ' ';
×
943
    }
944
    pos += taosStrfTime(buf + pos, sizeof(buf), "ms=%Y-%m-%d %H:%M:%S", &tm);
×
945
    pos += sprintf(buf + pos, ".%03d", (int32_t)(ts % 1000));
×
946
  }
947

948
  {
949
    time_t t = (time_t)(ts / 1000000);
×
950
    if (taosLocalTime(&t, &tm, buf, sizeof(buf), NULL) == NULL) {
×
951
      return buf;
×
952
    }
953
    if (pos > 0) {
×
954
      buf[pos++] = ' ';
×
955
      buf[pos++] = '|';
×
956
      buf[pos++] = ' ';
×
957
    }
958
    pos += taosStrfTime(buf + pos, sizeof(buf), "us=%Y-%m-%d %H:%M:%S", &tm);
×
959
    pos += sprintf(buf + pos, ".%06d", (int32_t)(ts % 1000000));
×
960
  }
961

962
  return buf;
×
963
}
964

965
int32_t taosFormatUtcTime(char* buf, int32_t bufLen, int64_t t, int32_t precision) {
81✔
966
  char      ts[40] = {0};
81✔
967
  struct tm ptm;
81✔
968

969
  int32_t fractionLen;
970
  char*   format = NULL;
81✔
971
  time_t  quot = 0;
81✔
972
  long    mod = 0;
81✔
973

974
  switch (precision) {
81✔
975
    case TSDB_TIME_PRECISION_MILLI: {
81✔
976
      quot = t / 1000;
81✔
977
      fractionLen = 5;
81✔
978
      format = ".%03" PRId64;
81✔
979
      mod = t % 1000;
81✔
980
      break;
81✔
981
    }
982

983
    case TSDB_TIME_PRECISION_MICRO: {
×
984
      quot = t / 1000000;
×
985
      fractionLen = 8;
×
986
      format = ".%06" PRId64;
×
987
      mod = t % 1000000;
×
988
      break;
×
989
    }
990

991
    case TSDB_TIME_PRECISION_NANO: {
×
992
      quot = t / 1000000000;
×
993
      fractionLen = 11;
×
994
      format = ".%09" PRId64;
×
995
      mod = t % 1000000000;
×
996
      break;
×
997
    }
998

999
    default:
×
1000
      fractionLen = 0;
×
1001
      TAOS_RETURN(TSDB_CODE_INVALID_PARA);
×
1002
  }
1003

1004
  if (NULL == taosLocalTime(&quot, &ptm, buf, bufLen, NULL)) {
81✔
1005
    TAOS_RETURN(TAOS_SYSTEM_ERROR(ERRNO));
×
1006
  }
1007
  int32_t length = (int32_t)taosStrfTime(ts, 40, "%Y-%m-%dT%H:%M:%S", &ptm);
81✔
1008
  length += tsnprintf(ts + length, fractionLen, format, mod);
81✔
1009
  length += (int32_t)taosStrfTime(ts + length, 40 - length, "%z", &ptm);
81✔
1010

1011
  tstrncpy(buf, ts, bufLen);
81✔
1012
  TAOS_RETURN(TSDB_CODE_SUCCESS);
81✔
1013
}
1014

1015
char* formatTimestampLocal(char* buf, int64_t val, int precision) {
94,434,201✔
1016
  time_t tt;
94,428,937✔
1017
  if (precision == TSDB_TIME_PRECISION_MICRO) {
94,436,585✔
1018
    tt = (time_t)(val / 1000000);
30,888✔
1019
  } else if (precision == TSDB_TIME_PRECISION_NANO) {
94,405,697✔
1020
    tt = (time_t)(val / 1000000000);
×
1021
  } else {
1022
    tt = (time_t)(val / 1000);
94,405,697✔
1023
  }
1024

1025
  struct tm tm;
94,431,321✔
1026
  if (taosLocalTime(&tt, &tm, NULL, 0, NULL) == NULL) {
94,436,073✔
1027
    return NULL;
×
1028
  }
1029
  size_t pos = taosStrfTime(buf, 32, "%Y-%m-%d %H:%M:%S", &tm);
94,435,939✔
1030

1031
  if (precision == TSDB_TIME_PRECISION_MICRO) {
94,436,080✔
1032
    sprintf(buf + pos, ".%06d", (int)(val % 1000000));
30,888✔
1033
  } else if (precision == TSDB_TIME_PRECISION_NANO) {
94,405,192✔
1034
    sprintf(buf + pos, ".%09d", (int)(val % 1000000000));
×
1035
  } else {
1036
    sprintf(buf + pos, ".%03d", (int)(val % 1000));
94,405,192✔
1037
  }
1038

1039
  return buf;
94,432,449✔
1040
}
1041

1042
int32_t taosTs2Tm(int64_t ts, int32_t precision, struct STm* tm, timezone_t tz) {
535,202,027✔
1043
  tm->fsec = ts % TICK_PER_SECOND[precision] * (TICK_PER_SECOND[TSDB_TIME_PRECISION_NANO] / TICK_PER_SECOND[precision]);
535,202,027✔
1044
  time_t t = ts / TICK_PER_SECOND[precision];
535,131,377✔
1045
  if (NULL == taosLocalTime(&t, &tm->tm, NULL, 0, tz)) {
535,349,627✔
1046
    TAOS_RETURN(TAOS_SYSTEM_ERROR(ERRNO));
×
1047
  }
1048
  return TSDB_CODE_SUCCESS;
535,220,927✔
1049
}
1050

1051
int32_t taosTm2Ts(struct STm* tm, int64_t* ts, int32_t precision, timezone_t tz) {
81,317,282✔
1052
  *ts = taosMktime(&tm->tm, tz);
81,317,282✔
1053
  *ts *= TICK_PER_SECOND[precision];
81,302,432✔
1054
  *ts += tm->fsec / (TICK_PER_SECOND[TSDB_TIME_PRECISION_NANO] / TICK_PER_SECOND[precision]);
81,313,232✔
1055
  return TSDB_CODE_SUCCESS;
81,328,982✔
1056
}
1057

1058
typedef struct {
1059
  const char* name;
1060
  int         len;
1061
  int         id;
1062
  bool        isDigit;
1063
} TSFormatKeyWord;
1064

1065
typedef enum {
1066
  // TSFKW_AD,   // BC AD
1067
  // TSFKW_A_D,  // A.D. B.C.
1068
  TSFKW_AM,   // AM, PM
1069
  TSFKW_A_M,  // A.M., P.M.
1070
  // TSFKW_BC,   // BC AD
1071
  // TSFKW_B_C,  // B.C. A.D.
1072
  TSFKW_DAY,  // MONDAY, TUESDAY ...
1073
  TSFKW_DDD,  // Day of year 001-366
1074
  TSFKW_DD,   // Day of month 01-31
1075
  TSFKW_Day,  // Sunday, Monday
1076
  TSFKW_DY,   // MON, TUE
1077
  TSFKW_Dy,   // Mon, Tue
1078
  TSFKW_D,    // 1-7 -> Sunday(1) -> Saturday(7)
1079
  TSFKW_HH24,
1080
  TSFKW_HH12,
1081
  TSFKW_HH,
1082
  TSFKW_MI,  // minute
1083
  TSFKW_MM,
1084
  TSFKW_MONTH,  // JANUARY, FEBRUARY
1085
  TSFKW_MON,
1086
  TSFKW_Month,
1087
  TSFKW_Mon,
1088
  TSFKW_MS,
1089
  TSFKW_NS,
1090
  // TSFKW_OF,
1091
  TSFKW_PM,
1092
  TSFKW_P_M,
1093
  TSFKW_SS,
1094
  TSFKW_TZH,
1095
  // TSFKW_TZM,
1096
  // TSFKW_TZ,
1097
  TSFKW_US,
1098
  TSFKW_YYYY,
1099
  TSFKW_YYY,
1100
  TSFKW_YY,
1101
  TSFKW_Y,
1102
  // TSFKW_a_d,
1103
  // TSFKW_ad,
1104
  TSFKW_am,
1105
  TSFKW_a_m,
1106
  // TSFKW_b_c,
1107
  // TSFKW_bc,
1108
  TSFKW_day,
1109
  TSFKW_ddd,
1110
  TSFKW_dd,
1111
  TSFKW_dy,  // mon, tue
1112
  TSFKW_d,
1113
  TSFKW_hh24,
1114
  TSFKW_hh12,
1115
  TSFKW_hh,
1116
  TSFKW_mi,
1117
  TSFKW_mm,
1118
  TSFKW_month,
1119
  TSFKW_mon,
1120
  TSFKW_ms,
1121
  TSFKW_ns,
1122
  TSFKW_pm,
1123
  TSFKW_p_m,
1124
  TSFKW_ss,
1125
  TSFKW_tzh,
1126
  // TSFKW_tzm,
1127
  // TSFKW_tz,
1128
  TSFKW_us,
1129
  TSFKW_yyyy,
1130
  TSFKW_yyy,
1131
  TSFKW_yy,
1132
  TSFKW_y,
1133
  TSFKW_last_
1134
} TSFormatKeywordId;
1135

1136
// clang-format off
1137
static const TSFormatKeyWord formatKeyWords[] = {
1138
  //{"AD", 2, TSFKW_AD, false},
1139
  //{"A.D.", 4, TSFKW_A_D},
1140
  {"AM", 2, TSFKW_AM, false},
1141
  {"A.M.", 4, TSFKW_A_M, false},
1142
  //{"BC", 2, TSFKW_BC, false},
1143
  //{"B.C.", 4, TSFKW_B_C, false},
1144
  {"DAY", 3, TSFKW_DAY, false},
1145
  {"DDD", 3, TSFKW_DDD, true},
1146
  {"DD", 2, TSFKW_DD, true},
1147
  {"Day", 3, TSFKW_Day, false},
1148
  {"DY", 2, TSFKW_DY, false},
1149
  {"Dy", 2, TSFKW_Dy, false},
1150
  {"D", 1, TSFKW_D, true},
1151
  {"HH24", 4, TSFKW_HH24, true},
1152
  {"HH12", 4, TSFKW_HH12, true},
1153
  {"HH", 2, TSFKW_HH, true},
1154
  {"MI", 2, TSFKW_MI, true},
1155
  {"MM", 2, TSFKW_MM, true},
1156
  {"MONTH", 5, TSFKW_MONTH, false},
1157
  {"MON", 3, TSFKW_MON, false},
1158
  {"Month", 5, TSFKW_Month, false},
1159
  {"Mon", 3, TSFKW_Mon, false},
1160
  {"MS", 2, TSFKW_MS, true},
1161
  {"NS", 2, TSFKW_NS, true},
1162
  //{"OF", 2, TSFKW_OF, false},
1163
  {"PM", 2, TSFKW_PM, false},
1164
  {"P.M.", 4, TSFKW_P_M, false},
1165
  {"SS", 2, TSFKW_SS, true},
1166
  {"TZH", 3, TSFKW_TZH, false},
1167
  //{"TZM", 3, TSFKW_TZM},
1168
  //{"TZ", 2, TSFKW_TZ},
1169
  {"US", 2, TSFKW_US, true},
1170
  {"YYYY", 4, TSFKW_YYYY, true},
1171
  {"YYY", 3, TSFKW_YYY, true},
1172
  {"YY", 2, TSFKW_YY, true},
1173
  {"Y", 1, TSFKW_Y, true},
1174
  //{"a.d.", 4, TSFKW_a_d, false},
1175
  //{"ad", 2, TSFKW_ad, false},
1176
  {"am", 2, TSFKW_am, false},
1177
  {"a.m.", 4, TSFKW_a_m, false},
1178
  //{"b.c.", 4, TSFKW_b_c, false},
1179
  //{"bc", 2, TSFKW_bc, false},
1180
  {"day", 3, TSFKW_day, false},
1181
  {"ddd", 3, TSFKW_DDD, true},
1182
  {"dd", 2, TSFKW_DD, true},
1183
  {"dy", 2, TSFKW_dy, false},
1184
  {"d", 1, TSFKW_D, true},
1185
  {"hh24", 4, TSFKW_HH24, true},
1186
  {"hh12", 4, TSFKW_HH12, true},
1187
  {"hh", 2, TSFKW_HH, true},
1188
  {"mi", 2, TSFKW_MI, true},
1189
  {"mm", 2, TSFKW_MM, true},
1190
  {"month", 5, TSFKW_month, false},
1191
  {"mon", 3, TSFKW_mon, false},
1192
  {"ms", 2, TSFKW_MS, true},
1193
  {"ns", 2, TSFKW_NS, true},
1194
  //{"of", 2, TSFKW_OF, false},
1195
  {"pm", 2, TSFKW_pm, false},
1196
  {"p.m.", 4, TSFKW_p_m, false},
1197
  {"ss", 2, TSFKW_SS, true},
1198
  {"tzh", 3, TSFKW_TZH, false},
1199
  //{"tzm", 3, TSFKW_TZM},
1200
  //{"tz", 2, TSFKW_tz},
1201
  {"us", 2, TSFKW_US, true},
1202
  {"yyyy", 4, TSFKW_YYYY, true},
1203
  {"yyy", 3, TSFKW_YYY, true},
1204
  {"yy", 2, TSFKW_YY, true},
1205
  {"y", 1, TSFKW_Y, true},
1206
  {NULL, 0, 0}
1207
};
1208
// clang-format on
1209

1210
#define TS_FROMAT_KEYWORD_INDEX_SIZE ('z' - 'A' + 1)
1211
static const int TSFormatKeywordIndex[TS_FROMAT_KEYWORD_INDEX_SIZE] = {
1212
    /*A*/ TSFKW_AM,     -1, -1,
1213
    /*D*/ TSFKW_DAY,    -1, -1, -1,
1214
    /*H*/ TSFKW_HH24,   -1, -1, -1, -1,
1215
    /*M*/ TSFKW_MI,
1216
    /*N*/ TSFKW_NS,     -1,
1217
    /*P*/ TSFKW_PM,     -1, -1,
1218
    /*S*/ TSFKW_SS,
1219
    /*T*/ TSFKW_TZH,
1220
    /*U*/ TSFKW_US,     -1, -1, -1,
1221
    /*Y*/ TSFKW_YYYY,   -1,
1222
    /*[ \ ] ^ _ `*/ -1, -1, -1, -1, -1, -1,
1223
    /*a*/ TSFKW_am,     -1, -1,
1224
    /*d*/ TSFKW_day,    -1, -1, -1,
1225
    /*h*/ TSFKW_hh24,   -1, -1, -1, -1,
1226
    /*m*/ TSFKW_mi,
1227
    /*n*/ TSFKW_ns,     -1,
1228
    /*p*/ TSFKW_pm,     -1, -1,
1229
    /*s*/ TSFKW_ss,
1230
    /*t*/ TSFKW_tzh,
1231
    /*u*/ TSFKW_us,     -1, -1, -1,
1232
    /*y*/ TSFKW_yyyy,   -1};
1233

1234
typedef struct {
1235
  uint8_t                type;
1236
  const char*            c;
1237
  int32_t                len;
1238
  const TSFormatKeyWord* key;
1239
} TSFormatNode;
1240

1241
static const char* const weekDays[] = {"Sunday",   "Monday", "Tuesday",  "Wednesday",
1242
                                       "Thursday", "Friday", "Saturday", "NULL"};
1243
static const char* const shortWeekDays[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "NULL"};
1244
static const char* const fullMonths[] = {"January", "February",  "March",   "April",    "May",      "June", "July",
1245
                                         "August",  "September", "October", "November", "December", NULL};
1246
static const char* const months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
1247
                                     "Aug", "Sep", "Oct", "Nov", "Dec", NULL};
1248
#define A_M_STR "A.M."
1249
#define a_m_str "a.m."
1250
#define AM_STR  "AM"
1251
#define am_str  "am"
1252
#define P_M_STR "P.M."
1253
#define p_m_str "p.m."
1254
#define PM_STR  "PM"
1255
#define pm_str  "pm"
1256
static const char* const apms[] = {AM_STR, PM_STR, am_str, pm_str, NULL};
1257
static const char* const long_apms[] = {A_M_STR, P_M_STR, a_m_str, p_m_str, NULL};
1258

1259
#define TS_FORMAT_NODE_TYPE_KEYWORD   1
1260
#define TS_FORMAT_NODE_TYPE_SEPARATOR 2
1261
#define TS_FORMAT_NODE_TYPE_CHAR      3
1262

1263
static const TSFormatKeyWord* keywordSearch(const char* str) {
246,335,148✔
1264
  if (*str < 'A' || *str > 'z' || (*str > 'Z' && *str < 'a')) return NULL;
246,335,148✔
1265
  int32_t idx = TSFormatKeywordIndex[str[0] - 'A'];
103,322,724✔
1266
  if (idx < 0) return NULL;
103,328,124✔
1267
  const TSFormatKeyWord* key = &formatKeyWords[idx++];
103,328,124✔
1268
  while (key->name && str[0] == key->name[0]) {
172,295,230✔
1269
    if (0 == strncmp(key->name, str, key->len)) {
172,254,734✔
1270
      return key;
103,284,928✔
1271
    }
1272
    key = &formatKeyWords[idx++];
68,968,456✔
1273
  }
1274
  return NULL;
39,596✔
1275
}
1276

1277
static bool isSeperatorChar(char c) {
467,756,270✔
1278
  return (c > 0x20 && c < 0x7F && !(c >= 'A' && c <= 'Z') && !(c >= 'a' && c <= 'z') && !(c >= '0' && c <= '9'));
467,756,270✔
1279
}
1280

1281
static int32_t parseTsFormat(const char* formatStr, SArray* formats) {
17,030,647✔
1282
  TSFormatNode* lastOtherFormat = NULL;
17,030,647✔
1283
  while (*formatStr) {
263,371,195✔
1284
    const TSFormatKeyWord* key = keywordSearch(formatStr);
246,336,498✔
1285
    if (key) {
246,328,848✔
1286
      TSFormatNode format = {.key = key, .type = TS_FORMAT_NODE_TYPE_KEYWORD};
103,283,578✔
1287
      if (NULL == taosArrayPush(formats, &format)) TAOS_RETURN(terrno);
103,284,928✔
1288
      formatStr += key->len;
103,284,928✔
1289
      lastOtherFormat = NULL;
103,285,828✔
1290
    } else {
1291
      if (*formatStr == '"') {
143,045,270✔
1292
        lastOtherFormat = NULL;
1,353✔
1293
        // for double quoted string
1294
        formatStr++;
1,353✔
1295
        TSFormatNode* last = NULL;
1,353✔
1296
        while (*formatStr) {
5,412✔
1297
          if (*formatStr == '"') {
5,412✔
1298
            formatStr++;
1,353✔
1299
            break;
1,353✔
1300
          }
1301
          if (*formatStr == '\\' && *(formatStr + 1)) {
4,059✔
1302
            formatStr++;
×
1303
            last = NULL;  // stop expanding last format, create new format
×
1304
          }
1305
          if (last) {
4,059✔
1306
            // expand
1307
            last->len++;
2,706✔
1308
            formatStr++;
2,706✔
1309
          } else {
1310
            // create new
1311
            TSFormatNode format = {.type = TS_FORMAT_NODE_TYPE_CHAR, .key = NULL};
1,353✔
1312
            format.c = formatStr;
1,353✔
1313
            format.len = 1;
1,353✔
1314
            if (NULL == taosArrayPush(formats, &format)) TAOS_RETURN(terrno);
1,353✔
1315
            formatStr++;
1,353✔
1316
            last = taosArrayGetLast(formats);
1,353✔
1317
          }
1318
        }
1319
      } else {
1320
        // for other strings
1321
        if (*formatStr == '\\' && *(formatStr + 1)) {
143,048,417✔
1322
          formatStr++;
×
1323
          lastOtherFormat = NULL;  // stop expanding
×
1324
        } else {
1325
          if (lastOtherFormat && !isSeperatorChar(*formatStr)) {
143,048,867✔
1326
            // expanding
1327
          } else {
1328
            // create new
1329
            lastOtherFormat = NULL;
86,202,743✔
1330
          }
1331
        }
1332
        if (lastOtherFormat) {
143,048,417✔
1333
          lastOtherFormat->len++;
56,845,674✔
1334
          formatStr++;
56,845,674✔
1335
        } else {
1336
          TSFormatNode format = {
172,406,386✔
1337
              .type = isSeperatorChar(*formatStr) ? TS_FORMAT_NODE_TYPE_SEPARATOR : TS_FORMAT_NODE_TYPE_CHAR,
86,202,743✔
1338
              .key = NULL};
1339
          format.c = formatStr;
86,203,643✔
1340
          format.len = 1;
86,203,643✔
1341
          if (NULL == taosArrayPush(formats, &format)) TAOS_RETURN(terrno);
86,203,193✔
1342
          formatStr++;
86,203,193✔
1343
          if (format.type == TS_FORMAT_NODE_TYPE_CHAR) lastOtherFormat = taosArrayGetLast(formats);
86,203,193✔
1344
        }
1345
      }
1346
    }
1347
  }
1348
  TAOS_RETURN(TSDB_CODE_SUCCESS);
17,030,197✔
1349
}
1350

1351
static int32_t tm2char(const SArray* formats, const struct STm* tm, char* s, int32_t outLen) {
181,376,369✔
1352
  int32_t     size = taosArrayGetSize(formats);
181,376,369✔
1353
  const char* start = s;
181,366,019✔
1354
  for (int32_t i = 0; i < size; ++i) {
2,147,483,647✔
1355
    TSFormatNode* format = taosArrayGet(formats, i);
2,122,779,414✔
1356
    if (format->type != TS_FORMAT_NODE_TYPE_KEYWORD) {
2,121,069,864✔
1357
      if (s - start + format->len + 1 > outLen) break;
995,747,219✔
1358
      (void)strncpy(s, format->c, format->len);
995,937,119✔
1359
      s += format->len;
996,105,869✔
1360
      continue;
997,883,819✔
1361
    }
1362
    if (s - start + 16 > outLen) break;
1,131,333,745✔
1363

1364
    switch (format->key->id) {
1,131,333,745✔
1365
      case TSFKW_AM:
902✔
1366
      case TSFKW_PM:
1367
        (void)sprintf(s, tm->tm.tm_hour % 24 >= 12 ? "PM" : "AM");
902✔
1368
        s += 2;
902✔
1369
        break;
902✔
1370
      case TSFKW_A_M:
×
1371
      case TSFKW_P_M:
1372
        (void)sprintf(s, tm->tm.tm_hour % 24 >= 12 ? "P.M." : "A.M.");
×
1373
        s += 4;
×
1374
        break;
×
1375
      case TSFKW_am:
1,533✔
1376
      case TSFKW_pm:
1377
        (void)sprintf(s, tm->tm.tm_hour % 24 >= 12 ? "pm" : "am");
1,533✔
1378
        s += 2;
1,533✔
1379
        break;
1,533✔
1380
      case TSFKW_a_m:
59,705✔
1381
      case TSFKW_p_m:
1382
        (void)sprintf(s, tm->tm.tm_hour % 24 >= 12 ? "p.m." : "a.m.");
59,705✔
1383
        s += 4;
59,705✔
1384
        break;
59,705✔
1385
      case TSFKW_DDD:
112,536✔
1386
        (void)sprintf(s, "%03d", tm->tm.tm_yday + 1);
112,536✔
1387
        s += strlen(s);
112,536✔
1388
        break;
112,536✔
1389
      case TSFKW_DD:
180,883,121✔
1390
        (void)sprintf(s, "%02d", tm->tm.tm_mday);
180,883,121✔
1391
        s += 2;
181,177,421✔
1392
        break;
181,216,571✔
1393
      case TSFKW_D:
97,948✔
1394
        (void)sprintf(s, "%d", tm->tm.tm_wday + 1);
97,948✔
1395
        s += 1;
97,948✔
1396
        break;
97,948✔
1397
      case TSFKW_DAY: {
4,168✔
1398
        // MONDAY, TUESDAY...
1399
        const char* wd = weekDays[tm->tm.tm_wday];
4,168✔
1400
        char        buf[10] = {0};
4,168✔
1401
        for (int32_t i = 0; i < strlen(wd); ++i) buf[i] = toupper(wd[i]);
29,176✔
1402
        (void)sprintf(s, "%-9s", buf);
4,168✔
1403
        s += strlen(s);
4,168✔
1404
        break;
4,168✔
1405
      }
1406
      case TSFKW_Day:
2,084✔
1407
        // Monday, TuesDay...
1408
        (void)sprintf(s, "%-9s", weekDays[tm->tm.tm_wday]);
2,084✔
1409
        s += strlen(s);
2,084✔
1410
        break;
2,084✔
1411
      case TSFKW_day: {
4,168✔
1412
        const char* wd = weekDays[tm->tm.tm_wday];
4,168✔
1413
        char        buf[10] = {0};
4,168✔
1414
        for (int32_t i = 0; i < strlen(wd); ++i) buf[i] = tolower(wd[i]);
29,176✔
1415
        (void)sprintf(s, "%-9s", buf);
4,168✔
1416
        s += strlen(s);
4,168✔
1417
        break;
4,168✔
1418
      }
1419
      case TSFKW_DY: {
85,444✔
1420
        // MON, TUE
1421
        const char* wd = shortWeekDays[tm->tm.tm_wday];
85,444✔
1422
        char        buf[8] = {0};
85,444✔
1423
        for (int32_t i = 0; i < strlen(wd); ++i) buf[i] = toupper(wd[i]);
341,776✔
1424
        (void)sprintf(s, "%3s", buf);
85,444✔
1425
        s += 3;
85,444✔
1426
        break;
85,444✔
1427
      }
1428
      case TSFKW_Dy:
4,168✔
1429
        // Mon, Tue
1430
        (void)sprintf(s, "%3s", shortWeekDays[tm->tm.tm_wday]);
4,168✔
1431
        s += 3;
4,168✔
1432
        break;
4,168✔
1433
      case TSFKW_dy: {
44,948,155✔
1434
        // mon, tue
1435
        const char* wd = shortWeekDays[tm->tm.tm_wday];
44,948,155✔
1436
        char        buf[8] = {0};
44,989,555✔
1437
        for (int32_t i = 0; i < strlen(wd); ++i) buf[i] = tolower(wd[i]);
179,413,720✔
1438
        (void)sprintf(s, "%3s", buf);
44,985,055✔
1439
        s += 3;
44,985,055✔
1440
        break;
44,977,855✔
1441
      }
1442
      case TSFKW_HH24:
135,803,796✔
1443
        (void)sprintf(s, "%02d", tm->tm.tm_hour);
135,803,796✔
1444
        s += 2;
135,766,446✔
1445
        break;
135,787,596✔
1446
      case TSFKW_HH:
45,246,368✔
1447
      case TSFKW_HH12:
1448
        // 0 or 12 o'clock in 24H coresponds to 12 o'clock (AM/PM) in 12H
1449
        (void)sprintf(s, "%02d", tm->tm.tm_hour % 12 == 0 ? 12 : tm->tm.tm_hour % 12);
45,246,368✔
1450
        s += 2;
45,234,218✔
1451
        break;
45,222,518✔
1452
      case TSFKW_MI:
181,006,514✔
1453
        (void)sprintf(s, "%02d", tm->tm.tm_min);
181,006,514✔
1454
        s += 2;
181,038,464✔
1455
        break;
181,029,014✔
1456
      case TSFKW_MM:
136,138,846✔
1457
        (void)sprintf(s, "%02d", tm->tm.tm_mon + 1);
136,138,846✔
1458
        s += 2;
136,162,246✔
1459
        break;
136,072,696✔
1460
      case TSFKW_MONTH: {
4,168✔
1461
        const char* mon = fullMonths[tm->tm.tm_mon];
4,168✔
1462
        char        buf[10] = {0};
4,168✔
1463
        for (int32_t i = 0; i < strlen(mon); ++i) buf[i] = toupper(mon[i]);
29,176✔
1464
        (void)sprintf(s, "%-9s", buf);
4,168✔
1465
        s += strlen(s);
4,168✔
1466
        break;
4,168✔
1467
      }
1468
      case TSFKW_MON: {
112,536✔
1469
        const char* mon = months[tm->tm.tm_mon];
112,536✔
1470
        char        buf[10] = {0};
112,536✔
1471
        for (int32_t i = 0; i < strlen(mon); ++i) buf[i] = toupper(mon[i]);
450,144✔
1472
        (void)sprintf(s, "%s", buf);
112,536✔
1473
        s += strlen(s);
112,536✔
1474
        break;
112,536✔
1475
      }
1476
      case TSFKW_Month:
2,084✔
1477
        (void)sprintf(s, "%-9s", fullMonths[tm->tm.tm_mon]);
2,084✔
1478
        s += strlen(s);
2,084✔
1479
        break;
2,084✔
1480
      case TSFKW_month: {
4,619✔
1481
        const char* mon = fullMonths[tm->tm.tm_mon];
4,619✔
1482
        char        buf[10] = {0};
4,619✔
1483
        for (int32_t i = 0; i < strlen(mon); ++i) buf[i] = tolower(mon[i]);
32,784✔
1484
        (void)sprintf(s, "%-9s", buf);
4,619✔
1485
        s += strlen(s);
4,619✔
1486
        break;
4,619✔
1487
      }
1488
      case TSFKW_Mon:
2,084✔
1489
        (void)sprintf(s, "%s", months[tm->tm.tm_mon]);
2,084✔
1490
        s += strlen(s);
2,084✔
1491
        break;
2,084✔
1492
      case TSFKW_mon: {
44,970,868✔
1493
        const char* mon = months[tm->tm.tm_mon];
44,970,868✔
1494
        char        buf[10] = {0};
44,991,568✔
1495
        for (int32_t i = 0; i < strlen(mon); ++i) buf[i] = tolower(mon[i]);
179,568,922✔
1496
        (void)sprintf(s, "%s", buf);
44,995,168✔
1497
        s += strlen(s);
44,995,168✔
1498
        break;
44,901,118✔
1499
      }
1500
      case TSFKW_SS:
181,049,594✔
1501
        (void)sprintf(s, "%02d", tm->tm.tm_sec);
181,049,594✔
1502
        s += 2;
181,046,894✔
1503
        break;
181,021,694✔
1504
      case TSFKW_MS:
2,818,313✔
1505
        (void)sprintf(s, "%03" PRId64, tm->fsec / 1000000L);
2,818,313✔
1506
        s += 3;
2,818,313✔
1507
        break;
2,818,313✔
1508
      case TSFKW_US:
7,605✔
1509
        (void)sprintf(s, "%06" PRId64, tm->fsec / 1000L);
7,605✔
1510
        s += 6;
7,605✔
1511
        break;
7,605✔
1512
      case TSFKW_NS:
9,405✔
1513
        (void)sprintf(s, "%09" PRId64, tm->fsec);
9,405✔
1514
        s += 9;
9,405✔
1515
        break;
9,405✔
1516
      case TSFKW_TZH:{
59,254✔
1517
#ifdef WINDOWS
1518
        int32_t gmtoff = -_timezone;
1519
#elif defined(TD_ASTRA)
1520
        int32_t gmtoff = -timezone;
1521
#else
1522
        int32_t gmtoff = tm->tm.tm_gmtoff;
59,254✔
1523
#endif
1524
        (void)sprintf(s, "%c%02d", (gmtoff >= 0) ? '+' : '-',
59,254✔
1525
                      abs(gmtoff) / 3600);
59,254✔
1526
        s += strlen(s);
59,254✔
1527
        break;
59,254✔
1528
      }
1529
      case TSFKW_YYYY:
136,207,108✔
1530
        (void)sprintf(s, "%04d", tm->tm.tm_year + 1900);
136,207,108✔
1531
        s += strlen(s);
136,230,958✔
1532
        break;
136,212,508✔
1533
      case TSFKW_YYY:
12,504✔
1534
        (void)sprintf(s, "%03d", (tm->tm.tm_year + 1900) % 1000);
12,504✔
1535
        s += strlen(s);
12,504✔
1536
        break;
12,504✔
1537
      case TSFKW_YY:
44,843,309✔
1538
        (void)sprintf(s, "%02d", (tm->tm.tm_year + 1900) % 100);
44,843,309✔
1539
        s += strlen(s);
44,859,059✔
1540
        break;
44,929,709✔
1541
      case TSFKW_Y:
14,588✔
1542
        (void)sprintf(s, "%01d", (tm->tm.tm_year + 1900) % 10);
14,588✔
1543
        s += strlen(s);
14,588✔
1544
        break;
14,588✔
1545
      default:
×
1546
        break;
×
1547
    }
1548
  }
1549
  return TSDB_CODE_SUCCESS;
181,784,969✔
1550
}
1551

1552
/// @brief find s in arr case insensitively
1553
/// @retval the index in arr if found, -1 if not found
1554
static int32_t strArrayCaseSearch(const char* const* arr, const char* s) {
90,101,013✔
1555
  if (!*s) return -1;
90,101,013✔
1556
  const char* const* fmt = arr;
90,105,063✔
1557
  for (; *fmt; ++fmt) {
635,652,881✔
1558
    const char *l, *r;
1559
    for (l = fmt[0], r = s;; l++, r++) {
919,920,548✔
1560
      if (*l == '\0') return fmt - arr;
919,840,898✔
1561
      if (*r == '\0' || tolower(*l) != tolower(*r)) break;
828,066,426✔
1562
    }
1563
  }
1564
  return -1;
541✔
1565
}
1566

1567
static const char* tsFormatStr2Int32(int32_t* dest, const char* str, int32_t len, bool needMoreDigit) {
441,809,784✔
1568
  char*       last;
441,809,784✔
1569
  int64_t     res;
1570
  const char* s = str;
441,830,484✔
1571
  if ('\0' == str[0]) return NULL;
441,830,484✔
1572
  if (len <= 0) {
441,943,434✔
1573
    res = taosStr2Int64(s, &last, 10);
26,812✔
1574
    s = last;
26,812✔
1575
  } else {
1576
    char buf[16] = {0};
441,916,622✔
1577
    (void)strncpy(buf, s, len);
441,940,472✔
1578
    int32_t copiedLen = strlen(buf);
441,940,472✔
1579
    if (copiedLen < len) {
441,940,472✔
1580
      if (!needMoreDigit) {
35,999,551✔
1581
        // digits not enough, that's ok, cause we do not need more digits
1582
        // '2023-1' 'YYYY-MM'
1583
        // '202a' 'YYYY' -> 202
1584
        res = taosStr2Int64(s, &last, 10);
35,999,551✔
1585
        s += copiedLen;
35,999,101✔
1586
      } else {
1587
        // bytes not enough, and there are other digit formats to match
1588
        // '2023-1' 'YYYY-MMDD'
1589
        return NULL;
×
1590
      }
1591
    } else {
1592
      if (needMoreDigit) {
405,940,921✔
1593
        res = taosStr2Int64(buf, &last, 10);
1,804✔
1594
        // bytes enough, but digits not enough, like '202a12' 'YYYYMM', YYYY needs four digits
1595
        if (last - buf < len) return NULL;
1,804✔
1596
        s += last - buf;
1,353✔
1597
      } else {
1598
        res = taosStr2Int64(s, &last, 10);
405,939,117✔
1599
        s = last;
405,953,967✔
1600
      }
1601
    }
1602
  }
1603
  if (s == str) {
442,018,583✔
1604
    // no integers found
1605
    return NULL;
541✔
1606
  }
1607
  if (ERRNO == ERANGE || res > INT32_MAX || res < INT32_MIN) {
442,018,042✔
1608
    // out of range
1609
    return NULL;
×
1610
  }
1611
  *dest = res;
442,031,992✔
1612
  return s;
442,032,442✔
1613
}
1614

1615
static int32_t adjustYearTo2020(int32_t year) {
45,010,168✔
1616
  if (year < 70) return year + 2000;    // 2000 - 2069
45,010,168✔
1617
  if (year < 100) return year + 1900;   // 1970 - 1999
×
1618
  if (year < 520) return year + 2000;   // 2100 - 2519
×
1619
  if (year < 1000) return year + 1000;  // 1520 - 1999
×
1620
  return year;
×
1621
}
1622

1623
static bool checkTm(const struct tm* tm) {
81,288,034✔
1624
  if (tm->tm_mon < 0 || tm->tm_mon > 11) return false;
81,288,034✔
1625
  if (tm->tm_wday < 0 || tm->tm_wday > 6) return false;
81,328,082✔
1626
  if (tm->tm_yday < 0 || tm->tm_yday > 365) return false;
81,330,332✔
1627
  if (tm->tm_mday < 0 || tm->tm_mday > 31) return false;
81,329,882✔
1628
  if (tm->tm_hour < 0 || tm->tm_hour > 23) return false;
81,331,682✔
1629
  if (tm->tm_min < 0 || tm->tm_min > 59) return false;
81,324,482✔
1630
  if (tm->tm_sec < 0 || tm->tm_sec > 60) return false;
81,328,532✔
1631
  return true;
81,295,682✔
1632
}
1633

1634
static bool needMoreDigits(SArray* formats, int32_t curIdx) {
441,777,834✔
1635
  if (curIdx == taosArrayGetSize(formats) - 1) return false;
441,777,834✔
1636
  TSFormatNode* pNextNode = taosArrayGet(formats, curIdx + 1);
405,496,370✔
1637
  if (pNextNode->type == TS_FORMAT_NODE_TYPE_SEPARATOR) {
405,333,020✔
1638
    return false;
279,496,944✔
1639
  } else if (pNextNode->type == TS_FORMAT_NODE_TYPE_KEYWORD) {
126,103,826✔
1640
    return pNextNode->key->isDigit;
31,773✔
1641
  } else {
1642
    return isdigit(pNextNode->c[0]);
126,071,153✔
1643
  }
1644
}
1645

1646
/// @brief convert a formatted time str to timestamp
1647
/// @param[in] s the formatted timestamp str
1648
/// @param[in] formats array of TSFormatNode, output of parseTsFormat
1649
/// @param[out] ts output timestamp
1650
/// @param precision the timestamp precision to convert to, sec/milli/micro/nano
1651
/// @param[out] sErrPos if not NULL, when err occured, points to the failed position of s, only set when ret is -1
1652
/// @param[out] fErrIdx if not NULL, when err occured, the idx of the failed format idx, only set when ret is -1
1653
/// @retval 0 for success
1654
/// @retval -1 for format and s mismatch error
1655
/// @retval -2 if datetime err, like 2023-13-32 25:61:69
1656
/// @retval -3 if not supported
1657
static int32_t char2ts(const char* s, SArray* formats, int64_t* ts, int32_t precision, const char** sErrPos,
81,306,335✔
1658
                       int32_t* fErrIdx, timezone_t tz) {
1659
  int32_t size = taosArrayGetSize(formats);
81,306,335✔
1660
  int32_t pm = 0;      // default am
81,318,035✔
1661
  int32_t hour12 = 0;  // default HH24
81,318,035✔
1662
  int32_t year = 0, mon = 0, yd = 0, md = 1, wd = 0;
81,318,035✔
1663
  int32_t hour = 0, min = 0, sec = 0, us = 0, ms = 0, ns = 0;
81,315,335✔
1664
  int32_t tzHour = 0;
81,310,385✔
1665
  int32_t err = 0;
81,320,285✔
1666
  bool    withYD = false, withMD = false;
81,320,285✔
1667

1668
  for (int32_t i = 0; i < size && *s != '\0'; ++i) {
1,064,390,842✔
1669
    while (isspace(*s) && *s != '\0') {
1,107,582,840✔
1670
      s++;
126,148,750✔
1671
    }
1672
    if (!s) break;
981,398,990✔
1673
    TSFormatNode* node = taosArrayGet(formats, i);
981,398,990✔
1674
    if (node->type == TS_FORMAT_NODE_TYPE_SEPARATOR) {
981,274,790✔
1675
      // separator matches any character
1676
      if (isSeperatorChar(s[0])) s += node->len;
324,725,852✔
1677
      continue;
324,748,352✔
1678
    }
1679
    if (node->type == TS_FORMAT_NODE_TYPE_CHAR) {
657,365,238✔
1680
      int32_t pos = 0;
126,119,541✔
1681
      // skip leading spaces
1682
      while (isspace(node->c[pos]) && node->len > 0) pos++;
252,169,303✔
1683
      while (pos < node->len && *s != '\0') {
127,950,659✔
1684
        if (!isspace(node->c[pos++])) {
1,858,118✔
1685
          while (isspace(*s) && *s != '\0') s++;
1,863,066✔
1686
          if (*s != '\0') s++;  // forward together
1,863,066✔
1687
        }
1688
      }
1689
      continue;
126,077,691✔
1690
    }
1691
    switch (node->key->id) {
531,193,947✔
1692
      case TSFKW_A_M:
27,714✔
1693
      case TSFKW_P_M:
1694
      case TSFKW_a_m:
1695
      case TSFKW_p_m: {
1696
        int32_t idx = strArrayCaseSearch(long_apms, s);
27,714✔
1697
        if (idx >= 0) {
27,714✔
1698
          s += 4;
27,714✔
1699
          pm = idx % 2;
27,714✔
1700
          hour12 = 1;
27,714✔
1701
        } else {
1702
          err = -1;
×
1703
        }
1704
      } break;
27,714✔
1705
      case TSFKW_AM:
3,247✔
1706
      case TSFKW_PM:
1707
      case TSFKW_am:
1708
      case TSFKW_pm: {
1709
        int32_t idx = strArrayCaseSearch(apms, s);
3,247✔
1710
        if (idx >= 0) {
3,247✔
1711
          s += 2;
2,706✔
1712
          pm = idx % 2;
2,706✔
1713
          hour12 = 1;
2,706✔
1714
        } else {
1715
          err = -1;
541✔
1716
        }
1717
      } break;
3,247✔
1718
      case TSFKW_HH:
11,833✔
1719
      case TSFKW_HH12: {
1720
        const char* newPos = tsFormatStr2Int32(&hour, s, 2, needMoreDigits(formats, i));
11,833✔
1721
        if (NULL == newPos || hour > 12 || hour <= 0) {
11,833✔
1722
          err = -1;
×
1723
        } else {
1724
          hour12 = 1;
11,833✔
1725
          s = newPos;
11,833✔
1726
        }
1727
      } break;
11,833✔
1728
      case TSFKW_HH24: {
81,045,699✔
1729
        const char* newPos = tsFormatStr2Int32(&hour, s, 2, needMoreDigits(formats, i));
81,045,699✔
1730
        if (NULL == newPos) {
80,981,349✔
1731
          err = -1;
×
1732
        } else {
1733
          hour12 = 0;
80,981,349✔
1734
          s = newPos;
80,981,349✔
1735
        }
1736
      } break;
80,981,349✔
1737
      case TSFKW_MI: {
81,061,132✔
1738
        const char* newPos = tsFormatStr2Int32(&min, s, 2, needMoreDigits(formats, i));
81,061,132✔
1739
        if (NULL == newPos) {
81,068,332✔
1740
          err = -1;
×
1741
        } else {
1742
          s = newPos;
81,068,332✔
1743
        }
1744
      } break;
81,068,332✔
1745
      case TSFKW_SS: {
81,060,682✔
1746
        const char* newPos = tsFormatStr2Int32(&sec, s, 2, needMoreDigits(formats, i));
81,060,682✔
1747
        if (NULL == newPos)
81,068,782✔
1748
          err = -1;
×
1749
        else
1750
          s = newPos;
81,068,782✔
1751
      } break;
81,068,782✔
1752
      case TSFKW_MS: {
43,826✔
1753
        const char* newPos = tsFormatStr2Int32(&ms, s, 3, needMoreDigits(formats, i));
43,826✔
1754
        if (NULL == newPos)
43,826✔
1755
          err = -1;
×
1756
        else {
1757
          int32_t len = newPos - s;
43,826✔
1758
          ms *= len == 1 ? 100 : len == 2 ? 10 : 1;
43,826✔
1759
          s = newPos;
43,826✔
1760
        }
1761
      } break;
43,826✔
1762
      case TSFKW_US: {
4,790✔
1763
        const char* newPos = tsFormatStr2Int32(&us, s, 6, needMoreDigits(formats, i));
4,790✔
1764
        if (NULL == newPos)
4,790✔
1765
          err = -1;
×
1766
        else {
1767
          int32_t len = newPos - s;
4,790✔
1768
          us *= len == 1 ? 100000 : len == 2 ? 10000 : len == 3 ? 1000 : len == 4 ? 100 : len == 5 ? 10 : 1;
4,790✔
1769
          s = newPos;
4,790✔
1770
        }
1771
      } break;
4,790✔
1772
      case TSFKW_NS: {
6,592✔
1773
        const char* newPos = tsFormatStr2Int32(&ns, s, 9, needMoreDigits(formats, i));
6,592✔
1774
        if (NULL == newPos)
6,592✔
1775
          err = -1;
×
1776
        else {
1777
          int32_t len = newPos - s;
6,592✔
1778
          ns *= len == 1   ? 100000000
6,592✔
1779
                : len == 2 ? 10000000
13,184✔
1780
                : len == 3 ? 1000000
13,184✔
1781
                : len == 4 ? 100000
13,184✔
1782
                : len == 5 ? 10000
13,184✔
1783
                : len == 6 ? 1000
13,184✔
1784
                : len == 7 ? 100
13,184✔
1785
                : len == 8 ? 10
13,184✔
1786
                           : 1;
6,592✔
1787
          s = newPos;
6,592✔
1788
        }
1789
      } break;
6,592✔
1790
      case TSFKW_TZH: {
26,812✔
1791
        const char* newPos = tsFormatStr2Int32(&tzHour, s, -1, needMoreDigits(formats, i));
26,812✔
1792
        if (NULL == newPos)
26,812✔
1793
          err = -1;
×
1794
        else {
1795
          s = newPos;
26,812✔
1796
        }
1797
      } break;
26,812✔
1798
      case TSFKW_MONTH:
5,070✔
1799
      case TSFKW_Month:
1800
      case TSFKW_month: {
1801
        int32_t idx = strArrayCaseSearch(fullMonths, s);
5,070✔
1802
        if (idx >= 0) {
5,070✔
1803
          s += strlen(fullMonths[idx]);
5,070✔
1804
          mon = idx;
5,070✔
1805
        } else {
1806
          err = -1;
×
1807
        }
1808
      } break;
5,070✔
1809
      case TSFKW_MON:
45,025,598✔
1810
      case TSFKW_Mon:
1811
      case TSFKW_mon: {
1812
        int32_t idx = strArrayCaseSearch(months, s);
45,025,598✔
1813
        if (idx >= 0) {
45,015,698✔
1814
          s += strlen(months[idx]);
45,015,698✔
1815
          mon = idx;
45,051,248✔
1816
        } else {
1817
          err = -1;
×
1818
        }
1819
      } break;
45,051,248✔
1820
      case TSFKW_MM: {
36,218,268✔
1821
        const char* newPos = tsFormatStr2Int32(&mon, s, 2, needMoreDigits(formats, i));
36,218,268✔
1822
        if (NULL == newPos) {
36,220,968✔
1823
          err = -1;
×
1824
        } else {
1825
          s = newPos;
36,220,968✔
1826
          mon -= 1;
36,220,968✔
1827
        }
1828
      } break;
36,220,968✔
1829
      case TSFKW_DAY:
4,168✔
1830
      case TSFKW_Day:
1831
      case TSFKW_day: {
1832
        int32_t idx = strArrayCaseSearch(weekDays, s);
4,168✔
1833
        if (idx >= 0) {
4,168✔
1834
          s += strlen(weekDays[idx]);
4,168✔
1835
          wd = idx;
4,168✔
1836
        } else {
1837
          err = -1;
×
1838
        }
1839
      } break;
4,168✔
1840
      case TSFKW_DY:
45,042,416✔
1841
      case TSFKW_Dy:
1842
      case TSFKW_dy: {
1843
        int32_t idx = strArrayCaseSearch(shortWeekDays, s);
45,042,416✔
1844
        if (idx >= 0) {
44,995,616✔
1845
          s += strlen(shortWeekDays[idx]);
44,995,616✔
1846
          wd = idx;
45,047,816✔
1847
        } else {
1848
          err = -1;
×
1849
        }
1850
      } break;
45,047,816✔
1851
      case TSFKW_DDD: {
45,848✔
1852
        const char* newPos = tsFormatStr2Int32(&yd, s, 3, needMoreDigits(formats, i));
45,848✔
1853
        if (NULL == newPos) {
45,848✔
1854
          err = -1;
×
1855
        } else {
1856
          s = newPos;
45,848✔
1857
        }
1858
        withYD = true;
45,848✔
1859
      } break;
45,848✔
1860
      case TSFKW_DD: {
81,257,582✔
1861
        const char* newPos = tsFormatStr2Int32(&md, s, 2, needMoreDigits(formats, i));
81,257,582✔
1862
        if (NULL == newPos) {
81,273,782✔
1863
          err = -1;
×
1864
        } else {
1865
          s = newPos;
81,273,782✔
1866
        }
1867
        withMD = true;
81,273,782✔
1868
      } break;
81,273,782✔
1869
      case TSFKW_D: {
41,680✔
1870
        const char* newPos = tsFormatStr2Int32(&wd, s, 1, needMoreDigits(formats, i));
41,680✔
1871
        if (NULL == newPos) {
41,680✔
1872
          err = -1;
×
1873
        } else {
1874
          s = newPos;
41,680✔
1875
        }
1876
      } break;
41,680✔
1877
      case TSFKW_YYYY: {
36,275,381✔
1878
        const char* newPos = tsFormatStr2Int32(&year, s, 4, needMoreDigits(formats, i));
36,275,381✔
1879
        if (NULL == newPos) {
36,278,981✔
1880
          err = -1;
451✔
1881
        } else {
1882
          s = newPos;
36,278,530✔
1883
        }
1884
      } break;
36,278,981✔
1885
      case TSFKW_YYY: {
8,336✔
1886
        const char* newPos = tsFormatStr2Int32(&year, s, 3, needMoreDigits(formats, i));
8,336✔
1887
        if (NULL == newPos) {
8,336✔
1888
          err = -1;
×
1889
        } else {
1890
          year = adjustYearTo2020(year);
8,336✔
1891
          s = newPos;
8,336✔
1892
        }
1893
      } break;
8,336✔
1894
      case TSFKW_YY: {
44,999,437✔
1895
        const char* newPos = tsFormatStr2Int32(&year, s, 2, needMoreDigits(formats, i));
44,999,437✔
1896
        if (NULL == newPos) {
45,009,787✔
1897
          err = -1;
541✔
1898
        } else {
1899
          year = adjustYearTo2020(year);
45,009,246✔
1900
          s = newPos;
45,015,996✔
1901
        }
1902
      } break;
45,016,537✔
1903
      case TSFKW_Y: {
8,336✔
1904
        const char* newPos = tsFormatStr2Int32(&year, s, 1, needMoreDigits(formats, i));
8,336✔
1905
        if (NULL == newPos) {
8,336✔
1906
          err = -1;
×
1907
        } else {
1908
          year = adjustYearTo2020(year);
8,336✔
1909
          s = newPos;
8,336✔
1910
        }
1911
      } break;
8,336✔
1912
      default:
×
1913
        break;
×
1914
    }
1915
    if (err) {
532,246,047✔
1916
      if (sErrPos) *sErrPos = s;
1,533✔
1917
      if (fErrIdx) *fErrIdx = i;
1,533✔
1918
      return err;
1,533✔
1919
    }
1920
  }
1921
  if (!withMD) {
82,980,602✔
1922
    // yyyy-mm-DDD, currently, the c api can't convert to correct timestamp, return not supported
1923
    if (withYD) return -3;
62,520✔
1924
  }
1925
  struct STm tm = {0};
82,976,434✔
1926
  tm.tm.tm_year = year - 1900;
81,317,734✔
1927
  tm.tm.tm_mon = mon;
81,317,734✔
1928
  tm.tm.tm_yday = yd;
81,317,734✔
1929
  tm.tm.tm_mday = md;
81,317,734✔
1930
  tm.tm.tm_wday = wd;
81,317,734✔
1931
  if (hour12) {
81,317,734✔
1932
    if (pm && hour < 12)
33,575✔
1933
      tm.tm.tm_hour = hour + 12;
2,706✔
1934
    else if (!pm && hour == 12)
30,869✔
1935
      tm.tm.tm_hour = 0;
3,606✔
1936
    else
1937
      tm.tm.tm_hour = hour;
27,263✔
1938
  } else {
1939
    tm.tm.tm_hour = hour;
81,284,159✔
1940
  }
1941
  tm.tm.tm_min = min;
81,317,734✔
1942
  tm.tm.tm_sec = sec;
81,317,734✔
1943
  if (!checkTm(&tm.tm)) return -2;
81,317,734✔
1944
  if (tzHour < -13 || tzHour > 13) return -2;
81,306,932✔
1945
  tm.fsec = ms * 1000000 + us * 1000 + ns;
81,327,632✔
1946
  int32_t ret = taosTm2Ts(&tm, ts, precision, tz);
81,327,632✔
1947
  if (tzHour != 0) {
81,312,332✔
1948
#ifdef WINDOWS
1949
    int32_t gmtoff = -_timezone;
1950
#elif defined(TD_ASTRA)
1951
    int32_t gmtoff = -timezone;
1952
#else
1953
    int32_t gmtoff = tm.tm.tm_gmtoff;
22,644✔
1954
#endif
1955
    *ts += (gmtoff - tzHour * 3600) * TICK_PER_SECOND[precision];
22,644✔
1956
  }
1957
  return ret;
81,316,832✔
1958
}
1959

1960
int32_t taosTs2Char(const char* format, SArray** formats, int64_t ts, int32_t precision, char* out, int32_t outLen, timezone_t tz) {
181,509,119✔
1961
  if (!*formats) {
181,509,119✔
1962
    *formats = taosArrayInit(8, sizeof(TSFormatNode));
3,239,346✔
1963
    if (!*formats) {
3,239,346✔
1964
      TAOS_RETURN(terrno);
×
1965
    }
1966
    TAOS_CHECK_RETURN(parseTsFormat(format, *formats));
3,239,346✔
1967
  }
1968
  struct STm tm;
181,604,519✔
1969
  TAOS_CHECK_RETURN(taosTs2Tm(ts, precision, &tm, tz));
181,608,119✔
1970
  return tm2char(*formats, &tm, out, outLen);
181,518,569✔
1971
}
1972

1973
int32_t taosChar2Ts(const char* format, SArray** formats, const char* tsStr, int64_t* ts, int32_t precision,
81,313,085✔
1974
                    char* errMsg, int32_t errMsgLen, timezone_t tz) {
1975
  const char* sErrPos;
81,313,085✔
1976
  int32_t     fErrIdx;
81,323,435✔
1977
  if (!*formats) {
81,327,935✔
1978
    *formats = taosArrayInit(4, sizeof(TSFormatNode));
13,791,301✔
1979
    if (!*formats) {
13,791,301✔
1980
      TAOS_RETURN(terrno);
×
1981
    }
1982
    TAOS_CHECK_RETURN(parseTsFormat(format, *formats));
13,791,301✔
1983
  }
1984
  int32_t code = char2ts(tsStr, *formats, ts, precision, &sErrPos, &fErrIdx, tz);
81,334,685✔
1985
  if (code == -1) {
81,324,335✔
1986
    TSFormatNode* fNode = (taosArrayGet(*formats, fErrIdx));
1,533✔
1987
    snprintf(errMsg, errMsgLen, "mismatch format for: %s and %s", sErrPos,
3,066✔
1988
             fErrIdx < taosArrayGetSize(*formats) ? ((TSFormatNode*)taosArrayGet(*formats, fErrIdx))->key->name : "");
3,066✔
1989
    code = TSDB_CODE_FUNC_TO_TIMESTAMP_FAILED_FORMAT_ERR;
1,533✔
1990
  } else if (code == -2) {
81,322,802✔
1991
    snprintf(errMsg, errMsgLen, "timestamp format error: %s -> %s", tsStr, format);
902✔
1992
    code = TSDB_CODE_FUNC_TO_TIMESTAMP_FAILED_TS_ERR;
902✔
1993
  } else if (code == -3) {
81,321,900✔
1994
    snprintf(errMsg, errMsgLen, "timestamp format not supported");
4,168✔
1995
    code = TSDB_CODE_FUNC_TO_TIMESTAMP_FAILED_NOT_SUPPORTED;
4,168✔
1996
  }
1997
  TAOS_RETURN(code);
81,324,335✔
1998
}
1999

2000
int32_t TEST_ts2char(const char* format, int64_t ts, int32_t precision, char* out, int32_t outLen) {
×
2001
  int32_t code = TSDB_CODE_SUCCESS;
×
2002

2003
  SArray* formats = taosArrayInit(4, sizeof(TSFormatNode));
×
2004
  if (!formats) {
×
2005
    TAOS_RETURN(terrno);
×
2006
  }
2007
  TAOS_CHECK_RETURN(parseTsFormat(format, formats));
×
2008
  struct STm tm;
×
2009
  TAOS_CHECK_GOTO(taosTs2Tm(ts, precision, &tm, NULL), NULL, _exit);
×
2010
  TAOS_CHECK_GOTO(tm2char(formats, &tm, out, outLen), NULL, _exit);
×
2011

2012
_exit:
×
2013
  taosArrayDestroy(formats);
×
2014
  TAOS_RETURN(TSDB_CODE_SUCCESS);
×
2015
}
2016

2017
int32_t TEST_char2ts(const char* format, int64_t* ts, int32_t precision, const char* tsStr) {
×
2018
  const char* sErrPos;
×
2019
  int32_t     fErrIdx;
×
2020
  SArray*     formats = taosArrayInit(4, sizeof(TSFormatNode));
×
2021
  TAOS_CHECK_RETURN(parseTsFormat(format, formats));
×
2022
  int32_t code = char2ts(tsStr, formats, ts, precision, &sErrPos, &fErrIdx, NULL);
×
2023
  if (code == -1) {
×
2024
    (void)printf("failed position: %s\n", sErrPos);
×
2025
    (void)printf("failed format: %s\n", ((TSFormatNode*)taosArrayGet(formats, fErrIdx))->key->name);
×
2026
  }
2027
  taosArrayDestroy(formats);
×
2028
  return code;
×
2029
}
2030

2031
static int8_t UNIT_INDEX[26] = {/*a*/ 2,  0,  -1, 6,  -1, -1, -1,
2032
                                /*h*/ 5,  -1, -1, -1, -1, 4,  8,
2033
                                /*o*/ -1, -1, -1, -1, 3,  -1,
2034
                                /*u*/ 1,  -1, 7,  -1, 9,  -1};
2035

2036
#define GET_UNIT_INDEX(idx) UNIT_INDEX[(idx)-97]
2037

2038
// clang-format off
2039
static int64_t UNIT_MATRIX[10][11] = {     /*  ns,   us,   ms,    s,   min,   h,   d,   w, month, y*/
2040
                                /*ns*/ {   1, 1000,    0},
2041
                                /*us*/ {1000,    1, 1000,    0},
2042
                                /*ms*/ {   0, 1000,    1, 1000,    0},
2043
                                 /*s*/ {   0,    0, 1000,    1,   60,    0},
2044
                               /*min*/ {   0,    0,    0,   60,    1,   60,   0},
2045
                                 /*h*/ {   0,    0,    0,    0,   60,    1,   1,   0},
2046
                                 /*d*/ {   0,    0,    0,    0,    0,   24,   1,   7,   1,   0},
2047
                                 /*w*/ {   0,    0,    0,    0,    0,    0,   7,   1,  -1,   0},
2048
                               /*mon*/ {   0,    0,    0,    0,    0,    0,   0,   0,   1,  12,  0},
2049
                                 /*y*/ {   0,    0,    0,    0,    0,    0,   0,   0,   12,   1,  0}};
2050
// clang-format on
2051

2052
static bool recursiveTsmaCheckRecursive(int64_t baseInterval, int8_t baseIdx, int64_t interval, int8_t idx,
×
2053
                                        bool checkEq) {
2054
  if (UNIT_MATRIX[baseIdx][idx] == -1) return false;
×
2055
  if (baseIdx == idx) {
×
2056
    if (interval < baseInterval) return false;
×
2057
    if (checkEq && interval == baseInterval) return false;
×
2058
    return interval % baseInterval == 0;
×
2059
  }
2060
  int8_t  next = baseIdx + 1;
×
2061
  int64_t val = UNIT_MATRIX[baseIdx][next];
×
2062
  while (val != 0 && next <= idx) {
×
2063
    if (val == -1) {
×
2064
      next++;
×
2065
      val = UNIT_MATRIX[baseIdx][next];
×
2066
      continue;
×
2067
    }
2068
    if (val % baseInterval == 0 || baseInterval % val == 0) {
×
2069
      int8_t extra = baseInterval >= val ? 0 : 1;
×
2070
      bool   needCheckEq = baseInterval >= val && !(baseIdx < next && val == 1);
×
2071
      if (!recursiveTsmaCheckRecursive(baseInterval / val + extra, next, interval, idx, needCheckEq && checkEq)) {
×
2072
        next++;
×
2073
        val = UNIT_MATRIX[baseIdx][next];
×
2074
        continue;
×
2075
      } else {
2076
        return true;
×
2077
      }
2078
    } else {
2079
      return false;
×
2080
    }
2081
  }
2082
  return false;
×
2083
}
2084

2085
static bool recursiveTsmaCheckRecursiveReverse(int64_t baseInterval, int8_t baseIdx, int64_t interval, int8_t idx,
×
2086
                                               bool checkEq) {
2087
  if (UNIT_MATRIX[baseIdx][idx] == -1) return false;
×
2088

2089
  if (baseIdx == idx) {
×
2090
    if (interval < baseInterval) return false;
×
2091
    if (checkEq && interval == baseInterval) return false;
×
2092
    return interval % baseInterval == 0;
×
2093
  }
2094

2095
  int8_t  next = baseIdx - 1;
×
2096
  int64_t val = UNIT_MATRIX[baseIdx][next];
×
2097
  while (val != 0 && next >= 0) {
×
2098
    return recursiveTsmaCheckRecursiveReverse(baseInterval * val, next, interval, idx, checkEq);
×
2099
  }
2100
  return false;
×
2101
}
2102

2103
/*
2104
 * @breif check if tsma with param [interval], [unit] can create based on base tsma with baseInterval and baseUnit
2105
 * @param baseInterval, baseUnit, interval/unit of base tsma
2106
 * @param interval the tsma interval going to create. Not that if unit is not calander unit, then interval has already
2107
 * been translated to TICKS of [precision]
2108
 * @param unit the tsma unit going to create
2109
 * @param precision the precision of this db
2110
 * @param checkEq pass true if same interval is not acceptable, false if acceptable.
2111
 * @ret true the tsma can be created, else cannot
2112
 * */
2113
bool checkRecursiveTsmaInterval(int64_t baseInterval, int8_t baseUnit, int64_t interval, int8_t unit, int8_t precision,
×
2114
                                bool checkEq) {
2115
  bool baseIsCalendarDuration = IS_CALENDAR_TIME_DURATION(baseUnit);
×
2116
  if (!baseIsCalendarDuration) {
×
2117
    if (TSDB_CODE_SUCCESS != convertTimeFromPrecisionToUnit(baseInterval, precision, baseUnit, &baseInterval)) {
×
2118
      return false;
×
2119
    }
2120
  }
2121
  bool isCalendarDuration = IS_CALENDAR_TIME_DURATION(unit);
×
2122
  if (!isCalendarDuration) {
×
2123
    if (TSDB_CODE_SUCCESS != convertTimeFromPrecisionToUnit(interval, precision, unit, &interval)) {
×
2124
      return false;
×
2125
    }
2126
  }
2127

2128
  bool needCheckEq = baseIsCalendarDuration == isCalendarDuration && checkEq;
×
2129

2130
  int8_t baseIdx = GET_UNIT_INDEX(baseUnit), idx = GET_UNIT_INDEX(unit);
×
2131
  if (baseIdx <= idx) {
×
2132
    return recursiveTsmaCheckRecursive(baseInterval, baseIdx, interval, idx, needCheckEq);
×
2133
  } else {
2134
    return recursiveTsmaCheckRecursiveReverse(baseInterval, baseIdx, interval, idx, checkEq);
×
2135
  }
2136
  return true;
2137
}
2138

2139
int64_t taosGetTimestampToday(int32_t precision, timezone_t tz) {
10,352,021✔
2140
  int64_t   factor =  (precision == TSDB_TIME_PRECISION_SECONDS) ? 1
10,352,021✔
2141
                    : (precision == TSDB_TIME_PRECISION_MILLI)   ? 1000
10,352,021✔
2142
                    : (precision == TSDB_TIME_PRECISION_MICRO)   ? 1000000
2143
                    : 1000000000;
2144
  time_t    t;
10,336,904✔
2145
  int32_t code = taosTime(&t);
10,352,021✔
2146
  if (code != 0) {
10,352,021✔
2147
    return -1;
×
2148
  }
2149
  struct tm tm;
10,336,904✔
2150
  if (taosLocalTime(&t, &tm, NULL, 0,  tz) == NULL){
10,352,021✔
2151
    uError("%s failed to get local time, code:%d", __FUNCTION__, ERRNO);
×
2152
    return t;
×
2153
  }
2154
  tm.tm_hour = 0;
10,352,021✔
2155
  tm.tm_min = 0;
10,352,021✔
2156
  tm.tm_sec = 0;
10,352,021✔
2157

2158
  time_t tmp = taosMktime(&tm, tz);
10,352,021✔
2159
  if (tmp == (time_t)-1) {
10,352,021✔
2160
    uError("%s failed to get timestamp of today, code:%d", __FUNCTION__, ERRNO);
×
2161
    return t;
×
2162
  }
2163
  return (int64_t)tmp * factor;
10,352,021✔
2164
}
2165

2166
int32_t taosParseShortWeekday(const char* str) {
288✔
2167
  for (int32_t i = 0; i < 7; i++) {
576✔
2168
    if (strcasecmp(shortWeekDays[i], str) == 0) {
576✔
2169
      return i;
288✔
2170
    }
2171
  }
2172
  return -1;
×
2173
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc