1 /* src/interfaces/ecpg/pgtypeslib/dt.h */
2 
3 #ifndef DT_H
4 #define DT_H
5 
6 #include <pgtypes_timestamp.h>
7 
8 #define MAXTZLEN			 10
9 
10 #ifdef HAVE_INT64_TIMESTAMP
11 
12 typedef int32 fsec_t;
13 #else
14 
15 typedef double fsec_t;
16 
17 /* round off to MAX_TIMESTAMP_PRECISION decimal places */
18 /* note: this is also used for rounding off intervals */
19 #define TS_PREC_INV 1000000.0
20 #define TSROUND(j) (rint(((double) (j)) * TS_PREC_INV) / TS_PREC_INV)
21 #endif
22 
23 #define USE_POSTGRES_DATES				0
24 #define USE_ISO_DATES					1
25 #define USE_SQL_DATES					2
26 #define USE_GERMAN_DATES				3
27 
28 #define INTSTYLE_POSTGRES			  0
29 #define INTSTYLE_POSTGRES_VERBOSE	  1
30 #define INTSTYLE_SQL_STANDARD		  2
31 #define INTSTYLE_ISO_8601			  3
32 
33 #define INTERVAL_FULL_RANGE (0x7FFF)
34 #define INTERVAL_MASK(b) (1 << (b))
35 #define MAX_INTERVAL_PRECISION 6
36 
37 #define DTERR_BAD_FORMAT		(-1)
38 #define DTERR_FIELD_OVERFLOW	(-2)
39 #define DTERR_MD_FIELD_OVERFLOW (-3)	/* triggers hint about DateStyle */
40 #define DTERR_INTERVAL_OVERFLOW (-4)
41 #define DTERR_TZDISP_OVERFLOW	(-5)
42 
43 
44 #define DAGO			"ago"
45 #define DCURRENT		"current"
46 #define EPOCH			"epoch"
47 #define INVALID			"invalid"
48 #define EARLY			"-infinity"
49 #define LATE			"infinity"
50 #define NOW				"now"
51 #define TODAY			"today"
52 #define TOMORROW		"tomorrow"
53 #define YESTERDAY		"yesterday"
54 #define ZULU			"zulu"
55 
56 #define DMICROSEC		"usecond"
57 #define DMILLISEC		"msecond"
58 #define DSECOND			"second"
59 #define DMINUTE			"minute"
60 #define DHOUR			"hour"
61 #define DDAY			"day"
62 #define DWEEK			"week"
63 #define DMONTH			"month"
64 #define DQUARTER		"quarter"
65 #define DYEAR			"year"
66 #define DDECADE			"decade"
67 #define DCENTURY		"century"
68 #define DMILLENNIUM		"millennium"
69 #define DA_D			"ad"
70 #define DB_C			"bc"
71 #define DTIMEZONE		"timezone"
72 
73 /*
74  * Fundamental time field definitions for parsing.
75  *
76  *	Meridian:  am, pm, or 24-hour style.
77  *	Millennium: ad, bc
78  */
79 
80 #define AM		0
81 #define PM		1
82 #define HR24	2
83 
84 #define AD		0
85 #define BC		1
86 
87 /*
88  * Field types for time decoding.
89  *
90  * Can't have more of these than there are bits in an unsigned int
91  * since these are turned into bit masks during parsing and decoding.
92  *
93  * Furthermore, the values for YEAR, MONTH, DAY, HOUR, MINUTE, SECOND
94  * must be in the range 0..14 so that the associated bitmasks can fit
95  * into the left half of an INTERVAL's typmod value.
96  *
97  * Copy&pasted these values from src/include/utils/datetime.h
98  * 2008-11-20, changing a number of their values.
99  */
100 
101 #define RESERV	0
102 #define MONTH	1
103 #define YEAR	2
104 #define DAY		3
105 #define JULIAN	4
106 #define TZ		5				/* fixed-offset timezone abbreviation */
107 #define DTZ		6				/* fixed-offset timezone abbrev, DST */
108 #define DYNTZ	7				/* dynamic timezone abbr (unimplemented) */
109 #define IGNORE_DTF	8
110 #define AMPM	9
111 #define HOUR	10
112 #define MINUTE	11
113 #define SECOND	12
114 #define MILLISECOND 13
115 #define MICROSECOND 14
116 #define DOY		15
117 #define DOW		16
118 #define UNITS	17
119 #define ADBC	18
120 /* these are only for relative dates */
121 #define AGO		19
122 #define ABS_BEFORE		20
123 #define ABS_AFTER		21
124 /* generic fields to help with parsing */
125 #define ISODATE 22
126 #define ISOTIME 23
127 /* hack for parsing two-word timezone specs "MET DST" etc */
128 #define DTZMOD	28				/* "DST" as a separate word */
129 /* reserved for unrecognized string values */
130 #define UNKNOWN_FIELD	31
131 
132 
133 /*
134  * Token field definitions for time parsing and decoding.
135  *
136  * Some field type codes (see above) use these as the "value" in datetktbl[].
137  * These are also used for bit masks in DecodeDateTime and friends
138  *	so actually restrict them to within [0,31] for now.
139  * - thomas 97/06/19
140  * Not all of these fields are used for masks in DecodeDateTime
141  *	so allow some larger than 31. - thomas 1997-11-17
142  *
143  * Caution: there are undocumented assumptions in the code that most of these
144  * values are not equal to IGNORE_DTF nor RESERV.  Be very careful when
145  * renumbering values in either of these apparently-independent lists :-(
146  */
147 
148 #define DTK_NUMBER		0
149 #define DTK_STRING		1
150 
151 #define DTK_DATE		2
152 #define DTK_TIME		3
153 #define DTK_TZ			4
154 #define DTK_AGO			5
155 
156 #define DTK_SPECIAL		6
157 #define DTK_INVALID		7
158 #define DTK_CURRENT		8
159 #define DTK_EARLY		9
160 #define DTK_LATE		10
161 #define DTK_EPOCH		11
162 #define DTK_NOW			12
163 #define DTK_YESTERDAY	13
164 #define DTK_TODAY		14
165 #define DTK_TOMORROW	15
166 #define DTK_ZULU		16
167 
168 #define DTK_DELTA		17
169 #define DTK_SECOND		18
170 #define DTK_MINUTE		19
171 #define DTK_HOUR		20
172 #define DTK_DAY			21
173 #define DTK_WEEK		22
174 #define DTK_MONTH		23
175 #define DTK_QUARTER		24
176 #define DTK_YEAR		25
177 #define DTK_DECADE		26
178 #define DTK_CENTURY		27
179 #define DTK_MILLENNIUM	28
180 #define DTK_MILLISEC	29
181 #define DTK_MICROSEC	30
182 #define DTK_JULIAN		31
183 
184 #define DTK_DOW			32
185 #define DTK_DOY			33
186 #define DTK_TZ_HOUR		34
187 #define DTK_TZ_MINUTE	35
188 #define DTK_ISOYEAR		36
189 #define DTK_ISODOW		37
190 
191 
192 /*
193  * Bit mask definitions for time parsing.
194  */
195 /* Copy&pasted these values from src/include/utils/datetime.h */
196 #define DTK_M(t)		(0x01 << (t))
197 #define DTK_ALL_SECS_M	   (DTK_M(SECOND) | DTK_M(MILLISECOND) | DTK_M(MICROSECOND))
198 #define DTK_DATE_M		(DTK_M(YEAR) | DTK_M(MONTH) | DTK_M(DAY))
199 #define DTK_TIME_M		(DTK_M(HOUR) | DTK_M(MINUTE) | DTK_M(SECOND))
200 
201 /*
202  * Working buffer size for input and output of interval, timestamp, etc.
203  * Inputs that need more working space will be rejected early.  Longer outputs
204  * will overrun buffers, so this must suffice for all possible output.  As of
205  * this writing, PGTYPESinterval_to_asc() needs the most space at ~90 bytes.
206  */
207 #define MAXDATELEN		128
208 /* maximum possible number of fields in a date string */
209 #define MAXDATEFIELDS	25
210 /* only this many chars are stored in datetktbl */
211 #define TOKMAXLEN		10
212 
213 /* keep this struct small; it gets used a lot */
214 typedef struct
215 {
216 	char		token[TOKMAXLEN + 1];	/* always NUL-terminated */
217 	char		type;			/* see field type codes above */
218 	int32		value;			/* meaning depends on type */
219 } datetkn;
220 
221 
222 /* FMODULO()
223  * Macro to replace modf(), which is broken on some platforms.
224  * t = input and remainder
225  * q = integer part
226  * u = divisor
227  */
228 #define FMODULO(t,q,u) \
229 do { \
230 	(q) = (((t) < 0) ? ceil((t) / (u)): floor((t) / (u))); \
231 	if ((q) != 0) (t) -= rint((q) * (u)); \
232 } while(0)
233 
234 /* TMODULO()
235  * Like FMODULO(), but work on the timestamp datatype (either int64 or float8).
236  * We assume that int64 follows the C99 semantics for division (negative
237  * quotients truncate towards zero).
238  */
239 #ifdef HAVE_INT64_TIMESTAMP
240 #define TMODULO(t,q,u) \
241 do { \
242 	(q) = ((t) / (u)); \
243 	if ((q) != 0) (t) -= ((q) * (u)); \
244 } while(0)
245 #else
246 #define TMODULO(t,q,u) \
247 do { \
248 	(q) = (((t) < 0) ? ceil((t) / (u)): floor((t) / (u))); \
249 	if ((q) != 0) (t) -= rint((q) * (u)); \
250 } while(0)
251 #endif
252 
253 /* in both timestamp.h and ecpg/dt.h */
254 #define DAYS_PER_YEAR	365.25	/* assumes leap year every four years */
255 #define MONTHS_PER_YEAR 12
256 /*
257  *	DAYS_PER_MONTH is very imprecise.  The more accurate value is
258  *	365.2425/12 = 30.436875, or '30 days 10:29:06'.  Right now we only
259  *	return an integral number of days, but someday perhaps we should
260  *	also return a 'time' value to be used as well.  ISO 8601 suggests
261  *	30 days.
262  */
263 #define DAYS_PER_MONTH	30		/* assumes exactly 30 days per month */
264 #define HOURS_PER_DAY	24		/* assume no daylight savings time changes */
265 
266 /*
267  *	This doesn't adjust for uneven daylight savings time intervals or leap
268  *	seconds, and it crudely estimates leap years.  A more accurate value
269  *	for days per years is 365.2422.
270  */
271 #define SECS_PER_YEAR	(36525 * 864)	/* avoid floating-point computation */
272 #define SECS_PER_DAY	86400
273 #define SECS_PER_HOUR	3600
274 #define SECS_PER_MINUTE 60
275 #define MINS_PER_HOUR	60
276 
277 #ifdef HAVE_INT64_TIMESTAMP
278 #define USECS_PER_DAY	INT64CONST(86400000000)
279 #define USECS_PER_HOUR	INT64CONST(3600000000)
280 #define USECS_PER_MINUTE INT64CONST(60000000)
281 #define USECS_PER_SEC	INT64CONST(1000000)
282 #endif
283 
284 /*
285  * Date/time validation
286  * Include check for leap year.
287  */
288 #define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
289 
290 /*
291  * Julian date support --- see comments in backend's timestamp.h.
292  */
293 
294 #define JULIAN_MINYEAR (-4713)
295 #define JULIAN_MINMONTH (11)
296 #define JULIAN_MINDAY (24)
297 #define JULIAN_MAXYEAR (5874898)
298 #define JULIAN_MAXMONTH (6)
299 #define JULIAN_MAXDAY (3)
300 
301 #define IS_VALID_JULIAN(y,m,d) \
302 	(((y) > JULIAN_MINYEAR || \
303 	  ((y) == JULIAN_MINYEAR && ((m) >= JULIAN_MINMONTH))) && \
304 	 ((y) < JULIAN_MAXYEAR || \
305 	  ((y) == JULIAN_MAXYEAR && ((m) < JULIAN_MAXMONTH))))
306 
307 #ifdef HAVE_INT64_TIMESTAMP
308 #define MIN_TIMESTAMP	INT64CONST(-211813488000000000)
309 #define END_TIMESTAMP	INT64CONST(9223371331200000000)
310 #else
311 #define MIN_TIMESTAMP	(-211813488000.0)
312 #define END_TIMESTAMP	185330760393600.0
313 #endif
314 
315 #define IS_VALID_TIMESTAMP(t)  (MIN_TIMESTAMP <= (t) && (t) < END_TIMESTAMP)
316 
317 #define UTIME_MINYEAR (1901)
318 #define UTIME_MINMONTH (12)
319 #define UTIME_MINDAY (14)
320 #define UTIME_MAXYEAR (2038)
321 #define UTIME_MAXMONTH (01)
322 #define UTIME_MAXDAY (18)
323 
324 #define IS_VALID_UTIME(y,m,d) ((((y) > UTIME_MINYEAR) \
325  || (((y) == UTIME_MINYEAR) && (((m) > UTIME_MINMONTH) \
326   || (((m) == UTIME_MINMONTH) && ((d) >= UTIME_MINDAY))))) \
327  && (((y) < UTIME_MAXYEAR) \
328  || (((y) == UTIME_MAXYEAR) && (((m) < UTIME_MAXMONTH) \
329   || (((m) == UTIME_MAXMONTH) && ((d) <= UTIME_MAXDAY))))))
330 
331 #ifdef HAVE_INT64_TIMESTAMP
332 
333 #define DT_NOBEGIN		(-INT64CONST(0x7fffffffffffffff) - 1)
334 #define DT_NOEND		(INT64CONST(0x7fffffffffffffff))
335 #else
336 
337 #ifdef HUGE_VAL
338 #define DT_NOBEGIN		(-HUGE_VAL)
339 #define DT_NOEND		(HUGE_VAL)
340 #else
341 #define DT_NOBEGIN		(-DBL_MAX)
342 #define DT_NOEND		(DBL_MAX)
343 #endif
344 #endif   /* HAVE_INT64_TIMESTAMP */
345 
346 #define TIMESTAMP_NOBEGIN(j)	do {(j) = DT_NOBEGIN;} while (0)
347 #define TIMESTAMP_NOEND(j)			do {(j) = DT_NOEND;} while (0)
348 #define TIMESTAMP_IS_NOBEGIN(j) ((j) == DT_NOBEGIN)
349 #define TIMESTAMP_IS_NOEND(j)	((j) == DT_NOEND)
350 #define TIMESTAMP_NOT_FINITE(j) (TIMESTAMP_IS_NOBEGIN(j) || TIMESTAMP_IS_NOEND(j))
351 
352 int			DecodeInterval(char **, int *, int, int *, struct tm *, fsec_t *);
353 int			DecodeTime(char *, int *, struct tm *, fsec_t *);
354 int			EncodeDateTime(struct tm * tm, fsec_t fsec, bool print_tz, int tz, const char *tzn, int style, char *str, bool EuroDates);
355 int			EncodeInterval(struct tm * tm, fsec_t fsec, int style, char *str);
356 int			tm2timestamp(struct tm *, fsec_t, int *, timestamp *);
357 int			DecodeUnits(int field, char *lowtoken, int *val);
358 bool		CheckDateTokenTables(void);
359 int			EncodeDateOnly(struct tm * tm, int style, char *str, bool EuroDates);
360 int			GetEpochTime(struct tm *);
361 int			ParseDateTime(char *, char *, char **, int *, int *, char **);
362 int			DecodeDateTime(char **, int *, int, int *, struct tm *, fsec_t *, bool);
363 void		j2date(int, int *, int *, int *);
364 void		GetCurrentDateTime(struct tm *);
365 int			date2j(int, int, int);
366 void		TrimTrailingZeros(char *);
367 void		dt2time(double, int *, int *, int *, fsec_t *);
368 int PGTYPEStimestamp_defmt_scan(char **str, char *fmt, timestamp * d,
369 							int *year, int *month, int *day,
370 							int *hour, int *minute, int *second,
371 							int *tz);
372 
373 extern char *pgtypes_date_weekdays_short[];
374 extern char *pgtypes_date_months[];
375 extern char *months[];
376 extern char *days[];
377 extern int	day_tab[2][13];
378 
379 #endif   /* DT_H */
380