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

16
#define _BSD_SOURCE
H
hzcheng 已提交
17
#define _XOPEN_SOURCE
S
slguan 已提交
18
#define _DEFAULT_SOURCE
H
hzcheng 已提交
19

S
Shengliang Guan 已提交
20
#include "os.h"
S
slguan 已提交
21
#include "taosdef.h"
H
hzcheng 已提交
22
#include "tutil.h"
S
Shengliang Guan 已提交
23

L
lihui 已提交
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
/*
 * mktime64 - Converts date to seconds.
 * Converts Gregorian date to seconds since 1970-01-01 00:00:00.
 * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
 * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
 *
 * [For the Julian calendar (which was used in Russia before 1917,
 * Britain & colonies before 1752, anywhere else before 1582,
 * and is still in use by some communities) leave out the
 * -year/100+year/400 terms, and add 10.]
 *
 * This algorithm was first published by Gauss (I think).
 *
 * A leap second can be indicated by calling this function with sec as
 * 60 (allowable under ISO 8601).  The leap second is treated the same
 * as the following second since they don't exist in UNIX time.
 *
 * An encoding of midnight at the end of the day as 24:00:00 - ie. midnight
 * tomorrow - (allowable under ISO 8601) is supported.
 */
L
[#1199]  
lihui 已提交
44
int64_t user_mktime64(const unsigned int year0, const unsigned int mon0,
L
lihui 已提交
45
		const unsigned int day, const unsigned int hour,
46
		const unsigned int min, const unsigned int sec, int64_t time_zone)
L
lihui 已提交
47
{
H
Haojun Liao 已提交
48
  unsigned int mon = mon0, year = year0;
L
lihui 已提交
49

H
Haojun Liao 已提交
50 51 52 53 54
  /* 1..12 -> 11,12,1..10 */
  if (0 >= (int) (mon -= 2)) {
    mon += 12;	/* Puts Feb last since it has leap day */
    year -= 1;
  }
L
lihui 已提交
55

H
Hui Li 已提交
56 57 58 59
  //int64_t res = (((((int64_t) (year/4 - year/100 + year/400 + 367*mon/12 + day) +
  //               year*365 - 719499)*24 + hour)*60 + min)*60 + sec);
  int64_t res;
  res  = 367*((int64_t)mon)/12;
H
Hui Li 已提交
60
  res += year/4 - year/100 + year/400 + day + ((int64_t)year)*365 - 719499;
H
Hui Li 已提交
61
  res  = res*24;
H
Hui Li 已提交
62
  res  = ((res + hour) * 60 + min) * 60 + sec;
L
lihui 已提交
63

64
  return (res + time_zone);
L
lihui 已提交
65
}
66

L
lihui 已提交
67 68 69 70 71 72 73 74 75 76 77
// ==== mktime() kernel code =================//
static int64_t m_deltaUtc = 0;
void deltaToUtcInitOnce() {  
  struct tm tm = {0};
  
  (void)strptime("1970-01-01 00:00:00", (const char *)("%Y-%m-%d %H:%M:%S"), &tm);
  m_deltaUtc = (int64_t)mktime(&tm);
  //printf("====delta:%lld\n\n", seconds);	
  return;
}

H
hzcheng 已提交
78 79 80
static int64_t parseFraction(char* str, char** end, int32_t timePrec);
static int32_t parseTimeWithTz(char* timestr, int64_t* time, int32_t timePrec);
static int32_t parseLocaltime(char* timestr, int64_t* time, int32_t timePrec);
dengyihao's avatar
dengyihao 已提交
81 82 83 84 85 86
static int32_t parseLocaltimeWithDst(char* timestr, int64_t* time, int32_t timePrec);

static int32_t (*parseLocaltimeFp[]) (char* timestr, int64_t* time, int32_t timePrec) = {
  parseLocaltime,
  parseLocaltimeWithDst
}; 
H
hzcheng 已提交
87 88 89

int32_t taosGetTimestampSec() { return (int32_t)time(NULL); }

90
int32_t taosParseTime(char* timestr, int64_t* time, int32_t len, int32_t timePrec, int8_t day_light) {
H
hzcheng 已提交
91
  /* parse datatime string in with tz */
S
slguan 已提交
92
  if (strnchr(timestr, 'T', len, false) != NULL) {
H
hzcheng 已提交
93 94
    return parseTimeWithTz(timestr, time, timePrec);
  } else {
95
    return (*parseLocaltimeFp[day_light])(timestr, time, timePrec);
H
hzcheng 已提交
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
  }
}

char* forwardToTimeStringEnd(char* str) {
  int32_t i = 0;
  int32_t numOfSep = 0;

  while (str[i] != 0 && numOfSep < 2) {
    if (str[i++] == ':') {
      numOfSep++;
    }
  }

  while (str[i] >= '0' && str[i] <= '9') {
    i++;
  }

  return &str[i];
}

int64_t parseFraction(char* str, char** end, int32_t timePrec) {
  int32_t i = 0;
  int64_t fraction = 0;

  const int32_t MILLI_SEC_FRACTION_LEN = 3;
  const int32_t MICRO_SEC_FRACTION_LEN = 6;

  int32_t factor[6] = {1, 10, 100, 1000, 10000, 100000};
  int32_t times = 1;

  while (str[i] >= '0' && str[i] <= '9') {
    i++;
  }

  int32_t totalLen = i;
  if (totalLen <= 0) {
    return -1;
  }

  /* parse the fraction */
  if (timePrec == TSDB_TIME_PRECISION_MILLI) {
    /* only use the initial 3 bits */
    if (i >= MILLI_SEC_FRACTION_LEN) {
      i = MILLI_SEC_FRACTION_LEN;
    }

    times = MILLI_SEC_FRACTION_LEN - i;
  } else {
    assert(timePrec == TSDB_TIME_PRECISION_MICRO);
    if (i >= MICRO_SEC_FRACTION_LEN) {
      i = MICRO_SEC_FRACTION_LEN;
    }
    times = MICRO_SEC_FRACTION_LEN - i;
  }

  fraction = strnatoi(str, i) * factor[times];
  *end = str + totalLen;

  return fraction;
}

int32_t parseTimezone(char* str, int64_t* tzOffset) {
  int64_t hour = 0;

  int32_t i = 0;
  if (str[i] != '+' && str[i] != '-') {
    return -1;
  }

  i++;

  char* sep = strchr(&str[i], ':');
  if (sep != NULL) {
S
slguan 已提交
169
    int32_t len = (int32_t)(sep - &str[i]);
H
hzcheng 已提交
170 171 172 173 174 175 176 177

    hour = strnatoi(&str[i], len);
    i += len + 1;
  } else {
    hour = strnatoi(&str[i], 2);
    i += 2;
  }

weixin_48148422's avatar
weixin_48148422 已提交
178 179
  int64_t minute = strnatoi(&str[i], 2);
  if (minute > 59) {
H
hzcheng 已提交
180 181 182 183
    return -1;
  }

  if (str[0] == '+') {
weixin_48148422's avatar
weixin_48148422 已提交
184
    *tzOffset = -(hour * 3600 + minute * 60);
H
hzcheng 已提交
185
  } else {
weixin_48148422's avatar
weixin_48148422 已提交
186
    *tzOffset = hour * 3600 + minute * 60;
H
hzcheng 已提交
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
  }

  return 0;
}

/*
 * rfc3339 format:
 * 2013-04-12T15:52:01+08:00
 * 2013-04-12T15:52:01.123+08:00
 *
 * 2013-04-12T15:52:01Z
 * 2013-04-12T15:52:01.123Z
 *
 * iso-8601 format:
 * 2013-04-12T15:52:01+0800
 * 2013-04-12T15:52:01.123+0800
 */
int32_t parseTimeWithTz(char* timestr, int64_t* time, int32_t timePrec) {
  int64_t factor = (timePrec == TSDB_TIME_PRECISION_MILLI) ? 1000 : 1000000;
  int64_t tzOffset = 0;

  struct tm tm = {0};
  char*     str = strptime(timestr, "%Y-%m-%dT%H:%M:%S", &tm);
  if (str == NULL) {
    return -1;
  }

S
slguan 已提交
214 215
/* mktime will be affected by TZ, set by using taos_options */
#ifdef WINDOWS
216
  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);
S
slguan 已提交
217
  //int64_t seconds = gmtime(&tm); 
S
slguan 已提交
218
#else
H
hzcheng 已提交
219
  int64_t seconds = timegm(&tm);
S
slguan 已提交
220
#endif
H
hzcheng 已提交
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272

  int64_t fraction = 0;
  str = forwardToTimeStringEnd(timestr);

  if (str[0] == 'Z' || str[0] == 'z') {
    /* utc time, no millisecond, return directly*/
    *time = seconds * factor;
  } else if (str[0] == '.') {
    str += 1;
    if ((fraction = parseFraction(str, &str, timePrec)) < 0) {
      return -1;
    }

    *time = seconds * factor + fraction;

    char seg = str[0];
    if (seg != 'Z' && seg != 'z' && seg != '+' && seg != '-') {
      return -1;
    } else if (seg == '+' || seg == '-') {
      // parse the timezone
      if (parseTimezone(str, &tzOffset) == -1) {
        return -1;
      }

      *time += tzOffset * factor;
    }

  } else if (str[0] == '+' || str[0] == '-') {
    *time = seconds * factor + fraction;

    // parse the timezone
    if (parseTimezone(str, &tzOffset) == -1) {
      return -1;
    }

    *time += tzOffset * factor;
  } else {
    return -1;
  }

  return 0;
}

int32_t parseLocaltime(char* timestr, int64_t* time, int32_t timePrec) {
  *time = 0;
  struct tm tm = {0};

  char* str = strptime(timestr, "%Y-%m-%d %H:%M:%S", &tm);
  if (str == NULL) {
    return -1;
  }

273 274 275 276 277 278 279
#ifdef _MSC_VER
#if _MSC_VER >= 1900
  int64_t timezone = _timezone;
#endif
#endif

  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, timezone);
L
lihui 已提交
280
  
H
hzcheng 已提交
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
  int64_t fraction = 0;

  if (*str == '.') {
    /* parse the second fraction part */
    if ((fraction = parseFraction(str + 1, &str, timePrec)) < 0) {
      return -1;
    }
  }

  int64_t factor = (timePrec == TSDB_TIME_PRECISION_MILLI) ? 1000 : 1000000;
  *time = factor * seconds + fraction;

  return 0;
}

dengyihao's avatar
dengyihao 已提交
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321
int32_t parseLocaltimeWithDst(char* timestr, int64_t* time, int32_t timePrec) {
  *time = 0;
  struct tm tm = {0};
  tm.tm_isdst = -1;

  char* str = strptime(timestr, "%Y-%m-%d %H:%M:%S", &tm);
  if (str == NULL) {
    return -1;
  }

  /* mktime will be affected by TZ, set by using taos_options */
  int64_t seconds = mktime(&tm);
  
  int64_t fraction = 0;

  if (*str == '.') {
    /* parse the second fraction part */
    if ((fraction = parseFraction(str + 1, &str, timePrec)) < 0) {
      return -1;
    }
  }

  int64_t factor = (timePrec == TSDB_TIME_PRECISION_MILLI) ? 1000 : 1000000;
  *time = factor * seconds + fraction;
  return 0;
}
B
Bomin Zhang 已提交
322 323


324
static int32_t getDurationInUs(int64_t val, char unit, int64_t* result) {
H
hzcheng 已提交
325 326
  *result = val;

H
Haojun Liao 已提交
327 328
  int64_t factor = 1000L;

H
hzcheng 已提交
329 330
  switch (unit) {
    case 's':
H
Haojun Liao 已提交
331
      (*result) *= MILLISECOND_PER_SECOND*factor;
H
hzcheng 已提交
332 333
      break;
    case 'm':
H
Haojun Liao 已提交
334
      (*result) *= MILLISECOND_PER_MINUTE*factor;
H
hzcheng 已提交
335 336
      break;
    case 'h':
H
Haojun Liao 已提交
337
      (*result) *= MILLISECOND_PER_HOUR*factor;
H
hzcheng 已提交
338 339
      break;
    case 'd':
H
Haojun Liao 已提交
340
      (*result) *= MILLISECOND_PER_DAY*factor;
H
hzcheng 已提交
341 342
      break;
    case 'w':
H
Haojun Liao 已提交
343
      (*result) *= MILLISECOND_PER_WEEK*factor;
H
hzcheng 已提交
344 345
      break;
    case 'a':
H
Haojun Liao 已提交
346 347 348
      (*result) *= factor;
      break;
    case 'u':
H
hzcheng 已提交
349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368
      break;
    default: {
      return -1;
    }
  }

  /* get the value in microsecond */
  return 0;
}

/*
 * a - Millionseconds
 * s - Seconds
 * m - Minutes
 * h - Hours
 * d - Days (24 hours)
 * w - Weeks (7 days)
 * n - Months (30 days)
 * y - Years (365 days)
 */
369
int32_t parseAbsoluteDuration(char* token, int32_t tokenlen, int64_t* duration) {
H
hzcheng 已提交
370 371 372 373 374 375 376 377 378
  errno = 0;
  char* endPtr = NULL;

  /* get the basic numeric value */
  int64_t timestamp = strtoll(token, &endPtr, 10);
  if (errno != 0) {
    return -1;
  }

379 380 381 382 383 384 385
  /* natual month/year are not allowed in absolute duration */
  char unit = token[tokenlen - 1];
  if (unit == 'n' || unit == 'y') {
    return -1;
  }

  return getDurationInUs(timestamp, unit, duration);
H
hzcheng 已提交
386
}
387

388
int32_t parseNatualDuration(const char* token, int32_t tokenLen, int64_t* duration, char* unit) {
B
Bomin Zhang 已提交
389 390 391 392 393 394 395 396 397 398 399 400 401
  errno = 0;

  /* get the basic numeric value */
  *duration = strtoll(token, NULL, 10);
  if (errno != 0) {
    return -1;
  }

  *unit = token[tokenLen - 1];
  if (*unit == 'n' || *unit == 'y') {
    return 0;
  }

402
  return getDurationInUs(*duration, *unit, duration);
B
Bomin Zhang 已提交
403 404
}

405 406 407 408 409 410 411 412 413 414 415
int64_t taosTimeAdd(int64_t t, int64_t duration, char unit, int32_t precision) {
  if (duration == 0) {
    return t;
  }
  if (unit == 'y') {
    duration *= 12;
  } else if (unit != 'n') {
    return t + duration;
  }

  struct tm tm;
B
Bomin Zhang 已提交
416
  time_t tt = (time_t)(t / TSDB_TICK_PER_SECOND(precision));
417 418 419 420 421
  localtime_r(&tt, &tm);
  int mon = tm.tm_year * 12 + tm.tm_mon + (int)duration;
  tm.tm_year = mon / 12;
  tm.tm_mon = mon % 12;

S
Shengliang Guan 已提交
422
  return (int64_t)(mktime(&tm) * TSDB_TICK_PER_SECOND(precision));
B
Bomin Zhang 已提交
423 424 425 426 427 428 429
}

int32_t taosTimeCountInterval(int64_t skey, int64_t ekey, int64_t interval, char unit, int32_t precision) {
  if (ekey < skey) {
    int64_t tmp = ekey;
    ekey = skey;
    skey = tmp;
430
  }
B
Bomin Zhang 已提交
431 432 433 434
  if (unit != 'n' && unit != 'y') {
    return (int32_t)((ekey - skey) / interval);
  }

S
Shengliang Guan 已提交
435 436
  skey /= (int64_t)(TSDB_TICK_PER_SECOND(precision));
  ekey /= (int64_t)(TSDB_TICK_PER_SECOND(precision));
437

B
Bomin Zhang 已提交
438 439 440 441 442 443 444 445 446 447 448 449 450 451
  struct tm tm;
  time_t t = (time_t)skey;
  localtime_r(&t, &tm);
  int smon = tm.tm_year * 12 + tm.tm_mon;

  t = (time_t)ekey;
  localtime_r(&t, &tm);
  int emon = tm.tm_year * 12 + tm.tm_mon;

  if (unit == 'y') {
    interval *= 12;
  }

  return (emon - smon) / (int32_t)interval;
452 453 454 455 456 457 458 459 460
}

int64_t taosTimeTruncate(int64_t t, const SInterval* pInterval, int32_t precision) {
  if (pInterval->sliding == 0) {
    assert(pInterval->interval == 0);
    return t;
  }

  int64_t start = t;
B
Bomin Zhang 已提交
461
  if (pInterval->slidingUnit == 'n' || pInterval->slidingUnit == 'y') {
S
Shengliang Guan 已提交
462
    start /= (int64_t)(TSDB_TICK_PER_SECOND(precision));
463
    struct tm tm;
B
Bomin Zhang 已提交
464 465
    time_t tt = (time_t)start;
    localtime_r(&tt, &tm);
466 467 468 469 470 471 472 473 474 475 476 477 478 479 480
    tm.tm_sec = 0;
    tm.tm_min = 0;
    tm.tm_hour = 0;
    tm.tm_mday = 1;

    if (pInterval->slidingUnit == 'y') {
      tm.tm_mon = 0;
      tm.tm_year = (int)(tm.tm_year / pInterval->sliding * pInterval->sliding);
    } else {
      int mon = tm.tm_year * 12 + tm.tm_mon;
      mon = (int)(mon / pInterval->sliding * pInterval->sliding);
      tm.tm_year = mon / 12;
      tm.tm_mon = mon % 12;
    }

S
Shengliang Guan 已提交
481
    start = (int64_t)(mktime(&tm) * TSDB_TICK_PER_SECOND(precision));
482 483
  } else {
    int64_t delta = t - pInterval->interval;
H
Haojun Liao 已提交
484
    int32_t factor = (delta >= 0) ? 1 : -1;
485 486 487 488

    start = (delta / pInterval->sliding + factor) * pInterval->sliding;

    if (pInterval->intervalUnit == 'd' || pInterval->intervalUnit == 'w') {
489
     /*
490 491 492 493 494 495 496 497 498 499 500
      * here we revised the start time of day according to the local time zone,
      * but in case of DST, the start time of one day need to be dynamically decided.
      */
      // todo refactor to extract function that is available for Linux/Windows/Mac platform
  #if defined(WINDOWS) && _MSC_VER >= 1900
      // see https://docs.microsoft.com/en-us/cpp/c-runtime-library/daylight-dstbias-timezone-and-tzname?view=vs-2019
      int64_t timezone = _timezone;
      int32_t daylight = _daylight;
      char**  tzname = _tzname;
  #endif

S
Shengliang Guan 已提交
501
      start += (int64_t)(timezone * TSDB_TICK_PER_SECOND(precision));
502 503
    }

H
Haojun Liao 已提交
504 505 506
    int64_t end = 0;

    // not enough time range
D
fix bug  
dapan1121 已提交
507
    if (start < 0 || INT64_MAX - start > pInterval->interval - 1) {
508
      end = start + pInterval->interval - 1;
H
Haojun Liao 已提交
509 510 511 512

      while(end < t && ((start + pInterval->sliding) <= INT64_MAX)) { // move forward to the correct time window
        start += pInterval->sliding;

D
fix bug  
dapan1121 已提交
513
        if (start < 0 || INT64_MAX - start > pInterval->interval - 1) {
H
Haojun Liao 已提交
514 515 516 517 518 519 520 521
          end = start + pInterval->interval - 1;
        } else {
          end = INT64_MAX;
          break;
        }
      }
    } else {
      end = INT64_MAX;
522 523 524
    }
  }

B
Bomin Zhang 已提交
525 526 527 528 529 530 531
  if (pInterval->offset > 0) {
    start = taosTimeAdd(start, pInterval->offset, pInterval->offsetUnit, precision);
    if (start > t) {
      start = taosTimeAdd(start, -pInterval->interval, pInterval->intervalUnit, precision);
    }
  }
  return start;
532 533
}

534 535 536 537 538 539 540 541
// internal function, when program is paused in debugger,
// one can call this function from debugger to print a
// timestamp as human readable string, for example (gdb):
//     p fmtts(1593769722)
// outputs:
//     2020-07-03 17:48:42
// and the parameter can also be a variable.
const char* fmtts(int64_t ts) {
B
Bomin Zhang 已提交
542 543 544
  static char buf[96];
  size_t pos = 0;
  struct tm tm;
545 546

  if (ts > -62135625943 && ts < 32503651200) {
B
Bomin Zhang 已提交
547 548 549
    time_t t = (time_t)ts;
    localtime_r(&t, &tm);
    pos += strftime(buf + pos, sizeof(buf), "s=%Y-%m-%d %H:%M:%S", &tm);
550 551
  }

B
Bomin Zhang 已提交
552 553 554 555 556 557 558 559 560 561 562
  if (ts > -62135625943000 && ts < 32503651200000) {
    time_t t = (time_t)(ts / 1000);
    localtime_r(&t, &tm);
    if (pos > 0) {
      buf[pos++] = ' ';
      buf[pos++] = '|';
      buf[pos++] = ' ';
    }
    pos += strftime(buf + pos, sizeof(buf), "ms=%Y-%m-%d %H:%M:%S", &tm);
    pos += sprintf(buf + pos, ".%03d", (int)(ts % 1000));
  }
563

B
Bomin Zhang 已提交
564 565 566 567 568 569 570 571 572 573
  {
    time_t t = (time_t)(ts / 1000000);
    localtime_r(&t, &tm);
    if (pos > 0) {
      buf[pos++] = ' ';
      buf[pos++] = '|';
      buf[pos++] = ' ';
    }
    pos += strftime(buf + pos, sizeof(buf), "us=%Y-%m-%d %H:%M:%S", &tm);
    pos += sprintf(buf + pos, ".%06d", (int)(ts % 1000000));
574 575 576
  }

  return buf;
577
}