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

taosdata / TDengine / #4917

07 Jan 2026 03:52PM UTC coverage: 65.42% (+0.02%) from 65.402%
#4917

push

travis-ci

web-flow
merge: from main to 3.0 branch #34204

31 of 34 new or added lines in 2 files covered. (91.18%)

819 existing lines in 129 files now uncovered.

202679 of 309814 relevant lines covered (65.42%)

116724351.99 hits per line

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

79.1
/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) {
1,018,987,822✔
36
  /* parse datatime string in with tz */
37
  if (strnchr(timestr, 'T', len, false) != NULL) {
1,018,987,822✔
38
    if (checkTzPresent(timestr, len)) {
39,396,347✔
39
      return parseTimeWithTz(timestr, utime, timePrec, 'T');
12,738,650✔
40
    } else {
41
      return parseLocaltimeDst((char*)timestr, len, utime, timePrec, 'T', tz);
26,657,208✔
42
    }
43
  } else {
44
    if (checkTzPresent(timestr, len)) {
979,577,469✔
45
      return parseTimeWithTz(timestr, utime, timePrec, 0);
2,544✔
46
    } else {
47
      return parseLocaltimeDst((char*)timestr, len, utime, timePrec, 0, tz);
979,585,188✔
48
    }
49
  }
50
}
51

52
bool checkTzPresent(const char* str, int32_t len) {
1,018,975,716✔
53
  char*   seg = forwardToTimeStringEnd((char*)str);
1,018,975,716✔
54
  int32_t seg_len = len - (int32_t)(seg - str);
1,018,980,700✔
55

56
  char* c = &seg[seg_len - 1];
1,018,980,700✔
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;
12,741,194✔
63
    }
64
    c--;
2,147,483,647✔
65
  }
66

67
  return false;
1,006,239,028✔
68
}
69

70
char* forwardToTimeStringEnd(char* str) {
1,029,250,501✔
71
  int32_t i = 0;
1,029,250,501✔
72
  int32_t numOfSep = 0;
1,029,250,501✔
73

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

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

84
  return &str[i];
1,029,249,254✔
85
}
86

87
int32_t parseFraction(char* str, char** end, int32_t timePrec, int64_t* pFraction) {
833,203,609✔
88
  int32_t i = 0;
833,203,609✔
89
  int64_t fraction = 0;
833,203,609✔
90

91
  const int32_t MILLI_SEC_FRACTION_LEN = 3;
833,203,609✔
92
  const int32_t MICRO_SEC_FRACTION_LEN = 6;
833,203,609✔
93
  const int32_t NANO_SEC_FRACTION_LEN = 9;
833,203,609✔
94

95
  int32_t factor[9] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000};
833,203,609✔
96
  int32_t times = 1;
833,203,609✔
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;
833,203,609✔
103
  if (totalLen <= 0) {
833,203,609✔
104
    TAOS_RETURN(TSDB_CODE_INVALID_PARA);
×
105
  }
106

107
  /* parse the fraction */
108
  if (timePrec == TSDB_TIME_PRECISION_MILLI) {
833,203,609✔
109
    /* only use the initial 3 bits */
110
    if (i >= MILLI_SEC_FRACTION_LEN) {
833,138,441✔
111
      i = MILLI_SEC_FRACTION_LEN;
790,692,880✔
112
    }
113

114
    times = MILLI_SEC_FRACTION_LEN - i;
833,138,441✔
115
  } else if (timePrec == TSDB_TIME_PRECISION_MICRO) {
65,168✔
116
    if (i >= MICRO_SEC_FRACTION_LEN) {
43,230✔
117
      i = MICRO_SEC_FRACTION_LEN;
27,384✔
118
    }
119
    times = MICRO_SEC_FRACTION_LEN - i;
43,230✔
120
  } else if (timePrec == TSDB_TIME_PRECISION_NANO) {
21,938✔
121
    if (i >= NANO_SEC_FRACTION_LEN) {
21,938✔
122
      i = NANO_SEC_FRACTION_LEN;
10,020✔
123
    }
124
    times = NANO_SEC_FRACTION_LEN - i;
21,938✔
125
  } else {
126
    TAOS_RETURN(TSDB_CODE_INVALID_PARA);
×
127
  }
128

129
  fraction = strnatoi(str, i) * factor[times];
833,203,609✔
130
  *end = str + totalLen;
833,203,609✔
131
  *pFraction = fraction;
833,203,609✔
132

133
  TAOS_RETURN(TSDB_CODE_SUCCESS);
833,203,609✔
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) {
40,020,237✔
143
  int64_t hour = 0;
40,020,237✔
144
  int64_t minute = 0;
40,020,237✔
145

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

151
  i++;
40,019,756✔
152

153
  int32_t j = i;
40,019,756✔
154
  while (str[j]) {
200,116,797✔
155
    if ((str[j] >= '0' && str[j] <= '9') || str[j] == ':') {
160,100,539✔
156
      ++j;
160,097,041✔
157
      continue;
160,097,041✔
158
    }
159

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

163
  char* sep = strchr(&str[i], ':');
40,011,536✔
164
  if (sep != NULL) {
40,012,378✔
165
    int32_t hourSize = (int32_t)(sep - &str[i]);
62,111✔
166
    PARSE(&str[i], hourSize, hour);
62,111✔
167

168
    i += hourSize + 1;
62,111✔
169
    size_t minSize = strlen(&str[i]);
62,111✔
170
    PARSE(&str[i], minSize, minute);
62,111✔
171
  } else {
172
    size_t hourSize = strlen(&str[i]);
39,950,267✔
173
    if (hourSize > 2){
39,954,171✔
174
      hourSize = 2;
39,950,694✔
175
    }
176
    PARSE(&str[i], hourSize, hour)
39,954,171✔
177
    i += hourSize;
39,954,035✔
178
    size_t minSize = strlen(&str[i]);
39,954,035✔
179
    if (minSize > 0){
39,953,546✔
180
      PARSE(&str[i], minSize, minute);
39,950,694✔
181
    }
182
  }
183

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

191
  if (str[0] == '+') {
40,016,648✔
192
    *tzOffset = -(hour * 3600 + minute * 60);
40,011,618✔
193
  } else {
194
    *tzOffset = hour * 3600 + minute * 60;
5,030✔
195
  }
196

197
  TAOS_RETURN(TSDB_CODE_SUCCESS);
40,016,648✔
198
}
199

200
int32_t offsetOfTimezone(char* tzStr, int64_t* offset) {
29,836,299✔
201
  if (tzStr && (tzStr[0] == 'z' || tzStr[0] == 'Z')) {
29,836,299✔
202
    *offset = 0;
1,956✔
203
    return TSDB_CODE_SUCCESS;
1,956✔
204
  }
205
  return parseTimezone(tzStr, offset);
29,834,343✔
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) {
12,741,194✔
221
  int64_t factor = TSDB_TICK_PER_SECOND(timePrec);
12,741,194✔
222
  int64_t tzOffset = 0;
12,741,194✔
223

224
  struct tm tm = {0};
12,741,194✔
225

226
  char* str;
12,741,066✔
227
  if (delim == 'T') {
12,741,194✔
228
    str = taosStrpTime(timestr, "%Y-%m-%dT%H:%M:%S", &tm);
12,738,650✔
229
  } else if (delim == 0) {
2,544✔
230
    str = taosStrpTime(timestr, "%Y-%m-%d %H:%M:%S", &tm);
2,544✔
231
  } else {
232
    str = NULL;
×
233
  }
234

235
  if (str == NULL) {
12,741,194✔
236
    TAOS_RETURN(TSDB_CODE_INVALID_PARA);
2,470,250✔
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);
10,270,944✔
245
  if (seconds == -1){
10,270,944✔
246
    TAOS_RETURN(TAOS_SYSTEM_ERROR(ERRNO));
×
247
  }
248
#endif
249

250
  int64_t fraction = 0;
10,270,944✔
251
  str = forwardToTimeStringEnd((char*)timestr);
10,270,944✔
252

253
  if ((str[0] == 'Z' || str[0] == 'z') && str[1] == '\0') {
10,270,944✔
254
    /* utc time, no millisecond, return directly*/
255
    *time = seconds * factor;
81,682✔
256
  } else if (str[0] == '.') {
10,189,262✔
257
    str += 1;
10,127,299✔
258
    TAOS_CHECK_RETURN(parseFraction(str, &str, timePrec, &fraction));
10,127,299✔
259

260
    *time = seconds * factor + fraction;
10,127,299✔
261

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

271
      *time += tzOffset * factor;
10,121,448✔
272
    }
273

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

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

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

285
  TAOS_RETURN(TSDB_CODE_SUCCESS);
10,268,461✔
286
}
287

288
static FORCE_INLINE bool validateTm(struct tm* pTm) {
289
  if (pTm == NULL) {
909,643,839✔
290
    return false;
×
291
  }
292

293
  int32_t dayOfMonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
909,643,839✔
294

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

299
  if (isLeapYear && (pTm->tm_mon == 1)) {
909,647,663✔
300
    if (pTm->tm_mday > leapYearMonthDay) {
3,448,716✔
301
      return false;
×
302
    }
303
  } else {
304
    if (pTm->tm_mday > dayOfMonth[pTm->tm_mon]) {
906,198,947✔
305
      return false;
×
306
    }
307
  }
308

309
  return true;
909,648,141✔
310
}
311

312
int32_t parseLocaltimeDst(char* timestr, int32_t len, int64_t* utime, int32_t timePrec, char delim, timezone_t tz) {
1,006,226,667✔
313
  *utime = 0;
1,006,226,667✔
314
  struct tm tm = {0};
1,006,247,139✔
315
  tm.tm_isdst = -1;
1,006,247,492✔
316

317
  char* str;
1,005,885,442✔
318
  if (delim == 'T') {
1,006,249,426✔
319
    str = taosStrpTime(timestr, "%Y-%m-%dT%H:%M:%S", &tm);
26,658,675✔
320
  } else if (delim == 0) {
979,590,751✔
321
    str = taosStrpTime(timestr, "%Y-%m-%d %H:%M:%S", &tm);
979,590,751✔
322
  } else {
323
    str = NULL;
×
324
  }
325

326
  if (str == NULL || (((str - timestr) < len) && (*str != '.')) || !validateTm(&tm)) {
1,915,777,924✔
327
    // if parse failed, try "%Y-%m-%d" format
328
    str = taosStrpTime(timestr, "%Y-%m-%d", &tm);
96,720,428✔
329
    if (str == NULL || (((str - timestr) < len) && (*str != '.')) || !validateTm(&tm)) {
96,837,453✔
330
      TAOS_RETURN(TSDB_CODE_INVALID_PARA);
96,602,969✔
331
    }
332
  }
333

334
  int64_t seconds = taosMktime(&tm, tz);
909,648,141✔
335

336
  int64_t fraction = 0;
909,645,273✔
337
  if (*str == '.') {
909,645,273✔
338
    /* parse the second fraction part */
339
    TAOS_CHECK_RETURN(parseFraction(str + 1, &str, timePrec, &fraction));
823,076,310✔
340
  }
341

342
  *utime = TSDB_TICK_PER_SECOND(timePrec) * seconds + fraction;
909,644,795✔
343
  TAOS_RETURN(TSDB_CODE_SUCCESS);
909,645,273✔
344
}
345

346
char getPrecisionUnit(int32_t precision) {
1,385,114✔
347
  static char units[3] = {TIME_UNIT_MILLISECOND, TIME_UNIT_MICROSECOND, TIME_UNIT_NANOSECOND};
348
  switch (precision) {
1,385,114✔
349
    case TSDB_TIME_PRECISION_MILLI:
1,385,114✔
350
    case TSDB_TIME_PRECISION_MICRO:
351
    case TSDB_TIME_PRECISION_NANO:
352
      return units[precision];
1,385,114✔
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:
380,090✔
365
          if (utime > INT64_MAX / 1000) {
380,090✔
366
            return INT64_MAX;
×
367
          }
368
          return utime * 1000;
380,090✔
369
        case TSDB_TIME_PRECISION_NANO:
5,831,668✔
370
          if (utime > INT64_MAX / 1000000) {
5,831,668✔
371
            return INT64_MAX;
×
372
          }
373
          return utime * 1000000;
5,831,668✔
374
        default:
262✔
375
          return utime;
262✔
376
      }
377
    }  // end from milli
378
    case TSDB_TIME_PRECISION_MICRO: {
177,229✔
379
      switch (toPrecision) {
177,229✔
380
        case TSDB_TIME_PRECISION_MILLI:
62,664✔
381
          return utime / 1000;
62,664✔
382
        case TSDB_TIME_PRECISION_MICRO:
56,843✔
383
          return utime;
56,843✔
384
        case TSDB_TIME_PRECISION_NANO:
57,722✔
385
          if (utime > INT64_MAX / 1000) {
57,722✔
386
            return INT64_MAX;
×
387
          }
388
          return utime * 1000;
57,722✔
389
        default:
×
390
          return utime;
×
391
      }
392
    }  // end from micro
393
    case TSDB_TIME_PRECISION_NANO: {
5,927,659✔
394
      switch (toPrecision) {
5,927,659✔
395
        case TSDB_TIME_PRECISION_MILLI:
5,071,643✔
396
          return utime / 1000000;
5,071,643✔
397
        case TSDB_TIME_PRECISION_MICRO:
25,574✔
398
          return utime / 1000;
25,574✔
399
        case TSDB_TIME_PRECISION_NANO:
830,356✔
400
          return utime;
830,356✔
401
        default:
86✔
402
          return utime;
86✔
403
      }
404
    }  // end from nano
UNCOV
405
    default: {
×
UNCOV
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) {
2,400,018✔
423
  if (fromPrecision != TSDB_TIME_PRECISION_MILLI && fromPrecision != TSDB_TIME_PRECISION_MICRO &&
2,400,018✔
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};
2,400,018✔
429
  double  tmp = time;
2,400,018✔
430
  switch (toUnit) {
2,400,018✔
431
    case 's': {
531,388✔
432
      time /= (NANOSECOND_PER_SEC / factors[fromPrecision]);
531,388✔
433
      tmp = (double)time;
531,388✔
434
      break;
531,388✔
435
    }
436
    case 'm':
1,206,942✔
437
      time /= (NANOSECOND_PER_MINUTE / factors[fromPrecision]);
1,206,942✔
438
      tmp = (double)time;
1,206,942✔
439
      break;
1,206,942✔
440
    case 'h':
6,130✔
441
      time /= (NANOSECOND_PER_HOUR / factors[fromPrecision]);
6,130✔
442
      tmp = (double)time;
6,130✔
443
      break;
6,130✔
444
    case 'd':
211,978✔
445
      time /= (NANOSECOND_PER_DAY / factors[fromPrecision]);
211,978✔
446
      tmp = (double)time;
211,978✔
447
      break;
211,978✔
448
    case 'w':
×
449
      time /= (NANOSECOND_PER_WEEK / factors[fromPrecision]);
×
450
      tmp = (double)time;
×
451
      break;
×
452
    case 'a':
435,060✔
453
      time /= (NANOSECOND_PER_MSEC / factors[fromPrecision]);
435,060✔
454
      tmp = (double)time;
435,060✔
455
      break;
435,060✔
456
    case 'u':
6,390✔
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,260✔
465
          time /= 1;
4,260✔
466
          tmp = (double)time;
4,260✔
467
          break;
4,260✔
468
        }
469
        case TSDB_TIME_PRECISION_NANO: {
2,130✔
470
          time /= 1000;
2,130✔
471
          tmp = (double)time;
2,130✔
472
          break;
2,130✔
473
        }
474
      }
475
      break;
6,390✔
476
    case 'b':
2,130✔
477
      tmp *= factors[fromPrecision];
2,130✔
478
      time *= factors[fromPrecision];
2,130✔
479
      break;
2,130✔
480
    default: {
×
481
      TAOS_RETURN(TSDB_CODE_INVALID_PARA);
×
482
    }
483
  }
484
  if (tmp >= (double)INT64_MAX) {
2,400,018✔
485
    *pRes = INT64_MAX;
×
486
  } else if (tmp <= (double)INT64_MIN) {
2,400,018✔
487
    *pRes = INT64_MIN;
×
488
  } else {
489
    *pRes = time;
2,400,018✔
490
  }
491

492
  TAOS_RETURN(TSDB_CODE_SUCCESS);
2,400,018✔
493
}
494

495
int32_t convertStringToTimestamp(int16_t type, char* inputData, int64_t timePrec, int64_t* timeVal, timezone_t tz, void* charsetCxt) {
119,613,360✔
496
  int32_t charLen = varDataLen(inputData);
119,613,360✔
497
  char*   newColData;
498
  if (type == TSDB_DATA_TYPE_BINARY || type == TSDB_DATA_TYPE_VARBINARY) {
149,953,922✔
499
    newColData = taosMemoryCalloc(1, charLen + 1);
48,854,242✔
500
    if (NULL == newColData) {
48,851,496✔
501
      TAOS_RETURN(terrno);
×
502
    }
503
    (void)memcpy(newColData, varDataVal(inputData), charLen);
48,851,496✔
504
    int32_t ret = taosParseTime(newColData, timeVal, charLen, (int32_t)timePrec, tz);
48,851,496✔
505
    if (ret != TSDB_CODE_SUCCESS) {
48,851,146✔
506
      taosMemoryFree(newColData);
18,511,065✔
507
      TAOS_RETURN(TSDB_CODE_INVALID_TIMESTAMP);
18,511,771✔
508
    }
509
    taosMemoryFree(newColData);
30,340,081✔
510
  } else if (type == TSDB_DATA_TYPE_NCHAR) {
70,759,599✔
511
    newColData = taosMemoryCalloc(1, charLen + TSDB_NCHAR_SIZE);
70,759,118✔
512
    if (NULL == newColData) {
70,736,275✔
513
      TAOS_RETURN(terrno);
×
514
    }
515
    int len = taosUcs4ToMbs((TdUcs4*)varDataVal(inputData), charLen, newColData, charsetCxt);
70,736,275✔
516
    if (len < 0) {
70,756,665✔
517
      taosMemoryFree(newColData);
×
518
      TAOS_RETURN(TSDB_CODE_FAILED);
×
519
    }
520
    newColData[len] = 0;
70,756,665✔
521
    int32_t ret = taosParseTime(newColData, timeVal, len, (int32_t)timePrec, tz);
70,756,665✔
522
    if (ret != TSDB_CODE_SUCCESS) {
70,757,665✔
523
      taosMemoryFree(newColData);
70,757,665✔
524
      TAOS_RETURN(ret);
70,753,753✔
525
    }
526
    taosMemoryFree(newColData);
×
527
  } else {
528
    TAOS_RETURN(TSDB_CODE_FAILED);
481✔
529
  }
530
  TAOS_RETURN(TSDB_CODE_SUCCESS);
30,340,081✔
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,832,601✔
542
      if (val > INT64_MAX / MILLISECOND_PER_MINUTE) {
10,832,601✔
543
        TAOS_RETURN(TSDB_CODE_OUT_OF_RANGE);
×
544
      }
545
      (*result) = convertTimePrecision(val * MILLISECOND_PER_MINUTE, TSDB_TIME_PRECISION_MILLI, timePrecision);
10,832,601✔
546
      break;
10,832,601✔
547
    case 'h':
2,212,576✔
548
      if (val > INT64_MAX / MILLISECOND_PER_MINUTE) {
2,212,576✔
549
        TAOS_RETURN(TSDB_CODE_OUT_OF_RANGE);
×
550
      }
551
      (*result) = convertTimePrecision(val * MILLISECOND_PER_HOUR, TSDB_TIME_PRECISION_MILLI, timePrecision);
2,212,576✔
552
      break;
2,213,071✔
553
    case 'd':
39,169,217✔
554
      if (val > INT64_MAX / MILLISECOND_PER_DAY) {
39,169,217✔
555
        TAOS_RETURN(TSDB_CODE_OUT_OF_RANGE);
×
556
      }
557
      (*result) = convertTimePrecision(val * MILLISECOND_PER_DAY, TSDB_TIME_PRECISION_MILLI, timePrecision);
39,169,217✔
558
      break;
39,169,217✔
559
    case 'w':
491,574✔
560
      if (val > INT64_MAX / MILLISECOND_PER_WEEK) {
491,574✔
561
        TAOS_RETURN(TSDB_CODE_OUT_OF_RANGE);
×
562
      }
563
      (*result) = convertTimePrecision(val * MILLISECOND_PER_WEEK, TSDB_TIME_PRECISION_MILLI, timePrecision);
491,574✔
564
      break;
491,574✔
565
    case 'a':
3,968,034✔
566
      (*result) = convertTimePrecision(val, TSDB_TIME_PRECISION_MILLI, timePrecision);
3,968,034✔
567
      break;
3,968,034✔
568
    case 'u':
175,679✔
569
      (*result) = convertTimePrecision(val, TSDB_TIME_PRECISION_MICRO, timePrecision);
175,679✔
570
      break;
175,679✔
571
    case 'b':
505,233✔
572
      (*result) = convertTimePrecision(val, TSDB_TIME_PRECISION_NANO, timePrecision);
505,233✔
573
      break;
505,233✔
574
    default: {
495✔
575
      TAOS_RETURN(TSDB_CODE_OUT_OF_RANGE);
495✔
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,921✔
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,
54,399,500✔
616
                            bool negativeAllow) {
617
  SET_ERRNO(0);
54,399,500✔
618

619
  /* get the basic numeric value */
620
  *duration = taosStr2Int64(token, NULL, 10);
54,398,616✔
621
  if ((*duration < 0 && !negativeAllow) || ERRNO != 0) {
54,399,005✔
622
    TAOS_RETURN(TAOS_SYSTEM_ERROR(ERRNO));
1,462✔
623
  }
624

625
  *unit = token[tokenLen - 1];
54,398,038✔
626
  if (*unit == 'n' || *unit == 'y') {
54,398,038✔
627
    TAOS_RETURN(TSDB_CODE_SUCCESS);
181,451✔
628
  }
629
  if (isdigit(*unit)) {
54,216,587✔
630
    *unit = getPrecisionUnit(timePrecision);
8,358✔
631
  }
632

633
  return getDuration(*duration, *unit, duration, timePrecision);
54,216,092✔
634
}
635

636
static bool taosIsLeapYear(int32_t year) { return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)); }
4,690,915✔
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;
44,375✔
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,690,151✔
659
  if(taosLocalTime(&tt, &tm, NULL, 0, tz) == NULL) {
4,690,151✔
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,690,915✔
664
  tm.tm_year = mon / 12;
4,690,915✔
665
  tm.tm_mon = mon % 12;
4,690,915✔
666
  int daysOfMonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
4,690,915✔
667
  if (taosIsLeapYear(1900 + tm.tm_year)) {
4,690,915✔
668
    daysOfMonth[1] = 29;
3,636,937✔
669
  }
670
  if (tm.tm_mday > daysOfMonth[tm.tm_mon]) {
4,690,915✔
671
    tm.tm_mday = daysOfMonth[tm.tm_mon];
54,004✔
672
  }
673

674
  tt = taosMktime(&tm, tz);
4,690,533✔
675
  if (tt == -1){
4,690,915✔
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,690,915✔
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,
287,976✔
712
                                     int32_t order) {
713
  if (ekey < skey) {
287,976✔
714
    int64_t tmp = ekey;
229,941✔
715
    ekey = skey;
229,941✔
716
    skey = tmp;
229,941✔
717
  }
718
  int32_t ret = 0;
287,976✔
719

720
  if (unit != 'n' && unit != 'y') {
287,976✔
721
    ret = (int32_t)((ekey - skey) / interval);
287,976✔
722
    if (order == TSDB_ORDER_DESC && ret * interval < (ekey - skey)) ret += 1;
287,976✔
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;
287,976✔
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));
431,733✔
764
    struct tm  tm;
431,733✔
765
    time_t     tt = (time_t)start;
431,733✔
766
    if (taosLocalTime(&tt, &tm, NULL, 0, pInterval->timezone) == NULL){
431,733✔
767
      uError("%s failed to convert time to local time, code:%d", __FUNCTION__, ERRNO);
×
768
      return ts;
×
769
    }
770
    tm.tm_sec = 0;
431,733✔
771
    tm.tm_min = 0;
431,733✔
772
    tm.tm_hour = 0;
431,733✔
773
    tm.tm_mday = 1;
431,733✔
774

775
    if (pInterval->slidingUnit == 'y') {
431,733✔
776
      tm.tm_mon = 0;
87,777✔
777
      tm.tm_year = (int32_t)(tm.tm_year / pInterval->sliding * pInterval->sliding);
87,777✔
778
    } else {
779
      int32_t mon = tm.tm_year * 12 + tm.tm_mon;
343,956✔
780
      mon = (int32_t)(mon / pInterval->sliding * pInterval->sliding);
343,956✔
781
      tm.tm_year = mon / 12;
343,956✔
782
      tm.tm_mon = mon % 12;
343,956✔
783
    }
784

785
    tt = taosMktime(&tm, pInterval->timezone);
431,733✔
786
    if (tt == -1){
431,733✔
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));
431,733✔
791
  } else {
792
    if (IS_CALENDAR_TIME_DURATION(pInterval->intervalUnit)) {
2,147,483,647✔
793
      int64_t news = (ts / pInterval->sliding) * pInterval->sliding;
154✔
794
      if (pInterval->slidingUnit == 'd' || pInterval->slidingUnit == 'w') {
329,764✔
795
#if defined(WINDOWS) && _MSC_VER >= 1900
796
        int64_t timezone = _timezone;
797
#endif
798
        news += (int64_t)(timezone * TSDB_TICK_PER_SECOND(precision));
329,764✔
799
      }
800

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

806
        if (newe < ts) {  // move towards the greater endpoint
330,146✔
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,265,060✔
815
            prev = news;
934,914✔
816
            news -= pInterval->sliding;
934,914✔
817
            newe = taosTimeAdd(news, pInterval->interval, pInterval->intervalUnit, precision, pInterval->timezone) - 1;
934,914✔
818
          }
819
        }
820

821
        start = prev;
330,146✔
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,140,830,760✔
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;
391,099,390✔
851

852
          if (start < 0 || INT64_MAX - start > pInterval->interval - 1) {
391,091,821✔
853
            end = start + pInterval->interval - 1;
391,101,953✔
854
          } else {
855
            end = INT64_MAX;
×
856
            break;
×
857
          }
858
        }
859
      } else {
860
        end = INT64_MAX;
995✔
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,458,697✔
868
    int64_t slidingStart = start;
2,458,697✔
869
    while (newe >= ts) {
6,412,799✔
870
      start = slidingStart;
3,954,102✔
871
      slidingStart = taosTimeAdd(slidingStart, -pInterval->sliding, pInterval->slidingUnit, precision, pInterval->timezone);
3,954,102✔
872
      int64_t news = taosTimeAdd(slidingStart, pInterval->offset, pInterval->offsetUnit, precision, pInterval->timezone);
3,954,102✔
873
      newe = taosTimeAdd(news, pInterval->interval, pInterval->intervalUnit, precision, pInterval->timezone) - 1;
3,954,102✔
874
    }
875
    start = taosTimeAdd(start, pInterval->offset, pInterval->offsetUnit, precision, pInterval->timezone);
2,458,697✔
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) {
253,919,468✔
887
  if (!interval || interval->offset != AUTO_DURATION_VALUE) {
253,919,468✔
888
    return;
253,464,874✔
889
  }
890

891
  interval->offset = 0;
550,383✔
892

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

897
  TSKEY skey = interval->timeRange.skey;
550,001✔
898
  TSKEY start = taosTimeTruncate(skey, interval);
550,001✔
899
  TSKEY news = start;
550,383✔
900
  while (news <= skey) {
1,490,676✔
901
    start = news;
940,675✔
902
    news = taosTimeAdd(start, interval->sliding, interval->slidingUnit, interval->precision, interval->timezone);
940,675✔
903
    if (news < start) {
940,293✔
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;
550,001✔
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) {
80✔
966
  char      ts[40] = {0};
80✔
967
  struct tm ptm;
80✔
968

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

974
  switch (precision) {
80✔
975
    case TSDB_TIME_PRECISION_MILLI: {
80✔
976
      quot = t / 1000;
80✔
977
      fractionLen = 5;
80✔
978
      format = ".%03" PRId64;
80✔
979
      mod = t % 1000;
80✔
980
      break;
80✔
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)) {
80✔
1005
    TAOS_RETURN(TAOS_SYSTEM_ERROR(ERRNO));
×
1006
  }
1007
  int32_t length = (int32_t)taosStrfTime(ts, 40, "%Y-%m-%dT%H:%M:%S", &ptm);
80✔
1008
  length += tsnprintf(ts + length, fractionLen, format, mod);
80✔
1009
  length += (int32_t)taosStrfTime(ts + length, 40 - length, "%z", &ptm);
80✔
1010

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

1015
char* formatTimestampLocal(char* buf, int64_t val, int precision) {
91,961,909✔
1016
  time_t tt;
91,956,783✔
1017
  if (precision == TSDB_TIME_PRECISION_MICRO) {
91,963,251✔
1018
    tt = (time_t)(val / 1000000);
35,280✔
1019
  } else if (precision == TSDB_TIME_PRECISION_NANO) {
91,927,971✔
1020
    tt = (time_t)(val / 1000000000);
×
1021
  } else {
1022
    tt = (time_t)(val / 1000);
91,927,971✔
1023
  }
1024

1025
  struct tm tm;
91,958,125✔
1026
  if (taosLocalTime(&tt, &tm, NULL, 0, NULL) == NULL) {
91,961,410✔
1027
    return NULL;
×
1028
  }
1029
  size_t pos = taosStrfTime(buf, 32, "%Y-%m-%d %H:%M:%S", &tm);
91,963,023✔
1030

1031
  if (precision == TSDB_TIME_PRECISION_MICRO) {
91,965,023✔
1032
    sprintf(buf + pos, ".%06d", (int)(val % 1000000));
35,280✔
1033
  } else if (precision == TSDB_TIME_PRECISION_NANO) {
91,929,743✔
1034
    sprintf(buf + pos, ".%09d", (int)(val % 1000000000));
×
1035
  } else {
1036
    sprintf(buf + pos, ".%03d", (int)(val % 1000));
91,929,743✔
1037
  }
1038

1039
  return buf;
91,964,973✔
1040
}
1041

1042
int32_t taosTs2Tm(int64_t ts, int32_t precision, struct STm* tm, timezone_t tz) {
93,517,486✔
1043
  tm->fsec = ts % TICK_PER_SECOND[precision] * (TICK_PER_SECOND[TSDB_TIME_PRECISION_NANO] / TICK_PER_SECOND[precision]);
93,517,486✔
1044
  time_t t = ts / TICK_PER_SECOND[precision];
93,674,838✔
1045
  if (NULL == taosLocalTime(&t, &tm->tm, NULL, 0, tz)) {
93,608,096✔
1046
    TAOS_RETURN(TAOS_SYSTEM_ERROR(ERRNO));
×
1047
  }
1048
  return TSDB_CODE_SUCCESS;
92,876,586✔
1049
}
1050

1051
int32_t taosTm2Ts(struct STm* tm, int64_t* ts, int32_t precision, timezone_t tz) {
79,847,922✔
1052
  *ts = taosMktime(&tm->tm, tz);
79,847,922✔
1053
  *ts *= TICK_PER_SECOND[precision];
79,795,324✔
1054
  *ts += tm->fsec / (TICK_PER_SECOND[TSDB_TIME_PRECISION_NANO] / TICK_PER_SECOND[precision]);
79,830,242✔
1055
  return TSDB_CODE_SUCCESS;
79,873,558✔
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) {
229,532,184✔
1264
  if (*str < 'A' || *str > 'z' || (*str > 'Z' && *str < 'a')) return NULL;
229,532,184✔
1265
  int32_t idx = TSFormatKeywordIndex[str[0] - 'A'];
94,786,209✔
1266
  if (idx < 0) return NULL;
94,791,513✔
1267
  const TSFormatKeyWord* key = &formatKeyWords[idx++];
94,791,513✔
1268
  while (key->name && str[0] == key->name[0]) {
154,042,513✔
1269
    if (0 == strncmp(key->name, str, key->len)) {
154,001,985✔
1270
      return key;
94,754,963✔
1271
    }
1272
    key = &formatKeyWords[idx++];
59,250,116✔
1273
  }
1274
  return NULL;
38,760✔
1275
}
1276

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

1281
static int32_t parseTsFormat(const char* formatStr, SArray* formats) {
15,763,165✔
1282
  TSFormatNode* lastOtherFormat = NULL;
15,763,165✔
1283
  while (*formatStr) {
245,303,305✔
1284
    const TSFormatKeyWord* key = keywordSearch(formatStr);
229,531,742✔
1285
    if (key) {
229,524,670✔
1286
      TSFormatNode format = {.key = key, .type = TS_FORMAT_NODE_TYPE_KEYWORD};
94,754,079✔
1287
      if (NULL == taosArrayPush(formats, &format)) TAOS_RETURN(terrno);
94,754,521✔
1288
      formatStr += key->len;
94,754,521✔
1289
      lastOtherFormat = NULL;
94,754,521✔
1290
    } else {
1291
      if (*formatStr == '"') {
134,770,591✔
1292
        lastOtherFormat = NULL;
1,335✔
1293
        // for double quoted string
1294
        formatStr++;
1,335✔
1295
        TSFormatNode* last = NULL;
1,335✔
1296
        while (*formatStr) {
5,340✔
1297
          if (*formatStr == '"') {
5,340✔
1298
            formatStr++;
1,335✔
1299
            break;
1,335✔
1300
          }
1301
          if (*formatStr == '\\' && *(formatStr + 1)) {
4,005✔
1302
            formatStr++;
×
1303
            last = NULL;  // stop expanding last format, create new format
×
1304
          }
1305
          if (last) {
4,005✔
1306
            // expand
1307
            last->len++;
2,670✔
1308
            formatStr++;
2,670✔
1309
          } else {
1310
            // create new
1311
            TSFormatNode format = {.type = TS_FORMAT_NODE_TYPE_CHAR, .key = NULL};
1,335✔
1312
            format.c = formatStr;
1,335✔
1313
            format.len = 1;
1,335✔
1314
            if (NULL == taosArrayPush(formats, &format)) TAOS_RETURN(terrno);
1,335✔
1315
            formatStr++;
1,335✔
1316
            last = taosArrayGetLast(formats);
1,335✔
1317
          }
1318
        }
1319
      } else {
1320
        // for other strings
1321
        if (*formatStr == '\\' && *(formatStr + 1)) {
134,782,958✔
1322
          formatStr++;
×
1323
          lastOtherFormat = NULL;  // stop expanding
×
1324
        } else {
1325
          if (lastOtherFormat && !isSeperatorChar(*formatStr)) {
134,782,958✔
1326
            // expanding
1327
          } else {
1328
            // create new
1329
            lastOtherFormat = NULL;
78,939,628✔
1330
          }
1331
        }
1332
        if (lastOtherFormat) {
134,782,958✔
1333
          lastOtherFormat->len++;
55,843,330✔
1334
          formatStr++;
55,843,330✔
1335
        } else {
1336
          TSFormatNode format = {
157,880,140✔
1337
              .type = isSeperatorChar(*formatStr) ? TS_FORMAT_NODE_TYPE_SEPARATOR : TS_FORMAT_NODE_TYPE_CHAR,
78,939,628✔
1338
              .key = NULL};
1339
          format.c = formatStr;
78,940,512✔
1340
          format.len = 1;
78,940,512✔
1341
          if (NULL == taosArrayPush(formats, &format)) TAOS_RETURN(terrno);
78,941,396✔
1342
          formatStr++;
78,941,396✔
1343
          if (format.type == TS_FORMAT_NODE_TYPE_CHAR) lastOtherFormat = taosArrayGetLast(formats);
78,941,396✔
1344
        }
1345
      }
1346
    }
1347
  }
1348
  TAOS_RETURN(TSDB_CODE_SUCCESS);
15,760,513✔
1349
}
1350

1351
static int32_t tm2char(const SArray* formats, const struct STm* tm, char* s, int32_t outLen) {
91,060,893✔
1352
  int32_t     size = taosArrayGetSize(formats);
91,060,893✔
1353
  const char* start = s;
91,071,943✔
1354
  for (int32_t i = 0; i < size; ++i) {
1,215,858,249✔
1355
    TSFormatNode* format = taosArrayGet(formats, i);
1,123,878,438✔
1356
    if (format->type != TS_FORMAT_NODE_TYPE_KEYWORD) {
1,111,593,048✔
1357
      if (s - start + format->len + 1 > outLen) break;
540,916,545✔
1358
      (void)strncpy(s, format->c, format->len);
540,887,815✔
1359
      s += format->len;
541,134,009✔
1360
      continue;
542,263,319✔
1361
    }
1362
    if (s - start + 16 > outLen) break;
585,149,351✔
1363

1364
    switch (format->key->id) {
585,149,351✔
1365
      case TSFKW_AM:
890✔
1366
      case TSFKW_PM:
1367
        (void)sprintf(s, tm->tm.tm_hour % 24 >= 12 ? "PM" : "AM");
890✔
1368
        s += 2;
890✔
1369
        break;
890✔
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,505✔
1376
      case TSFKW_pm:
1377
        (void)sprintf(s, tm->tm.tm_hour % 24 >= 12 ? "pm" : "am");
1,505✔
1378
        s += 2;
1,505✔
1379
        break;
1,505✔
1380
      case TSFKW_a_m:
58,455✔
1381
      case TSFKW_p_m:
1382
        (void)sprintf(s, tm->tm.tm_hour % 24 >= 12 ? "p.m." : "a.m.");
58,455✔
1383
        s += 4;
58,455✔
1384
        break;
58,455✔
1385
      case TSFKW_DDD:
110,160✔
1386
        (void)sprintf(s, "%03d", tm->tm.tm_yday + 1);
110,160✔
1387
        s += strlen(s);
110,160✔
1388
        break;
110,160✔
1389
      case TSFKW_DD:
90,649,829✔
1390
        (void)sprintf(s, "%02d", tm->tm.tm_mday);
90,649,829✔
1391
        s += 2;
90,638,337✔
1392
        break;
90,762,539✔
1393
      case TSFKW_D:
95,880✔
1394
        (void)sprintf(s, "%d", tm->tm.tm_wday + 1);
95,880✔
1395
        s += 1;
95,880✔
1396
        break;
95,880✔
1397
      case TSFKW_DAY: {
4,080✔
1398
        // MONDAY, TUESDAY...
1399
        const char* wd = weekDays[tm->tm.tm_wday];
4,080✔
1400
        char        buf[10] = {0};
4,080✔
1401
        for (int32_t i = 0; i < strlen(wd); ++i) buf[i] = toupper(wd[i]);
28,560✔
1402
        (void)sprintf(s, "%-9s", buf);
4,080✔
1403
        s += strlen(s);
4,080✔
1404
        break;
4,080✔
1405
      }
1406
      case TSFKW_Day:
2,040✔
1407
        // Monday, TuesDay...
1408
        (void)sprintf(s, "%-9s", weekDays[tm->tm.tm_wday]);
2,040✔
1409
        s += strlen(s);
2,040✔
1410
        break;
2,040✔
1411
      case TSFKW_day: {
4,080✔
1412
        const char* wd = weekDays[tm->tm.tm_wday];
4,080✔
1413
        char        buf[10] = {0};
4,080✔
1414
        for (int32_t i = 0; i < strlen(wd); ++i) buf[i] = tolower(wd[i]);
28,560✔
1415
        (void)sprintf(s, "%-9s", buf);
4,080✔
1416
        s += strlen(s);
4,080✔
1417
        break;
4,080✔
1418
      }
1419
      case TSFKW_DY: {
83,640✔
1420
        // MON, TUE
1421
        const char* wd = shortWeekDays[tm->tm.tm_wday];
83,640✔
1422
        char        buf[8] = {0};
83,640✔
1423
        for (int32_t i = 0; i < strlen(wd); ++i) buf[i] = toupper(wd[i]);
334,560✔
1424
        (void)sprintf(s, "%3s", buf);
83,640✔
1425
        s += 3;
83,640✔
1426
        break;
83,640✔
1427
      }
1428
      case TSFKW_Dy:
4,080✔
1429
        // Mon, Tue
1430
        (void)sprintf(s, "%3s", shortWeekDays[tm->tm.tm_wday]);
4,080✔
1431
        s += 3;
4,080✔
1432
        break;
4,080✔
1433
      case TSFKW_dy: {
44,036,327✔
1434
        // mon, tue
1435
        const char* wd = shortWeekDays[tm->tm.tm_wday];
44,036,327✔
1436
        char        buf[8] = {0};
44,083,621✔
1437
        for (int32_t i = 0; i < strlen(wd); ++i) buf[i] = tolower(wd[i]);
175,938,452✔
1438
        (void)sprintf(s, "%3s", buf);
44,174,231✔
1439
        s += 3;
44,174,231✔
1440
        break;
44,179,093✔
1441
      }
1442
      case TSFKW_HH24:
46,079,287✔
1443
        (void)sprintf(s, "%02d", tm->tm.tm_hour);
46,079,287✔
1444
        s += 2;
46,081,055✔
1445
        break;
46,172,991✔
1446
      case TSFKW_HH:
44,425,028✔
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);
44,425,028✔
1450
        s += 2;
44,394,972✔
1451
        break;
44,428,122✔
1452
      case TSFKW_MI:
90,483,983✔
1453
        (void)sprintf(s, "%02d", tm->tm.tm_min);
90,483,983✔
1454
        s += 2;
90,502,105✔
1455
        break;
90,315,139✔
1456
      case TSFKW_MM:
46,493,074✔
1457
        (void)sprintf(s, "%02d", tm->tm.tm_mon + 1);
46,493,074✔
1458
        s += 2;
46,538,158✔
1459
        break;
46,595,618✔
1460
      case TSFKW_MONTH: {
4,080✔
1461
        const char* mon = fullMonths[tm->tm.tm_mon];
4,080✔
1462
        char        buf[10] = {0};
4,080✔
1463
        for (int32_t i = 0; i < strlen(mon); ++i) buf[i] = toupper(mon[i]);
28,560✔
1464
        (void)sprintf(s, "%-9s", buf);
4,080✔
1465
        s += strlen(s);
4,080✔
1466
        break;
4,080✔
1467
      }
1468
      case TSFKW_MON: {
110,160✔
1469
        const char* mon = months[tm->tm.tm_mon];
110,160✔
1470
        char        buf[10] = {0};
110,160✔
1471
        for (int32_t i = 0; i < strlen(mon); ++i) buf[i] = toupper(mon[i]);
440,640✔
1472
        (void)sprintf(s, "%s", buf);
110,160✔
1473
        s += strlen(s);
110,160✔
1474
        break;
110,160✔
1475
      }
1476
      case TSFKW_Month:
2,040✔
1477
        (void)sprintf(s, "%-9s", fullMonths[tm->tm.tm_mon]);
2,040✔
1478
        s += strlen(s);
2,040✔
1479
        break;
2,040✔
1480
      case TSFKW_month: {
4,525✔
1481
        const char* mon = fullMonths[tm->tm.tm_mon];
4,525✔
1482
        char        buf[10] = {0};
4,525✔
1483
        for (int32_t i = 0; i < strlen(mon); ++i) buf[i] = tolower(mon[i]);
32,120✔
1484
        (void)sprintf(s, "%-9s", buf);
4,525✔
1485
        s += strlen(s);
4,525✔
1486
        break;
4,525✔
1487
      }
1488
      case TSFKW_Mon:
2,040✔
1489
        (void)sprintf(s, "%s", months[tm->tm.tm_mon]);
2,040✔
1490
        s += strlen(s);
2,040✔
1491
        break;
2,040✔
1492
      case TSFKW_mon: {
44,033,910✔
1493
        const char* mon = months[tm->tm.tm_mon];
44,033,910✔
1494
        char        buf[10] = {0};
44,048,496✔
1495
        for (int32_t i = 0; i < strlen(mon); ++i) buf[i] = tolower(mon[i]);
174,882,570✔
1496
        (void)sprintf(s, "%s", buf);
43,965,842✔
1497
        s += strlen(s);
43,965,842✔
1498
        break;
43,985,290✔
1499
      }
1500
      case TSFKW_SS:
90,491,497✔
1501
        (void)sprintf(s, "%02d", tm->tm.tm_sec);
90,491,497✔
1502
        s += 2;
90,484,425✔
1503
        break;
90,609,511✔
1504
      case TSFKW_MS:
1,833,496✔
1505
        (void)sprintf(s, "%03" PRId64, tm->fsec / 1000000L);
1,833,496✔
1506
        s += 3;
1,833,496✔
1507
        break;
1,833,496✔
1508
      case TSFKW_US:
7,455✔
1509
        (void)sprintf(s, "%06" PRId64, tm->fsec / 1000L);
7,455✔
1510
        s += 6;
7,455✔
1511
        break;
7,455✔
1512
      case TSFKW_NS:
9,223✔
1513
        (void)sprintf(s, "%09" PRId64, tm->fsec);
9,223✔
1514
        s += 9;
9,223✔
1515
        break;
9,223✔
1516
      case TSFKW_TZH:{
58,010✔
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;
58,010✔
1523
#endif
1524
        (void)sprintf(s, "%c%02d", (gmtoff >= 0) ? '+' : '-',
58,010✔
1525
                      abs(gmtoff) / 3600);
58,010✔
1526
        s += strlen(s);
58,010✔
1527
        break;
58,010✔
1528
      }
1529
      case TSFKW_YYYY:
46,616,618✔
1530
        (void)sprintf(s, "%04d", tm->tm.tm_year + 1900);
46,616,618✔
1531
        s += strlen(s);
46,664,796✔
1532
        break;
46,695,736✔
1533
      case TSFKW_YYY:
12,240✔
1534
        (void)sprintf(s, "%03d", (tm->tm.tm_year + 1900) % 1000);
12,240✔
1535
        s += strlen(s);
12,240✔
1536
        break;
12,240✔
1537
      case TSFKW_YY:
43,949,707✔
1538
        (void)sprintf(s, "%02d", (tm->tm.tm_year + 1900) % 100);
43,949,707✔
1539
        s += strlen(s);
43,950,149✔
1540
        break;
44,184,851✔
1541
      case TSFKW_Y:
14,280✔
1542
        (void)sprintf(s, "%01d", (tm->tm.tm_year + 1900) % 10);
14,280✔
1543
        s += strlen(s);
14,280✔
1544
        break;
14,280✔
1545
      default:
×
1546
        break;
×
1547
    }
1548
  }
1549
  return TSDB_CODE_SUCCESS;
91,979,811✔
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) {
88,371,542✔
1555
  if (!*s) return -1;
88,371,542✔
1556
  const char* const* fmt = arr;
88,378,614✔
1557
  for (; *fmt; ++fmt) {
624,851,768✔
1558
    const char *l, *r;
1559
    for (l = fmt[0], r = s;; l++, r++) {
903,703,670✔
1560
      if (*l == '\0') return fmt - arr;
903,697,482✔
1561
      if (*r == '\0' || tolower(*l) != tolower(*r)) break;
814,005,332✔
1562
    }
1563
  }
1564
  return -1;
530✔
1565
}
1566

1567
static const char* tsFormatStr2Int32(int32_t* dest, const char* str, int32_t len, bool needMoreDigit) {
433,417,753✔
1568
  char*       last;
433,417,753✔
1569
  int64_t     res;
1570
  const char* s = str;
433,441,621✔
1571
  if ('\0' == str[0]) return NULL;
433,441,621✔
1572
  if (len <= 0) {
434,006,055✔
1573
    res = taosStr2Int64(s, &last, 10);
26,260✔
1574
    s = last;
26,260✔
1575
  } else {
1576
    char buf[16] = {0};
433,979,795✔
1577
    (void)strncpy(buf, s, len);
434,073,499✔
1578
    int32_t copiedLen = strlen(buf);
434,073,499✔
1579
    if (copiedLen < len) {
434,073,499✔
1580
      if (!needMoreDigit) {
35,360,445✔
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,360,445✔
1585
        s += copiedLen;
35,359,561✔
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) {
398,713,054✔
1593
        res = taosStr2Int64(buf, &last, 10);
1,780✔
1594
        // bytes enough, but digits not enough, like '202a12' 'YYYYMM', YYYY needs four digits
1595
        if (last - buf < len) return NULL;
1,780✔
1596
        s += last - buf;
1,335✔
1597
      } else {
1598
        res = taosStr2Int64(s, &last, 10);
398,711,274✔
1599
        s = last;
398,635,250✔
1600
      }
1601
    }
1602
  }
1603
  if (s == str) {
434,100,198✔
1604
    // no integers found
1605
    return NULL;
530✔
1606
  }
1607
  if (ERRNO == ERANGE || res > INT32_MAX || res < INT32_MIN) {
434,099,668✔
1608
    // out of range
1609
    return NULL;
×
1610
  }
1611
  *dest = res;
434,167,294✔
1612
  return s;
434,040,440✔
1613
}
1614

1615
static int32_t adjustYearTo2020(int32_t year) {
44,097,656✔
1616
  if (year < 70) return year + 2000;    // 2000 - 2069
44,097,656✔
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) {
79,767,042✔
1624
  if (tm->tm_mon < 0 || tm->tm_mon > 11) return false;
79,767,042✔
1625
  if (tm->tm_wday < 0 || tm->tm_wday > 6) return false;
79,856,320✔
1626
  if (tm->tm_yday < 0 || tm->tm_yday > 365) return false;
79,877,536✔
1627
  if (tm->tm_mday < 0 || tm->tm_mday > 31) return false;
79,832,010✔
1628
  if (tm->tm_hour < 0 || tm->tm_hour > 23) return false;
79,867,812✔
1629
  if (tm->tm_min < 0 || tm->tm_min > 59) return false;
79,807,258✔
1630
  if (tm->tm_sec < 0 || tm->tm_sec > 60) return false;
79,862,066✔
1631
  return true;
79,862,066✔
1632
}
1633

1634
static bool needMoreDigits(SArray* formats, int32_t curIdx) {
433,762,513✔
1635
  if (curIdx == taosArrayGetSize(formats) - 1) return false;
433,762,513✔
1636
  TSFormatNode* pNextNode = taosArrayGet(formats, curIdx + 1);
398,129,286✔
1637
  if (pNextNode->type == TS_FORMAT_NODE_TYPE_SEPARATOR) {
398,192,050✔
1638
    return false;
274,445,706✔
1639
  } else if (pNextNode->type == TS_FORMAT_NODE_TYPE_KEYWORD) {
123,859,496✔
1640
    return pNextNode->key->isDigit;
31,155✔
1641
  } else {
1642
    return isdigit(pNextNode->c[0]);
123,833,645✔
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,
79,613,949✔
1658
                       int32_t* fErrIdx, timezone_t tz) {
1659
  int32_t size = taosArrayGetSize(formats);
79,613,949✔
1660
  int32_t pm = 0;      // default am
79,812,407✔
1661
  int32_t hour12 = 0;  // default HH24
79,812,407✔
1662
  int32_t year = 0, mon = 0, yd = 0, md = 1, wd = 0;
79,812,407✔
1663
  int32_t hour = 0, min = 0, sec = 0, us = 0, ms = 0, ns = 0;
79,883,569✔
1664
  int32_t tzHour = 0;
79,879,149✔
1665
  int32_t err = 0;
79,858,817✔
1666
  bool    withYD = false, withMD = false;
79,858,817✔
1667

1668
  for (int32_t i = 0; i < size && *s != '\0'; ++i) {
1,045,329,412✔
1669
    while (isspace(*s) && *s != '\0') {
1,087,343,604✔
1670
      s++;
123,411,432✔
1671
    }
1672
    if (!s) break;
963,567,964✔
1673
    TSFormatNode* node = taosArrayGet(formats, i);
963,567,964✔
1674
    if (node->type == TS_FORMAT_NODE_TYPE_SEPARATOR) {
963,676,696✔
1675
      // separator matches any character
1676
      if (isSeperatorChar(s[0])) s += node->len;
318,963,182✔
1677
      continue;
318,915,004✔
1678
    }
1679
    if (node->type == TS_FORMAT_NODE_TYPE_CHAR) {
645,796,414✔
1680
      int32_t pos = 0;
123,885,569✔
1681
      // skip leading spaces
1682
      while (isspace(node->c[pos]) && node->len > 0) pos++;
247,716,343✔
1683
      while (pos < node->len && *s != '\0') {
125,709,139✔
1684
        if (!isspace(node->c[pos++])) {
1,837,714✔
1685
          while (isspace(*s) && *s != '\0') s++;
1,838,150✔
1686
          if (*s != '\0') s++;  // forward together
1,838,150✔
1687
        }
1688
      }
1689
      continue;
123,865,679✔
1690
    }
1691
    switch (node->key->id) {
520,658,217✔
1692
      case TSFKW_A_M:
27,150✔
1693
      case TSFKW_P_M:
1694
      case TSFKW_a_m:
1695
      case TSFKW_p_m: {
1696
        int32_t idx = strArrayCaseSearch(long_apms, s);
27,150✔
1697
        if (idx >= 0) {
27,150✔
1698
          s += 4;
27,150✔
1699
          pm = idx % 2;
27,150✔
1700
          hour12 = 1;
27,150✔
1701
        } else {
1702
          err = -1;
×
1703
        }
1704
      } break;
27,150✔
1705
      case TSFKW_AM:
3,200✔
1706
      case TSFKW_PM:
1707
      case TSFKW_am:
1708
      case TSFKW_pm: {
1709
        int32_t idx = strArrayCaseSearch(apms, s);
3,200✔
1710
        if (idx >= 0) {
3,200✔
1711
          s += 2;
2,670✔
1712
          pm = idx % 2;
2,670✔
1713
          hour12 = 1;
2,670✔
1714
        } else {
1715
          err = -1;
530✔
1716
        }
1717
      } break;
3,200✔
1718
      case TSFKW_HH:
11,639✔
1719
      case TSFKW_HH12: {
1720
        const char* newPos = tsFormatStr2Int32(&hour, s, 2, needMoreDigits(formats, i));
11,639✔
1721
        if (NULL == newPos || hour > 12 || hour <= 0) {
11,639✔
1722
          err = -1;
×
1723
        } else {
1724
          hour12 = 1;
11,639✔
1725
          s = newPos;
11,639✔
1726
        }
1727
      } break;
11,639✔
1728
      case TSFKW_HH24: {
79,603,013✔
1729
        const char* newPos = tsFormatStr2Int32(&hour, s, 2, needMoreDigits(formats, i));
79,603,013✔
1730
        if (NULL == newPos) {
79,612,737✔
1731
          err = -1;
×
1732
        } else {
1733
          hour12 = 0;
79,612,737✔
1734
          s = newPos;
79,612,737✔
1735
        }
1736
      } break;
79,612,737✔
1737
      case TSFKW_MI: {
79,615,536✔
1738
        const char* newPos = tsFormatStr2Int32(&min, s, 2, needMoreDigits(formats, i));
79,615,536✔
1739
        if (NULL == newPos) {
79,623,492✔
1740
          err = -1;
×
1741
        } else {
1742
          s = newPos;
79,623,492✔
1743
        }
1744
      } break;
79,623,492✔
1745
      case TSFKW_SS: {
79,607,580✔
1746
        const char* newPos = tsFormatStr2Int32(&sec, s, 2, needMoreDigits(formats, i));
79,607,580✔
1747
        if (NULL == newPos)
79,620,398✔
1748
          err = -1;
×
1749
        else
1750
          s = newPos;
79,620,398✔
1751
      } break;
79,620,398✔
1752
      case TSFKW_MS: {
42,950✔
1753
        const char* newPos = tsFormatStr2Int32(&ms, s, 3, needMoreDigits(formats, i));
42,950✔
1754
        if (NULL == newPos)
42,950✔
1755
          err = -1;
×
1756
        else {
1757
          int32_t len = newPos - s;
42,950✔
1758
          ms *= len == 1 ? 100 : len == 2 ? 10 : 1;
42,950✔
1759
          s = newPos;
42,950✔
1760
        }
1761
      } break;
42,950✔
1762
      case TSFKW_US: {
4,710✔
1763
        const char* newPos = tsFormatStr2Int32(&us, s, 6, needMoreDigits(formats, i));
4,710✔
1764
        if (NULL == newPos)
4,710✔
1765
          err = -1;
×
1766
        else {
1767
          int32_t len = newPos - s;
4,710✔
1768
          us *= len == 1 ? 100000 : len == 2 ? 10000 : len == 3 ? 1000 : len == 4 ? 100 : len == 5 ? 10 : 1;
4,710✔
1769
          s = newPos;
4,710✔
1770
        }
1771
      } break;
4,710✔
1772
      case TSFKW_NS: {
6,484✔
1773
        const char* newPos = tsFormatStr2Int32(&ns, s, 9, needMoreDigits(formats, i));
6,484✔
1774
        if (NULL == newPos)
6,484✔
1775
          err = -1;
×
1776
        else {
1777
          int32_t len = newPos - s;
6,484✔
1778
          ns *= len == 1   ? 100000000
6,484✔
1779
                : len == 2 ? 10000000
12,968✔
1780
                : len == 3 ? 1000000
12,968✔
1781
                : len == 4 ? 100000
12,968✔
1782
                : len == 5 ? 10000
12,968✔
1783
                : len == 6 ? 1000
12,968✔
1784
                : len == 7 ? 100
12,968✔
1785
                : len == 8 ? 10
12,968✔
1786
                           : 1;
6,484✔
1787
          s = newPos;
6,484✔
1788
        }
1789
      } break;
6,484✔
1790
      case TSFKW_TZH: {
26,260✔
1791
        const char* newPos = tsFormatStr2Int32(&tzHour, s, -1, needMoreDigits(formats, i));
26,260✔
1792
        if (NULL == newPos)
26,260✔
1793
          err = -1;
×
1794
        else {
1795
          s = newPos;
26,260✔
1796
        }
1797
      } break;
26,260✔
1798
      case TSFKW_MONTH:
4,970✔
1799
      case TSFKW_Month:
1800
      case TSFKW_month: {
1801
        int32_t idx = strArrayCaseSearch(fullMonths, s);
4,970✔
1802
        if (idx >= 0) {
4,970✔
1803
          s += strlen(fullMonths[idx]);
4,970✔
1804
          mon = idx;
4,970✔
1805
        } else {
1806
          err = -1;
×
1807
        }
1808
      } break;
4,970✔
1809
      case TSFKW_MON:
44,103,440✔
1810
      case TSFKW_Mon:
1811
      case TSFKW_mon: {
1812
        int32_t idx = strArrayCaseSearch(months, s);
44,103,440✔
1813
        if (idx >= 0) {
44,114,048✔
1814
          s += strlen(months[idx]);
44,114,048✔
1815
          mon = idx;
44,235,598✔
1816
        } else {
1817
          err = -1;
×
1818
        }
1819
      } break;
44,235,598✔
1820
      case TSFKW_MM: {
35,574,856✔
1821
        const char* newPos = tsFormatStr2Int32(&mon, s, 2, needMoreDigits(formats, i));
35,574,856✔
1822
        if (NULL == newPos) {
35,576,182✔
1823
          err = -1;
×
1824
        } else {
1825
          s = newPos;
35,576,182✔
1826
          mon -= 1;
35,576,182✔
1827
        }
1828
      } break;
35,576,182✔
1829
      case TSFKW_DAY:
4,080✔
1830
      case TSFKW_Day:
1831
      case TSFKW_day: {
1832
        int32_t idx = strArrayCaseSearch(weekDays, s);
4,080✔
1833
        if (idx >= 0) {
4,080✔
1834
          s += strlen(weekDays[idx]);
4,080✔
1835
          wd = idx;
4,080✔
1836
        } else {
1837
          err = -1;
×
1838
        }
1839
      } break;
4,080✔
1840
      case TSFKW_DY:
44,254,780✔
1841
      case TSFKW_Dy:
1842
      case TSFKW_dy: {
1843
        int32_t idx = strArrayCaseSearch(shortWeekDays, s);
44,254,780✔
1844
        if (idx >= 0) {
44,193,784✔
1845
          s += strlen(shortWeekDays[idx]);
44,193,784✔
1846
          wd = idx;
44,244,614✔
1847
        } else {
1848
          err = -1;
×
1849
        }
1850
      } break;
44,244,614✔
1851
      case TSFKW_DDD: {
44,880✔
1852
        const char* newPos = tsFormatStr2Int32(&yd, s, 3, needMoreDigits(formats, i));
44,880✔
1853
        if (NULL == newPos) {
44,880✔
1854
          err = -1;
×
1855
        } else {
1856
          s = newPos;
44,880✔
1857
        }
1858
        withYD = true;
44,880✔
1859
      } break;
44,880✔
1860
      case TSFKW_DD: {
79,821,306✔
1861
        const char* newPos = tsFormatStr2Int32(&md, s, 2, needMoreDigits(formats, i));
79,821,306✔
1862
        if (NULL == newPos) {
79,818,212✔
1863
          err = -1;
×
1864
        } else {
1865
          s = newPos;
79,818,212✔
1866
        }
1867
        withMD = true;
79,818,212✔
1868
      } break;
79,818,212✔
1869
      case TSFKW_D: {
40,800✔
1870
        const char* newPos = tsFormatStr2Int32(&wd, s, 1, needMoreDigits(formats, i));
40,800✔
1871
        if (NULL == newPos) {
40,800✔
1872
          err = -1;
×
1873
        } else {
1874
          s = newPos;
40,800✔
1875
        }
1876
      } break;
40,800✔
1877
      case TSFKW_YYYY: {
35,633,825✔
1878
        const char* newPos = tsFormatStr2Int32(&year, s, 4, needMoreDigits(formats, i));
35,633,825✔
1879
        if (NULL == newPos) {
35,633,383✔
1880
          err = -1;
445✔
1881
        } else {
1882
          s = newPos;
35,632,938✔
1883
        }
1884
      } break;
35,633,383✔
1885
      case TSFKW_YYY: {
8,160✔
1886
        const char* newPos = tsFormatStr2Int32(&year, s, 3, needMoreDigits(formats, i));
8,160✔
1887
        if (NULL == newPos) {
8,160✔
1888
          err = -1;
×
1889
        } else {
1890
          year = adjustYearTo2020(year);
8,160✔
1891
          s = newPos;
8,160✔
1892
        }
1893
      } break;
8,160✔
1894
      case TSFKW_YY: {
44,113,690✔
1895
        const char* newPos = tsFormatStr2Int32(&year, s, 2, needMoreDigits(formats, i));
44,113,690✔
1896
        if (NULL == newPos) {
44,199,438✔
1897
          err = -1;
530✔
1898
        } else {
1899
          year = adjustYearTo2020(year);
44,198,908✔
1900
          s = newPos;
44,092,828✔
1901
        }
1902
      } break;
44,093,358✔
1903
      case TSFKW_Y: {
8,160✔
1904
        const char* newPos = tsFormatStr2Int32(&year, s, 1, needMoreDigits(formats, i));
8,160✔
1905
        if (NULL == newPos) {
8,160✔
1906
          err = -1;
×
1907
        } else {
1908
          year = adjustYearTo2020(year);
8,160✔
1909
          s = newPos;
8,160✔
1910
        }
1911
      } break;
8,160✔
1912
      default:
×
1913
        break;
×
1914
    }
1915
    if (err) {
522,691,417✔
1916
      if (sErrPos) *sErrPos = s;
1,505✔
1917
      if (fErrIdx) *fErrIdx = i;
1,505✔
1918
      return err;
1,505✔
1919
    }
1920
  }
1921
  if (!withMD) {
81,960,348✔
1922
    // yyyy-mm-DDD, currently, the c api can't convert to correct timestamp, return not supported
1923
    if (withYD) return -3;
61,200✔
1924
  }
1925
  struct STm tm = {0};
81,956,268✔
1926
  tm.tm.tm_year = year - 1900;
79,864,282✔
1927
  tm.tm.tm_mon = mon;
79,864,282✔
1928
  tm.tm.tm_yday = yd;
79,864,282✔
1929
  tm.tm.tm_mday = md;
79,864,282✔
1930
  tm.tm.tm_wday = wd;
79,864,282✔
1931
  if (hour12) {
79,864,282✔
1932
    if (pm && hour < 12)
32,929✔
1933
      tm.tm.tm_hour = hour + 12;
2,670✔
1934
    else if (!pm && hour == 12)
30,259✔
1935
      tm.tm.tm_hour = 0;
3,554✔
1936
    else
1937
      tm.tm.tm_hour = hour;
26,705✔
1938
  } else {
1939
    tm.tm.tm_hour = hour;
79,831,353✔
1940
  }
1941
  tm.tm.tm_min = min;
79,864,282✔
1942
  tm.tm.tm_sec = sec;
79,864,282✔
1943
  if (!checkTm(&tm.tm)) return -2;
79,864,282✔
1944
  if (tzHour < -13 || tzHour > 13) return -2;
79,734,770✔
1945
  tm.fsec = ms * 1000000 + us * 1000 + ns;
79,866,928✔
1946
  int32_t ret = taosTm2Ts(&tm, ts, precision, tz);
79,866,928✔
1947
  if (tzHour != 0) {
79,870,464✔
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,180✔
1954
#endif
1955
    *ts += (gmtoff - tzHour * 3600) * TICK_PER_SECOND[precision];
22,180✔
1956
  }
1957
  return ret;
79,874,000✔
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) {
91,169,625✔
1961
  if (!*formats) {
91,169,625✔
1962
    *formats = taosArrayInit(8, sizeof(TSFormatNode));
2,218,050✔
1963
    if (!*formats) {
2,218,050✔
1964
      TAOS_RETURN(terrno);
×
1965
    }
1966
    TAOS_CHECK_RETURN(parseTsFormat(format, *formats));
2,218,050✔
1967
  }
1968
  struct STm tm;
91,184,211✔
1969
  TAOS_CHECK_RETURN(taosTs2Tm(ts, precision, &tm, tz));
91,134,265✔
1970
  return tm2char(*formats, &tm, out, outLen);
90,477,453✔
1971
}
1972

1973
int32_t taosChar2Ts(const char* format, SArray** formats, const char* tsStr, int64_t* ts, int32_t precision,
79,796,937✔
1974
                    char* errMsg, int32_t errMsgLen, timezone_t tz) {
1975
  const char* sErrPos;
79,796,937✔
1976
  int32_t     fErrIdx;
79,834,507✔
1977
  if (!*formats) {
79,854,839✔
1978
    *formats = taosArrayInit(4, sizeof(TSFormatNode));
13,545,115✔
1979
    if (!*formats) {
13,545,115✔
1980
      TAOS_RETURN(terrno);
×
1981
    }
1982
    TAOS_CHECK_RETURN(parseTsFormat(format, *formats));
13,545,115✔
1983
  }
1984
  int32_t code = char2ts(tsStr, *formats, ts, precision, &sErrPos, &fErrIdx, tz);
79,872,077✔
1985
  if (code == -1) {
79,810,639✔
1986
    TSFormatNode* fNode = (taosArrayGet(*formats, fErrIdx));
1,505✔
1987
    snprintf(errMsg, errMsgLen, "mismatch format for: %s and %s", sErrPos,
3,010✔
1988
             fErrIdx < taosArrayGetSize(*formats) ? ((TSFormatNode*)taosArrayGet(*formats, fErrIdx))->key->name : "");
3,010✔
1989
    code = TSDB_CODE_FUNC_TO_TIMESTAMP_FAILED_FORMAT_ERR;
1,505✔
1990
  } else if (code == -2) {
79,809,134✔
1991
    snprintf(errMsg, errMsgLen, "timestamp format error: %s -> %s", tsStr, format);
890✔
1992
    code = TSDB_CODE_FUNC_TO_TIMESTAMP_FAILED_TS_ERR;
890✔
1993
  } else if (code == -3) {
79,808,244✔
1994
    snprintf(errMsg, errMsgLen, "timestamp format not supported");
4,080✔
1995
    code = TSDB_CODE_FUNC_TO_TIMESTAMP_FAILED_NOT_SUPPORTED;
4,080✔
1996
  }
1997
  TAOS_RETURN(code);
79,810,639✔
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,361,403✔
2140
  int64_t   factor =  (precision == TSDB_TIME_PRECISION_SECONDS) ? 1
10,361,403✔
2141
                    : (precision == TSDB_TIME_PRECISION_MILLI)   ? 1000
10,361,403✔
2142
                    : (precision == TSDB_TIME_PRECISION_MICRO)   ? 1000000
2143
                    : 1000000000;
2144
  time_t    t;
10,346,028✔
2145
  int32_t code = taosTime(&t);
10,361,403✔
2146
  if (code != 0) {
10,361,403✔
2147
    return -1;
×
2148
  }
2149
  struct tm tm;
10,346,028✔
2150
  if (taosLocalTime(&t, &tm, NULL, 0,  tz) == NULL){
10,361,403✔
2151
    uError("%s failed to get local time, code:%d", __FUNCTION__, ERRNO);
×
2152
    return t;
×
2153
  }
2154
  tm.tm_hour = 0;
10,361,403✔
2155
  tm.tm_min = 0;
10,361,403✔
2156
  tm.tm_sec = 0;
10,361,403✔
2157

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

2166
int32_t taosParseShortWeekday(const char* str) {
×
2167
  for (int32_t i = 0; i < 7; i++) {
×
2168
    if (strcasecmp(shortWeekDays[i], str) == 0) {
×
2169
      return i;
×
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