📄 dt_common.c
字号:
static voidabstime2tm(AbsoluteTime _time, int *tzp, struct tm * tm, char **tzn){ time_t time = (time_t) _time; struct tm *tx; if (tzp != NULL) tx = localtime((time_t *) &time); else tx = gmtime((time_t *) &time); tm->tm_year = tx->tm_year + 1900; tm->tm_mon = tx->tm_mon + 1; tm->tm_mday = tx->tm_mday; tm->tm_hour = tx->tm_hour; tm->tm_min = tx->tm_min; tm->tm_sec = tx->tm_sec; tm->tm_isdst = tx->tm_isdst;#if defined(HAVE_TM_ZONE) tm->tm_gmtoff = tx->tm_gmtoff; tm->tm_zone = tx->tm_zone; if (tzp != NULL) { /* * We have a brute force time zone per SQL99? Then use it without * change since we have already rotated to the time zone. */ *tzp = -tm->tm_gmtoff; /* tm_gmtoff is Sun/DEC-ism */ /* * XXX FreeBSD man pages indicate that this should work - tgl 97/04/23 */ if (tzn != NULL) { /* * Copy no more than MAXTZLEN bytes of timezone to tzn, in case it * contains an error message, which doesn't fit in the buffer */ StrNCpy(*tzn, tm->tm_zone, MAXTZLEN + 1); if (strlen(tm->tm_zone) > MAXTZLEN) tm->tm_isdst = -1; } } else tm->tm_isdst = -1;#elif defined(HAVE_INT_TIMEZONE) if (tzp != NULL) { *tzp = (tm->tm_isdst > 0) ? TIMEZONE_GLOBAL - SECS_PER_HOUR : TIMEZONE_GLOBAL; if (tzn != NULL) { /* * Copy no more than MAXTZLEN bytes of timezone to tzn, in case it * contains an error message, which doesn't fit in the buffer */ StrNCpy(*tzn, TZNAME_GLOBAL[tm->tm_isdst], MAXTZLEN + 1); if (strlen(TZNAME_GLOBAL[tm->tm_isdst]) > MAXTZLEN) tm->tm_isdst = -1; } } else tm->tm_isdst = -1;#else /* not (HAVE_TM_ZONE || HAVE_INT_TIMEZONE) */ if (tzp != NULL) { /* default to UTC */ *tzp = 0; if (tzn != NULL) *tzn = NULL; } else tm->tm_isdst = -1;#endif}voidGetCurrentDateTime(struct tm * tm){ int tz; abstime2tm(time(NULL), &tz, tm, NULL);}/* DetermineLocalTimeZone() * * Given a struct tm in which tm_year, tm_mon, tm_mday, tm_hour, tm_min, and * tm_sec fields are set, attempt to determine the applicable local zone * (ie, regular or daylight-savings time) at that time. Set the struct tm's * tm_isdst field accordingly, and return the actual timezone offset. * * This subroutine exists to centralize uses of mktime() and defend against * mktime() bugs/restrictions on various platforms. This should be * the *only* call of mktime() in the backend. */static intDetermineLocalTimeZone(struct tm * tm){ int tz; if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday)) {#if defined(HAVE_TM_ZONE) || defined(HAVE_INT_TIMEZONE) /* * Some buggy mktime() implementations may change the year/month/day * when given a time right at a DST boundary. To prevent corruption * of the caller's data, give mktime() a copy... */ struct tm tt, *tmp = &tt; *tmp = *tm; /* change to Unix conventions for year/month */ tmp->tm_year -= 1900; tmp->tm_mon -= 1; /* indicate timezone unknown */ tmp->tm_isdst = -1; if (mktime(tmp) != (time_t) -1 && tmp->tm_isdst >= 0) { /* mktime() succeeded, trust its result */ tm->tm_isdst = tmp->tm_isdst;#if defined(HAVE_TM_ZONE) /* tm_gmtoff is Sun/DEC-ism */ tz = -tmp->tm_gmtoff;#elif defined(HAVE_INT_TIMEZONE) tz = (tmp->tm_isdst > 0) ? TIMEZONE_GLOBAL - SECS_PER_HOUR : TIMEZONE_GLOBAL;#endif /* HAVE_INT_TIMEZONE */ } else { /* * We have a buggy (not to say deliberately brain damaged) * mktime(). Work around it by using localtime() instead. * * First, generate the time_t value corresponding to the given * y/m/d/h/m/s taken as GMT time. This will not overflow (at * least not for time_t taken as signed) because of the range * check we did above. */ long day, mysec, locsec, delta1, delta2; time_t mytime; day = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(1970, 1, 1)); mysec = tm->tm_sec + (tm->tm_min + (day * HOURS_PER_DAY + tm->tm_hour) * MINS_PER_HOUR) * SECS_PER_MINUTE; mytime = (time_t) mysec; /* * Use localtime to convert that time_t to broken-down time, and * reassemble to get a representation of local time. */ tmp = localtime(&mytime); day = (date2j(tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday) - date2j(1970, 1, 1)); locsec = tmp->tm_sec + (tmp->tm_min + (day * HOURS_PER_DAY + tmp->tm_hour) * MINS_PER_HOUR) * SECS_PER_MINUTE; /* * The local time offset corresponding to that GMT time is now * computable as mysec - locsec. */ delta1 = mysec - locsec; /* * However, if that GMT time and the local time we are actually * interested in are on opposite sides of a daylight-savings-time * transition, then this is not the time offset we want. So, * adjust the time_t to be what we think the GMT time * corresponding to our target local time is, and repeat the * localtime() call and delta calculation. We may have to do it * twice before we have a trustworthy delta. * * Note: think not to put a loop here, since if we've been given * an "impossible" local time (in the gap during a spring-forward * transition) we'd never get out of the loop. Twice is enough to * give the behavior we want, which is that "impossible" times are * taken as standard time, while at a fall-back boundary ambiguous * times are also taken as standard. */ mysec += delta1; mytime = (time_t) mysec; tmp = localtime(&mytime); day = (date2j(tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday) - date2j(1970, 1, 1)); locsec = tmp->tm_sec + (tmp->tm_min + (day * HOURS_PER_DAY + tmp->tm_hour) * MINS_PER_HOUR) * SECS_PER_MINUTE; delta2 = mysec - locsec; if (delta2 != delta1) { mysec += (delta2 - delta1); mytime = (time_t) mysec; tmp = localtime(&mytime); day = (date2j(tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday) - date2j(1970, 1, 1)); locsec = tmp->tm_sec + (tmp->tm_min + (day * HOURS_PER_DAY + tmp->tm_hour) * MINS_PER_HOUR) * SECS_PER_MINUTE; delta2 = mysec - locsec; } tm->tm_isdst = tmp->tm_isdst; tz = (int) delta2; }#else /* not (HAVE_TM_ZONE || HAVE_INT_TIMEZONE) */ /* Assume UTC if no system timezone info available */ tm->tm_isdst = 0; tz = 0;#endif } else { /* Given date is out of range, so assume UTC */ tm->tm_isdst = 0; tz = 0; } return tz;}static voiddt2time(double jd, int *hour, int *min, int *sec, fsec_t *fsec){#ifdef HAVE_INT64_TIMESTAMP int64 time;#else double time;#endif time = jd;#ifdef HAVE_INT64_TIMESTAMP *hour = time / USECS_PER_HOUR; time -= (*hour) * USECS_PER_HOUR; *min = time / USECS_PER_MINUTE; time -= (*min) * USECS_PER_MINUTE; *sec = time / USECS_PER_SEC; *fsec = time - (*sec * USECS_PER_SEC);#else *hour = time / SECS_PER_HOUR; time -= (*hour) * SECS_PER_HOUR; *min = time / SECS_PER_MINUTE; time -= (*min) * SECS_PER_MINUTE; *sec = time; *fsec = time - *sec;#endif} /* dt2time() *//* DecodeNumberField() * Interpret numeric string as a concatenated date or time field. * Use the context of previously decoded fields to help with * the interpretation. */static intDecodeNumberField(int len, char *str, int fmask, int *tmask, struct tm * tm, fsec_t *fsec, int *is2digits, bool EuroDates){ char *cp; /* * Have a decimal point? Then this is a date or something with a seconds * field... */ if ((cp = strchr(str, '.')) != NULL) {#ifdef HAVE_INT64_TIMESTAMP char fstr[MAXDATELEN + 1]; /* * OK, we have at most six digits to care about. Let's construct a * string and then do the conversion to an integer. */ strcpy(fstr, (cp + 1)); strcpy(fstr + strlen(fstr), "000000"); *(fstr + 6) = '\0'; *fsec = strtol(fstr, NULL, 10);#else *fsec = strtod(cp, NULL);#endif *cp = '\0'; len = strlen(str); } /* No decimal point and no complete date yet? */ else if ((fmask & DTK_DATE_M) != DTK_DATE_M) { /* yyyymmdd? */ if (len == 8) { *tmask = DTK_DATE_M; tm->tm_mday = atoi(str + 6); *(str + 6) = '\0'; tm->tm_mon = atoi(str + 4); *(str + 4) = '\0'; tm->tm_year = atoi(str + 0); return DTK_DATE; } /* yymmdd? */ else if (len == 6) { *tmask = DTK_DATE_M; tm->tm_mday = atoi(str + 4); *(str + 4) = '\0'; tm->tm_mon = atoi(str + 2); *(str + 2) = '\0'; tm->tm_year = atoi(str + 0); *is2digits = TRUE; return DTK_DATE; } /* yyddd? */ else if (len == 5) { *tmask = DTK_DATE_M; tm->tm_mday = atoi(str + 2); *(str + 2) = '\0'; tm->tm_mon = 1; tm->tm_year = atoi(str + 0); *is2digits = TRUE; return DTK_DATE; } } /* not all time fields are specified? */ if ((fmask & DTK_TIME_M) != DTK_TIME_M) { /* hhmmss */ if (len == 6) { *tmask = DTK_TIME_M; tm->tm_sec = atoi(str + 4); *(str + 4) = '\0'; tm->tm_min = atoi(str + 2); *(str + 2) = '\0'; tm->tm_hour = atoi(str + 0); return DTK_TIME; } /* hhmm? */ else if (len == 4) { *tmask = DTK_TIME_M; tm->tm_sec = 0; tm->tm_min = atoi(str + 2); *(str + 2) = '\0'; tm->tm_hour = atoi(str + 0); return DTK_TIME; } } return -1;} /* DecodeNumberField() *//* DecodeNumber() * Interpret plain numeric field as a date value in context. */static intDecodeNumber(int flen, char *str, int fmask, int *tmask, struct tm * tm, fsec_t *fsec, int *is2digits, bool EuroDates){ int val; char *cp; *tmask = 0; val = strtol(str, &cp, 10); if (cp == str) return -1; if (*cp == '.') { /* * More than two digits? Then could be a date or a run-together time: * 2001.360 20011225 040506.789 */ if (cp - str > 2) return DecodeNumberField(flen, str, (fmask | DTK_DATE_M), tmask, tm, fsec, is2digits, EuroDates); *fsec = strtod(cp, &cp); if (*cp != '\0') return -1; } else if (*cp != '\0') return -1; /* Special case day of year? */ if (flen == 3 && (fmask & DTK_M(YEAR)) && val >= 1 && val <= 366) { *tmask = (DTK_M(DOY) | DTK_M(MONTH) | DTK_M(DAY)); tm->tm_yday = val; j2date(date2j(tm->tm_year, 1, 1) + tm->tm_yday - 1, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); } /*** * Enough digits to be unequivocal year? Used to test for 4 digits or * more, but we now test first for a three-digit doy so anything * bigger than two digits had better be an explicit year. * - thomas 1999-01-09 * Back to requiring a 4 digit year. We accept a two digit * year farther down. - thomas 2000-03-28 ***/ else if (flen >= 4) { *tmask = DTK_M(YEAR); /* already have a year? then see if we can substitute... */ if ((fmask & DTK_M(YEAR)) && !(fmask & DTK_M(DAY)) && tm->tm_year >= 1 && tm->tm_year <= 31) { tm->tm_mday = tm->tm_year; *tmask = DTK_M(DAY); } tm->tm_year = val; } /* already have year? then could be month */ else if ((fmask & DTK_M(YEAR)) && !(fmask & DTK_M(MONTH)) && val >= 1 && val <= MONTHS_PER_YEAR) { *tmask = DTK_M(MONTH); tm->tm_mon = val; } /* no year and EuroDates enabled? then could be day */ else if ((EuroDates || (fmask & DTK_M(MONTH))) && !(fmask & DTK_M(YEAR)) && !(fmask & DTK_M(DAY)) && val >= 1 && val <= 31) { *tmask = DTK_M(DAY); tm->tm_mday = val; } else if (!(fmask & DTK_M(MONTH)) && val >= 1 && val <= MONTHS_PER_YEAR) { *tmask = DTK_M(MONTH); tm->tm_mon = val; } else if (!(fmask & DTK_M(DAY)) && val >= 1 && val <= 31) { *tmask = DTK_M(DAY); tm->tm_mday = val; } /* * Check for 2 or 4 or more digits, but currently we reach here only if * two digits. - thomas 2000-03-28 */ else if (!(fmask & DTK_M(YEAR)) && (flen >= 4 || flen == 2)) { *tmask = DTK_M(YEAR); tm->tm_year = val; /* adjust ONLY if exactly two digits... */ *is2digits = (flen == 2); } else return -1; return 0;} /* DecodeNumber() *//* DecodeDate() * Decode date string which includes delimiters. * Insist on a complete set of fields. */static intDecodeDate(char *str, int fmask, int *tmask, struct tm * tm, bool EuroDates){ fsec_t fsec; int nf = 0; int i, len; int bc = FALSE; int is2digits = FALSE; int type, val, dmask = 0; char *field[MAXDATEFIELDS]; /* parse this string... */ while (*str != '\0' && nf < MAXDATEFIELDS) { /* skip field separators */ while (!isalnum((unsigned char) *str)) str++; field[nf] = str; if (isdigit((unsigned char) *str)) { while (isdigit((unsigned char) *str))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -