ttime.c 27.6 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
#ifdef DARWIN
H
hzcheng 已提交
17
#define _XOPEN_SOURCE
18 19 20 21
#else
#define _XOPEN_SOURCE 500
#endif

S
common  
Shengliang Guan 已提交
22
#define _BSD_SOURCE
S
slguan 已提交
23
#define _DEFAULT_SOURCE
S
Shengliang Guan 已提交
24
#include "ttime.h"
S
Shengliang Guan 已提交
25

S
Shengliang Guan 已提交
26 27
#include "tlog.h"

L
lihui 已提交
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
/*
 * 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.
 */
S
Shengliang Guan 已提交
48 49 50
static int64_t user_mktime64(const uint32_t year0, const uint32_t mon0, const uint32_t day, const uint32_t hour,
                             const uint32_t min, const uint32_t sec, int64_t time_zone) {
  uint32_t mon = mon0, year = year0;
L
lihui 已提交
51

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

S
Shengliang Guan 已提交
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);
H
Hui Li 已提交
60
  int64_t res;
S
Shengliang Guan 已提交
61 62 63 64
  res = 367 * ((int64_t)mon) / 12;
  res += year / 4 - year / 100 + year / 400 + day + ((int64_t)year) * 365 - 719499;
  res = res * 24;
  res = ((res + hour) * 60 + min) * 60 + sec;
L
lihui 已提交
65

66
  return (res + time_zone);
L
lihui 已提交
67
}
68

L
lihui 已提交
69 70
// ==== mktime() kernel code =================//
static int64_t m_deltaUtc = 0;
71

72 73 74 75 76
void deltaToUtcInitOnce() {
  struct tm tm = {0};
  (void)taosStrpTime("1970-01-01 00:00:00", (const char*)("%Y-%m-%d %H:%M:%S"), &tm);
  m_deltaUtc = (int64_t)taosMktime(&tm);
  // printf("====delta:%lld\n\n", seconds);
L
lihui 已提交
77 78
}

H
hzcheng 已提交
79
static int64_t parseFraction(char* str, char** end, int32_t timePrec);
80
static int32_t parseTimeWithTz(const char* timestr, int64_t* time, int32_t timePrec, char delim);
81 82
static int32_t parseLocaltime(char* timestr, int32_t len, int64_t* utime, int32_t timePrec, char delim);
static int32_t parseLocaltimeDst(char* timestr, int32_t len, int64_t* utime, int32_t timePrec, char delim);
S
Shengliang Guan 已提交
83 84
static char*   forwardToTimeStringEnd(char* str);
static bool    checkTzPresent(const char* str, int32_t len);
85
static int32_t parseTimezone(char* str, int64_t* tzOffset);
dengyihao's avatar
dengyihao 已提交
86

H
Hongze Cheng 已提交
87 88
static int32_t (*parseLocaltimeFp[])(char* timestr, int32_t len, int64_t* utime, int32_t timePrec, char delim) = {
    parseLocaltime, parseLocaltimeDst};
H
hzcheng 已提交
89

90
int32_t taosParseTime(const char* timestr, int64_t* utime, 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) {
93 94 95
    if (checkTzPresent(timestr, len)) {
      return parseTimeWithTz(timestr, utime, timePrec, 'T');
    } else {
96
      return parseLocaltimeDst((char*)timestr, len, utime, timePrec, 'T');
97
    }
H
hzcheng 已提交
98
  } else {
99 100 101
    if (checkTzPresent(timestr, len)) {
      return parseTimeWithTz(timestr, utime, timePrec, 0);
    } else {
102
      return parseLocaltimeDst((char*)timestr, len, utime, timePrec, 0);
103
    }
H
hzcheng 已提交
104 105 106
  }
}

S
Shengliang Guan 已提交
107 108
bool checkTzPresent(const char* str, int32_t len) {
  char*   seg = forwardToTimeStringEnd((char*)str);
109 110
  int32_t seg_len = len - (int32_t)(seg - str);

S
Shengliang Guan 已提交
111 112 113
  char* c = &seg[seg_len - 1];
  for (int32_t i = 0; i < seg_len; ++i) {
    if (*c == 'Z' || *c == 'z' || *c == '+' || *c == '-') {
114 115 116 117 118
      return true;
    }
    c--;
  }

119
  return false;
120 121
}

H
hzcheng 已提交
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
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;
145
  const int32_t NANO_SEC_FRACTION_LEN = 9;
H
hzcheng 已提交
146

147
  int32_t factor[9] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000};
H
hzcheng 已提交
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
  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;
167
  } else if (timePrec == TSDB_TIME_PRECISION_MICRO) {
H
hzcheng 已提交
168 169 170 171
    if (i >= MICRO_SEC_FRACTION_LEN) {
      i = MICRO_SEC_FRACTION_LEN;
    }
    times = MICRO_SEC_FRACTION_LEN - i;
G
Ganlin Zhao 已提交
172
  } else if (timePrec == TSDB_TIME_PRECISION_NANO) {
173 174 175 176
    if (i >= NANO_SEC_FRACTION_LEN) {
      i = NANO_SEC_FRACTION_LEN;
    }
    times = NANO_SEC_FRACTION_LEN - i;
G
Ganlin Zhao 已提交
177 178
  } else {
    return -1;
H
hzcheng 已提交
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
  }

  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++;

D
dapan1121 已提交
197 198 199 200
  int32_t j = i;
  while (str[j]) {
    if ((str[j] >= '0' && str[j] <= '9') || str[j] == ':') {
      ++j;
D
dapan1121 已提交
201 202 203 204 205 206
      continue;
    }

    return -1;
  }

H
hzcheng 已提交
207 208
  char* sep = strchr(&str[i], ':');
  if (sep != NULL) {
S
slguan 已提交
209
    int32_t len = (int32_t)(sep - &str[i]);
H
hzcheng 已提交
210 211 212 213 214 215 216 217

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

S
Shengliang Guan 已提交
218 219
  // return error if there're illegal charaters after min(2 Digits)
  char* minStr = &str[i];
220
  if (minStr[1] != '\0' && minStr[2] != '\0') {
S
Shengliang Guan 已提交
221
    return -1;
222 223
  }

weixin_48148422's avatar
weixin_48148422 已提交
224 225
  int64_t minute = strnatoi(&str[i], 2);
  if (minute > 59) {
H
hzcheng 已提交
226 227 228 229
    return -1;
  }

  if (str[0] == '+') {
weixin_48148422's avatar
weixin_48148422 已提交
230
    *tzOffset = -(hour * 3600 + minute * 60);
H
hzcheng 已提交
231
  } else {
weixin_48148422's avatar
weixin_48148422 已提交
232
    *tzOffset = hour * 3600 + minute * 60;
H
hzcheng 已提交
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
  }

  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
 */
250
int32_t parseTimeWithTz(const char* timestr, int64_t* time, int32_t timePrec, char delim) {
251
  int64_t factor = TSDB_TICK_PER_SECOND(timePrec);
H
hzcheng 已提交
252 253 254
  int64_t tzOffset = 0;

  struct tm tm = {0};
255 256 257

  char* str;
  if (delim == 'T') {
wafwerar's avatar
wafwerar 已提交
258
    str = taosStrpTime(timestr, "%Y-%m-%dT%H:%M:%S", &tm);
259
  } else if (delim == 0) {
wafwerar's avatar
wafwerar 已提交
260
    str = taosStrpTime(timestr, "%Y-%m-%d %H:%M:%S", &tm);
261 262 263 264
  } else {
    str = NULL;
  }

H
hzcheng 已提交
265 266 267 268
  if (str == NULL) {
    return -1;
  }

S
slguan 已提交
269 270
/* mktime will be affected by TZ, set by using taos_options */
#ifdef WINDOWS
S
Shengliang Guan 已提交
271 272
  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);
  // int64_t seconds = gmtime(&tm);
S
slguan 已提交
273
#else
H
hzcheng 已提交
274
  int64_t seconds = timegm(&tm);
S
slguan 已提交
275
#endif
H
hzcheng 已提交
276 277

  int64_t fraction = 0;
S
Shengliang Guan 已提交
278
  str = forwardToTimeStringEnd((char*)timestr);
H
hzcheng 已提交
279

280
  if ((str[0] == 'Z' || str[0] == 'z') && str[1] == '\0') {
H
hzcheng 已提交
281 282 283 284 285 286 287 288 289 290 291 292 293
    /* 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;
294 295
    } else if ((seg == 'Z' || seg == 'z') && str[1] != '\0') {
      return -1;
H
hzcheng 已提交
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
    } 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;
}

321 322 323 324 325 326 327 328 329
static FORCE_INLINE bool validateTm(struct tm* pTm) {
  if (pTm == NULL) {
    return false;
  }

  int32_t dayOfMonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

  int32_t leapYearMonthDay = 29;
  int32_t year = pTm->tm_year + 1900;
H
Hongze Cheng 已提交
330
  bool    isLeapYear = ((year % 100) == 0) ? ((year % 400) == 0) : ((year % 4) == 0);
331 332 333 334 335 336 337 338 339 340 341

  if (isLeapYear && (pTm->tm_mon == 1)) {
    if (pTm->tm_mday > leapYearMonthDay) {
      return false;
    }
  } else {
    if (pTm->tm_mday > dayOfMonth[pTm->tm_mon]) {
      return false;
    }
  }

H
Hongze Cheng 已提交
342
  return true;
343 344
}

345 346
int32_t parseLocaltime(char* timestr, int32_t len, int64_t* utime, int32_t timePrec, char delim) {
  *utime = 0;
H
hzcheng 已提交
347 348
  struct tm tm = {0};

H
Hongze Cheng 已提交
349
  char* str;
350 351 352 353 354 355 356 357
  if (delim == 'T') {
    str = taosStrpTime(timestr, "%Y-%m-%dT%H:%M:%S", &tm);
  } else if (delim == 0) {
    str = taosStrpTime(timestr, "%Y-%m-%d %H:%M:%S", &tm);
  } else {
    str = NULL;
  }

358
  if (str == NULL || (((str - timestr) < len) && (*str != '.')) || !validateTm(&tm)) {
H
Hongze Cheng 已提交
359
    // if parse failed, try "%Y-%m-%d" format
360 361 362 363
    str = taosStrpTime(timestr, "%Y-%m-%d", &tm);
    if (str == NULL || (((str - timestr) < len) && (*str != '.')) || !validateTm(&tm)) {
      return -1;
    }
H
hzcheng 已提交
364 365
  }

366 367 368 369 370 371
#ifdef _MSC_VER
#if _MSC_VER >= 1900
  int64_t timezone = _timezone;
#endif
#endif

S
Shengliang Guan 已提交
372 373 374
  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);

H
hzcheng 已提交
375 376 377 378 379 380 381 382 383
  int64_t fraction = 0;

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

384
  *utime = TSDB_TICK_PER_SECOND(timePrec) * seconds + fraction;
H
hzcheng 已提交
385 386 387
  return 0;
}

388 389
int32_t parseLocaltimeDst(char* timestr, int32_t len, int64_t* utime, int32_t timePrec, char delim) {
  *utime = 0;
dengyihao's avatar
dengyihao 已提交
390 391 392
  struct tm tm = {0};
  tm.tm_isdst = -1;

H
Hongze Cheng 已提交
393
  char* str;
394 395 396 397 398 399 400 401
  if (delim == 'T') {
    str = taosStrpTime(timestr, "%Y-%m-%dT%H:%M:%S", &tm);
  } else if (delim == 0) {
    str = taosStrpTime(timestr, "%Y-%m-%d %H:%M:%S", &tm);
  } else {
    str = NULL;
  }

402
  if (str == NULL || (((str - timestr) < len) && (*str != '.')) || !validateTm(&tm)) {
H
Hongze Cheng 已提交
403
    // if parse failed, try "%Y-%m-%d" format
404 405 406 407
    str = taosStrpTime(timestr, "%Y-%m-%d", &tm);
    if (str == NULL || (((str - timestr) < len) && (*str != '.')) || !validateTm(&tm)) {
      return -1;
    }
dengyihao's avatar
dengyihao 已提交
408 409 410
  }

  /* mktime will be affected by TZ, set by using taos_options */
411
  int64_t seconds = taosMktime(&tm);
S
Shengliang Guan 已提交
412

dengyihao's avatar
dengyihao 已提交
413 414 415 416 417 418 419 420
  int64_t fraction = 0;
  if (*str == '.') {
    /* parse the second fraction part */
    if ((fraction = parseFraction(str + 1, &str, timePrec)) < 0) {
      return -1;
    }
  }

421
  *utime = TSDB_TICK_PER_SECOND(timePrec) * seconds + fraction;
dengyihao's avatar
dengyihao 已提交
422 423
  return 0;
}
B
Bomin Zhang 已提交
424

D
dapan1121 已提交
425 426 427 428 429 430 431 432 433 434 435 436
char getPrecisionUnit(int32_t precision) {
  static char units[3] = {TIME_UNIT_MILLISECOND, TIME_UNIT_MICROSECOND, TIME_UNIT_NANOSECOND};
  switch (precision) {
    case TSDB_TIME_PRECISION_MILLI:
    case TSDB_TIME_PRECISION_MICRO:
    case TSDB_TIME_PRECISION_NANO:
      return units[precision];
    default:
      return 0;
  }
}

437
int64_t convertTimePrecision(int64_t utime, int32_t fromPrecision, int32_t toPrecision) {
438
  ASSERT(fromPrecision == TSDB_TIME_PRECISION_MILLI || fromPrecision == TSDB_TIME_PRECISION_MICRO ||
439
         fromPrecision == TSDB_TIME_PRECISION_NANO);
440
  ASSERT(toPrecision == TSDB_TIME_PRECISION_MILLI || toPrecision == TSDB_TIME_PRECISION_MICRO ||
441
         toPrecision == TSDB_TIME_PRECISION_NANO);
442

H
Hongze Cheng 已提交
443
  switch (fromPrecision) {
444 445 446
    case TSDB_TIME_PRECISION_MILLI: {
      switch (toPrecision) {
        case TSDB_TIME_PRECISION_MILLI:
447
          return utime;
448
        case TSDB_TIME_PRECISION_MICRO:
449 450 451
          if (utime > INT64_MAX / 1000) {
            return INT64_MAX;
          }
G
Ganlin Zhao 已提交
452
          return utime * 1000;
453
        case TSDB_TIME_PRECISION_NANO:
454 455 456
          if (utime > INT64_MAX / 1000000) {
            return INT64_MAX;
          }
G
Ganlin Zhao 已提交
457
          return utime * 1000000;
G
Ganlin Zhao 已提交
458
        default:
459
          ASSERT(0);
G
Ganlin Zhao 已提交
460
          return utime;
461
      }
H
Hongze Cheng 已提交
462
    }  // end from milli
463 464 465
    case TSDB_TIME_PRECISION_MICRO: {
      switch (toPrecision) {
        case TSDB_TIME_PRECISION_MILLI:
466
          return utime / 1000;
467
        case TSDB_TIME_PRECISION_MICRO:
468
          return utime;
469
        case TSDB_TIME_PRECISION_NANO:
470 471 472
          if (utime > INT64_MAX / 1000) {
            return INT64_MAX;
          }
G
Ganlin Zhao 已提交
473
          return utime * 1000;
G
Ganlin Zhao 已提交
474
        default:
475
          ASSERT(0);
G
Ganlin Zhao 已提交
476
          return utime;
477
      }
H
Hongze Cheng 已提交
478
    }  // end from micro
479 480 481
    case TSDB_TIME_PRECISION_NANO: {
      switch (toPrecision) {
        case TSDB_TIME_PRECISION_MILLI:
482
          return utime / 1000000;
483
        case TSDB_TIME_PRECISION_MICRO:
484
          return utime / 1000;
485
        case TSDB_TIME_PRECISION_NANO:
486
          return utime;
G
Ganlin Zhao 已提交
487
        default:
488
          ASSERT(0);
G
Ganlin Zhao 已提交
489
          return utime;
490
      }
H
Hongze Cheng 已提交
491
    }  // end from nano
492
    default: {
493
      ASSERT(0);
494
      return utime;  // only to pass windows compilation
495
    }
H
Hongze Cheng 已提交
496
  }  // end switch fromPrecision
497 498

  return utime;
499
}
500

H
Hongze Cheng 已提交
501 502 503
// !!!!notice:there are precision problems, double lose precison if time is too large, for example:
// 1626006833631000000*1.0 = double = 1626006833631000064
// int64_t convertTimePrecision(int64_t time, int32_t fromPrecision, int32_t toPrecision) {
504 505 506 507 508 509 510 511
//  assert(fromPrecision == TSDB_TIME_PRECISION_MILLI || fromPrecision == TSDB_TIME_PRECISION_MICRO ||
//         fromPrecision == TSDB_TIME_PRECISION_NANO);
//  assert(toPrecision == TSDB_TIME_PRECISION_MILLI || toPrecision == TSDB_TIME_PRECISION_MICRO ||
//         toPrecision == TSDB_TIME_PRECISION_NANO);
//  static double factors[3][3] = {{1., 1000., 1000000.}, {1.0 / 1000, 1., 1000.}, {1.0 / 1000000, 1.0 / 1000, 1.}};
//  ((double)time * factors[fromPrecision][toPrecision]);
//}

H
Hongze Cheng 已提交
512 513
// !!!!notice: double lose precison if time is too large, for example: 1626006833631000000*1.0 = double =
// 1626006833631000064
D
dapan1121 已提交
514
int64_t convertTimeFromPrecisionToUnit(int64_t time, int32_t fromPrecision, char toUnit) {
G
Ganlin Zhao 已提交
515 516 517 518 519
  if (fromPrecision != TSDB_TIME_PRECISION_MILLI && fromPrecision != TSDB_TIME_PRECISION_MICRO &&
      fromPrecision != TSDB_TIME_PRECISION_NANO) {
    return -1;
  }

520
  int64_t factors[3] = {NANOSECOND_PER_MSEC, NANOSECOND_PER_USEC, 1};
H
Hongze Cheng 已提交
521
  double  tmp = time;
D
dapan1121 已提交
522
  switch (toUnit) {
H
Hongze Cheng 已提交
523 524
    case 's': {
      time /= (NANOSECOND_PER_SEC / factors[fromPrecision]);
wmmhello's avatar
wmmhello 已提交
525
      tmp = (double)time;
526 527
      break;
    }
D
dapan1121 已提交
528
    case 'm':
H
Hongze Cheng 已提交
529
      time /= (NANOSECOND_PER_MINUTE / factors[fromPrecision]);
wmmhello's avatar
wmmhello 已提交
530
      tmp = (double)time;
531
      break;
D
dapan1121 已提交
532
    case 'h':
H
Hongze Cheng 已提交
533
      time /= (NANOSECOND_PER_HOUR / factors[fromPrecision]);
wmmhello's avatar
wmmhello 已提交
534
      tmp = (double)time;
535
      break;
D
dapan1121 已提交
536
    case 'd':
H
Hongze Cheng 已提交
537
      time /= (NANOSECOND_PER_DAY / factors[fromPrecision]);
wmmhello's avatar
wmmhello 已提交
538
      tmp = (double)time;
539
      break;
D
dapan1121 已提交
540
    case 'w':
H
Hongze Cheng 已提交
541
      time /= (NANOSECOND_PER_WEEK / factors[fromPrecision]);
wmmhello's avatar
wmmhello 已提交
542
      tmp = (double)time;
543
      break;
D
dapan1121 已提交
544
    case 'a':
H
Hongze Cheng 已提交
545
      time /= (NANOSECOND_PER_MSEC / factors[fromPrecision]);
wmmhello's avatar
wmmhello 已提交
546
      tmp = (double)time;
547
      break;
D
dapan1121 已提交
548
    case 'u':
549 550
      // the result of (NANOSECOND_PER_USEC/(double)factors[fromPrecision]) maybe a double
      switch (fromPrecision) {
H
Hongze Cheng 已提交
551
        case TSDB_TIME_PRECISION_MILLI: {
552 553
          tmp *= 1000;
          time *= 1000;
554 555
          break;
        }
H
Hongze Cheng 已提交
556
        case TSDB_TIME_PRECISION_MICRO: {
557
          time /= 1;
wmmhello's avatar
wmmhello 已提交
558
          tmp = (double)time;
559 560
          break;
        }
H
Hongze Cheng 已提交
561
        case TSDB_TIME_PRECISION_NANO: {
562
          time /= 1000;
wmmhello's avatar
wmmhello 已提交
563
          tmp = (double)time;
564 565 566 567
          break;
        }
      }
      break;
D
dapan1121 已提交
568
    case 'b':
569 570 571
      tmp *= factors[fromPrecision];
      time *= factors[fromPrecision];
      break;
D
dapan1121 已提交
572 573 574
    default: {
      return -1;
    }
575
  }
576 577 578
  if (tmp >= (double)INT64_MAX) return INT64_MAX;
  if (tmp <= (double)INT64_MIN) return INT64_MIN;
  return time;
579 580
}

H
Hongze Cheng 已提交
581
int32_t convertStringToTimestamp(int16_t type, char* inputData, int64_t timePrec, int64_t* timeVal) {
582
  int32_t charLen = varDataLen(inputData);
H
Hongze Cheng 已提交
583
  char*   newColData;
X
Xiaoyu Wang 已提交
584
  if (type == TSDB_DATA_TYPE_BINARY || type == TSDB_DATA_TYPE_VARBINARY) {
H
Hongze Cheng 已提交
585
    newColData = taosMemoryCalloc(1, charLen + 1);
586
    memcpy(newColData, varDataVal(inputData), charLen);
D
dapan1121 已提交
587
    int32_t ret = taosParseTime(newColData, timeVal, charLen, (int32_t)timePrec, tsDaylight);
588 589
    if (ret != TSDB_CODE_SUCCESS) {
      taosMemoryFree(newColData);
D
dapan1121 已提交
590
      return TSDB_CODE_INVALID_TIMESTAMP;
591
    }
592 593
    taosMemoryFree(newColData);
  } else if (type == TSDB_DATA_TYPE_NCHAR) {
H
Hongze Cheng 已提交
594 595 596
    newColData = taosMemoryCalloc(1, charLen + TSDB_NCHAR_SIZE);
    int len = taosUcs4ToMbs((TdUcs4*)varDataVal(inputData), charLen, newColData);
    if (len < 0) {
597 598 599 600
      taosMemoryFree(newColData);
      return TSDB_CODE_FAILED;
    }
    newColData[len] = 0;
601
    int32_t ret = taosParseTime(newColData, timeVal, len, (int32_t)timePrec, tsDaylight);
602 603 604 605
    if (ret != TSDB_CODE_SUCCESS) {
      taosMemoryFree(newColData);
      return ret;
    }
606 607 608 609 610
    taosMemoryFree(newColData);
  } else {
    return TSDB_CODE_FAILED;
  }
  return TSDB_CODE_SUCCESS;
D
dapan1121 已提交
611 612
}

613
static int32_t getDuration(int64_t val, char unit, int64_t* result, int32_t timePrecision) {
H
hzcheng 已提交
614 615
  switch (unit) {
    case 's':
616 617 618
      if (val > INT64_MAX / MILLISECOND_PER_SECOND) {
        return -1;
      }
619
      (*result) = convertTimePrecision(val * MILLISECOND_PER_SECOND, TSDB_TIME_PRECISION_MILLI, timePrecision);
H
hzcheng 已提交
620 621
      break;
    case 'm':
622 623 624
      if (val > INT64_MAX / MILLISECOND_PER_MINUTE) {
        return -1;
      }
625
      (*result) = convertTimePrecision(val * MILLISECOND_PER_MINUTE, TSDB_TIME_PRECISION_MILLI, timePrecision);
H
hzcheng 已提交
626 627
      break;
    case 'h':
628 629 630
      if (val > INT64_MAX / MILLISECOND_PER_MINUTE) {
        return -1;
      }
631
      (*result) = convertTimePrecision(val * MILLISECOND_PER_HOUR, TSDB_TIME_PRECISION_MILLI, timePrecision);
H
hzcheng 已提交
632 633
      break;
    case 'd':
634 635 636
      if (val > INT64_MAX / MILLISECOND_PER_DAY) {
        return -1;
      }
637
      (*result) = convertTimePrecision(val * MILLISECOND_PER_DAY, TSDB_TIME_PRECISION_MILLI, timePrecision);
H
hzcheng 已提交
638 639
      break;
    case 'w':
640 641 642
      if (val > INT64_MAX / MILLISECOND_PER_WEEK) {
        return -1;
      }
643
      (*result) = convertTimePrecision(val * MILLISECOND_PER_WEEK, TSDB_TIME_PRECISION_MILLI, timePrecision);
H
hzcheng 已提交
644 645
      break;
    case 'a':
646
      (*result) = convertTimePrecision(val, TSDB_TIME_PRECISION_MILLI, timePrecision);
H
Haojun Liao 已提交
647 648
      break;
    case 'u':
649 650 651 652
      (*result) = convertTimePrecision(val, TSDB_TIME_PRECISION_MICRO, timePrecision);
      break;
    case 'b':
      (*result) = convertTimePrecision(val, TSDB_TIME_PRECISION_NANO, timePrecision);
H
hzcheng 已提交
653 654 655 656 657 658 659 660 661
      break;
    default: {
      return -1;
    }
  }
  return 0;
}

/*
662 663 664 665
 * n - months
 * y - Years
 * is not allowed, since the duration of month or year are both variable.
 *
666 667
 * b - nanoseconds;
 * u - microseconds;
H
hzcheng 已提交
668 669 670 671 672 673 674
 * a - Millionseconds
 * s - Seconds
 * m - Minutes
 * h - Hours
 * d - Days (24 hours)
 * w - Weeks (7 days)
 */
S
Shengliang Guan 已提交
675 676
int32_t parseAbsoluteDuration(const char* token, int32_t tokenlen, int64_t* duration, char* unit,
                              int32_t timePrecision) {
H
hzcheng 已提交
677 678 679 680
  errno = 0;
  char* endPtr = NULL;

  /* get the basic numeric value */
wafwerar's avatar
wafwerar 已提交
681
  int64_t timestamp = taosStr2Int64(token, &endPtr, 10);
682
  if (timestamp < 0 || errno != 0) {
H
hzcheng 已提交
683 684 685
    return -1;
  }

686
  /* natual month/year are not allowed in absolute duration */
687 688
  *unit = token[tokenlen - 1];
  if (*unit == 'n' || *unit == 'y') {
689 690 691
    return -1;
  }

692
  return getDuration(timestamp, *unit, duration, timePrecision);
H
hzcheng 已提交
693
}
694

695
int32_t parseNatualDuration(const char* token, int32_t tokenLen, int64_t* duration, char* unit, int32_t timePrecision) {
B
Bomin Zhang 已提交
696 697 698
  errno = 0;

  /* get the basic numeric value */
wafwerar's avatar
wafwerar 已提交
699
  *duration = taosStr2Int64(token, NULL, 10);
700
  if (*duration < 0 || errno != 0) {
B
Bomin Zhang 已提交
701 702 703 704 705 706 707 708
    return -1;
  }

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

709
  return getDuration(*duration, *unit, duration, timePrecision);
B
Bomin Zhang 已提交
710 711
}

712 713 714 715
int64_t taosTimeAdd(int64_t t, int64_t duration, char unit, int32_t precision) {
  if (duration == 0) {
    return t;
  }
H
Haojun Liao 已提交
716

717
  if (!IS_CALENDAR_TIME_DURATION(unit)) {
718 719 720
    return t + duration;
  }

H
Haojun Liao 已提交
721
  // The following code handles the y/n time duration
722
  int64_t numOfMonth = (unit == 'y')? duration*12:duration;
723 724
  int64_t fraction = t % TSDB_TICK_PER_SECOND(precision);

725
  struct tm tm;
S
Shengliang Guan 已提交
726
  time_t    tt = (time_t)(t / TSDB_TICK_PER_SECOND(precision));
727
  taosLocalTime(&tt, &tm, NULL);
H
Haojun Liao 已提交
728
  int32_t mon = tm.tm_year * 12 + tm.tm_mon + (int32_t)numOfMonth;
729 730 731
  tm.tm_year = mon / 12;
  tm.tm_mon = mon % 12;

732
  return (int64_t)(taosMktime(&tm) * TSDB_TICK_PER_SECOND(precision) + fraction);
B
Bomin Zhang 已提交
733 734 735 736 737 738 739
}

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;
740
  }
H
Haojun Liao 已提交
741

B
Bomin Zhang 已提交
742 743 744 745
  if (unit != 'n' && unit != 'y') {
    return (int32_t)((ekey - skey) / interval);
  }

S
Shengliang Guan 已提交
746 747
  skey /= (int64_t)(TSDB_TICK_PER_SECOND(precision));
  ekey /= (int64_t)(TSDB_TICK_PER_SECOND(precision));
748

B
Bomin Zhang 已提交
749
  struct tm tm;
S
Shengliang Guan 已提交
750
  time_t    t = (time_t)skey;
751
  taosLocalTime(&t, &tm, NULL);
S
Shengliang Guan 已提交
752
  int32_t smon = tm.tm_year * 12 + tm.tm_mon;
B
Bomin Zhang 已提交
753 754

  t = (time_t)ekey;
755
  taosLocalTime(&t, &tm, NULL);
S
Shengliang Guan 已提交
756
  int32_t emon = tm.tm_year * 12 + tm.tm_mon;
B
Bomin Zhang 已提交
757 758 759 760 761 762

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

  return (emon - smon) / (int32_t)interval;
763 764
}

765
int64_t taosTimeTruncate(int64_t ts, const SInterval* pInterval) {
G
Ganlin Zhao 已提交
766
  if (pInterval->sliding == 0 && pInterval->interval == 0) {
767
    return ts;
768 769
  }

770 771 772 773 774
  int64_t start = ts;
  int32_t precision = pInterval->precision;

  if (IS_CALENDAR_TIME_DURATION(pInterval->slidingUnit)) {

S
Shengliang Guan 已提交
775
    start /= (int64_t)(TSDB_TICK_PER_SECOND(precision));
776
    struct tm tm;
S
Shengliang Guan 已提交
777
    time_t    tt = (time_t)start;
778
    taosLocalTime(&tt, &tm, NULL);
779 780 781 782 783 784 785
    tm.tm_sec = 0;
    tm.tm_min = 0;
    tm.tm_hour = 0;
    tm.tm_mday = 1;

    if (pInterval->slidingUnit == 'y') {
      tm.tm_mon = 0;
S
Shengliang Guan 已提交
786
      tm.tm_year = (int32_t)(tm.tm_year / pInterval->sliding * pInterval->sliding);
787
    } else {
S
Shengliang Guan 已提交
788 789
      int32_t mon = tm.tm_year * 12 + tm.tm_mon;
      mon = (int32_t)(mon / pInterval->sliding * pInterval->sliding);
790 791 792 793
      tm.tm_year = mon / 12;
      tm.tm_mon = mon % 12;
    }

794
    start = (int64_t)(taosMktime(&tm) * TSDB_TICK_PER_SECOND(precision));
795
  } else {
796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823
    if (IS_CALENDAR_TIME_DURATION(pInterval->intervalUnit)) {
      int64_t news = (ts / pInterval->sliding) * pInterval->sliding;
      ASSERT(news <= ts);

      if (news <= ts) {
        int64_t prev = news;
        int64_t newe = taosTimeAdd(news, pInterval->interval, pInterval->intervalUnit, precision) - 1;

        if (newe < ts) {  // move towards the greater endpoint
          while(newe < ts && news < ts) {
            news += pInterval->sliding;
            newe = taosTimeAdd(news, pInterval->interval, pInterval->intervalUnit, precision) - 1;
          }

          prev = news;
        } else {
          while (newe >= ts) {
            prev = news;
            news -= pInterval->sliding;
            newe = taosTimeAdd(news, pInterval->interval, pInterval->intervalUnit, precision) - 1;
          }
        }

        return prev;
      }
    } else {
      int64_t delta = ts - pInterval->interval;
      int32_t factor = (delta >= 0) ? 1 : -1;
824

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

827 828 829 830 831 832
      if (pInterval->intervalUnit == 'd' || pInterval->intervalUnit == 'w') {
        /*
         * 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
S
Shengliang Guan 已提交
833
#if defined(WINDOWS) && _MSC_VER >= 1900
834 835 836 837 838
        // 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;
S
Shengliang Guan 已提交
839
#endif
840

841 842
        start += (int64_t)(timezone * TSDB_TICK_PER_SECOND(precision));
      }
843

844
      int64_t end = 0;
H
Haojun Liao 已提交
845

846 847 848 849 850
      // not enough time range
      if (start < 0 || INT64_MAX - start > pInterval->interval - 1) {
        end = taosTimeAdd(start, pInterval->interval, pInterval->intervalUnit, precision) - 1;
        while (end < ts) {  // move forward to the correct time window
          start += pInterval->sliding;
H
Haojun Liao 已提交
851

852 853 854 855 856 857
          if (start < 0 || INT64_MAX - start > pInterval->interval - 1) {
            end = start + pInterval->interval - 1;
          } else {
            end = INT64_MAX;
            break;
          }
H
Haojun Liao 已提交
858
        }
859 860
      } else {
        end = INT64_MAX;
H
Haojun Liao 已提交
861
      }
862 863 864
    }
  }

865
  ASSERT(pInterval->offset >= 0);
H
Haojun Liao 已提交
866

B
Bomin Zhang 已提交
867 868
  if (pInterval->offset > 0) {
    start = taosTimeAdd(start, pInterval->offset, pInterval->offsetUnit, precision);
869

H
Haojun Liao 已提交
870 871
    // try to move current window to the left-hande-side, due to the offset effect.
    int64_t end = taosTimeAdd(start, pInterval->interval, pInterval->intervalUnit, precision) - 1;
872

873 874 875 876
    int64_t newe = end;
    while (newe >= ts) {
      end = newe;
      newe = taosTimeAdd(newe, -pInterval->sliding, pInterval->slidingUnit, precision);
B
Bomin Zhang 已提交
877
    }
H
Haojun Liao 已提交
878 879

    start = taosTimeAdd(end, -pInterval->interval, pInterval->intervalUnit, precision) + 1;
B
Bomin Zhang 已提交
880
  }
H
Haojun Liao 已提交
881

B
Bomin Zhang 已提交
882
  return start;
883 884
}

885 886 887 888 889 890 891 892
// 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) {
C
Cary Xu 已提交
893
  static char buf[96] = {0};
S
Shengliang Guan 已提交
894 895
  size_t      pos = 0;
  struct tm   tm;
896 897

  if (ts > -62135625943 && ts < 32503651200) {
B
Bomin Zhang 已提交
898
    time_t t = (time_t)ts;
899
    if (taosLocalTime(&t, &tm, buf) == NULL) {
900 901
      return buf;
    }
B
Bomin Zhang 已提交
902
    pos += strftime(buf + pos, sizeof(buf), "s=%Y-%m-%d %H:%M:%S", &tm);
903 904
  }

B
Bomin Zhang 已提交
905 906
  if (ts > -62135625943000 && ts < 32503651200000) {
    time_t t = (time_t)(ts / 1000);
907
    if (taosLocalTime(&t, &tm, buf) == NULL) {
908 909
      return buf;
    }
B
Bomin Zhang 已提交
910 911 912 913 914 915
    if (pos > 0) {
      buf[pos++] = ' ';
      buf[pos++] = '|';
      buf[pos++] = ' ';
    }
    pos += strftime(buf + pos, sizeof(buf), "ms=%Y-%m-%d %H:%M:%S", &tm);
S
Shengliang Guan 已提交
916
    pos += sprintf(buf + pos, ".%03d", (int32_t)(ts % 1000));
B
Bomin Zhang 已提交
917
  }
918

B
Bomin Zhang 已提交
919 920
  {
    time_t t = (time_t)(ts / 1000000);
921
    if (taosLocalTime(&t, &tm, buf) == NULL) {
922 923
      return buf;
    }
B
Bomin Zhang 已提交
924 925 926 927 928 929
    if (pos > 0) {
      buf[pos++] = ' ';
      buf[pos++] = '|';
      buf[pos++] = ' ';
    }
    pos += strftime(buf + pos, sizeof(buf), "us=%Y-%m-%d %H:%M:%S", &tm);
S
Shengliang Guan 已提交
930
    pos += sprintf(buf + pos, ".%06d", (int32_t)(ts % 1000000));
931 932 933
  }

  return buf;
934
}
935 936

void taosFormatUtcTime(char* buf, int32_t bufLen, int64_t t, int32_t precision) {
H
Hongze Cheng 已提交
937 938
  char      ts[40] = {0};
  struct tm ptm;
939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971

  int32_t fractionLen;
  char*   format = NULL;
  time_t  quot = 0;
  long    mod = 0;

  switch (precision) {
    case TSDB_TIME_PRECISION_MILLI: {
      quot = t / 1000;
      fractionLen = 5;
      format = ".%03" PRId64;
      mod = t % 1000;
      break;
    }

    case TSDB_TIME_PRECISION_MICRO: {
      quot = t / 1000000;
      fractionLen = 8;
      format = ".%06" PRId64;
      mod = t % 1000000;
      break;
    }

    case TSDB_TIME_PRECISION_NANO: {
      quot = t / 1000000000;
      fractionLen = 11;
      format = ".%09" PRId64;
      mod = t % 1000000000;
      break;
    }

    default:
      fractionLen = 0;
G
Ganlin Zhao 已提交
972
      ASSERT(false);
973 974
  }

975
  if (taosLocalTime(&quot, &ptm, buf) == NULL) {
976 977
    return;
  }
978
  int32_t length = (int32_t)strftime(ts, 40, "%Y-%m-%dT%H:%M:%S", &ptm);
979
  length += snprintf(ts + length, fractionLen, format, mod);
980
  length += (int32_t)strftime(ts + length, 40 - length, "%z", &ptm);
981 982

  tstrncpy(buf, ts, bufLen);
D
dapan1121 已提交
983
}