📄 datetime.c
字号:
/* Used for SET australian_timezones to override North American ones */static datetkn australian_datetktbl[] = { {"acst", TZ, POS(38)}, /* Cent. Australia */ {"cst", TZ, POS(42)}, /* Australia Central Std Time */ {"east", TZ, POS(40)}, /* East Australian Std Time */ {"est", TZ, POS(40)}, /* Australia Eastern Std Time */ {"sat", TZ, POS(38)},};static unsigned int australian_szdatetktbl = sizeof australian_datetktbl /sizeof australian_datetktbl[0];static datetkn deltatktbl[] = { /* text, token, lexval */ {"@", IGNORE_DTF, 0}, /* postgres relative prefix */ {DAGO, AGO, 0}, /* "ago" indicates negative time offset */ {"c", UNITS, DTK_CENTURY}, /* "century" relative */ {"cent", UNITS, DTK_CENTURY}, /* "century" relative */ {"centuries", UNITS, DTK_CENTURY}, /* "centuries" relative */ {DCENTURY, UNITS, DTK_CENTURY}, /* "century" relative */ {"d", UNITS, DTK_DAY}, /* "day" relative */ {DDAY, UNITS, DTK_DAY}, /* "day" relative */ {"days", UNITS, DTK_DAY}, /* "days" relative */ {"dec", UNITS, DTK_DECADE}, /* "decade" relative */ {DDECADE, UNITS, DTK_DECADE}, /* "decade" relative */ {"decades", UNITS, DTK_DECADE}, /* "decades" relative */ {"decs", UNITS, DTK_DECADE}, /* "decades" relative */ {"h", UNITS, DTK_HOUR}, /* "hour" relative */ {DHOUR, UNITS, DTK_HOUR}, /* "hour" relative */ {"hours", UNITS, DTK_HOUR}, /* "hours" relative */ {"hr", UNITS, DTK_HOUR}, /* "hour" relative */ {"hrs", UNITS, DTK_HOUR}, /* "hours" relative */ {INVALID, RESERV, DTK_INVALID}, /* reserved for invalid time */ {"m", UNITS, DTK_MINUTE}, /* "minute" relative */ {"microsecon", UNITS, DTK_MICROSEC}, /* "microsecond" relative */ {"mil", UNITS, DTK_MILLENNIUM}, /* "millennium" relative */ {"millennia", UNITS, DTK_MILLENNIUM}, /* "millennia" relative */ {DMILLENNIUM, UNITS, DTK_MILLENNIUM}, /* "millennium" relative */ {"millisecon", UNITS, DTK_MILLISEC}, /* relative */ {"mils", UNITS, DTK_MILLENNIUM}, /* "millennia" relative */ {"min", UNITS, DTK_MINUTE}, /* "minute" relative */ {"mins", UNITS, DTK_MINUTE}, /* "minutes" relative */ {DMINUTE, UNITS, DTK_MINUTE}, /* "minute" relative */ {"minutes", UNITS, DTK_MINUTE}, /* "minutes" relative */ {"mon", UNITS, DTK_MONTH}, /* "months" relative */ {"mons", UNITS, DTK_MONTH}, /* "months" relative */ {DMONTH, UNITS, DTK_MONTH}, /* "month" relative */ {"months", UNITS, DTK_MONTH}, {"ms", UNITS, DTK_MILLISEC}, {"msec", UNITS, DTK_MILLISEC}, {DMILLISEC, UNITS, DTK_MILLISEC}, {"mseconds", UNITS, DTK_MILLISEC}, {"msecs", UNITS, DTK_MILLISEC}, {"qtr", UNITS, DTK_QUARTER}, /* "quarter" relative */ {DQUARTER, UNITS, DTK_QUARTER}, /* "quarter" relative */ {"reltime", IGNORE_DTF, 0}, /* pre-v6.1 "Undefined Reltime" */ {"s", UNITS, DTK_SECOND}, {"sec", UNITS, DTK_SECOND}, {DSECOND, UNITS, DTK_SECOND}, {"seconds", UNITS, DTK_SECOND}, {"secs", UNITS, DTK_SECOND}, {DTIMEZONE, UNITS, DTK_TZ}, /* "timezone" time offset */ {"timezone_h", UNITS, DTK_TZ_HOUR}, /* timezone hour units */ {"timezone_m", UNITS, DTK_TZ_MINUTE}, /* timezone minutes units */ {"undefined", RESERV, DTK_INVALID}, /* pre-v6.1 invalid time */ {"us", UNITS, DTK_MICROSEC}, /* "microsecond" relative */ {"usec", UNITS, DTK_MICROSEC}, /* "microsecond" relative */ {DMICROSEC, UNITS, DTK_MICROSEC}, /* "microsecond" relative */ {"useconds", UNITS, DTK_MICROSEC}, /* "microseconds" relative */ {"usecs", UNITS, DTK_MICROSEC}, /* "microseconds" relative */ {"w", UNITS, DTK_WEEK}, /* "week" relative */ {DWEEK, UNITS, DTK_WEEK}, /* "week" relative */ {"weeks", UNITS, DTK_WEEK}, /* "weeks" relative */ {"y", UNITS, DTK_YEAR}, /* "year" relative */ {DYEAR, UNITS, DTK_YEAR}, /* "year" relative */ {"years", UNITS, DTK_YEAR}, /* "years" relative */ {"yr", UNITS, DTK_YEAR}, /* "year" relative */ {"yrs", UNITS, DTK_YEAR}, /* "years" relative */};static unsigned int szdeltatktbl = sizeof deltatktbl / sizeof deltatktbl[0];static datetkn *datecache[MAXDATEFIELDS] = {NULL};static datetkn *deltacache[MAXDATEFIELDS] = {NULL};/* * 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() *//* * j2day - convert Julian date to day-of-week (0..6 == Sun..Sat) * * Note: various places use the locution j2day(date - 1) to produce a * result according to the convention 0..6 = Mon..Sun. This is a bit of * a crock, but will work as long as the computation here is just a modulo. */intj2day(int date){ unsigned int day; day = date; day += 1; day %= 7; return (int) day;} /* j2day() *//* * GetCurrentDateTime() * * Get the transaction start time ("now()") broken down as a struct pg_tm. */voidGetCurrentDateTime(struct pg_tm * tm){ int tz; fsec_t fsec; timestamp2tm(GetCurrentTransactionStartTimestamp(), &tz, tm, &fsec, NULL, NULL); /* Note: don't pass NULL tzp to timestamp2tm; affects behavior */}/* * GetCurrentTimeUsec() * * Get the transaction start time ("now()") broken down as a struct pg_tm, * including fractional seconds and timezone offset. */voidGetCurrentTimeUsec(struct pg_tm * tm, fsec_t *fsec, int *tzp){ int tz; timestamp2tm(GetCurrentTransactionStartTimestamp(), &tz, tm, fsec, NULL, NULL); /* Note: don't pass NULL tzp to timestamp2tm; affects behavior */ if (tzp != NULL) *tzp = tz;}/* TrimTrailingZeros() * ... resulting from printing numbers with full precision. */static voidTrimTrailingZeros(char *str){ int len = strlen(str);#if 0 /* chop off trailing one to cope with interval rounding */ if (strcmp(str + len - 4, "0001") == 0) { len -= 4; *(str + len) = '\0'; }#endif /* chop off trailing zeros... but leave at least 2 fractional digits */ while (*(str + len - 1) == '0' && *(str + len - 3) != '.') { len--; *(str + len) = '\0'; }}/* ParseDateTime() * Break string into tokens based on a date/time context. * Returns 0 if successful, DTERR code if bogus input detected. * * timestr - the input string * workbuf - workspace for field string storage. This must be * larger than the largest legal input for this datetime type -- * some additional space will be needed to NUL terminate fields. * buflen - the size of workbuf * field[] - pointers to field strings are returned in this array * ftype[] - field type indicators are returned in this array * maxfields - dimensions of the above two arrays * *numfields - set to the actual number of fields detected * * The fields extracted from the input are stored as separate, * null-terminated strings in the workspace at workbuf. Any text is * converted to lower case. * * Several field types are assigned: * DTK_NUMBER - digits and (possibly) a decimal point * DTK_DATE - digits and two delimiters, or digits and text * DTK_TIME - digits, colon delimiters, and possibly a decimal point * DTK_STRING - text (no digits) * DTK_SPECIAL - leading "+" or "-" followed by text * DTK_TZ - leading "+" or "-" followed by digits * * Note that some field types can hold unexpected items: * DTK_NUMBER can hold date fields (yy.ddd) * DTK_STRING can hold months (January) and time zones (PST) * DTK_DATE can hold Posix time zones (GMT-8) */intParseDateTime(const char *timestr, char *workbuf, size_t buflen, char **field, int *ftype, int maxfields, int *numfields){ int nf = 0; const char *cp = timestr; char *bufp = workbuf; const char *bufend = workbuf + buflen; /* * Set the character pointed-to by "bufptr" to "newchar", and increment * "bufptr". "end" gives the end of the buffer -- we return an error if * there is no space left to append a character to the buffer. Note that * "bufptr" is evaluated twice. */#define APPEND_CHAR(bufptr, end, newchar) \ do \ { \ if (((bufptr) + 1) >= (end)) \ return DTERR_BAD_FORMAT; \ *(bufptr)++ = newchar; \ } while (0) /* outer loop through fields */ while (*cp != '\0') { /* Ignore spaces between fields */ if (isspace((unsigned char) *cp)) { cp++; continue; } /* Record start of current field */ if (nf >= maxfields) return DTERR_BAD_FORMAT; field[nf] = bufp; /* leading digit? then date or time */ if (isdigit((unsigned char) *cp)) { APPEND_CHAR(bufp, bufend, *cp++); while (isdigit((unsigned char) *cp)) APPEND_CHAR(bufp, bufend, *cp++); /* time field? */ if (*cp == ':') { ftype[nf] = DTK_TIME; APPEND_CHAR(bufp, bufend, *cp++); while (isdigit((unsigned char) *cp) || (*cp == ':') || (*cp == '.')) APPEND_CHAR(bufp, bufend, *cp++); } /* date field? allow embedded text month */ else if (*cp == '-' || *cp == '/' || *cp == '.') { /* save delimiting character to use later */ char delim = *cp; APPEND_CHAR(bufp, bufend, *cp++); /* second field is all digits? then no embedded text month */ if (isdigit((unsigned char) *cp)) { ftype[nf] = ((delim == '.') ? DTK_NUMBER : DTK_DATE); while (isdigit((unsigned char) *cp)) APPEND_CHAR(bufp, bufend, *cp++); /* * insist that the delimiters match to get a three-field * date. */ if (*cp == delim) { ftype[nf] = DTK_DATE; APPEND_CHAR(bufp, bufend, *cp++); while (isdigit((unsigned char) *cp) || *cp == delim) APPEND_CHAR(bufp, bufend, *cp++); } } else { ftype[nf] = DTK_DATE; while (isalnum((unsigned char) *cp) || *cp == delim) APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++)); } } /* * otherwise, number only and will determine year, month, day, or * concatenated fields later... */ else ftype[nf] = DTK_NUMBER; } /* Leading decimal point? Then fractional seconds... */ else if (*cp == '.') { APPEND_CHAR(bufp, bufend, *cp++); while (isdigit((unsigned char) *cp)) APPEND_CHAR(bufp, bufend, *cp++); ftype[nf] = DTK_NUMBER; } /* * text? then date string, month, day of week, special, or timezone */ else if (isalpha((unsigned char) *cp)) { ftype[nf] = DTK_STRING; APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++)); while (isalpha((unsigned char) *cp)) APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++)); /* * Full date string with leading text month? Could also be a POSIX * time zone... */ if (*cp == '-' || *cp == '/' || *cp == '.') { char delim = *cp; ftype[nf] = DTK_DATE; APPEND_CHAR(bufp, bufend, *cp++); while (isdigit((unsigned char) *cp) || *cp == delim) APPEND_CHAR(bufp, bufend, *cp++); } } /* sign? then special or numeric timezone */ else if (*cp == '+' || *cp == '-') { APPEND_CHAR(bufp, bufend, *cp++); /* soak up leading whitespace */ while (isspace((unsigned char) *cp)) cp++; /* numeric timezone? */ if (isdigit((unsigned char) *cp)) { ftype[nf] = DTK_TZ; APPEND_CHAR(bufp, bufend, *cp++); while (isdigit((unsigned char) *cp) || *cp == ':' || *cp == '.') APPEND_CHAR(bufp, bufend, *cp++); } /* special? */ else if (isalpha((unsigned char) *cp)) { ftype[nf] = DTK_SPECIAL; APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++)); while (isalpha((unsigned char) *cp)) APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++)); } /* otherwise something wrong... */ else return DTERR_BAD_FORMAT; } /* ignore other punctuation but use as delimiter */ else if (ispunct((unsigned char) *cp)) { cp++; continue; } /* otherwise, something is not right... */ else return DTERR_BAD_FORMAT; /* force in a delimiter after each field */ *bufp++ = '\0'; nf++; } *numfields = nf; return 0;}/* DecodeDateTime() * Interpret previously parsed fields for general date and time. * Return 0 if full date, 1 if only time, and negative DTERR code if problems. * (Currently, all callers treat 1 as an error return too.) * * External format(s): * "<weekday> <month>-<day>-<year> <hour>:<minute>:<second>" * "Fri Feb-7-1997 15:23:27" * "Feb-7-1997 15:23:27" * "2-7-1997 15:23:27" * "1997-2-7 15:23:27" * "1997.038 15:23:27" (day of year 1-366) * Also supports input in compact time: * "970207 152327" * "97038 152327" * "20011225T040506.789-07" * * Use the system-provided functions to get the current time zone * if not specified in the input string. * If the date is outside the time_t system-supported time range, * then assume UTC time zone. - thomas 1997-05-27 */intDecodeDateTime(char **field, int *ftype, int nf, int *dtype, struct pg_tm * tm, fsec_t *fsec, int *tzp){ int fmask = 0, tmask, type; int ptype = 0; /* "prefix type" for ISO y2001m02d04 format */ int i; int val; int dterr; int mer = HR24; bool haveTextMonth = FALSE; int is2digits = FALSE; int bc = FALSE; /* * We'll insist on at least all of the date fields, but initialize the * remaining fields in case they are not set later... */ *dtype = DTK_DATE; tm->tm_hour = 0; tm->tm_min = 0; tm->tm_sec = 0; *fsec = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -