📄 dt_common.c
字号:
char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL};char *days[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", NULL};char *pgtypes_date_weekdays_short[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL};char *pgtypes_date_months[] = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", NULL};static datetkn *datebsearch(char *key, datetkn *base, unsigned int nel){ datetkn *last = base + nel - 1, *position; int result; while (last >= base) { position = base + ((last - base) >> 1); result = key[0] - position->token[0]; if (result == 0) { result = strncmp(key, position->token, TOKMAXLEN); if (result == 0) return position; } if (result < 0) last = position - 1; else base = position + 1; } return NULL;}/* DecodeUnits() * Decode text string using lookup table. * This routine supports time interval decoding. */intDecodeUnits(int field, char *lowtoken, int *val){ int type; datetkn *tp; if (deltacache[field] != NULL && strncmp(lowtoken, deltacache[field]->token, TOKMAXLEN) == 0) tp = deltacache[field]; else tp = datebsearch(lowtoken, deltatktbl, szdeltatktbl); deltacache[field] = tp; if (tp == NULL) { type = UNKNOWN_FIELD; *val = 0; } else { type = tp->type; if (type == TZ || type == DTZ) *val = FROMVAL(tp); else *val = tp->value; } return type;} /* DecodeUnits() *//* * Calendar time to Julian date conversions. * Julian date is commonly used in astronomical applications, * since it is numerically accurate and computationally simple. * The algorithms here will accurately convert between Julian day * and calendar date for all non-negative Julian days * (i.e. from Nov 24, -4713 on). * * These routines will be used by other date/time packages * - thomas 97/02/25 * * Rewritten to eliminate overflow problems. This now allows the * routines to work correctly for all Julian day counts from * 0 to 2147483647 (Nov 24, -4713 to Jun 3, 5874898) assuming * a 32-bit integer. Longer types should also work to the limits * of their precision. */intdate2j(int y, int m, int d){ int julian; int century; if (m > 2) { m += 1; y += 4800; } else { m += 13; y += 4799; } century = y / 100; julian = y * 365 - 32167; julian += y / 4 - century + century / 4; julian += 7834 * m / 256 + d; return julian;} /* date2j() */voidj2date(int jd, int *year, int *month, int *day){ unsigned int julian; unsigned int quad; unsigned int extra; int y; julian = jd; julian += 32044; quad = julian / 146097; extra = (julian - quad * 146097) * 4 + 3; julian += 60 + quad * 3 + extra / 146097; quad = julian / 1461; julian -= quad * 1461; y = julian * 4 / 1461; julian = ((y != 0) ? (julian + 305) % 365 : (julian + 306) % 366) + 123; y += quad * 4; *year = y - 4800; quad = julian * 2141 / 65536; *day = julian - 7834 * quad / 256; *month = (quad + 10) % 12 + 1; return;} /* j2date() *//* DecodeSpecial() * Decode text string using lookup table. * Implement a cache lookup since it is likely that dates * will be related in format. */static intDecodeSpecial(int field, char *lowtoken, int *val){ int type; datetkn *tp; if (datecache[field] != NULL && strncmp(lowtoken, datecache[field]->token, TOKMAXLEN) == 0) tp = datecache[field]; else { tp = NULL; if (!tp) tp = datebsearch(lowtoken, datetktbl, szdatetktbl); } datecache[field] = tp; if (tp == NULL) { type = UNKNOWN_FIELD; *val = 0; } else { type = tp->type; switch (type) { case TZ: case DTZ: case DTZMOD: *val = FROMVAL(tp); break; default: *val = tp->value; break; } } return type;} /* DecodeSpecial() *//* EncodeDateOnly() * Encode date as local time. */intEncodeDateOnly(struct tm * tm, int style, char *str, bool EuroDates){ if (tm->tm_mon < 1 || tm->tm_mon > MONTHS_PER_YEAR) return -1; switch (style) { case USE_ISO_DATES: /* compatible with ISO date formats */ if (tm->tm_year > 0) sprintf(str, "%04d-%02d-%02d", tm->tm_year, tm->tm_mon, tm->tm_mday); else sprintf(str, "%04d-%02d-%02d %s", -(tm->tm_year - 1), tm->tm_mon, tm->tm_mday, "BC"); break; case USE_SQL_DATES: /* compatible with Oracle/Ingres date formats */ if (EuroDates) sprintf(str, "%02d/%02d", tm->tm_mday, tm->tm_mon); else sprintf(str, "%02d/%02d", tm->tm_mon, tm->tm_mday); if (tm->tm_year > 0) sprintf(str + 5, "/%04d", tm->tm_year); else sprintf(str + 5, "/%04d %s", -(tm->tm_year - 1), "BC"); break; case USE_GERMAN_DATES: /* German-style date format */ sprintf(str, "%02d.%02d", tm->tm_mday, tm->tm_mon); if (tm->tm_year > 0) sprintf(str + 5, ".%04d", tm->tm_year); else sprintf(str + 5, ".%04d %s", -(tm->tm_year - 1), "BC"); break; case USE_POSTGRES_DATES: default: /* traditional date-only style for Postgres */ if (EuroDates) sprintf(str, "%02d-%02d", tm->tm_mday, tm->tm_mon); else sprintf(str, "%02d-%02d", tm->tm_mon, tm->tm_mday); if (tm->tm_year > 0) sprintf(str + 5, "-%04d", tm->tm_year); else sprintf(str + 5, "-%04d %s", -(tm->tm_year - 1), "BC"); break; } return TRUE;} /* EncodeDateOnly() */static voidTrimTrailingZeros(char *str){ int len = strlen(str); /* chop off trailing zeros... but leave at least 2 fractional digits */ while (*(str + len - 1) == '0' && *(str + len - 3) != '.') { len--; *(str + len) = '\0'; }}/* EncodeDateTime() * Encode date and time interpreted as local time. * Support several date styles: * Postgres - day mon hh:mm:ss yyyy tz * SQL - mm/dd/yyyy hh:mm:ss.ss tz * ISO - yyyy-mm-dd hh:mm:ss+/-tz * German - dd.mm.yyyy hh:mm:ss tz * Variants (affects order of month and day for Postgres and SQL styles): * US - mm/dd/yyyy * European - dd/mm/yyyy */intEncodeDateTime(struct tm * tm, fsec_t fsec, int *tzp, char **tzn, int style, char *str, bool EuroDates){ int day, hour, min; switch (style) { case USE_ISO_DATES: /* Compatible with ISO-8601 date formats */ sprintf(str, "%04d-%02d-%02d %02d:%02d", (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min); /* * Print fractional seconds if any. The field widths here should * be at least equal to MAX_TIMESTAMP_PRECISION. * * In float mode, don't print fractional seconds before 1 AD, * since it's unlikely there's any precision left ... */#ifdef HAVE_INT64_TIMESTAMP if (fsec != 0) { sprintf(str + strlen(str), ":%02d.%06d", tm->tm_sec, fsec);#else if ((fsec != 0) && (tm->tm_year > 0)) { sprintf(str + strlen(str), ":%09.6f", tm->tm_sec + fsec);#endif TrimTrailingZeros(str); } else sprintf(str + strlen(str), ":%02d", tm->tm_sec); if (tm->tm_year <= 0) sprintf(str + strlen(str), " BC"); /* * tzp == NULL indicates that we don't want *any* time zone info * in the output string. *tzn != NULL indicates that we have alpha * time zone info available. tm_isdst != -1 indicates that we have * a valid time zone translation. */ if (tzp != NULL && tm->tm_isdst >= 0) { hour = -(*tzp / SECS_PER_HOUR); min = (abs(*tzp) / MINS_PER_HOUR) % MINS_PER_HOUR; sprintf(str + strlen(str), (min != 0) ? "%+03d:%02d" : "%+03d", hour, min); } break; case USE_SQL_DATES: /* Compatible with Oracle/Ingres date formats */ if (EuroDates) sprintf(str, "%02d/%02d", tm->tm_mday, tm->tm_mon); else sprintf(str, "%02d/%02d", tm->tm_mon, tm->tm_mday); sprintf(str + 5, "/%04d %02d:%02d", (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), tm->tm_hour, tm->tm_min); /* * Print fractional seconds if any. The field widths here should * be at least equal to MAX_TIMESTAMP_PRECISION. * * In float mode, don't print fractional seconds before 1 AD, * since it's unlikely there's any precision left ... */#ifdef HAVE_INT64_TIMESTAMP if (fsec != 0) { sprintf(str + strlen(str), ":%02d.%06d", tm->tm_sec, fsec);#else if (fsec != 0 && tm->tm_year > 0) { sprintf(str + strlen(str), ":%09.6f", tm->tm_sec + fsec);#endif TrimTrailingZeros(str); } else sprintf(str + strlen(str), ":%02d", tm->tm_sec); if (tm->tm_year <= 0) sprintf(str + strlen(str), " BC"); if (tzp != NULL && tm->tm_isdst >= 0) { if (*tzn != NULL) sprintf(str + strlen(str), " %.*s", MAXTZLEN, *tzn); else { hour = -(*tzp / SECS_PER_HOUR); min = (abs(*tzp) / MINS_PER_HOUR) % MINS_PER_HOUR; sprintf(str + strlen(str), (min != 0) ? "%+03d:%02d" : "%+03d", hour, min); } } break; case USE_GERMAN_DATES: /* German variant on European style */ sprintf(str, "%02d.%02d", tm->tm_mday, tm->tm_mon); sprintf(str + 5, ".%04d %02d:%02d", (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), tm->tm_hour, tm->tm_min); /* * Print fractional seconds if any. The field widths here should * be at least equal to MAX_TIMESTAMP_PRECISION. * * In float mode, don't print fractional seconds before 1 AD, * since it's unlikely there's any precision left ... */#ifdef HAVE_INT64_TIMESTAMP if (fsec != 0) { sprintf(str + strlen(str), ":%02d.%06d", tm->tm_sec, fsec);#else if (fsec != 0 && tm->tm_year > 0) { sprintf(str + strlen(str), ":%09.6f", tm->tm_sec + fsec);#endif TrimTrailingZeros(str); } else sprintf(str + strlen(str), ":%02d", tm->tm_sec); if (tm->tm_year <= 0) sprintf(str + strlen(str), " BC"); if (tzp != NULL && tm->tm_isdst >= 0) { if (*tzn != NULL) sprintf(str + strlen(str), " %.*s", MAXTZLEN, *tzn); else { hour = -(*tzp / SECS_PER_HOUR); min = (abs(*tzp) / MINS_PER_HOUR) % MINS_PER_HOUR; sprintf(str + strlen(str), (min != 0) ? "%+03d:%02d" : "%+03d", hour, min); } } break; case USE_POSTGRES_DATES: default: /* Backward-compatible with traditional Postgres abstime dates */ day = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday); tm->tm_wday = (int) ((day + date2j(2000, 1, 1) + 1) % 7); strncpy(str, days[tm->tm_wday], 3); strcpy(str + 3, " "); if (EuroDates) sprintf(str + 4, "%02d %3s", tm->tm_mday, months[tm->tm_mon - 1]); else sprintf(str + 4, "%3s %02d", months[tm->tm_mon - 1], tm->tm_mday); sprintf(str + 10, " %02d:%02d", tm->tm_hour, tm->tm_min); /* * Print fractional seconds if any. The field widths here should * be at least equal to MAX_TIMESTAMP_PRECISION. * * In float mode, don't print fractional seconds before 1 AD, * since it's unlikely there's any precision left ... */#ifdef HAVE_INT64_TIMESTAMP if (fsec != 0) { sprintf(str + strlen(str), ":%02d.%06d", tm->tm_sec, fsec);#else if (fsec != 0 && tm->tm_year > 0) { sprintf(str + strlen(str), ":%09.6f", tm->tm_sec + fsec);#endif TrimTrailingZeros(str); } else sprintf(str + strlen(str), ":%02d", tm->tm_sec); sprintf(str + strlen(str), " %04d", (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1)); if (tm->tm_year <= 0) sprintf(str + strlen(str), " BC"); if (tzp != NULL && tm->tm_isdst >= 0) { if (*tzn != NULL) sprintf(str + strlen(str), " %.*s", MAXTZLEN, *tzn); else { /* * We have a time zone, but no string version. Use the * numeric form, but be sure to include a leading space to * avoid formatting something which would be rejected by * the date/time parser later. - thomas 2001-10-19 */ hour = -(*tzp / SECS_PER_HOUR); min = (abs(*tzp) / MINS_PER_HOUR) % MINS_PER_HOUR; sprintf(str + strlen(str), (min != 0) ? " %+03d:%02d" : " %+03d", hour, min); } } break; } return TRUE;} /* EncodeDateTime() */voidGetEpochTime(struct tm * tm){ struct tm *t0; time_t epoch = 0; t0 = gmtime(&epoch); tm->tm_year = t0->tm_year; tm->tm_mon = t0->tm_mon; tm->tm_mday = t0->tm_mday; tm->tm_hour = t0->tm_hour; tm->tm_min = t0->tm_min; tm->tm_sec = t0->tm_sec; if (tm->tm_year < 1900) tm->tm_year += 1900; tm->tm_mon++; return;} /* GetEpochTime() */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -