/* src/interfaces/ecpg/pgtypeslib/dt.h */ #ifndef DT_H #define DT_H #include #include #define MAXTZLEN 10 typedef int32 fsec_t; #define USE_POSTGRES_DATES 0 #define USE_ISO_DATES 1 #define USE_SQL_DATES 2 #define USE_GERMAN_DATES 3 #define INTSTYLE_POSTGRES 0 #define INTSTYLE_POSTGRES_VERBOSE 1 #define INTSTYLE_SQL_STANDARD 2 #define INTSTYLE_ISO_8601 3 #define INTERVAL_FULL_RANGE (0x7FFF) #define INTERVAL_MASK(b) (1 << (b)) #define MAX_INTERVAL_PRECISION 6 #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) #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. * * Copy&pasted these values from src/include/utils/datetime.h * 2008-11-20, changing a number of their values. */ #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 abbr (unimplemented) */ #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 /* 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. */ /* Copy&pasted these values from src/include/utils/datetime.h */ #define DTK_M(t) (0x01 << (t)) #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_M(SECOND)) /* * 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, PGTYPESinterval_to_asc() 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; /* 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) /* in both timestamp.h and ecpg/dt.h */ #define DAYS_PER_YEAR 365.25 /* assumes leap year every four years */ #define MONTHS_PER_YEAR 12 /* * DAYS_PER_MONTH is very imprecise. The more accurate value is * 365.2425/12 = 30.436875, or '30 days 10:29:06'. Right now we only * return an integral number of days, but someday perhaps we should * also return a 'time' value to be used as well. ISO 8601 suggests * 30 days. */ #define DAYS_PER_MONTH 30 /* assumes exactly 30 days per month */ #define HOURS_PER_DAY 24 /* assume no daylight savings time changes */ /* * This doesn't adjust for uneven daylight savings time intervals or leap * seconds, and it crudely estimates leap years. A more accurate value * for days per years is 365.2422. */ #define SECS_PER_YEAR (36525 * 864) /* avoid floating-point computation */ #define SECS_PER_DAY 86400 #define SECS_PER_HOUR 3600 #define SECS_PER_MINUTE 60 #define MINS_PER_HOUR 60 #define USECS_PER_DAY INT64CONST(86400000000) #define USECS_PER_HOUR INT64CONST(3600000000) #define USECS_PER_MINUTE INT64CONST(60000000) #define USECS_PER_SEC INT64CONST(1000000) /* * Date/time validation * Include check for leap year. */ #define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) /* * Julian date support --- see comments in backend's timestamp.h. */ #define JULIAN_MINYEAR (-4713) #define JULIAN_MINMONTH (11) #define JULIAN_MINDAY (24) #define JULIAN_MAXYEAR (5874898) #define JULIAN_MAXMONTH (6) #define JULIAN_MAXDAY (3) #define IS_VALID_JULIAN(y,m,d) \ (((y) > JULIAN_MINYEAR || \ ((y) == JULIAN_MINYEAR && ((m) >= JULIAN_MINMONTH))) && \ ((y) < JULIAN_MAXYEAR || \ ((y) == JULIAN_MAXYEAR && ((m) < JULIAN_MAXMONTH)))) #define MIN_TIMESTAMP INT64CONST(-211813488000000000) #define END_TIMESTAMP INT64CONST(9223371331200000000) #define IS_VALID_TIMESTAMP(t) (MIN_TIMESTAMP <= (t) && (t) < END_TIMESTAMP) #define UTIME_MINYEAR (1901) #define UTIME_MINMONTH (12) #define UTIME_MINDAY (14) #define UTIME_MAXYEAR (2038) #define UTIME_MAXMONTH (01) #define UTIME_MAXDAY (18) #define IS_VALID_UTIME(y,m,d) ((((y) > UTIME_MINYEAR) \ || (((y) == UTIME_MINYEAR) && (((m) > UTIME_MINMONTH) \ || (((m) == UTIME_MINMONTH) && ((d) >= UTIME_MINDAY))))) \ && (((y) < UTIME_MAXYEAR) \ || (((y) == UTIME_MAXYEAR) && (((m) < UTIME_MAXMONTH) \ || (((m) == UTIME_MAXMONTH) && ((d) <= UTIME_MAXDAY)))))) #define DT_NOBEGIN (-INT64CONST(0x7fffffffffffffff) - 1) #define DT_NOEND (INT64CONST(0x7fffffffffffffff)) #define TIMESTAMP_NOBEGIN(j) do {(j) = DT_NOBEGIN;} while (0) #define TIMESTAMP_NOEND(j) do {(j) = DT_NOEND;} while (0) #define TIMESTAMP_IS_NOBEGIN(j) ((j) == DT_NOBEGIN) #define TIMESTAMP_IS_NOEND(j) ((j) == DT_NOEND) #define TIMESTAMP_NOT_FINITE(j) (TIMESTAMP_IS_NOBEGIN(j) || TIMESTAMP_IS_NOEND(j)) int DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct tm *tm, fsec_t *fsec); int DecodeTime(char *str, int *tmask, struct tm *tm, fsec_t *fsec); void EncodeDateTime(struct tm *tm, fsec_t fsec, bool print_tz, int tz, const char *tzn, int style, char *str, bool EuroDates); void EncodeInterval(struct tm *tm, fsec_t fsec, int style, char *str); int tm2timestamp(struct tm *tm, fsec_t fsec, int *tzp, timestamp * result); int DecodeUnits(int field, char *lowtoken, int *val); bool CheckDateTokenTables(void); void EncodeDateOnly(struct tm *tm, int style, char *str, bool EuroDates); int GetEpochTime(struct tm *tm); int ParseDateTime(char *timestr, char *lowstr, char **field, int *ftype, int *numfields, char **endstr); int DecodeDateTime(char **field, int *ftype, int nf, int *dtype, struct tm *tm, fsec_t *fsec, bool EuroDates); void j2date(int jd, int *year, int *month, int *day); void GetCurrentDateTime(struct tm *tm); int date2j(int y, int m, int d); void TrimTrailingZeros(char *str); void dt2time(double jd, int *hour, int *min, int *sec, fsec_t *fsec); int PGTYPEStimestamp_defmt_scan(char **str, char *fmt, timestamp * d, int *year, int *month, int *day, int *hour, int *minute, int *second, int *tz); extern char *pgtypes_date_weekdays_short[]; extern char *pgtypes_date_months[]; extern char *months[]; extern char *days[]; extern const int day_tab[2][13]; #endif /* DT_H */