diff options
Diffstat (limited to '')
-rw-r--r-- | src/include/utils/datetime.h | 344 |
1 files changed, 344 insertions, 0 deletions
diff --git a/src/include/utils/datetime.h b/src/include/utils/datetime.h new file mode 100644 index 0000000..4527e82 --- /dev/null +++ b/src/include/utils/datetime.h @@ -0,0 +1,344 @@ +/*------------------------------------------------------------------------- + * + * datetime.h + * Definitions for date/time support code. + * The support code is shared with other date data types, + * including date, and time. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/datetime.h + * + *------------------------------------------------------------------------- + */ +#ifndef DATETIME_H +#define DATETIME_H + +#include "nodes/nodes.h" +#include "utils/timestamp.h" + +/* this struct is declared in utils/tzparser.h: */ +struct tzEntry; + + +/* ---------------------------------------------------------------- + * time types + support macros + * + * String definitions for standard time quantities. + * + * These strings are the defaults used to form output time strings. + * Other alternative forms are hardcoded into token tables in datetime.c. + * ---------------------------------------------------------------- + */ + +#define DAGO "ago" +#define DCURRENT "current" +#define EPOCH "epoch" +#define INVALID "invalid" +#define EARLY "-infinity" +#define LATE "infinity" +#define NOW "now" +#define TODAY "today" +#define TOMORROW "tomorrow" +#define YESTERDAY "yesterday" +#define ZULU "zulu" + +#define DMICROSEC "usecond" +#define DMILLISEC "msecond" +#define DSECOND "second" +#define DMINUTE "minute" +#define DHOUR "hour" +#define DDAY "day" +#define DWEEK "week" +#define DMONTH "month" +#define DQUARTER "quarter" +#define DYEAR "year" +#define DDECADE "decade" +#define DCENTURY "century" +#define DMILLENNIUM "millennium" +#define DA_D "ad" +#define DB_C "bc" +#define DTIMEZONE "timezone" + +/* + * Fundamental time field definitions for parsing. + * + * Meridian: am, pm, or 24-hour style. + * Millennium: ad, bc + */ + +#define AM 0 +#define PM 1 +#define HR24 2 + +#define AD 0 +#define BC 1 + +/* + * Field types for time decoding. + * + * Can't have more of these than there are bits in an unsigned int + * since these are turned into bit masks during parsing and decoding. + * + * Furthermore, the values for YEAR, MONTH, DAY, HOUR, MINUTE, SECOND + * must be in the range 0..14 so that the associated bitmasks can fit + * into the left half of an INTERVAL's typmod value. Since those bits + * are stored in typmods, you can't change them without initdb! + */ + +#define RESERV 0 +#define MONTH 1 +#define YEAR 2 +#define DAY 3 +#define JULIAN 4 +#define TZ 5 /* fixed-offset timezone abbreviation */ +#define DTZ 6 /* fixed-offset timezone abbrev, DST */ +#define DYNTZ 7 /* dynamic timezone abbreviation */ +#define IGNORE_DTF 8 +#define AMPM 9 +#define HOUR 10 +#define MINUTE 11 +#define SECOND 12 +#define MILLISECOND 13 +#define MICROSECOND 14 +#define DOY 15 +#define DOW 16 +#define UNITS 17 +#define ADBC 18 +/* these are only for relative dates */ +#define AGO 19 +#define ABS_BEFORE 20 +#define ABS_AFTER 21 +/* generic fields to help with parsing */ +#define ISODATE 22 +#define ISOTIME 23 +/* these are only for parsing intervals */ +#define WEEK 24 +#define DECADE 25 +#define CENTURY 26 +#define MILLENNIUM 27 +/* hack for parsing two-word timezone specs "MET DST" etc */ +#define DTZMOD 28 /* "DST" as a separate word */ +/* reserved for unrecognized string values */ +#define UNKNOWN_FIELD 31 + +/* + * Token field definitions for time parsing and decoding. + * + * Some field type codes (see above) use these as the "value" in datetktbl[]. + * These are also used for bit masks in DecodeDateTime and friends + * so actually restrict them to within [0,31] for now. + * - thomas 97/06/19 + * Not all of these fields are used for masks in DecodeDateTime + * so allow some larger than 31. - thomas 1997-11-17 + * + * Caution: there are undocumented assumptions in the code that most of these + * values are not equal to IGNORE_DTF nor RESERV. Be very careful when + * renumbering values in either of these apparently-independent lists :-( + */ + +#define DTK_NUMBER 0 +#define DTK_STRING 1 + +#define DTK_DATE 2 +#define DTK_TIME 3 +#define DTK_TZ 4 +#define DTK_AGO 5 + +#define DTK_SPECIAL 6 +#define DTK_EARLY 9 +#define DTK_LATE 10 +#define DTK_EPOCH 11 +#define DTK_NOW 12 +#define DTK_YESTERDAY 13 +#define DTK_TODAY 14 +#define DTK_TOMORROW 15 +#define DTK_ZULU 16 + +#define DTK_DELTA 17 +#define DTK_SECOND 18 +#define DTK_MINUTE 19 +#define DTK_HOUR 20 +#define DTK_DAY 21 +#define DTK_WEEK 22 +#define DTK_MONTH 23 +#define DTK_QUARTER 24 +#define DTK_YEAR 25 +#define DTK_DECADE 26 +#define DTK_CENTURY 27 +#define DTK_MILLENNIUM 28 +#define DTK_MILLISEC 29 +#define DTK_MICROSEC 30 +#define DTK_JULIAN 31 + +#define DTK_DOW 32 +#define DTK_DOY 33 +#define DTK_TZ_HOUR 34 +#define DTK_TZ_MINUTE 35 +#define DTK_ISOYEAR 36 +#define DTK_ISODOW 37 + + +/* + * Bit mask definitions for time parsing. + */ + +#define DTK_M(t) (0x01 << (t)) + +/* Convenience: a second, plus any fractional component */ +#define DTK_ALL_SECS_M (DTK_M(SECOND) | DTK_M(MILLISECOND) | DTK_M(MICROSECOND)) +#define DTK_DATE_M (DTK_M(YEAR) | DTK_M(MONTH) | DTK_M(DAY)) +#define DTK_TIME_M (DTK_M(HOUR) | DTK_M(MINUTE) | DTK_ALL_SECS_M) + +/* + * Working buffer size for input and output of interval, timestamp, etc. + * Inputs that need more working space will be rejected early. Longer outputs + * will overrun buffers, so this must suffice for all possible output. As of + * this writing, interval_out() needs the most space at ~90 bytes. + */ +#define MAXDATELEN 128 +/* maximum possible number of fields in a date string */ +#define MAXDATEFIELDS 25 +/* only this many chars are stored in datetktbl */ +#define TOKMAXLEN 10 + +/* keep this struct small; it gets used a lot */ +typedef struct +{ + char token[TOKMAXLEN + 1]; /* always NUL-terminated */ + char type; /* see field type codes above */ + int32 value; /* meaning depends on type */ +} datetkn; + +/* one of its uses is in tables of time zone abbreviations */ +typedef struct TimeZoneAbbrevTable +{ + Size tblsize; /* size in bytes of TimeZoneAbbrevTable */ + int numabbrevs; /* number of entries in abbrevs[] array */ + datetkn abbrevs[FLEXIBLE_ARRAY_MEMBER]; + /* DynamicZoneAbbrev(s) may follow the abbrevs[] array */ +} TimeZoneAbbrevTable; + +/* auxiliary data for a dynamic time zone abbreviation (non-fixed-offset) */ +typedef struct DynamicZoneAbbrev +{ + pg_tz *tz; /* NULL if not yet looked up */ + char zone[FLEXIBLE_ARRAY_MEMBER]; /* NUL-terminated zone name */ +} DynamicZoneAbbrev; + + +/* FMODULO() + * Macro to replace modf(), which is broken on some platforms. + * t = input and remainder + * q = integer part + * u = divisor + */ +#define FMODULO(t,q,u) \ +do { \ + (q) = (((t) < 0) ? ceil((t) / (u)) : floor((t) / (u))); \ + if ((q) != 0) (t) -= rint((q) * (u)); \ +} while(0) + +/* TMODULO() + * Like FMODULO(), but work on the timestamp datatype (now always int64). + * We assume that int64 follows the C99 semantics for division (negative + * quotients truncate towards zero). + */ +#define TMODULO(t,q,u) \ +do { \ + (q) = ((t) / (u)); \ + if ((q) != 0) (t) -= ((q) * (u)); \ +} while(0) + +/* + * Date/time validation + * Include check for leap year. + */ + +extern PGDLLIMPORT const char *const months[]; /* months (3-char + * abbreviations) */ +extern PGDLLIMPORT const char *const days[]; /* days (full names) */ +extern PGDLLIMPORT const int day_tab[2][13]; + +/* + * These are the rules for the Gregorian calendar, which was adopted in 1582. + * However, we use this calculation for all prior years as well because the + * SQL standard specifies use of the Gregorian calendar. This prevents the + * date 1500-02-29 from being stored, even though it is valid in the Julian + * calendar. + */ +#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) + + +/* + * Datetime input parsing routines (ParseDateTime, DecodeDateTime, etc) + * return zero or a positive value on success. On failure, they return + * one of these negative code values. DateTimeParseError may be used to + * produce a correct ereport. + */ +#define DTERR_BAD_FORMAT (-1) +#define DTERR_FIELD_OVERFLOW (-2) +#define DTERR_MD_FIELD_OVERFLOW (-3) /* triggers hint about DateStyle */ +#define DTERR_INTERVAL_OVERFLOW (-4) +#define DTERR_TZDISP_OVERFLOW (-5) + + +extern void GetCurrentDateTime(struct pg_tm *tm); +extern void GetCurrentTimeUsec(struct pg_tm *tm, fsec_t *fsec, int *tzp); +extern void j2date(int jd, int *year, int *month, int *day); +extern int date2j(int year, int month, int day); + +extern int ParseDateTime(const char *timestr, char *workbuf, size_t buflen, + char **field, int *ftype, + int maxfields, int *numfields); +extern int DecodeDateTime(char **field, int *ftype, + int nf, int *dtype, + struct pg_tm *tm, fsec_t *fsec, int *tzp); +extern int DecodeTimezone(char *str, int *tzp); +extern int DecodeTimeOnly(char **field, int *ftype, + int nf, int *dtype, + struct pg_tm *tm, fsec_t *fsec, int *tzp); +extern int DecodeInterval(char **field, int *ftype, int nf, int range, + int *dtype, struct pg_itm_in *itm_in); +extern int DecodeISO8601Interval(char *str, + int *dtype, struct pg_itm_in *itm_in); + +extern void DateTimeParseError(int dterr, const char *str, + const char *datatype) pg_attribute_noreturn(); + +extern int DetermineTimeZoneOffset(struct pg_tm *tm, pg_tz *tzp); +extern int DetermineTimeZoneAbbrevOffset(struct pg_tm *tm, const char *abbr, pg_tz *tzp); +extern int DetermineTimeZoneAbbrevOffsetTS(TimestampTz ts, const char *abbr, + pg_tz *tzp, int *isdst); + +extern void EncodeDateOnly(struct pg_tm *tm, int style, char *str); +extern void EncodeTimeOnly(struct pg_tm *tm, fsec_t fsec, bool print_tz, int tz, int style, char *str); +extern void EncodeDateTime(struct pg_tm *tm, fsec_t fsec, bool print_tz, int tz, const char *tzn, int style, char *str); +extern void EncodeInterval(struct pg_itm *itm, int style, char *str); +extern void EncodeSpecialTimestamp(Timestamp dt, char *str); + +extern int ValidateDate(int fmask, bool isjulian, bool is2digits, bool bc, + struct pg_tm *tm); + +extern int DecodeTimezoneAbbrev(int field, char *lowtoken, + int *offset, pg_tz **tz); +extern int DecodeSpecial(int field, char *lowtoken, int *val); +extern int DecodeUnits(int field, char *lowtoken, int *val); + +extern int j2day(int jd); + +extern Node *TemporalSimplify(int32 max_precis, Node *node); + +extern bool CheckDateTokenTables(void); + +extern TimeZoneAbbrevTable *ConvertTimeZoneAbbrevs(struct tzEntry *abbrevs, + int n); +extern void InstallTimeZoneAbbrevs(TimeZoneAbbrevTable *tbl); + +extern void AdjustTimestampForTypmod(Timestamp *time, int32 typmod); +extern bool AdjustTimestampForTypmodError(Timestamp *time, int32 typmod, + bool *error); + +#endif /* DATETIME_H */ |