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

taosdata / TDengine / #4308

14 Jun 2025 02:06PM UTC coverage: 62.454% (-0.3%) from 62.777%
#4308

push

travis-ci

web-flow
fix: taosdump windows pthread_mutex_unlock crash(3.0) (#31357)

* fix: windows pthread_mutex_unlock crash

* enh: sync from main fix taosdump crash windows

* fix: restore .github action branch to main

153985 of 315105 branches covered (48.87%)

Branch coverage included in aggregate %.

238120 of 312727 relevant lines covered (76.14%)

6462519.65 hits per line

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

81.19
/source/os/src/osTime.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
#define ALLOW_FORBID_FUNC
17
#define _BSD_SOURCE
18

19
#ifdef DARWIN
20
#define _XOPEN_SOURCE
21
#else
22
#define _XOPEN_SOURCE 500
23
#endif
24

25
#define _DEFAULT_SOURCE
26

27
#include "os.h"
28

29
#if defined(WINDOWS) || defined(TD_ASTRA)
30

31
#include <stdlib.h>
32
#include <string.h>
33
#include <time.h>
34
// #define TM_YEAR_BASE 1970 //origin
35
#define TM_YEAR_BASE 1900  // slguan
36

37
// This magic number is the number of 100 nanosecond intervals since January 1, 1601 (UTC)
38
// until 00:00:00 January 1, 1970
39
static const uint64_t TIMEEPOCH = ((uint64_t)116444736000000000ULL);
40

41
/*
42
 * We do not implement alternate representations. However, we always
43
 * check whether a given modifier is allowed for a certain conversion.
44
 */
45
#define ALT_E 0x01
46
#define ALT_O 0x02
47
#define LEGAL_ALT(x)                   \
48
  {                                    \
49
    if (alt_format & ~(x)) return (0); \
50
  }
51

52
static int conv_num(const char **buf, int *dest, int llim, int ulim) {
53
  int result = 0;
54

55
  /* The limit also determines the number of valid digits. */
56
  int rulim = ulim;
57

58
  if (**buf < '0' || **buf > '9') return (0);
59

60
  do {
61
    result *= 10;
62
    result += *(*buf)++ - '0';
63
    rulim /= 10;
64
  } while ((result * 10 <= ulim) && rulim && **buf >= '0' && **buf <= '9');
65

66
  if (result < llim || result > ulim) return (0);
67

68
  *dest = result;
69
  return (1);
70
}
71

72
static const char *day[7] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
73
static const char *abday[7] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
74
static const char *mon[12] = {"January", "February", "March",     "April",   "May",      "June",
75
                              "July",    "August",   "September", "October", "November", "December"};
76
static const char *abmon[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
77
static const char *am_pm[2] = {"AM", "PM"};
78

79
#else
80
#include <sys/time.h>
81
#endif
82

83
char *taosStrpTime(const char *buf, const char *fmt, struct tm *tm) {
3,352,672✔
84
  if (!buf || !fmt || !tm) return NULL;
3,352,672✔
85
#if defined(WINDOWS) || defined(TD_ASTRA) 
86
  char        c;
87
  const char *bp;
88
  size_t      len = 0;
89
  int         alt_format, i, split_year = 0;
90

91
  bp = buf;
92

93
  while ((c = *fmt) != '\0') {
94
    /* Clear `alternate' modifier prior to new conversion. */
95
    alt_format = 0;
96

97
    /* Eat up white-space. */
98
    if (isspace(c)) {
99
      while (isspace(*bp)) bp++;
100

101
      fmt++;
102
      continue;
103
    }
104

105
    if ((c = *fmt++) != '%') goto literal;
106

107
  again:
108
    switch (c = *fmt++) {
109
      case '%': /* "%%" is converted to "%". */
110
      literal:
111
        if (c != *bp++) return (0);
112
        break;
113

114
        /*
115
         * "Alternative" modifiers. Just set the appropriate flag
116
         * and start over again.
117
         */
118
      case 'E': /* "%E?" alternative conversion modifier. */
119
        LEGAL_ALT(0);
120
        alt_format |= ALT_E;
121
        goto again;
122

123
      case 'O': /* "%O?" alternative conversion modifier. */
124
        LEGAL_ALT(0);
125
        alt_format |= ALT_O;
126
        goto again;
127

128
        /*
129
         * "Complex" conversion rules, implemented through recursion.
130
         */
131
      case 'c': /* Date and time, using the locale's format. */
132
        LEGAL_ALT(ALT_E);
133
        if (!(bp = taosStrpTime(bp, "%x %X", tm))) return (0);
134
        break;
135

136
      case 'D': /* The date as "%m/%d/%y". */
137
        LEGAL_ALT(0);
138
        if (!(bp = taosStrpTime(bp, "%m/%d/%y", tm))) return (0);
139
        break;
140

141
      case 'R': /* The time as "%H:%M". */
142
        LEGAL_ALT(0);
143
        if (!(bp = taosStrpTime(bp, "%H:%M", tm))) return (0);
144
        break;
145

146
      case 'r': /* The time in 12-hour clock representation. */
147
        LEGAL_ALT(0);
148
        if (!(bp = taosStrpTime(bp, "%I:%M:%S %p", tm))) return (0);
149
        break;
150

151
      case 'T': /* The time as "%H:%M:%S". */
152
        LEGAL_ALT(0);
153
        if (!(bp = taosStrpTime(bp, "%H:%M:%S", tm))) return (0);
154
        break;
155

156
      case 'X': /* The time, using the locale's format. */
157
        LEGAL_ALT(ALT_E);
158
        if (!(bp = taosStrpTime(bp, "%H:%M:%S", tm))) return (0);
159
        break;
160

161
      case 'x': /* The date, using the locale's format. */
162
        LEGAL_ALT(ALT_E);
163
        if (!(bp = taosStrpTime(bp, "%m/%d/%y", tm))) return (0);
164
        break;
165

166
        /*
167
         * "Elementary" conversion rules.
168
         */
169
      case 'A': /* The day of week, using the locale's form. */
170
      case 'a':
171
        LEGAL_ALT(0);
172
        for (i = 0; i < 7; i++) {
173
          /* Full name. */
174
          len = strlen(day[i]);
175
          if (strncmp(day[i], bp, len) == 0) break;
176

177
          /* Abbreviated name. */
178
          len = strlen(abday[i]);
179
          if (strncmp(abday[i], bp, len) == 0) break;
180
        }
181

182
        /* Nothing matched. */
183
        if (i == 7) return (0);
184

185
        tm->tm_wday = i;
186
        bp += len;
187
        break;
188

189
      case 'B': /* The month, using the locale's form. */
190
      case 'b':
191
      case 'h':
192
        LEGAL_ALT(0);
193
        for (i = 0; i < 12; i++) {
194
          /* Full name. */
195
          len = strlen(mon[i]);
196
          if (strncmp(mon[i], bp, len) == 0) break;
197

198
          /* Abbreviated name. */
199
          len = strlen(abmon[i]);
200
          if (strncmp(abmon[i], bp, len) == 0) break;
201
        }
202

203
        /* Nothing matched. */
204
        if (i == 12) return (0);
205

206
        tm->tm_mon = i;
207
        bp += len;
208
        break;
209

210
      case 'C': /* The century number. */
211
        LEGAL_ALT(ALT_E);
212
        if (!(conv_num(&bp, &i, 0, 99))) return (0);
213

214
        if (split_year) {
215
          tm->tm_year = (tm->tm_year % 100) + (i * 100);
216
        } else {
217
          tm->tm_year = i * 100;
218
          split_year = 1;
219
        }
220
        break;
221

222
      case 'd': /* The day of month. */
223
      case 'e':
224
        LEGAL_ALT(ALT_O);
225
        if (!(conv_num(&bp, &tm->tm_mday, 1, 31))) return (0);
226
        break;
227

228
      case 'k': /* The hour (24-hour clock representation). */
229
        LEGAL_ALT(0);
230
        /* FALLTHROUGH */
231
      case 'H':
232
        LEGAL_ALT(ALT_O);
233
        if (!(conv_num(&bp, &tm->tm_hour, 0, 23))) return (0);
234
        break;
235

236
      case 'l': /* The hour (12-hour clock representation). */
237
        LEGAL_ALT(0);
238
        /* FALLTHROUGH */
239
      case 'I':
240
        LEGAL_ALT(ALT_O);
241
        if (!(conv_num(&bp, &tm->tm_hour, 1, 12))) return (0);
242
        if (tm->tm_hour == 12) tm->tm_hour = 0;
243
        break;
244

245
      case 'j': /* The day of year. */
246
        LEGAL_ALT(0);
247
        if (!(conv_num(&bp, &i, 1, 366))) return (0);
248
        tm->tm_yday = i - 1;
249
        break;
250

251
      case 'M': /* The minute. */
252
        LEGAL_ALT(ALT_O);
253
        if (!(conv_num(&bp, &tm->tm_min, 0, 59))) return (0);
254
        break;
255

256
      case 'm': /* The month. */
257
        LEGAL_ALT(ALT_O);
258
        if (!(conv_num(&bp, &i, 1, 12))) return (0);
259
        tm->tm_mon = i - 1;
260
        break;
261

262
      case 'p': /* The locale's equivalent of AM/PM. */
263
        LEGAL_ALT(0);
264
        /* AM? */
265
        if (strcmp(am_pm[0], bp) == 0) {
266
          if (tm->tm_hour > 11) return (0);
267

268
          bp += strlen(am_pm[0]);
269
          break;
270
        }
271
        /* PM? */
272
        else if (strcmp(am_pm[1], bp) == 0) {
273
          if (tm->tm_hour > 11) return (0);
274

275
          tm->tm_hour += 12;
276
          bp += strlen(am_pm[1]);
277
          break;
278
        }
279

280
        /* Nothing matched. */
281
        return (0);
282

283
      case 'S': /* The seconds. */
284
        LEGAL_ALT(ALT_O);
285
        if (!(conv_num(&bp, &tm->tm_sec, 0, 61))) return (0);
286
        break;
287

288
      case 'U': /* The week of year, beginning on sunday. */
289
      case 'W': /* The week of year, beginning on monday. */
290
        LEGAL_ALT(ALT_O);
291
        /*
292
         * XXX This is bogus, as we can not assume any valid
293
         * information present in the tm structure at this
294
         * point to calculate a real value, so just check the
295
         * range for now.
296
         */
297
        if (!(conv_num(&bp, &i, 0, 53))) return (0);
298
        break;
299

300
      case 'w': /* The day of week, beginning on sunday. */
301
        LEGAL_ALT(ALT_O);
302
        if (!(conv_num(&bp, &tm->tm_wday, 0, 6))) return (0);
303
        break;
304

305
      case 'Y': /* The year. */
306
        LEGAL_ALT(ALT_E);
307
        if (!(conv_num(&bp, &i, 0, 9999))) return (0);
308

309
        tm->tm_year = i - TM_YEAR_BASE;
310
        break;
311

312
      case 'y': /* The year within 100 years of the epoch. */
313
        LEGAL_ALT(ALT_E | ALT_O);
314
        if (!(conv_num(&bp, &i, 0, 99))) return (0);
315

316
        if (split_year) {
317
          tm->tm_year = ((tm->tm_year / 100) * 100) + i;
318
          break;
319
        }
320
        split_year = 1;
321
        if (i <= 68)
322
          tm->tm_year = i + 2000 - TM_YEAR_BASE;
323
        else
324
          tm->tm_year = i + 1900 - TM_YEAR_BASE;
325
        break;
326

327
        /*
328
         * Miscellaneous conversions.
329
         */
330
      case 'n': /* Any kind of white-space. */
331
      case 't':
332
        LEGAL_ALT(0);
333
        while (isspace(*bp)) bp++;
334
        break;
335

336
      default: /* Unknown/unsupported conversion. */
337
        return (0);
338
    }
339
  }
340

341
  /* LINTED functional specification */
342
  return ((char *)bp);
343
#else
344
  return strptime(buf, fmt, tm);
3,352,632✔
345
#endif
346
}
347

348
size_t taosStrfTime(char *s, size_t maxsize, char const *format, struct tm const *t) {
53,331,478✔
349
  if (!s || !format || !t) return 0;
53,331,478!
350
  return strftime(s, maxsize, format, t);
53,331,503✔
351
}
352

353
int32_t taosGetTimeOfDay(struct timeval *tv) {
1,068,011,815✔
354
  if (tv == NULL) {
1,068,011,815✔
355
    return TSDB_CODE_INVALID_PARA;
1✔
356
  }
357
  int32_t code = 0;
1,068,011,814✔
358
#ifdef WINDOWS
359
  LARGE_INTEGER t;
360
  FILETIME      f;
361

362
  GetSystemTimeAsFileTime(&f);
363
  t.QuadPart = f.dwHighDateTime;
364
  t.QuadPart <<= 32;
365
  t.QuadPart |= f.dwLowDateTime;
366

367
  t.QuadPart -= TIMEEPOCH;
368
  tv->tv_sec = t.QuadPart / 10000000;
369
  tv->tv_usec = (t.QuadPart % 10000000) / 10;
370
  return 0;
371
#else
372
  code = gettimeofday(tv, NULL);
1,068,011,814✔
373
  return (-1 == code) ? (terrno = TAOS_SYSTEM_ERROR(ERRNO)) : 0;
1,068,431,114!
374
#endif
375
}
376

377
int32_t taosTime(time_t *t) {
126,225✔
378
  if (t == NULL) {
126,225✔
379
    return TSDB_CODE_INVALID_PARA;
1✔
380
  }
381
  time_t r = time(t);
126,224✔
382
  if (r == (time_t)-1) {
126,224!
383
    return TAOS_SYSTEM_ERROR(ERRNO);
×
384
  }
385
  return 0;
126,224✔
386
}
387

388
/*
389
 * mktime64 - Converts date to seconds.
390
 * Converts Gregorian date to seconds since 1970-01-01 00:00:00.
391
 * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
392
 * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
393
 *
394
 * [For the Julian calendar (which was used in Russia before 1917,
395
 * Britain & colonies before 1752, anywhere else before 1582,
396
 * and is still in use by some communities) leave out the
397
 * -year/100+year/400 terms, and add 10.]
398
 *
399
 * This algorithm was first published by Gauss (I think).
400
 *
401
 * A leap second can be indicated by calling this function with sec as
402
 * 60 (allowable under ISO 8601).  The leap second is treated the same
403
 * as the following second since they don't exist in UNIX time.
404
 *
405
 * An encoding of midnight at the end of the day as 24:00:00 - ie. midnight
406
 * tomorrow - (allowable under ISO 8601) is supported.
407
 */
408
int64_t user_mktime64(const uint32_t year, const uint32_t mon, const uint32_t day, const uint32_t hour,
2✔
409
                      const uint32_t min, const uint32_t sec, int64_t time_zone) {
410
  uint32_t _mon = mon, _year = year;
2✔
411

412
  /* 1..12 -> 11,12,1..10 */
413
  if (0 >= (int32_t)(_mon -= 2)) {
2✔
414
    _mon += 12; /* Puts Feb last since it has leap day */
1✔
415
    _year -= 1;
1✔
416
  }
417

418
  // int64_t _res = (((((int64_t) (_year/4 - _year/100 + _year/400 + 367*_mon/12 + day) +
419
  //                _year*365 - 719499)*24 + hour)*60 + min)*60 + sec);
420
  int64_t _res = 367 * ((int64_t)_mon) / 12;
2✔
421
  _res += _year / 4 - _year / 100 + _year / 400 + day + ((int64_t)_year) * 365 - 719499;
2✔
422
  _res *= 24;
2✔
423
  _res = ((_res + hour) * 60 + min) * 60 + sec;
2✔
424

425
  return _res + time_zone;
2✔
426
}
427

428
time_t taosMktime(struct tm *timep, timezone_t tz) {
2,009,435✔
429
#ifdef WINDOWS
430
  time_t result = mktime(timep);
431
  if (result != -1) {
432
    return result;
433
  }
434
  int64_t tzw = 0;
435
#ifdef _MSC_VER
436
#if _MSC_VER >= 1900
437
  tzw = _timezone;
438
#endif
439
#endif
440
  return user_mktime64(timep->tm_year + 1900, timep->tm_mon + 1, timep->tm_mday, timep->tm_hour, timep->tm_min,
441
                       timep->tm_sec, tzw);
442
#elif defined(TD_ASTRA)
443
  time_t r =  mktime(timep);
444
  if (r == (time_t)-1) {
445
    terrno = TAOS_SYSTEM_ERROR(ERRNO);
446
  }
447
  return r;
448
#else
449
  time_t r = (tz != NULL ? mktime_z(tz, timep) : mktime(timep));
2,009,435✔
450
  if (r == (time_t)-1) {
2,009,447!
451
    terrno = TAOS_SYSTEM_ERROR(ERRNO);
×
452
  }
453
  timezone = -timep->tm_gmtoff;
2,009,447✔
454
  return r;
2,009,447✔
455
#endif
456
}
457

458
struct tm *taosGmTimeR(const time_t *timep, struct tm *result) {
479,937✔
459
  if (timep == NULL || result == NULL) {
479,937!
460
    return NULL;
×
461
  }
462
#ifdef WINDOWS
463
  errno_t code = gmtime_s(result, timep);
464
  return (code == 0) ? result : NULL;
465
#else
466
  return gmtime_r(timep, result);
479,958✔
467
#endif
468
}
469

470
time_t taosTimeGm(struct tm *tmp) {
275,230✔
471
  if (tmp == NULL) {
275,230✔
472
    return -1;
1✔
473
  }
474
#ifdef WINDOWS
475
  return _mkgmtime(tmp);
476
#elif defined(TD_ASTRA)
477
  time_t    local = mktime(tmp);
478
  struct tm local_tm = *localtime(&local);
479
  struct tm utc_tm = *gmtime(&local);
480
  time_t    offset = (local_tm.tm_hour - utc_tm.tm_hour) * 3600 + (local_tm.tm_min - utc_tm.tm_min) * 60 +
481
                  (local_tm.tm_sec - utc_tm.tm_sec);
482
  return local - offset;
483
#else
484
  return timegm(tmp);
275,229✔
485
#endif
486
}
487

488
struct tm *taosLocalTime(const time_t *timep, struct tm *result, char *buf, int32_t bufSize, timezone_t tz) {
740,713,969✔
489
  struct tm *res = NULL;
740,713,969✔
490
  if (timep == NULL || result == NULL) {
740,713,969!
491
    return NULL;
×
492
  }
493
#ifdef WINDOWS
494
  if (*timep < -2208988800LL) {
495
    if (buf != NULL) {
496
      snprintf(buf, bufSize, "NaN");
497
    }
498
    return NULL;
499
  } else if (*timep < 0) {
500
    SYSTEMTIME ss, s;
501
    FILETIME   ff, f;
502

503
    LARGE_INTEGER offset;
504
    struct tm     tm1;
505
    time_t        tt = 0;
506
    if (localtime_s(&tm1, &tt) != 0) {
507
      if (buf != NULL) {
508
        snprintf(buf, bufSize, "NaN");
509
      }
510
      return NULL;
511
    }
512
    ss.wYear = tm1.tm_year + 1900;
513
    ss.wMonth = tm1.tm_mon + 1;
514
    ss.wDay = tm1.tm_mday;
515
    ss.wHour = tm1.tm_hour;
516
    ss.wMinute = tm1.tm_min;
517
    ss.wSecond = tm1.tm_sec;
518
    ss.wMilliseconds = 0;
519
    SystemTimeToFileTime(&ss, &ff);
520
    offset.QuadPart = ff.dwHighDateTime;
521
    offset.QuadPart <<= 32;
522
    offset.QuadPart |= ff.dwLowDateTime;
523
    offset.QuadPart += *timep * 10000000;
524
    f.dwLowDateTime = offset.QuadPart & 0xffffffff;
525
    f.dwHighDateTime = (offset.QuadPart >> 32) & 0xffffffff;
526
    FileTimeToSystemTime(&f, &s);
527
    result->tm_sec = s.wSecond;
528
    result->tm_min = s.wMinute;
529
    result->tm_hour = s.wHour;
530
    result->tm_mday = s.wDay;
531
    result->tm_mon = s.wMonth - 1;
532
    result->tm_year = s.wYear - 1900;
533
    result->tm_wday = s.wDayOfWeek;
534
    result->tm_yday = 0;
535
    result->tm_isdst = 0;
536
  } else {
537
    if (localtime_s(result, timep) != 0) {
538
      if (buf != NULL) {
539
        snprintf(buf, bufSize, "NaN");
540
      }
541
      return NULL;
542
    }
543
  }
544
  return result;
545
#elif defined(TD_ASTRA)
546
  res = localtime_r(timep, result);
547
  if (res == NULL && buf != NULL) {
548
    (void)sprintf(buf, "NaN");
549
  }
550
  return res;
551
#else
552
  res = (tz != NULL ? localtime_rz(tz, timep, result) : localtime_r(timep, result));
740,767,736✔
553
  if (res == NULL && buf != NULL) {
741,149,166!
554
    (void)snprintf(buf, bufSize, "NaN");
×
555
  }
556
  timezone = -result->tm_gmtoff;
741,149,166✔
557
  return res;
741,149,166✔
558
#endif
559
}
560

561
int32_t taosGetTimestampSec() { return (int32_t)time(NULL); }
6,606,398✔
562

563
int32_t taosClockGetTime(int clock_id, struct timespec *pTS) {
11,321,504✔
564
  int32_t code = 0;
11,321,504✔
565
#ifdef WINDOWS
566
  LARGE_INTEGER t;
567
  FILETIME      f;
568

569
  GetSystemTimeAsFileTime(&f);
570
  t.QuadPart = f.dwHighDateTime;
571
  t.QuadPart <<= 32;
572
  t.QuadPart |= f.dwLowDateTime;
573

574
  t.QuadPart -= TIMEEPOCH;
575
  pTS->tv_sec = t.QuadPart / 10000000;
576
  pTS->tv_nsec = (t.QuadPart % 10000000) * 100;
577
  return (0);
578
#else
579
  code = clock_gettime(clock_id, pTS);
11,321,504✔
580
  return (-1 == code) ? (terrno = TAOS_SYSTEM_ERROR(ERRNO)) : 0;
11,322,548!
581
#endif
582
}
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