1 /* src/interfaces/ecpg/pgtypeslib/dt_common.c */
2 
3 #include "postgres_fe.h"
4 
5 #include <time.h>
6 #include <ctype.h>
7 #include <math.h>
8 
9 #include "extern.h"
10 #include "dt.h"
11 #include "pgtypes_timestamp.h"
12 
13 int			day_tab[2][13] = {
14 	{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0},
15 {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0}};
16 
17 typedef long AbsoluteTime;
18 
19 static datetkn datetktbl[] = {
20 /*	text, token, lexval */
21 	{EARLY, RESERV, DTK_EARLY}, /* "-infinity" reserved for "early time" */
22 	{"acsst", DTZ, 37800},		/* Cent. Australia */
23 	{"acst", DTZ, -14400},		/* Atlantic/Porto Acre */
24 	{"act", TZ, -18000},		/* Atlantic/Porto Acre */
25 	{DA_D, ADBC, AD},			/* "ad" for years >= 0 */
26 	{"adt", DTZ, -10800},		/* Atlantic Daylight Time */
27 	{"aesst", DTZ, 39600},		/* E. Australia */
28 	{"aest", TZ, 36000},		/* Australia Eastern Std Time */
29 	{"aft", TZ, 16200},			/* Kabul */
30 	{"ahst", TZ, -36000},		/* Alaska-Hawaii Std Time */
31 	{"akdt", DTZ, -28800},		/* Alaska Daylight Time */
32 	{"akst", DTZ, -32400},		/* Alaska Standard Time */
33 	{"allballs", RESERV, DTK_ZULU}, /* 00:00:00 */
34 	{"almst", TZ, 25200},		/* Almaty Savings Time */
35 	{"almt", TZ, 21600},		/* Almaty Time */
36 	{"am", AMPM, AM},
37 	{"amst", DTZ, 18000},		/* Armenia Summer Time (Yerevan) */
38 #if 0
39 	{"amst", DTZ, -10800},		/* Porto Velho */
40 #endif
41 	{"amt", TZ, 14400},			/* Armenia Time (Yerevan) */
42 	{"anast", DTZ, 46800},		/* Anadyr Summer Time (Russia) */
43 	{"anat", TZ, 43200},		/* Anadyr Time (Russia) */
44 	{"apr", MONTH, 4},
45 	{"april", MONTH, 4},
46 #if 0
47 	aqtst
48 	aqtt
49 	arst
50 #endif
51 	{"art", TZ, -10800},		/* Argentina Time */
52 #if 0
53 	ashst
54 	ast							/* Atlantic Standard Time, Arabia Standard
55 								 * Time, Acre Standard Time */
56 #endif
57 	{"ast", TZ, -14400},		/* Atlantic Std Time (Canada) */
58 	{"at", IGNORE_DTF, 0},		/* "at" (throwaway) */
59 	{"aug", MONTH, 8},
60 	{"august", MONTH, 8},
61 	{"awsst", DTZ, 32400},		/* W. Australia */
62 	{"awst", TZ, 28800},		/* W. Australia */
63 	{"awt", DTZ, -10800},
64 	{"azost", DTZ, 0},			/* Azores Summer Time */
65 	{"azot", TZ, -3600},		/* Azores Time */
66 	{"azst", DTZ, 18000},		/* Azerbaijan Summer Time */
67 	{"azt", TZ, 14400},			/* Azerbaijan Time */
68 	{DB_C, ADBC, BC},			/* "bc" for years < 0 */
69 	{"bdst", TZ, 7200},			/* British Double Summer Time */
70 	{"bdt", TZ, 21600},			/* Dacca */
71 	{"bnt", TZ, 28800},			/* Brunei Darussalam Time */
72 	{"bort", TZ, 28800},		/* Borneo Time (Indonesia) */
73 #if 0
74 	bortst
75 	bost
76 #endif
77 	{"bot", TZ, -14400},		/* Bolivia Time */
78 	{"bra", TZ, -10800},		/* Brazil Time */
79 #if 0
80 	brst
81 	brt
82 #endif
83 	{"bst", DTZ, 3600},			/* British Summer Time */
84 #if 0
85 	{"bst", TZ, -10800},		/* Brazil Standard Time */
86 	{"bst", DTZ, -39600},		/* Bering Summer Time */
87 #endif
88 	{"bt", TZ, 10800},			/* Baghdad Time */
89 	{"btt", TZ, 21600},			/* Bhutan Time */
90 	{"cadt", DTZ, 37800},		/* Central Australian DST */
91 	{"cast", TZ, 34200},		/* Central Australian ST */
92 	{"cat", TZ, -36000},		/* Central Alaska Time */
93 	{"cct", TZ, 28800},			/* China Coast Time */
94 #if 0
95 	{"cct", TZ, 23400},			/* Indian Cocos (Island) Time */
96 #endif
97 	{"cdt", DTZ, -18000},		/* Central Daylight Time */
98 	{"cest", DTZ, 7200},		/* Central European Dayl.Time */
99 	{"cet", TZ, 3600},			/* Central European Time */
100 	{"cetdst", DTZ, 7200},		/* Central European Dayl.Time */
101 	{"chadt", DTZ, 49500},		/* Chatham Island Daylight Time (13:45) */
102 	{"chast", TZ, 45900},		/* Chatham Island Time (12:45) */
103 #if 0
104 	ckhst
105 #endif
106 	{"ckt", TZ, 43200},			/* Cook Islands Time */
107 	{"clst", DTZ, -10800},		/* Chile Summer Time */
108 	{"clt", TZ, -14400},		/* Chile Time */
109 #if 0
110 	cost
111 #endif
112 	{"cot", TZ, -18000},		/* Columbia Time */
113 	{"cst", TZ, -21600},		/* Central Standard Time */
114 	{DCURRENT, RESERV, DTK_CURRENT},	/* "current" is always now */
115 #if 0
116 	cvst
117 #endif
118 	{"cvt", TZ, 25200},			/* Christmas Island Time (Indian Ocean) */
119 	{"cxt", TZ, 25200},			/* Christmas Island Time (Indian Ocean) */
120 	{"d", UNITS, DTK_DAY},		/* "day of month" for ISO input */
121 	{"davt", TZ, 25200},		/* Davis Time (Antarctica) */
122 	{"ddut", TZ, 36000},		/* Dumont-d'Urville Time (Antarctica) */
123 	{"dec", MONTH, 12},
124 	{"december", MONTH, 12},
125 	{"dnt", TZ, 3600},			/* Dansk Normal Tid */
126 	{"dow", UNITS, DTK_DOW},	/* day of week */
127 	{"doy", UNITS, DTK_DOY},	/* day of year */
128 	{"dst", DTZMOD, SECS_PER_HOUR},
129 #if 0
130 	{"dusst", DTZ, 21600},		/* Dushanbe Summer Time */
131 #endif
132 	{"easst", DTZ, -18000},		/* Easter Island Summer Time */
133 	{"east", TZ, -21600},		/* Easter Island Time */
134 	{"eat", TZ, 10800},			/* East Africa Time */
135 #if 0
136 	{"east", DTZ, 14400},		/* Indian Antananarivo Savings Time */
137 	{"eat", TZ, 10800},			/* Indian Antananarivo Time */
138 	{"ect", TZ, -14400},		/* Eastern Caribbean Time */
139 	{"ect", TZ, -18000},		/* Ecuador Time */
140 #endif
141 	{"edt", DTZ, -14400},		/* Eastern Daylight Time */
142 	{"eest", DTZ, 10800},		/* Eastern Europe Summer Time */
143 	{"eet", TZ, 7200},			/* East. Europe, USSR Zone 1 */
144 	{"eetdst", DTZ, 10800},		/* Eastern Europe Daylight Time */
145 	{"egst", DTZ, 0},			/* East Greenland Summer Time */
146 	{"egt", TZ, -3600},			/* East Greenland Time */
147 #if 0
148 	ehdt
149 #endif
150 	{EPOCH, RESERV, DTK_EPOCH}, /* "epoch" reserved for system epoch time */
151 	{"est", TZ, -18000},		/* Eastern Standard Time */
152 	{"feb", MONTH, 2},
153 	{"february", MONTH, 2},
154 	{"fjst", DTZ, -46800},		/* Fiji Summer Time (13 hour offset!) */
155 	{"fjt", TZ, -43200},		/* Fiji Time */
156 	{"fkst", DTZ, -10800},		/* Falkland Islands Summer Time */
157 	{"fkt", TZ, -7200},			/* Falkland Islands Time */
158 #if 0
159 	fnst
160 	fnt
161 #endif
162 	{"fri", DOW, 5},
163 	{"friday", DOW, 5},
164 	{"fst", TZ, 3600},			/* French Summer Time */
165 	{"fwt", DTZ, 7200},			/* French Winter Time  */
166 	{"galt", TZ, -21600},		/* Galapagos Time */
167 	{"gamt", TZ, -32400},		/* Gambier Time */
168 	{"gest", DTZ, 18000},		/* Georgia Summer Time */
169 	{"get", TZ, 14400},			/* Georgia Time */
170 	{"gft", TZ, -10800},		/* French Guiana Time */
171 #if 0
172 	ghst
173 #endif
174 	{"gilt", TZ, 43200},		/* Gilbert Islands Time */
175 	{"gmt", TZ, 0},				/* Greenwish Mean Time */
176 	{"gst", TZ, 36000},			/* Guam Std Time, USSR Zone 9 */
177 	{"gyt", TZ, -14400},		/* Guyana Time */
178 	{"h", UNITS, DTK_HOUR},		/* "hour" */
179 #if 0
180 	hadt
181 	hast
182 #endif
183 	{"hdt", DTZ, -32400},		/* Hawaii/Alaska Daylight Time */
184 #if 0
185 	hkst
186 #endif
187 	{"hkt", TZ, 28800},			/* Hong Kong Time */
188 #if 0
189 	{"hmt", TZ, 10800},			/* Hellas ? ? */
190 	hovst
191 	hovt
192 #endif
193 	{"hst", TZ, -36000},		/* Hawaii Std Time */
194 #if 0
195 	hwt
196 #endif
197 	{"ict", TZ, 25200},			/* Indochina Time */
198 	{"idle", TZ, 43200},		/* Intl. Date Line, East */
199 	{"idlw", TZ, -43200},		/* Intl. Date Line, West */
200 #if 0
201 	idt							/* Israeli, Iran, Indian Daylight Time */
202 #endif
203 	{LATE, RESERV, DTK_LATE},	/* "infinity" reserved for "late time" */
204 	{INVALID, RESERV, DTK_INVALID}, /* "invalid" reserved for bad time */
205 	{"iot", TZ, 18000},			/* Indian Chagos Time */
206 	{"irkst", DTZ, 32400},		/* Irkutsk Summer Time */
207 	{"irkt", TZ, 28800},		/* Irkutsk Time */
208 	{"irt", TZ, 12600},			/* Iran Time */
209 	{"isodow", UNITS, DTK_ISODOW},	/* ISO day of week, Sunday == 7 */
210 #if 0
211 	isst
212 #endif
213 	{"ist", TZ, 7200},			/* Israel */
214 	{"it", TZ, 12600},			/* Iran Time */
215 	{"j", UNITS, DTK_JULIAN},
216 	{"jan", MONTH, 1},
217 	{"january", MONTH, 1},
218 	{"javt", TZ, 25200},		/* Java Time (07:00? see JT) */
219 	{"jayt", TZ, 32400},		/* Jayapura Time (Indonesia) */
220 	{"jd", UNITS, DTK_JULIAN},
221 	{"jst", TZ, 32400},			/* Japan Std Time,USSR Zone 8 */
222 	{"jt", TZ, 27000},			/* Java Time (07:30? see JAVT) */
223 	{"jul", MONTH, 7},
224 	{"julian", UNITS, DTK_JULIAN},
225 	{"july", MONTH, 7},
226 	{"jun", MONTH, 6},
227 	{"june", MONTH, 6},
228 	{"kdt", DTZ, 36000},		/* Korea Daylight Time */
229 	{"kgst", DTZ, 21600},		/* Kyrgyzstan Summer Time */
230 	{"kgt", TZ, 18000},			/* Kyrgyzstan Time */
231 	{"kost", TZ, 43200},		/* Kosrae Time */
232 	{"krast", DTZ, 25200},		/* Krasnoyarsk Summer Time */
233 	{"krat", TZ, 28800},		/* Krasnoyarsk Standard Time */
234 	{"kst", TZ, 32400},			/* Korea Standard Time */
235 	{"lhdt", DTZ, 39600},		/* Lord Howe Daylight Time, Australia */
236 	{"lhst", TZ, 37800},		/* Lord Howe Standard Time, Australia */
237 	{"ligt", TZ, 36000},		/* From Melbourne, Australia */
238 	{"lint", TZ, 50400},		/* Line Islands Time (Kiribati; +14 hours!) */
239 	{"lkt", TZ, 21600},			/* Lanka Time */
240 	{"m", UNITS, DTK_MONTH},	/* "month" for ISO input */
241 	{"magst", DTZ, 43200},		/* Magadan Summer Time */
242 	{"magt", TZ, 39600},		/* Magadan Time */
243 	{"mar", MONTH, 3},
244 	{"march", MONTH, 3},
245 	{"mart", TZ, -34200},		/* Marquesas Time */
246 	{"mawt", TZ, 21600},		/* Mawson, Antarctica */
247 	{"may", MONTH, 5},
248 	{"mdt", DTZ, -21600},		/* Mountain Daylight Time */
249 	{"mest", DTZ, 7200},		/* Middle Europe Summer Time */
250 	{"met", TZ, 3600},			/* Middle Europe Time */
251 	{"metdst", DTZ, 7200},		/* Middle Europe Daylight Time */
252 	{"mewt", TZ, 3600},			/* Middle Europe Winter Time */
253 	{"mez", TZ, 3600},			/* Middle Europe Zone */
254 	{"mht", TZ, 43200},			/* Kwajalein */
255 	{"mm", UNITS, DTK_MINUTE},	/* "minute" for ISO input */
256 	{"mmt", TZ, 23400},			/* Myannar Time */
257 	{"mon", DOW, 1},
258 	{"monday", DOW, 1},
259 #if 0
260 	most
261 #endif
262 	{"mpt", TZ, 36000},			/* North Mariana Islands Time */
263 	{"msd", DTZ, 14400},		/* Moscow Summer Time */
264 	{"msk", TZ, 10800},			/* Moscow Time */
265 	{"mst", TZ, -25200},		/* Mountain Standard Time */
266 	{"mt", TZ, 30600},			/* Moluccas Time */
267 	{"mut", TZ, 14400},			/* Mauritius Island Time */
268 	{"mvt", TZ, 18000},			/* Maldives Island Time */
269 	{"myt", TZ, 28800},			/* Malaysia Time */
270 #if 0
271 	ncst
272 #endif
273 	{"nct", TZ, 39600},			/* New Caledonia Time */
274 	{"ndt", DTZ, -9000},		/* Nfld. Daylight Time */
275 	{"nft", TZ, -12600},		/* Newfoundland Standard Time */
276 	{"nor", TZ, 3600},			/* Norway Standard Time */
277 	{"nov", MONTH, 11},
278 	{"november", MONTH, 11},
279 	{"novst", DTZ, 25200},		/* Novosibirsk Summer Time */
280 	{"novt", TZ, 21600},		/* Novosibirsk Standard Time */
281 	{NOW, RESERV, DTK_NOW},		/* current transaction time */
282 	{"npt", TZ, 20700},			/* Nepal Standard Time (GMT-5:45) */
283 	{"nst", TZ, -12600},		/* Nfld. Standard Time */
284 	{"nt", TZ, -39600},			/* Nome Time */
285 	{"nut", TZ, -39600},		/* Niue Time */
286 	{"nzdt", DTZ, 46800},		/* New Zealand Daylight Time */
287 	{"nzst", TZ, 43200},		/* New Zealand Standard Time */
288 	{"nzt", TZ, 43200},			/* New Zealand Time */
289 	{"oct", MONTH, 10},
290 	{"october", MONTH, 10},
291 	{"omsst", DTZ, 25200},		/* Omsk Summer Time */
292 	{"omst", TZ, 21600},		/* Omsk Time */
293 	{"on", IGNORE_DTF, 0},		/* "on" (throwaway) */
294 	{"pdt", DTZ, -25200},		/* Pacific Daylight Time */
295 #if 0
296 	pest
297 #endif
298 	{"pet", TZ, -18000},		/* Peru Time */
299 	{"petst", DTZ, 46800},		/* Petropavlovsk-Kamchatski Summer Time */
300 	{"pett", TZ, 43200},		/* Petropavlovsk-Kamchatski Time */
301 	{"pgt", TZ, 36000},			/* Papua New Guinea Time */
302 	{"phot", TZ, 46800},		/* Phoenix Islands (Kiribati) Time */
303 #if 0
304 	phst
305 #endif
306 	{"pht", TZ, 28800},			/* Philippine Time */
307 	{"pkt", TZ, 18000},			/* Pakistan Time */
308 	{"pm", AMPM, PM},
309 	{"pmdt", DTZ, -7200},		/* Pierre & Miquelon Daylight Time */
310 #if 0
311 	pmst
312 #endif
313 	{"pont", TZ, 39600},		/* Ponape Time (Micronesia) */
314 	{"pst", TZ, -28800},		/* Pacific Standard Time */
315 	{"pwt", TZ, 32400},			/* Palau Time */
316 	{"pyst", DTZ, -10800},		/* Paraguay Summer Time */
317 	{"pyt", TZ, -14400},		/* Paraguay Time */
318 	{"ret", DTZ, 14400},		/* Reunion Island Time */
319 	{"s", UNITS, DTK_SECOND},	/* "seconds" for ISO input */
320 	{"sadt", DTZ, 37800},		/* S. Australian Dayl. Time */
321 #if 0
322 	samst
323 	samt
324 #endif
325 	{"sast", TZ, 34200},		/* South Australian Std Time */
326 	{"sat", DOW, 6},
327 	{"saturday", DOW, 6},
328 #if 0
329 	sbt
330 #endif
331 	{"sct", DTZ, 14400},		/* Mahe Island Time */
332 	{"sep", MONTH, 9},
333 	{"sept", MONTH, 9},
334 	{"september", MONTH, 9},
335 	{"set", TZ, -3600},			/* Seychelles Time ?? */
336 #if 0
337 	sgt
338 #endif
339 	{"sst", DTZ, 7200},			/* Swedish Summer Time */
340 	{"sun", DOW, 0},
341 	{"sunday", DOW, 0},
342 	{"swt", TZ, 3600},			/* Swedish Winter Time */
343 #if 0
344 	syot
345 #endif
346 	{"t", ISOTIME, DTK_TIME},	/* Filler for ISO time fields */
347 	{"tft", TZ, 18000},			/* Kerguelen Time */
348 	{"that", TZ, -36000},		/* Tahiti Time */
349 	{"thu", DOW, 4},
350 	{"thur", DOW, 4},
351 	{"thurs", DOW, 4},
352 	{"thursday", DOW, 4},
353 	{"tjt", TZ, 18000},			/* Tajikistan Time */
354 	{"tkt", TZ, -36000},		/* Tokelau Time */
355 	{"tmt", TZ, 18000},			/* Turkmenistan Time */
356 	{TODAY, RESERV, DTK_TODAY}, /* midnight */
357 	{TOMORROW, RESERV, DTK_TOMORROW},	/* tomorrow midnight */
358 #if 0
359 	tost
360 #endif
361 	{"tot", TZ, 46800},			/* Tonga Time */
362 #if 0
363 	tpt
364 #endif
365 	{"truk", TZ, 36000},		/* Truk Time */
366 	{"tue", DOW, 2},
367 	{"tues", DOW, 2},
368 	{"tuesday", DOW, 2},
369 	{"tvt", TZ, 43200},			/* Tuvalu Time */
370 #if 0
371 	uct
372 #endif
373 	{"ulast", DTZ, 32400},		/* Ulan Bator Summer Time */
374 	{"ulat", TZ, 28800},		/* Ulan Bator Time */
375 	{"undefined", RESERV, DTK_INVALID}, /* pre-v6.1 invalid time */
376 	{"ut", TZ, 0},
377 	{"utc", TZ, 0},
378 	{"uyst", DTZ, -7200},		/* Uruguay Summer Time */
379 	{"uyt", TZ, -10800},		/* Uruguay Time */
380 	{"uzst", DTZ, 21600},		/* Uzbekistan Summer Time */
381 	{"uzt", TZ, 18000},			/* Uzbekistan Time */
382 	{"vet", TZ, -14400},		/* Venezuela Time */
383 	{"vlast", DTZ, 39600},		/* Vladivostok Summer Time */
384 	{"vlat", TZ, 36000},		/* Vladivostok Time */
385 #if 0
386 	vust
387 #endif
388 	{"vut", TZ, 39600},			/* Vanuata Time */
389 	{"wadt", DTZ, 28800},		/* West Australian DST */
390 	{"wakt", TZ, 43200},		/* Wake Time */
391 #if 0
392 	warst
393 #endif
394 	{"wast", TZ, 25200},		/* West Australian Std Time */
395 	{"wat", TZ, -3600},			/* West Africa Time */
396 	{"wdt", DTZ, 32400},		/* West Australian DST */
397 	{"wed", DOW, 3},
398 	{"wednesday", DOW, 3},
399 	{"weds", DOW, 3},
400 	{"west", DTZ, 3600},		/* Western Europe Summer Time */
401 	{"wet", TZ, 0},				/* Western Europe */
402 	{"wetdst", DTZ, 3600},		/* Western Europe Daylight Savings Time */
403 	{"wft", TZ, 43200},			/* Wallis and Futuna Time */
404 	{"wgst", DTZ, -7200},		/* West Greenland Summer Time */
405 	{"wgt", TZ, -10800},		/* West Greenland Time */
406 	{"wst", TZ, 28800},			/* West Australian Standard Time */
407 	{"y", UNITS, DTK_YEAR},		/* "year" for ISO input */
408 	{"yakst", DTZ, 36000},		/* Yakutsk Summer Time */
409 	{"yakt", TZ, 32400},		/* Yakutsk Time */
410 	{"yapt", TZ, 36000},		/* Yap Time (Micronesia) */
411 	{"ydt", DTZ, -28800},		/* Yukon Daylight Time */
412 	{"yekst", DTZ, 21600},		/* Yekaterinburg Summer Time */
413 	{"yekt", TZ, 18000},		/* Yekaterinburg Time */
414 	{YESTERDAY, RESERV, DTK_YESTERDAY}, /* yesterday midnight */
415 	{"yst", TZ, -32400},		/* Yukon Standard Time */
416 	{"z", TZ, 0},				/* time zone tag per ISO-8601 */
417 	{"zp4", TZ, -14400},		/* UTC +4  hours. */
418 	{"zp5", TZ, -18000},		/* UTC +5  hours. */
419 	{"zp6", TZ, -21600},		/* UTC +6  hours. */
420 	{ZULU, TZ, 0},				/* UTC */
421 };
422 
423 static datetkn deltatktbl[] = {
424 	/* text, token, lexval */
425 	{"@", IGNORE_DTF, 0},		/* postgres relative prefix */
426 	{DAGO, AGO, 0},				/* "ago" indicates negative time offset */
427 	{"c", UNITS, DTK_CENTURY},	/* "century" relative */
428 	{"cent", UNITS, DTK_CENTURY},	/* "century" relative */
429 	{"centuries", UNITS, DTK_CENTURY},	/* "centuries" relative */
430 	{DCENTURY, UNITS, DTK_CENTURY}, /* "century" relative */
431 	{"d", UNITS, DTK_DAY},		/* "day" relative */
432 	{DDAY, UNITS, DTK_DAY},		/* "day" relative */
433 	{"days", UNITS, DTK_DAY},	/* "days" relative */
434 	{"dec", UNITS, DTK_DECADE}, /* "decade" relative */
435 	{DDECADE, UNITS, DTK_DECADE},	/* "decade" relative */
436 	{"decades", UNITS, DTK_DECADE}, /* "decades" relative */
437 	{"decs", UNITS, DTK_DECADE},	/* "decades" relative */
438 	{"h", UNITS, DTK_HOUR},		/* "hour" relative */
439 	{DHOUR, UNITS, DTK_HOUR},	/* "hour" relative */
440 	{"hours", UNITS, DTK_HOUR}, /* "hours" relative */
441 	{"hr", UNITS, DTK_HOUR},	/* "hour" relative */
442 	{"hrs", UNITS, DTK_HOUR},	/* "hours" relative */
443 	{INVALID, RESERV, DTK_INVALID}, /* reserved for invalid time */
444 	{"m", UNITS, DTK_MINUTE},	/* "minute" relative */
445 	{"microsecon", UNITS, DTK_MICROSEC},	/* "microsecond" relative */
446 	{"mil", UNITS, DTK_MILLENNIUM}, /* "millennium" relative */
447 	{"millennia", UNITS, DTK_MILLENNIUM},	/* "millennia" relative */
448 	{DMILLENNIUM, UNITS, DTK_MILLENNIUM},	/* "millennium" relative */
449 	{"millisecon", UNITS, DTK_MILLISEC},	/* relative */
450 	{"mils", UNITS, DTK_MILLENNIUM},	/* "millennia" relative */
451 	{"min", UNITS, DTK_MINUTE}, /* "minute" relative */
452 	{"mins", UNITS, DTK_MINUTE},	/* "minutes" relative */
453 	{DMINUTE, UNITS, DTK_MINUTE},	/* "minute" relative */
454 	{"minutes", UNITS, DTK_MINUTE}, /* "minutes" relative */
455 	{"mon", UNITS, DTK_MONTH},	/* "months" relative */
456 	{"mons", UNITS, DTK_MONTH}, /* "months" relative */
457 	{DMONTH, UNITS, DTK_MONTH}, /* "month" relative */
458 	{"months", UNITS, DTK_MONTH},
459 	{"ms", UNITS, DTK_MILLISEC},
460 	{"msec", UNITS, DTK_MILLISEC},
461 	{DMILLISEC, UNITS, DTK_MILLISEC},
462 	{"mseconds", UNITS, DTK_MILLISEC},
463 	{"msecs", UNITS, DTK_MILLISEC},
464 	{"qtr", UNITS, DTK_QUARTER},	/* "quarter" relative */
465 	{DQUARTER, UNITS, DTK_QUARTER}, /* "quarter" relative */
466 	{"s", UNITS, DTK_SECOND},
467 	{"sec", UNITS, DTK_SECOND},
468 	{DSECOND, UNITS, DTK_SECOND},
469 	{"seconds", UNITS, DTK_SECOND},
470 	{"secs", UNITS, DTK_SECOND},
471 	{DTIMEZONE, UNITS, DTK_TZ}, /* "timezone" time offset */
472 	{"timezone_h", UNITS, DTK_TZ_HOUR}, /* timezone hour units */
473 	{"timezone_m", UNITS, DTK_TZ_MINUTE},	/* timezone minutes units */
474 	{"undefined", RESERV, DTK_INVALID}, /* pre-v6.1 invalid time */
475 	{"us", UNITS, DTK_MICROSEC},	/* "microsecond" relative */
476 	{"usec", UNITS, DTK_MICROSEC},	/* "microsecond" relative */
477 	{DMICROSEC, UNITS, DTK_MICROSEC},	/* "microsecond" relative */
478 	{"useconds", UNITS, DTK_MICROSEC},	/* "microseconds" relative */
479 	{"usecs", UNITS, DTK_MICROSEC}, /* "microseconds" relative */
480 	{"w", UNITS, DTK_WEEK},		/* "week" relative */
481 	{DWEEK, UNITS, DTK_WEEK},	/* "week" relative */
482 	{"weeks", UNITS, DTK_WEEK}, /* "weeks" relative */
483 	{"y", UNITS, DTK_YEAR},		/* "year" relative */
484 	{DYEAR, UNITS, DTK_YEAR},	/* "year" relative */
485 	{"years", UNITS, DTK_YEAR}, /* "years" relative */
486 	{"yr", UNITS, DTK_YEAR},	/* "year" relative */
487 	{"yrs", UNITS, DTK_YEAR},	/* "years" relative */
488 };
489 
490 static const unsigned int szdatetktbl = lengthof(datetktbl);
491 static const unsigned int szdeltatktbl = lengthof(deltatktbl);
492 
493 static datetkn *datecache[MAXDATEFIELDS] = {NULL};
494 
495 static datetkn *deltacache[MAXDATEFIELDS] = {NULL};
496 
497 char	   *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL};
498 
499 char	   *days[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", NULL};
500 
501 char	   *pgtypes_date_weekdays_short[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL};
502 
503 char	   *pgtypes_date_months[] = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", NULL};
504 
505 static datetkn *
datebsearch(char * key,datetkn * base,unsigned int nel)506 datebsearch(char *key, datetkn *base, unsigned int nel)
507 {
508 	if (nel > 0)
509 	{
510 		datetkn    *last = base + nel - 1,
511 				   *position;
512 		int			result;
513 
514 		while (last >= base)
515 		{
516 			position = base + ((last - base) >> 1);
517 			/* precheck the first character for a bit of extra speed */
518 			result = (int) key[0] - (int) position->token[0];
519 			if (result == 0)
520 			{
521 				/* use strncmp so that we match truncated tokens */
522 				result = strncmp(key, position->token, TOKMAXLEN);
523 				if (result == 0)
524 					return position;
525 			}
526 			if (result < 0)
527 				last = position - 1;
528 			else
529 				base = position + 1;
530 		}
531 	}
532 	return NULL;
533 }
534 
535 /* DecodeUnits()
536  * Decode text string using lookup table.
537  * This routine supports time interval decoding.
538  */
539 int
DecodeUnits(int field,char * lowtoken,int * val)540 DecodeUnits(int field, char *lowtoken, int *val)
541 {
542 	int			type;
543 	datetkn    *tp;
544 
545 	/* use strncmp so that we match truncated tokens */
546 	if (deltacache[field] != NULL &&
547 		strncmp(lowtoken, deltacache[field]->token, TOKMAXLEN) == 0)
548 		tp = deltacache[field];
549 	else
550 		tp = datebsearch(lowtoken, deltatktbl, szdeltatktbl);
551 	deltacache[field] = tp;
552 	if (tp == NULL)
553 	{
554 		type = UNKNOWN_FIELD;
555 		*val = 0;
556 	}
557 	else
558 	{
559 		type = tp->type;
560 		*val = tp->value;
561 	}
562 
563 	return type;
564 }								/* DecodeUnits() */
565 
566 /*
567  * Calendar time to Julian date conversions.
568  * Julian date is commonly used in astronomical applications,
569  *	since it is numerically accurate and computationally simple.
570  * The algorithms here will accurately convert between Julian day
571  *	and calendar date for all non-negative Julian days
572  *	(i.e. from Nov 24, -4713 on).
573  *
574  * These routines will be used by other date/time packages
575  * - thomas 97/02/25
576  *
577  * Rewritten to eliminate overflow problems. This now allows the
578  * routines to work correctly for all Julian day counts from
579  * 0 to 2147483647	(Nov 24, -4713 to Jun 3, 5874898) assuming
580  * a 32-bit integer. Longer types should also work to the limits
581  * of their precision.
582  */
583 
584 int
date2j(int y,int m,int d)585 date2j(int y, int m, int d)
586 {
587 	int			julian;
588 	int			century;
589 
590 	if (m > 2)
591 	{
592 		m += 1;
593 		y += 4800;
594 	}
595 	else
596 	{
597 		m += 13;
598 		y += 4799;
599 	}
600 
601 	century = y / 100;
602 	julian = y * 365 - 32167;
603 	julian += y / 4 - century + century / 4;
604 	julian += 7834 * m / 256 + d;
605 
606 	return julian;
607 }								/* date2j() */
608 
609 void
j2date(int jd,int * year,int * month,int * day)610 j2date(int jd, int *year, int *month, int *day)
611 {
612 	unsigned int julian;
613 	unsigned int quad;
614 	unsigned int extra;
615 	int			y;
616 
617 	julian = jd;
618 	julian += 32044;
619 	quad = julian / 146097;
620 	extra = (julian - quad * 146097) * 4 + 3;
621 	julian += 60 + quad * 3 + extra / 146097;
622 	quad = julian / 1461;
623 	julian -= quad * 1461;
624 	y = julian * 4 / 1461;
625 	julian = ((y != 0) ? (julian + 305) % 365 : (julian + 306) % 366) + 123;
626 	y += quad * 4;
627 	*year = y - 4800;
628 	quad = julian * 2141 / 65536;
629 	*day = julian - 7834 * quad / 256;
630 	*month = (quad + 10) % 12 + 1;
631 
632 	return;
633 }								/* j2date() */
634 
635 /* DecodeSpecial()
636  * Decode text string using lookup table.
637  * Implement a cache lookup since it is likely that dates
638  *	will be related in format.
639  */
640 static int
DecodeSpecial(int field,char * lowtoken,int * val)641 DecodeSpecial(int field, char *lowtoken, int *val)
642 {
643 	int			type;
644 	datetkn    *tp;
645 
646 	/* use strncmp so that we match truncated tokens */
647 	if (datecache[field] != NULL &&
648 		strncmp(lowtoken, datecache[field]->token, TOKMAXLEN) == 0)
649 		tp = datecache[field];
650 	else
651 	{
652 		tp = NULL;
653 		if (!tp)
654 			tp = datebsearch(lowtoken, datetktbl, szdatetktbl);
655 	}
656 	datecache[field] = tp;
657 	if (tp == NULL)
658 	{
659 		type = UNKNOWN_FIELD;
660 		*val = 0;
661 	}
662 	else
663 	{
664 		type = tp->type;
665 		*val = tp->value;
666 	}
667 
668 	return type;
669 }								/* DecodeSpecial() */
670 
671 /* EncodeDateOnly()
672  * Encode date as local time.
673  */
674 void
EncodeDateOnly(struct tm * tm,int style,char * str,bool EuroDates)675 EncodeDateOnly(struct tm *tm, int style, char *str, bool EuroDates)
676 {
677 	Assert(tm->tm_mon >= 1 && tm->tm_mon <= MONTHS_PER_YEAR);
678 
679 	switch (style)
680 	{
681 		case USE_ISO_DATES:
682 			/* compatible with ISO date formats */
683 			if (tm->tm_year > 0)
684 				sprintf(str, "%04d-%02d-%02d",
685 						tm->tm_year, tm->tm_mon, tm->tm_mday);
686 			else
687 				sprintf(str, "%04d-%02d-%02d %s",
688 						-(tm->tm_year - 1), tm->tm_mon, tm->tm_mday, "BC");
689 			break;
690 
691 		case USE_SQL_DATES:
692 			/* compatible with Oracle/Ingres date formats */
693 			if (EuroDates)
694 				sprintf(str, "%02d/%02d", tm->tm_mday, tm->tm_mon);
695 			else
696 				sprintf(str, "%02d/%02d", tm->tm_mon, tm->tm_mday);
697 			if (tm->tm_year > 0)
698 				sprintf(str + 5, "/%04d", tm->tm_year);
699 			else
700 				sprintf(str + 5, "/%04d %s", -(tm->tm_year - 1), "BC");
701 			break;
702 
703 		case USE_GERMAN_DATES:
704 			/* German-style date format */
705 			sprintf(str, "%02d.%02d", tm->tm_mday, tm->tm_mon);
706 			if (tm->tm_year > 0)
707 				sprintf(str + 5, ".%04d", tm->tm_year);
708 			else
709 				sprintf(str + 5, ".%04d %s", -(tm->tm_year - 1), "BC");
710 			break;
711 
712 		case USE_POSTGRES_DATES:
713 		default:
714 			/* traditional date-only style for Postgres */
715 			if (EuroDates)
716 				sprintf(str, "%02d-%02d", tm->tm_mday, tm->tm_mon);
717 			else
718 				sprintf(str, "%02d-%02d", tm->tm_mon, tm->tm_mday);
719 			if (tm->tm_year > 0)
720 				sprintf(str + 5, "-%04d", tm->tm_year);
721 			else
722 				sprintf(str + 5, "-%04d %s", -(tm->tm_year - 1), "BC");
723 			break;
724 	}
725 }
726 
727 void
TrimTrailingZeros(char * str)728 TrimTrailingZeros(char *str)
729 {
730 	int			len = strlen(str);
731 
732 	/* chop off trailing zeros... but leave at least 2 fractional digits */
733 	while (*(str + len - 1) == '0' && *(str + len - 3) != '.')
734 	{
735 		len--;
736 		*(str + len) = '\0';
737 	}
738 }
739 
740 /* EncodeDateTime()
741  * Encode date and time interpreted as local time.
742  *
743  * tm and fsec are the value to encode, print_tz determines whether to include
744  * a time zone (the difference between timestamp and timestamptz types), tz is
745  * the numeric time zone offset, tzn is the textual time zone, which if
746  * specified will be used instead of tz by some styles, style is the date
747  * style, str is where to write the output.
748  *
749  * Supported date styles:
750  *	Postgres - day mon hh:mm:ss yyyy tz
751  *	SQL - mm/dd/yyyy hh:mm:ss.ss tz
752  *	ISO - yyyy-mm-dd hh:mm:ss+/-tz
753  *	German - dd.mm.yyyy hh:mm:ss tz
754  * Variants (affects order of month and day for Postgres and SQL styles):
755  *	US - mm/dd/yyyy
756  *	European - dd/mm/yyyy
757  */
758 void
EncodeDateTime(struct tm * tm,fsec_t fsec,bool print_tz,int tz,const char * tzn,int style,char * str,bool EuroDates)759 EncodeDateTime(struct tm *tm, fsec_t fsec, bool print_tz, int tz, const char *tzn, int style, char *str, bool EuroDates)
760 {
761 	int			day,
762 				hour,
763 				min;
764 
765 	/*
766 	 * Negative tm_isdst means we have no valid time zone translation.
767 	 */
768 	if (tm->tm_isdst < 0)
769 		print_tz = false;
770 
771 	switch (style)
772 	{
773 		case USE_ISO_DATES:
774 			/* Compatible with ISO-8601 date formats */
775 
776 			sprintf(str, "%04d-%02d-%02d %02d:%02d",
777 					(tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1),
778 					tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min);
779 
780 			/*
781 			 * Print fractional seconds if any.  The field widths here should
782 			 * be at least equal to MAX_TIMESTAMP_PRECISION.
783 			 */
784 			if (fsec != 0)
785 			{
786 				sprintf(str + strlen(str), ":%02d.%06d", tm->tm_sec, fsec);
787 				TrimTrailingZeros(str);
788 			}
789 			else
790 				sprintf(str + strlen(str), ":%02d", tm->tm_sec);
791 
792 			if (tm->tm_year <= 0)
793 				sprintf(str + strlen(str), " BC");
794 
795 			if (print_tz)
796 			{
797 				hour = -(tz / SECS_PER_HOUR);
798 				min = (abs(tz) / MINS_PER_HOUR) % MINS_PER_HOUR;
799 				if (min != 0)
800 					sprintf(str + strlen(str), "%+03d:%02d", hour, min);
801 				else
802 					sprintf(str + strlen(str), "%+03d", hour);
803 			}
804 			break;
805 
806 		case USE_SQL_DATES:
807 			/* Compatible with Oracle/Ingres date formats */
808 
809 			if (EuroDates)
810 				sprintf(str, "%02d/%02d", tm->tm_mday, tm->tm_mon);
811 			else
812 				sprintf(str, "%02d/%02d", tm->tm_mon, tm->tm_mday);
813 
814 			sprintf(str + 5, "/%04d %02d:%02d",
815 					(tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1),
816 					tm->tm_hour, tm->tm_min);
817 
818 			/*
819 			 * Print fractional seconds if any.  The field widths here should
820 			 * be at least equal to MAX_TIMESTAMP_PRECISION.
821 			 */
822 			if (fsec != 0)
823 			{
824 				sprintf(str + strlen(str), ":%02d.%06d", tm->tm_sec, fsec);
825 				TrimTrailingZeros(str);
826 			}
827 			else
828 				sprintf(str + strlen(str), ":%02d", tm->tm_sec);
829 
830 			if (tm->tm_year <= 0)
831 				sprintf(str + strlen(str), " BC");
832 
833 			/*
834 			 * Note: the uses of %.*s in this function would be risky if the
835 			 * timezone names ever contain non-ASCII characters.  However, all
836 			 * TZ abbreviations in the IANA database are plain ASCII.
837 			 */
838 
839 			if (print_tz)
840 			{
841 				if (tzn)
842 					sprintf(str + strlen(str), " %.*s", MAXTZLEN, tzn);
843 				else
844 				{
845 					hour = -(tz / SECS_PER_HOUR);
846 					min = (abs(tz) / MINS_PER_HOUR) % MINS_PER_HOUR;
847 					if (min != 0)
848 						sprintf(str + strlen(str), "%+03d:%02d", hour, min);
849 					else
850 						sprintf(str + strlen(str), "%+03d", hour);
851 				}
852 			}
853 			break;
854 
855 		case USE_GERMAN_DATES:
856 			/* German variant on European style */
857 
858 			sprintf(str, "%02d.%02d", tm->tm_mday, tm->tm_mon);
859 
860 			sprintf(str + 5, ".%04d %02d:%02d",
861 					(tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1),
862 					tm->tm_hour, tm->tm_min);
863 
864 			/*
865 			 * Print fractional seconds if any.  The field widths here should
866 			 * be at least equal to MAX_TIMESTAMP_PRECISION.
867 			 */
868 			if (fsec != 0)
869 			{
870 				sprintf(str + strlen(str), ":%02d.%06d", tm->tm_sec, fsec);
871 				TrimTrailingZeros(str);
872 			}
873 			else
874 				sprintf(str + strlen(str), ":%02d", tm->tm_sec);
875 
876 			if (tm->tm_year <= 0)
877 				sprintf(str + strlen(str), " BC");
878 
879 			if (print_tz)
880 			{
881 				if (tzn)
882 					sprintf(str + strlen(str), " %.*s", MAXTZLEN, tzn);
883 				else
884 				{
885 					hour = -(tz / SECS_PER_HOUR);
886 					min = (abs(tz) / MINS_PER_HOUR) % MINS_PER_HOUR;
887 					if (min != 0)
888 						sprintf(str + strlen(str), "%+03d:%02d", hour, min);
889 					else
890 						sprintf(str + strlen(str), "%+03d", hour);
891 				}
892 			}
893 			break;
894 
895 		case USE_POSTGRES_DATES:
896 		default:
897 			/* Backward-compatible with traditional Postgres abstime dates */
898 
899 			day = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
900 			tm->tm_wday = (int) ((day + date2j(2000, 1, 1) + 1) % 7);
901 
902 			memcpy(str, days[tm->tm_wday], 3);
903 			strcpy(str + 3, " ");
904 
905 			if (EuroDates)
906 				sprintf(str + 4, "%02d %3s", tm->tm_mday, months[tm->tm_mon - 1]);
907 			else
908 				sprintf(str + 4, "%3s %02d", months[tm->tm_mon - 1], tm->tm_mday);
909 
910 			sprintf(str + 10, " %02d:%02d", tm->tm_hour, tm->tm_min);
911 
912 			/*
913 			 * Print fractional seconds if any.  The field widths here should
914 			 * be at least equal to MAX_TIMESTAMP_PRECISION.
915 			 */
916 			if (fsec != 0)
917 			{
918 				sprintf(str + strlen(str), ":%02d.%06d", tm->tm_sec, fsec);
919 				TrimTrailingZeros(str);
920 			}
921 			else
922 				sprintf(str + strlen(str), ":%02d", tm->tm_sec);
923 
924 			sprintf(str + strlen(str), " %04d",
925 					(tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1));
926 			if (tm->tm_year <= 0)
927 				sprintf(str + strlen(str), " BC");
928 
929 			if (print_tz)
930 			{
931 				if (tzn)
932 					sprintf(str + strlen(str), " %.*s", MAXTZLEN, tzn);
933 				else
934 				{
935 					/*
936 					 * We have a time zone, but no string version. Use the
937 					 * numeric form, but be sure to include a leading space to
938 					 * avoid formatting something which would be rejected by
939 					 * the date/time parser later. - thomas 2001-10-19
940 					 */
941 					hour = -(tz / SECS_PER_HOUR);
942 					min = (abs(tz) / MINS_PER_HOUR) % MINS_PER_HOUR;
943 					if (min != 0)
944 						sprintf(str + strlen(str), " %+03d:%02d", hour, min);
945 					else
946 						sprintf(str + strlen(str), " %+03d", hour);
947 				}
948 			}
949 			break;
950 	}
951 }
952 
953 int
GetEpochTime(struct tm * tm)954 GetEpochTime(struct tm *tm)
955 {
956 	struct tm  *t0;
957 	time_t		epoch = 0;
958 
959 	t0 = gmtime(&epoch);
960 
961 	if (t0)
962 	{
963 		tm->tm_year = t0->tm_year + 1900;
964 		tm->tm_mon = t0->tm_mon + 1;
965 		tm->tm_mday = t0->tm_mday;
966 		tm->tm_hour = t0->tm_hour;
967 		tm->tm_min = t0->tm_min;
968 		tm->tm_sec = t0->tm_sec;
969 
970 		return 0;
971 	}
972 
973 	return -1;
974 }								/* GetEpochTime() */
975 
976 static void
abstime2tm(AbsoluteTime _time,int * tzp,struct tm * tm,char ** tzn)977 abstime2tm(AbsoluteTime _time, int *tzp, struct tm *tm, char **tzn)
978 {
979 	time_t		time = (time_t) _time;
980 	struct tm  *tx;
981 
982 	errno = 0;
983 	if (tzp != NULL)
984 		tx = localtime((time_t *) &time);
985 	else
986 		tx = gmtime((time_t *) &time);
987 
988 	if (!tx)
989 	{
990 		errno = PGTYPES_TS_BAD_TIMESTAMP;
991 		return;
992 	}
993 
994 	tm->tm_year = tx->tm_year + 1900;
995 	tm->tm_mon = tx->tm_mon + 1;
996 	tm->tm_mday = tx->tm_mday;
997 	tm->tm_hour = tx->tm_hour;
998 	tm->tm_min = tx->tm_min;
999 	tm->tm_sec = tx->tm_sec;
1000 	tm->tm_isdst = tx->tm_isdst;
1001 
1002 #if defined(HAVE_TM_ZONE)
1003 	tm->tm_gmtoff = tx->tm_gmtoff;
1004 	tm->tm_zone = tx->tm_zone;
1005 
1006 	if (tzp != NULL)
1007 	{
1008 		/*
1009 		 * We have a brute force time zone per SQL99? Then use it without
1010 		 * change since we have already rotated to the time zone.
1011 		 */
1012 		*tzp = -tm->tm_gmtoff;	/* tm_gmtoff is Sun/DEC-ism */
1013 
1014 		/*
1015 		 * FreeBSD man pages indicate that this should work - tgl 97/04/23
1016 		 */
1017 		if (tzn != NULL)
1018 		{
1019 			/*
1020 			 * Copy no more than MAXTZLEN bytes of timezone to tzn, in case it
1021 			 * contains an error message, which doesn't fit in the buffer
1022 			 */
1023 			StrNCpy(*tzn, tm->tm_zone, MAXTZLEN + 1);
1024 			if (strlen(tm->tm_zone) > MAXTZLEN)
1025 				tm->tm_isdst = -1;
1026 		}
1027 	}
1028 	else
1029 		tm->tm_isdst = -1;
1030 #elif defined(HAVE_INT_TIMEZONE)
1031 	if (tzp != NULL)
1032 	{
1033 		*tzp = (tm->tm_isdst > 0) ? TIMEZONE_GLOBAL - SECS_PER_HOUR : TIMEZONE_GLOBAL;
1034 
1035 		if (tzn != NULL)
1036 		{
1037 			/*
1038 			 * Copy no more than MAXTZLEN bytes of timezone to tzn, in case it
1039 			 * contains an error message, which doesn't fit in the buffer
1040 			 */
1041 			StrNCpy(*tzn, TZNAME_GLOBAL[tm->tm_isdst], MAXTZLEN + 1);
1042 			if (strlen(TZNAME_GLOBAL[tm->tm_isdst]) > MAXTZLEN)
1043 				tm->tm_isdst = -1;
1044 		}
1045 	}
1046 	else
1047 		tm->tm_isdst = -1;
1048 #else							/* not (HAVE_TM_ZONE || HAVE_INT_TIMEZONE) */
1049 	if (tzp != NULL)
1050 	{
1051 		/* default to UTC */
1052 		*tzp = 0;
1053 		if (tzn != NULL)
1054 			*tzn = NULL;
1055 	}
1056 	else
1057 		tm->tm_isdst = -1;
1058 #endif
1059 }
1060 
1061 void
GetCurrentDateTime(struct tm * tm)1062 GetCurrentDateTime(struct tm *tm)
1063 {
1064 	int			tz;
1065 
1066 	abstime2tm(time(NULL), &tz, tm, NULL);
1067 }
1068 
1069 void
dt2time(double jd,int * hour,int * min,int * sec,fsec_t * fsec)1070 dt2time(double jd, int *hour, int *min, int *sec, fsec_t *fsec)
1071 {
1072 	int64		time;
1073 
1074 	time = jd;
1075 	*hour = time / USECS_PER_HOUR;
1076 	time -= (*hour) * USECS_PER_HOUR;
1077 	*min = time / USECS_PER_MINUTE;
1078 	time -= (*min) * USECS_PER_MINUTE;
1079 	*sec = time / USECS_PER_SEC;
1080 	*fsec = time - (*sec * USECS_PER_SEC);
1081 }								/* dt2time() */
1082 
1083 
1084 
1085 /* DecodeNumberField()
1086  * Interpret numeric string as a concatenated date or time field.
1087  * Use the context of previously decoded fields to help with
1088  * the interpretation.
1089  */
1090 static int
DecodeNumberField(int len,char * str,int fmask,int * tmask,struct tm * tm,fsec_t * fsec,bool * is2digits)1091 DecodeNumberField(int len, char *str, int fmask,
1092 				  int *tmask, struct tm *tm, fsec_t *fsec, bool *is2digits)
1093 {
1094 	char	   *cp;
1095 
1096 	/*
1097 	 * Have a decimal point? Then this is a date or something with a seconds
1098 	 * field...
1099 	 */
1100 	if ((cp = strchr(str, '.')) != NULL)
1101 	{
1102 		char		fstr[7];
1103 		int			i;
1104 
1105 		cp++;
1106 
1107 		/*
1108 		 * OK, we have at most six digits to care about. Let's construct a
1109 		 * string with those digits, zero-padded on the right, and then do the
1110 		 * conversion to an integer.
1111 		 *
1112 		 * XXX This truncates the seventh digit, unlike rounding it as the
1113 		 * backend does.
1114 		 */
1115 		for (i = 0; i < 6; i++)
1116 			fstr[i] = *cp != '\0' ? *cp++ : '0';
1117 		fstr[i] = '\0';
1118 		*fsec = strtol(fstr, NULL, 10);
1119 		*cp = '\0';
1120 		len = strlen(str);
1121 	}
1122 	/* No decimal point and no complete date yet? */
1123 	else if ((fmask & DTK_DATE_M) != DTK_DATE_M)
1124 	{
1125 		/* yyyymmdd? */
1126 		if (len == 8)
1127 		{
1128 			*tmask = DTK_DATE_M;
1129 
1130 			tm->tm_mday = atoi(str + 6);
1131 			*(str + 6) = '\0';
1132 			tm->tm_mon = atoi(str + 4);
1133 			*(str + 4) = '\0';
1134 			tm->tm_year = atoi(str + 0);
1135 
1136 			return DTK_DATE;
1137 		}
1138 		/* yymmdd? */
1139 		else if (len == 6)
1140 		{
1141 			*tmask = DTK_DATE_M;
1142 			tm->tm_mday = atoi(str + 4);
1143 			*(str + 4) = '\0';
1144 			tm->tm_mon = atoi(str + 2);
1145 			*(str + 2) = '\0';
1146 			tm->tm_year = atoi(str + 0);
1147 			*is2digits = true;
1148 
1149 			return DTK_DATE;
1150 		}
1151 		/* yyddd? */
1152 		else if (len == 5)
1153 		{
1154 			*tmask = DTK_DATE_M;
1155 			tm->tm_mday = atoi(str + 2);
1156 			*(str + 2) = '\0';
1157 			tm->tm_mon = 1;
1158 			tm->tm_year = atoi(str + 0);
1159 			*is2digits = true;
1160 
1161 			return DTK_DATE;
1162 		}
1163 	}
1164 
1165 	/* not all time fields are specified? */
1166 	if ((fmask & DTK_TIME_M) != DTK_TIME_M)
1167 	{
1168 		/* hhmmss */
1169 		if (len == 6)
1170 		{
1171 			*tmask = DTK_TIME_M;
1172 			tm->tm_sec = atoi(str + 4);
1173 			*(str + 4) = '\0';
1174 			tm->tm_min = atoi(str + 2);
1175 			*(str + 2) = '\0';
1176 			tm->tm_hour = atoi(str + 0);
1177 
1178 			return DTK_TIME;
1179 		}
1180 		/* hhmm? */
1181 		else if (len == 4)
1182 		{
1183 			*tmask = DTK_TIME_M;
1184 			tm->tm_sec = 0;
1185 			tm->tm_min = atoi(str + 2);
1186 			*(str + 2) = '\0';
1187 			tm->tm_hour = atoi(str + 0);
1188 
1189 			return DTK_TIME;
1190 		}
1191 	}
1192 
1193 	return -1;
1194 }								/* DecodeNumberField() */
1195 
1196 
1197 /* DecodeNumber()
1198  * Interpret plain numeric field as a date value in context.
1199  */
1200 static int
DecodeNumber(int flen,char * str,int fmask,int * tmask,struct tm * tm,fsec_t * fsec,bool * is2digits,bool EuroDates)1201 DecodeNumber(int flen, char *str, int fmask,
1202 			 int *tmask, struct tm *tm, fsec_t *fsec, bool *is2digits, bool EuroDates)
1203 {
1204 	int			val;
1205 	char	   *cp;
1206 
1207 	*tmask = 0;
1208 
1209 	val = strtol(str, &cp, 10);
1210 	if (cp == str)
1211 		return -1;
1212 
1213 	if (*cp == '.')
1214 	{
1215 		/*
1216 		 * More than two digits? Then could be a date or a run-together time:
1217 		 * 2001.360 20011225 040506.789
1218 		 */
1219 		if (cp - str > 2)
1220 			return DecodeNumberField(flen, str, (fmask | DTK_DATE_M),
1221 									 tmask, tm, fsec, is2digits);
1222 
1223 		*fsec = strtod(cp, &cp);
1224 		if (*cp != '\0')
1225 			return -1;
1226 	}
1227 	else if (*cp != '\0')
1228 		return -1;
1229 
1230 	/* Special case day of year? */
1231 	if (flen == 3 && (fmask & DTK_M(YEAR)) && val >= 1 && val <= 366)
1232 	{
1233 		*tmask = (DTK_M(DOY) | DTK_M(MONTH) | DTK_M(DAY));
1234 		tm->tm_yday = val;
1235 		j2date(date2j(tm->tm_year, 1, 1) + tm->tm_yday - 1,
1236 			   &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
1237 	}
1238 
1239 	/***
1240 	 * Enough digits to be unequivocal year? Used to test for 4 digits or
1241 	 * more, but we now test first for a three-digit doy so anything
1242 	 * bigger than two digits had better be an explicit year.
1243 	 * - thomas 1999-01-09
1244 	 * Back to requiring a 4 digit year. We accept a two digit
1245 	 * year farther down. - thomas 2000-03-28
1246 	 ***/
1247 	else if (flen >= 4)
1248 	{
1249 		*tmask = DTK_M(YEAR);
1250 
1251 		/* already have a year? then see if we can substitute... */
1252 		if ((fmask & DTK_M(YEAR)) && !(fmask & DTK_M(DAY)) &&
1253 			tm->tm_year >= 1 && tm->tm_year <= 31)
1254 		{
1255 			tm->tm_mday = tm->tm_year;
1256 			*tmask = DTK_M(DAY);
1257 		}
1258 
1259 		tm->tm_year = val;
1260 	}
1261 
1262 	/* already have year? then could be month */
1263 	else if ((fmask & DTK_M(YEAR)) && !(fmask & DTK_M(MONTH)) && val >= 1 && val <= MONTHS_PER_YEAR)
1264 	{
1265 		*tmask = DTK_M(MONTH);
1266 		tm->tm_mon = val;
1267 	}
1268 	/* no year and EuroDates enabled? then could be day */
1269 	else if ((EuroDates || (fmask & DTK_M(MONTH))) &&
1270 			 !(fmask & DTK_M(YEAR)) && !(fmask & DTK_M(DAY)) &&
1271 			 val >= 1 && val <= 31)
1272 	{
1273 		*tmask = DTK_M(DAY);
1274 		tm->tm_mday = val;
1275 	}
1276 	else if (!(fmask & DTK_M(MONTH)) && val >= 1 && val <= MONTHS_PER_YEAR)
1277 	{
1278 		*tmask = DTK_M(MONTH);
1279 		tm->tm_mon = val;
1280 	}
1281 	else if (!(fmask & DTK_M(DAY)) && val >= 1 && val <= 31)
1282 	{
1283 		*tmask = DTK_M(DAY);
1284 		tm->tm_mday = val;
1285 	}
1286 
1287 	/*
1288 	 * Check for 2 or 4 or more digits, but currently we reach here only if
1289 	 * two digits. - thomas 2000-03-28
1290 	 */
1291 	else if (!(fmask & DTK_M(YEAR)) && (flen >= 4 || flen == 2))
1292 	{
1293 		*tmask = DTK_M(YEAR);
1294 		tm->tm_year = val;
1295 
1296 		/* adjust ONLY if exactly two digits... */
1297 		*is2digits = (flen == 2);
1298 	}
1299 	else
1300 		return -1;
1301 
1302 	return 0;
1303 }								/* DecodeNumber() */
1304 
1305 /* DecodeDate()
1306  * Decode date string which includes delimiters.
1307  * Insist on a complete set of fields.
1308  */
1309 static int
DecodeDate(char * str,int fmask,int * tmask,struct tm * tm,bool EuroDates)1310 DecodeDate(char *str, int fmask, int *tmask, struct tm *tm, bool EuroDates)
1311 {
1312 	fsec_t		fsec;
1313 
1314 	int			nf = 0;
1315 	int			i,
1316 				len;
1317 	bool		bc = false;
1318 	bool		is2digits = false;
1319 	int			type,
1320 				val,
1321 				dmask = 0;
1322 	char	   *field[MAXDATEFIELDS];
1323 
1324 	/* parse this string... */
1325 	while (*str != '\0' && nf < MAXDATEFIELDS)
1326 	{
1327 		/* skip field separators */
1328 		while (!isalnum((unsigned char) *str))
1329 			str++;
1330 
1331 		field[nf] = str;
1332 		if (isdigit((unsigned char) *str))
1333 		{
1334 			while (isdigit((unsigned char) *str))
1335 				str++;
1336 		}
1337 		else if (isalpha((unsigned char) *str))
1338 		{
1339 			while (isalpha((unsigned char) *str))
1340 				str++;
1341 		}
1342 
1343 		/* Just get rid of any non-digit, non-alpha characters... */
1344 		if (*str != '\0')
1345 			*str++ = '\0';
1346 		nf++;
1347 	}
1348 
1349 #if 0
1350 	/* don't allow too many fields */
1351 	if (nf > 3)
1352 		return -1;
1353 #endif
1354 
1355 	*tmask = 0;
1356 
1357 	/* look first for text fields, since that will be unambiguous month */
1358 	for (i = 0; i < nf; i++)
1359 	{
1360 		if (isalpha((unsigned char) *field[i]))
1361 		{
1362 			type = DecodeSpecial(i, field[i], &val);
1363 			if (type == IGNORE_DTF)
1364 				continue;
1365 
1366 			dmask = DTK_M(type);
1367 			switch (type)
1368 			{
1369 				case MONTH:
1370 					tm->tm_mon = val;
1371 					break;
1372 
1373 				case ADBC:
1374 					bc = (val == BC);
1375 					break;
1376 
1377 				default:
1378 					return -1;
1379 			}
1380 			if (fmask & dmask)
1381 				return -1;
1382 
1383 			fmask |= dmask;
1384 			*tmask |= dmask;
1385 
1386 			/* mark this field as being completed */
1387 			field[i] = NULL;
1388 		}
1389 	}
1390 
1391 	/* now pick up remaining numeric fields */
1392 	for (i = 0; i < nf; i++)
1393 	{
1394 		if (field[i] == NULL)
1395 			continue;
1396 
1397 		if ((len = strlen(field[i])) <= 0)
1398 			return -1;
1399 
1400 		if (DecodeNumber(len, field[i], fmask, &dmask, tm, &fsec, &is2digits, EuroDates) != 0)
1401 			return -1;
1402 
1403 		if (fmask & dmask)
1404 			return -1;
1405 
1406 		fmask |= dmask;
1407 		*tmask |= dmask;
1408 	}
1409 
1410 	if ((fmask & ~(DTK_M(DOY) | DTK_M(TZ))) != DTK_DATE_M)
1411 		return -1;
1412 
1413 	/* there is no year zero in AD/BC notation; i.e. "1 BC" == year 0 */
1414 	if (bc)
1415 	{
1416 		if (tm->tm_year > 0)
1417 			tm->tm_year = -(tm->tm_year - 1);
1418 		else
1419 			return -1;
1420 	}
1421 	else if (is2digits)
1422 	{
1423 		if (tm->tm_year < 70)
1424 			tm->tm_year += 2000;
1425 		else if (tm->tm_year < 100)
1426 			tm->tm_year += 1900;
1427 	}
1428 
1429 	return 0;
1430 }								/* DecodeDate() */
1431 
1432 
1433 /* DecodeTime()
1434  * Decode time string which includes delimiters.
1435  * Only check the lower limit on hours, since this same code
1436  *	can be used to represent time spans.
1437  */
1438 int
DecodeTime(char * str,int * tmask,struct tm * tm,fsec_t * fsec)1439 DecodeTime(char *str, int *tmask, struct tm *tm, fsec_t *fsec)
1440 {
1441 	char	   *cp;
1442 
1443 	*tmask = DTK_TIME_M;
1444 
1445 	tm->tm_hour = strtol(str, &cp, 10);
1446 	if (*cp != ':')
1447 		return -1;
1448 	str = cp + 1;
1449 	tm->tm_min = strtol(str, &cp, 10);
1450 	if (*cp == '\0')
1451 	{
1452 		tm->tm_sec = 0;
1453 		*fsec = 0;
1454 	}
1455 	else if (*cp != ':')
1456 		return -1;
1457 	else
1458 	{
1459 		str = cp + 1;
1460 		tm->tm_sec = strtol(str, &cp, 10);
1461 		if (*cp == '\0')
1462 			*fsec = 0;
1463 		else if (*cp == '.')
1464 		{
1465 			char		fstr[7];
1466 			int			i;
1467 
1468 			cp++;
1469 
1470 			/*
1471 			 * OK, we have at most six digits to care about. Let's construct a
1472 			 * string with those digits, zero-padded on the right, and then do
1473 			 * the conversion to an integer.
1474 			 *
1475 			 * XXX This truncates the seventh digit, unlike rounding it as the
1476 			 * backend does.
1477 			 */
1478 			for (i = 0; i < 6; i++)
1479 				fstr[i] = *cp != '\0' ? *cp++ : '0';
1480 			fstr[i] = '\0';
1481 			*fsec = strtol(fstr, &cp, 10);
1482 			if (*cp != '\0')
1483 				return -1;
1484 		}
1485 		else
1486 			return -1;
1487 	}
1488 
1489 	/* do a sanity check */
1490 	if (tm->tm_hour < 0 || tm->tm_min < 0 || tm->tm_min > 59 ||
1491 		tm->tm_sec < 0 || tm->tm_sec > 59 || *fsec >= USECS_PER_SEC)
1492 		return -1;
1493 
1494 	return 0;
1495 }								/* DecodeTime() */
1496 
1497 /* DecodeTimezone()
1498  * Interpret string as a numeric timezone.
1499  *
1500  * Note: we allow timezone offsets up to 13:59.  There are places that
1501  * use +1300 summer time.
1502  */
1503 static int
DecodeTimezone(char * str,int * tzp)1504 DecodeTimezone(char *str, int *tzp)
1505 {
1506 	int			tz;
1507 	int			hr,
1508 				min;
1509 	char	   *cp;
1510 	int			len;
1511 
1512 	/* assume leading character is "+" or "-" */
1513 	hr = strtol(str + 1, &cp, 10);
1514 
1515 	/* explicit delimiter? */
1516 	if (*cp == ':')
1517 		min = strtol(cp + 1, &cp, 10);
1518 	/* otherwise, might have run things together... */
1519 	else if (*cp == '\0' && (len = strlen(str)) > 3)
1520 	{
1521 		min = strtol(str + len - 2, &cp, 10);
1522 		if (min < 0 || min >= 60)
1523 			return -1;
1524 
1525 		*(str + len - 2) = '\0';
1526 		hr = strtol(str + 1, &cp, 10);
1527 		if (hr < 0 || hr > 13)
1528 			return -1;
1529 	}
1530 	else
1531 		min = 0;
1532 
1533 	tz = (hr * MINS_PER_HOUR + min) * SECS_PER_MINUTE;
1534 	if (*str == '-')
1535 		tz = -tz;
1536 
1537 	*tzp = -tz;
1538 	return *cp != '\0';
1539 }								/* DecodeTimezone() */
1540 
1541 
1542 /* DecodePosixTimezone()
1543  * Interpret string as a POSIX-compatible timezone:
1544  *	PST-hh:mm
1545  *	PST+h
1546  * - thomas 2000-03-15
1547  */
1548 static int
DecodePosixTimezone(char * str,int * tzp)1549 DecodePosixTimezone(char *str, int *tzp)
1550 {
1551 	int			val,
1552 				tz;
1553 	int			type;
1554 	char	   *cp;
1555 	char		delim;
1556 
1557 	cp = str;
1558 	while (*cp != '\0' && isalpha((unsigned char) *cp))
1559 		cp++;
1560 
1561 	if (DecodeTimezone(cp, &tz) != 0)
1562 		return -1;
1563 
1564 	delim = *cp;
1565 	*cp = '\0';
1566 	type = DecodeSpecial(MAXDATEFIELDS - 1, str, &val);
1567 	*cp = delim;
1568 
1569 	switch (type)
1570 	{
1571 		case DTZ:
1572 		case TZ:
1573 			*tzp = -(val + tz);
1574 			break;
1575 
1576 		default:
1577 			return -1;
1578 	}
1579 
1580 	return 0;
1581 }								/* DecodePosixTimezone() */
1582 
1583 /* ParseDateTime()
1584  * Break string into tokens based on a date/time context.
1585  * Several field types are assigned:
1586  *	DTK_NUMBER - digits and (possibly) a decimal point
1587  *	DTK_DATE - digits and two delimiters, or digits and text
1588  *	DTK_TIME - digits, colon delimiters, and possibly a decimal point
1589  *	DTK_STRING - text (no digits)
1590  *	DTK_SPECIAL - leading "+" or "-" followed by text
1591  *	DTK_TZ - leading "+" or "-" followed by digits
1592  * Note that some field types can hold unexpected items:
1593  *	DTK_NUMBER can hold date fields (yy.ddd)
1594  *	DTK_STRING can hold months (January) and time zones (PST)
1595  *	DTK_DATE can hold Posix time zones (GMT-8)
1596  *
1597  * The "lowstr" work buffer must have at least strlen(timestr) + MAXDATEFIELDS
1598  * bytes of space.  On output, field[] entries will point into it.
1599  * The field[] and ftype[] arrays must have at least MAXDATEFIELDS entries.
1600  */
1601 int
ParseDateTime(char * timestr,char * lowstr,char ** field,int * ftype,int * numfields,char ** endstr)1602 ParseDateTime(char *timestr, char *lowstr,
1603 			  char **field, int *ftype, int *numfields, char **endstr)
1604 {
1605 	int			nf = 0;
1606 	char	   *lp = lowstr;
1607 
1608 	*endstr = timestr;
1609 	/* outer loop through fields */
1610 	while (*(*endstr) != '\0')
1611 	{
1612 		/* Record start of current field */
1613 		if (nf >= MAXDATEFIELDS)
1614 			return -1;
1615 		field[nf] = lp;
1616 
1617 		/* leading digit? then date or time */
1618 		if (isdigit((unsigned char) *(*endstr)))
1619 		{
1620 			*lp++ = *(*endstr)++;
1621 			while (isdigit((unsigned char) *(*endstr)))
1622 				*lp++ = *(*endstr)++;
1623 
1624 			/* time field? */
1625 			if (*(*endstr) == ':')
1626 			{
1627 				ftype[nf] = DTK_TIME;
1628 				*lp++ = *(*endstr)++;
1629 				while (isdigit((unsigned char) *(*endstr)) ||
1630 					   (*(*endstr) == ':') || (*(*endstr) == '.'))
1631 					*lp++ = *(*endstr)++;
1632 			}
1633 			/* date field? allow embedded text month */
1634 			else if (*(*endstr) == '-' || *(*endstr) == '/' || *(*endstr) == '.')
1635 			{
1636 				/* save delimiting character to use later */
1637 				char	   *dp = (*endstr);
1638 
1639 				*lp++ = *(*endstr)++;
1640 				/* second field is all digits? then no embedded text month */
1641 				if (isdigit((unsigned char) *(*endstr)))
1642 				{
1643 					ftype[nf] = (*dp == '.') ? DTK_NUMBER : DTK_DATE;
1644 					while (isdigit((unsigned char) *(*endstr)))
1645 						*lp++ = *(*endstr)++;
1646 
1647 					/*
1648 					 * insist that the delimiters match to get a three-field
1649 					 * date.
1650 					 */
1651 					if (*(*endstr) == *dp)
1652 					{
1653 						ftype[nf] = DTK_DATE;
1654 						*lp++ = *(*endstr)++;
1655 						while (isdigit((unsigned char) *(*endstr)) || (*(*endstr) == *dp))
1656 							*lp++ = *(*endstr)++;
1657 					}
1658 				}
1659 				else
1660 				{
1661 					ftype[nf] = DTK_DATE;
1662 					while (isalnum((unsigned char) *(*endstr)) || (*(*endstr) == *dp))
1663 						*lp++ = pg_tolower((unsigned char) *(*endstr)++);
1664 				}
1665 			}
1666 
1667 			/*
1668 			 * otherwise, number only and will determine year, month, day, or
1669 			 * concatenated fields later...
1670 			 */
1671 			else
1672 				ftype[nf] = DTK_NUMBER;
1673 		}
1674 		/* Leading decimal point? Then fractional seconds... */
1675 		else if (*(*endstr) == '.')
1676 		{
1677 			*lp++ = *(*endstr)++;
1678 			while (isdigit((unsigned char) *(*endstr)))
1679 				*lp++ = *(*endstr)++;
1680 
1681 			ftype[nf] = DTK_NUMBER;
1682 		}
1683 
1684 		/*
1685 		 * text? then date string, month, day of week, special, or timezone
1686 		 */
1687 		else if (isalpha((unsigned char) *(*endstr)))
1688 		{
1689 			ftype[nf] = DTK_STRING;
1690 			*lp++ = pg_tolower((unsigned char) *(*endstr)++);
1691 			while (isalpha((unsigned char) *(*endstr)))
1692 				*lp++ = pg_tolower((unsigned char) *(*endstr)++);
1693 
1694 			/*
1695 			 * Full date string with leading text month? Could also be a POSIX
1696 			 * time zone...
1697 			 */
1698 			if (*(*endstr) == '-' || *(*endstr) == '/' || *(*endstr) == '.')
1699 			{
1700 				char	   *dp = (*endstr);
1701 
1702 				ftype[nf] = DTK_DATE;
1703 				*lp++ = *(*endstr)++;
1704 				while (isdigit((unsigned char) *(*endstr)) || *(*endstr) == *dp)
1705 					*lp++ = *(*endstr)++;
1706 			}
1707 		}
1708 		/* skip leading spaces */
1709 		else if (isspace((unsigned char) *(*endstr)))
1710 		{
1711 			(*endstr)++;
1712 			continue;
1713 		}
1714 		/* sign? then special or numeric timezone */
1715 		else if (*(*endstr) == '+' || *(*endstr) == '-')
1716 		{
1717 			*lp++ = *(*endstr)++;
1718 			/* soak up leading whitespace */
1719 			while (isspace((unsigned char) *(*endstr)))
1720 				(*endstr)++;
1721 			/* numeric timezone? */
1722 			if (isdigit((unsigned char) *(*endstr)))
1723 			{
1724 				ftype[nf] = DTK_TZ;
1725 				*lp++ = *(*endstr)++;
1726 				while (isdigit((unsigned char) *(*endstr)) ||
1727 					   (*(*endstr) == ':') || (*(*endstr) == '.'))
1728 					*lp++ = *(*endstr)++;
1729 			}
1730 			/* special? */
1731 			else if (isalpha((unsigned char) *(*endstr)))
1732 			{
1733 				ftype[nf] = DTK_SPECIAL;
1734 				*lp++ = pg_tolower((unsigned char) *(*endstr)++);
1735 				while (isalpha((unsigned char) *(*endstr)))
1736 					*lp++ = pg_tolower((unsigned char) *(*endstr)++);
1737 			}
1738 			/* otherwise something wrong... */
1739 			else
1740 				return -1;
1741 		}
1742 		/* ignore punctuation but use as delimiter */
1743 		else if (ispunct((unsigned char) *(*endstr)))
1744 		{
1745 			(*endstr)++;
1746 			continue;
1747 
1748 		}
1749 		/* otherwise, something is not right... */
1750 		else
1751 			return -1;
1752 
1753 		/* force in a delimiter after each field */
1754 		*lp++ = '\0';
1755 		nf++;
1756 	}
1757 
1758 	*numfields = nf;
1759 
1760 	return 0;
1761 }								/* ParseDateTime() */
1762 
1763 
1764 /* DecodeDateTime()
1765  * Interpret previously parsed fields for general date and time.
1766  * Return 0 if full date, 1 if only time, and -1 if problems.
1767  *		External format(s):
1768  *				"<weekday> <month>-<day>-<year> <hour>:<minute>:<second>"
1769  *				"Fri Feb-7-1997 15:23:27"
1770  *				"Feb-7-1997 15:23:27"
1771  *				"2-7-1997 15:23:27"
1772  *				"1997-2-7 15:23:27"
1773  *				"1997.038 15:23:27"		(day of year 1-366)
1774  *		Also supports input in compact time:
1775  *				"970207 152327"
1776  *				"97038 152327"
1777  *				"20011225T040506.789-07"
1778  *
1779  * Use the system-provided functions to get the current time zone
1780  *	if not specified in the input string.
1781  * If the date is outside the time_t system-supported time range,
1782  *	then assume UTC time zone. - thomas 1997-05-27
1783  */
1784 int
DecodeDateTime(char ** field,int * ftype,int nf,int * dtype,struct tm * tm,fsec_t * fsec,bool EuroDates)1785 DecodeDateTime(char **field, int *ftype, int nf,
1786 			   int *dtype, struct tm *tm, fsec_t *fsec, bool EuroDates)
1787 {
1788 	int			fmask = 0,
1789 				tmask,
1790 				type;
1791 	int			ptype = 0;		/* "prefix type" for ISO y2001m02d04 format */
1792 	int			i;
1793 	int			val;
1794 	int			mer = HR24;
1795 	bool		haveTextMonth = false;
1796 	bool		is2digits = false;
1797 	bool		bc = false;
1798 	int			t = 0;
1799 	int		   *tzp = &t;
1800 
1801 	/***
1802 	 * We'll insist on at least all of the date fields, but initialize the
1803 	 * remaining fields in case they are not set later...
1804 	 ***/
1805 	*dtype = DTK_DATE;
1806 	tm->tm_hour = 0;
1807 	tm->tm_min = 0;
1808 	tm->tm_sec = 0;
1809 	*fsec = 0;
1810 	/* don't know daylight savings time status apriori */
1811 	tm->tm_isdst = -1;
1812 	if (tzp != NULL)
1813 		*tzp = 0;
1814 
1815 	for (i = 0; i < nf; i++)
1816 	{
1817 		switch (ftype[i])
1818 		{
1819 			case DTK_DATE:
1820 				/***
1821 				 * Integral julian day with attached time zone?
1822 				 * All other forms with JD will be separated into
1823 				 * distinct fields, so we handle just this case here.
1824 				 ***/
1825 				if (ptype == DTK_JULIAN)
1826 				{
1827 					char	   *cp;
1828 					int			val;
1829 
1830 					if (tzp == NULL)
1831 						return -1;
1832 
1833 					val = strtol(field[i], &cp, 10);
1834 					if (*cp != '-')
1835 						return -1;
1836 
1837 					j2date(val, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
1838 					/* Get the time zone from the end of the string */
1839 					if (DecodeTimezone(cp, tzp) != 0)
1840 						return -1;
1841 
1842 					tmask = DTK_DATE_M | DTK_TIME_M | DTK_M(TZ);
1843 					ptype = 0;
1844 					break;
1845 				}
1846 				/***
1847 				 * Already have a date? Then this might be a POSIX time
1848 				 * zone with an embedded dash (e.g. "PST-3" == "EST") or
1849 				 * a run-together time with trailing time zone (e.g. hhmmss-zz).
1850 				 * - thomas 2001-12-25
1851 				 ***/
1852 				else if (((fmask & DTK_DATE_M) == DTK_DATE_M)
1853 						 || (ptype != 0))
1854 				{
1855 					/* No time zone accepted? Then quit... */
1856 					if (tzp == NULL)
1857 						return -1;
1858 
1859 					if (isdigit((unsigned char) *field[i]) || ptype != 0)
1860 					{
1861 						char	   *cp;
1862 
1863 						if (ptype != 0)
1864 						{
1865 							/* Sanity check; should not fail this test */
1866 							if (ptype != DTK_TIME)
1867 								return -1;
1868 							ptype = 0;
1869 						}
1870 
1871 						/*
1872 						 * Starts with a digit but we already have a time
1873 						 * field? Then we are in trouble with a date and time
1874 						 * already...
1875 						 */
1876 						if ((fmask & DTK_TIME_M) == DTK_TIME_M)
1877 							return -1;
1878 
1879 						if ((cp = strchr(field[i], '-')) == NULL)
1880 							return -1;
1881 
1882 						/* Get the time zone from the end of the string */
1883 						if (DecodeTimezone(cp, tzp) != 0)
1884 							return -1;
1885 						*cp = '\0';
1886 
1887 						/*
1888 						 * Then read the rest of the field as a concatenated
1889 						 * time
1890 						 */
1891 						if ((ftype[i] = DecodeNumberField(strlen(field[i]), field[i], fmask,
1892 														  &tmask, tm, fsec, &is2digits)) < 0)
1893 							return -1;
1894 
1895 						/*
1896 						 * modify tmask after returning from
1897 						 * DecodeNumberField()
1898 						 */
1899 						tmask |= DTK_M(TZ);
1900 					}
1901 					else
1902 					{
1903 						if (DecodePosixTimezone(field[i], tzp) != 0)
1904 							return -1;
1905 
1906 						ftype[i] = DTK_TZ;
1907 						tmask = DTK_M(TZ);
1908 					}
1909 				}
1910 				else if (DecodeDate(field[i], fmask, &tmask, tm, EuroDates) != 0)
1911 					return -1;
1912 				break;
1913 
1914 			case DTK_TIME:
1915 				if (DecodeTime(field[i], &tmask, tm, fsec) != 0)
1916 					return -1;
1917 
1918 				/*
1919 				 * Check upper limit on hours; other limits checked in
1920 				 * DecodeTime()
1921 				 */
1922 				/* test for > 24:00:00 */
1923 				if (tm->tm_hour > 24 ||
1924 					(tm->tm_hour == 24 && (tm->tm_min > 0 || tm->tm_sec > 0)))
1925 					return -1;
1926 				break;
1927 
1928 			case DTK_TZ:
1929 				{
1930 					int			tz;
1931 
1932 					if (tzp == NULL)
1933 						return -1;
1934 
1935 					if (DecodeTimezone(field[i], &tz) != 0)
1936 						return -1;
1937 
1938 					/*
1939 					 * Already have a time zone? Then maybe this is the second
1940 					 * field of a POSIX time: EST+3 (equivalent to PST)
1941 					 */
1942 					if (i > 0 && (fmask & DTK_M(TZ)) != 0 &&
1943 						ftype[i - 1] == DTK_TZ &&
1944 						isalpha((unsigned char) *field[i - 1]))
1945 					{
1946 						*tzp -= tz;
1947 						tmask = 0;
1948 					}
1949 					else
1950 					{
1951 						*tzp = tz;
1952 						tmask = DTK_M(TZ);
1953 					}
1954 				}
1955 				break;
1956 
1957 			case DTK_NUMBER:
1958 
1959 				/*
1960 				 * Was this an "ISO date" with embedded field labels? An
1961 				 * example is "y2001m02d04" - thomas 2001-02-04
1962 				 */
1963 				if (ptype != 0)
1964 				{
1965 					char	   *cp;
1966 					int			val;
1967 
1968 					val = strtol(field[i], &cp, 10);
1969 
1970 					/*
1971 					 * only a few kinds are allowed to have an embedded
1972 					 * decimal
1973 					 */
1974 					if (*cp == '.')
1975 						switch (ptype)
1976 						{
1977 							case DTK_JULIAN:
1978 							case DTK_TIME:
1979 							case DTK_SECOND:
1980 								break;
1981 							default:
1982 								return 1;
1983 								break;
1984 						}
1985 					else if (*cp != '\0')
1986 						return -1;
1987 
1988 					switch (ptype)
1989 					{
1990 						case DTK_YEAR:
1991 							tm->tm_year = val;
1992 							tmask = DTK_M(YEAR);
1993 							break;
1994 
1995 						case DTK_MONTH:
1996 
1997 							/*
1998 							 * already have a month and hour? then assume
1999 							 * minutes
2000 							 */
2001 							if ((fmask & DTK_M(MONTH)) != 0 &&
2002 								(fmask & DTK_M(HOUR)) != 0)
2003 							{
2004 								tm->tm_min = val;
2005 								tmask = DTK_M(MINUTE);
2006 							}
2007 							else
2008 							{
2009 								tm->tm_mon = val;
2010 								tmask = DTK_M(MONTH);
2011 							}
2012 							break;
2013 
2014 						case DTK_DAY:
2015 							tm->tm_mday = val;
2016 							tmask = DTK_M(DAY);
2017 							break;
2018 
2019 						case DTK_HOUR:
2020 							tm->tm_hour = val;
2021 							tmask = DTK_M(HOUR);
2022 							break;
2023 
2024 						case DTK_MINUTE:
2025 							tm->tm_min = val;
2026 							tmask = DTK_M(MINUTE);
2027 							break;
2028 
2029 						case DTK_SECOND:
2030 							tm->tm_sec = val;
2031 							tmask = DTK_M(SECOND);
2032 							if (*cp == '.')
2033 							{
2034 								double		frac;
2035 
2036 								frac = strtod(cp, &cp);
2037 								if (*cp != '\0')
2038 									return -1;
2039 								*fsec = frac * 1000000;
2040 							}
2041 							break;
2042 
2043 						case DTK_TZ:
2044 							tmask = DTK_M(TZ);
2045 							if (DecodeTimezone(field[i], tzp) != 0)
2046 								return -1;
2047 							break;
2048 
2049 						case DTK_JULIAN:
2050 							/***
2051 							 * previous field was a label for "julian date"?
2052 							 ***/
2053 							tmask = DTK_DATE_M;
2054 							j2date(val, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
2055 							/* fractional Julian Day? */
2056 							if (*cp == '.')
2057 							{
2058 								double		time;
2059 
2060 								time = strtod(cp, &cp);
2061 								if (*cp != '\0')
2062 									return -1;
2063 
2064 								tmask |= DTK_TIME_M;
2065 								dt2time((time * USECS_PER_DAY), &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec);
2066 							}
2067 							break;
2068 
2069 						case DTK_TIME:
2070 							/* previous field was "t" for ISO time */
2071 							if ((ftype[i] = DecodeNumberField(strlen(field[i]), field[i], (fmask | DTK_DATE_M),
2072 															  &tmask, tm, fsec, &is2digits)) < 0)
2073 								return -1;
2074 
2075 							if (tmask != DTK_TIME_M)
2076 								return -1;
2077 							break;
2078 
2079 						default:
2080 							return -1;
2081 							break;
2082 					}
2083 
2084 					ptype = 0;
2085 					*dtype = DTK_DATE;
2086 				}
2087 				else
2088 				{
2089 					char	   *cp;
2090 					int			flen;
2091 
2092 					flen = strlen(field[i]);
2093 					cp = strchr(field[i], '.');
2094 
2095 					/* Embedded decimal and no date yet? */
2096 					if (cp != NULL && !(fmask & DTK_DATE_M))
2097 					{
2098 						if (DecodeDate(field[i], fmask, &tmask, tm, EuroDates) != 0)
2099 							return -1;
2100 					}
2101 					/* embedded decimal and several digits before? */
2102 					else if (cp != NULL && flen - strlen(cp) > 2)
2103 					{
2104 						/*
2105 						 * Interpret as a concatenated date or time Set the
2106 						 * type field to allow decoding other fields later.
2107 						 * Example: 20011223 or 040506
2108 						 */
2109 						if ((ftype[i] = DecodeNumberField(flen, field[i], fmask,
2110 														  &tmask, tm, fsec, &is2digits)) < 0)
2111 							return -1;
2112 					}
2113 					else if (flen > 4)
2114 					{
2115 						if ((ftype[i] = DecodeNumberField(flen, field[i], fmask,
2116 														  &tmask, tm, fsec, &is2digits)) < 0)
2117 							return -1;
2118 					}
2119 					/* otherwise it is a single date/time field... */
2120 					else if (DecodeNumber(flen, field[i], fmask,
2121 										  &tmask, tm, fsec, &is2digits, EuroDates) != 0)
2122 						return -1;
2123 				}
2124 				break;
2125 
2126 			case DTK_STRING:
2127 			case DTK_SPECIAL:
2128 				type = DecodeSpecial(i, field[i], &val);
2129 				if (type == IGNORE_DTF)
2130 					continue;
2131 
2132 				tmask = DTK_M(type);
2133 				switch (type)
2134 				{
2135 					case RESERV:
2136 						switch (val)
2137 						{
2138 							case DTK_NOW:
2139 								tmask = (DTK_DATE_M | DTK_TIME_M | DTK_M(TZ));
2140 								*dtype = DTK_DATE;
2141 								GetCurrentDateTime(tm);
2142 								break;
2143 
2144 							case DTK_YESTERDAY:
2145 								tmask = DTK_DATE_M;
2146 								*dtype = DTK_DATE;
2147 								GetCurrentDateTime(tm);
2148 								j2date(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - 1,
2149 									   &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
2150 								tm->tm_hour = 0;
2151 								tm->tm_min = 0;
2152 								tm->tm_sec = 0;
2153 								break;
2154 
2155 							case DTK_TODAY:
2156 								tmask = DTK_DATE_M;
2157 								*dtype = DTK_DATE;
2158 								GetCurrentDateTime(tm);
2159 								tm->tm_hour = 0;
2160 								tm->tm_min = 0;
2161 								tm->tm_sec = 0;
2162 								break;
2163 
2164 							case DTK_TOMORROW:
2165 								tmask = DTK_DATE_M;
2166 								*dtype = DTK_DATE;
2167 								GetCurrentDateTime(tm);
2168 								j2date(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) + 1,
2169 									   &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
2170 								tm->tm_hour = 0;
2171 								tm->tm_min = 0;
2172 								tm->tm_sec = 0;
2173 								break;
2174 
2175 							case DTK_ZULU:
2176 								tmask = (DTK_TIME_M | DTK_M(TZ));
2177 								*dtype = DTK_DATE;
2178 								tm->tm_hour = 0;
2179 								tm->tm_min = 0;
2180 								tm->tm_sec = 0;
2181 								if (tzp != NULL)
2182 									*tzp = 0;
2183 								break;
2184 
2185 							default:
2186 								*dtype = val;
2187 						}
2188 
2189 						break;
2190 
2191 					case MONTH:
2192 
2193 						/*
2194 						 * already have a (numeric) month? then see if we can
2195 						 * substitute...
2196 						 */
2197 						if ((fmask & DTK_M(MONTH)) && !haveTextMonth &&
2198 							!(fmask & DTK_M(DAY)) && tm->tm_mon >= 1 && tm->tm_mon <= 31)
2199 						{
2200 							tm->tm_mday = tm->tm_mon;
2201 							tmask = DTK_M(DAY);
2202 						}
2203 						haveTextMonth = true;
2204 						tm->tm_mon = val;
2205 						break;
2206 
2207 					case DTZMOD:
2208 
2209 						/*
2210 						 * daylight savings time modifier (solves "MET DST"
2211 						 * syntax)
2212 						 */
2213 						tmask |= DTK_M(DTZ);
2214 						tm->tm_isdst = 1;
2215 						if (tzp == NULL)
2216 							return -1;
2217 						*tzp -= val;
2218 						break;
2219 
2220 					case DTZ:
2221 
2222 						/*
2223 						 * set mask for TZ here _or_ check for DTZ later when
2224 						 * getting default timezone
2225 						 */
2226 						tmask |= DTK_M(TZ);
2227 						tm->tm_isdst = 1;
2228 						if (tzp == NULL)
2229 							return -1;
2230 						*tzp = -val;
2231 						ftype[i] = DTK_TZ;
2232 						break;
2233 
2234 					case TZ:
2235 						tm->tm_isdst = 0;
2236 						if (tzp == NULL)
2237 							return -1;
2238 						*tzp = -val;
2239 						ftype[i] = DTK_TZ;
2240 						break;
2241 
2242 					case IGNORE_DTF:
2243 						break;
2244 
2245 					case AMPM:
2246 						mer = val;
2247 						break;
2248 
2249 					case ADBC:
2250 						bc = (val == BC);
2251 						break;
2252 
2253 					case DOW:
2254 						tm->tm_wday = val;
2255 						break;
2256 
2257 					case UNITS:
2258 						tmask = 0;
2259 						ptype = val;
2260 						break;
2261 
2262 					case ISOTIME:
2263 
2264 						/*
2265 						 * This is a filler field "t" indicating that the next
2266 						 * field is time. Try to verify that this is sensible.
2267 						 */
2268 						tmask = 0;
2269 
2270 						/* No preceding date? Then quit... */
2271 						if ((fmask & DTK_DATE_M) != DTK_DATE_M)
2272 							return -1;
2273 
2274 						/***
2275 						 * We will need one of the following fields:
2276 						 *	DTK_NUMBER should be hhmmss.fff
2277 						 *	DTK_TIME should be hh:mm:ss.fff
2278 						 *	DTK_DATE should be hhmmss-zz
2279 						 ***/
2280 						if (i >= nf - 1 ||
2281 							(ftype[i + 1] != DTK_NUMBER &&
2282 							 ftype[i + 1] != DTK_TIME &&
2283 							 ftype[i + 1] != DTK_DATE))
2284 							return -1;
2285 
2286 						ptype = val;
2287 						break;
2288 
2289 					default:
2290 						return -1;
2291 				}
2292 				break;
2293 
2294 			default:
2295 				return -1;
2296 		}
2297 
2298 		if (tmask & fmask)
2299 			return -1;
2300 		fmask |= tmask;
2301 	}
2302 
2303 	/* there is no year zero in AD/BC notation; i.e. "1 BC" == year 0 */
2304 	if (bc)
2305 	{
2306 		if (tm->tm_year > 0)
2307 			tm->tm_year = -(tm->tm_year - 1);
2308 		else
2309 			return -1;
2310 	}
2311 	else if (is2digits)
2312 	{
2313 		if (tm->tm_year < 70)
2314 			tm->tm_year += 2000;
2315 		else if (tm->tm_year < 100)
2316 			tm->tm_year += 1900;
2317 	}
2318 
2319 	if (mer != HR24 && tm->tm_hour > 12)
2320 		return -1;
2321 	if (mer == AM && tm->tm_hour == 12)
2322 		tm->tm_hour = 0;
2323 	else if (mer == PM && tm->tm_hour != 12)
2324 		tm->tm_hour += 12;
2325 
2326 	/* do additional checking for full date specs... */
2327 	if (*dtype == DTK_DATE)
2328 	{
2329 		if ((fmask & DTK_DATE_M) != DTK_DATE_M)
2330 			return ((fmask & DTK_TIME_M) == DTK_TIME_M) ? 1 : -1;
2331 
2332 		/*
2333 		 * check for valid day of month, now that we know for sure the month
2334 		 * and year...
2335 		 */
2336 		if (tm->tm_mday < 1 || tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1])
2337 			return -1;
2338 
2339 		/*
2340 		 * backend tried to find local timezone here but we don't use the
2341 		 * result afterwards anyway so we only check for this error: daylight
2342 		 * savings time modifier but no standard timezone?
2343 		 */
2344 		if ((fmask & DTK_DATE_M) == DTK_DATE_M && tzp != NULL && !(fmask & DTK_M(TZ)) && (fmask & DTK_M(DTZMOD)))
2345 			return -1;
2346 	}
2347 
2348 	return 0;
2349 }								/* DecodeDateTime() */
2350 
2351 /* Function works as follows:
2352  *
2353  *
2354  * */
2355 
2356 static char *
find_end_token(char * str,char * fmt)2357 find_end_token(char *str, char *fmt)
2358 {
2359 	/*
2360 	 * str: here is28the day12the hour fmt: here is%dthe day%hthe hour
2361 	 *
2362 	 * we extract the 28, we read the percent sign and the type "d" then this
2363 	 * functions gets called as find_end_token("28the day12the hour", "the
2364 	 * day%hthehour")
2365 	 *
2366 	 * fmt points to "the day%hthehour", next_percent points to %hthehour and
2367 	 * we have to find a match for everything between these positions ("the
2368 	 * day"). We look for "the day" in str and know that the pattern we are
2369 	 * about to scan ends where this string starts (right after the "28")
2370 	 *
2371 	 * At the end, *fmt is '\0' and *str isn't. end_position then is
2372 	 * unchanged.
2373 	 */
2374 	char	   *end_position = NULL;
2375 	char	   *next_percent,
2376 			   *subst_location = NULL;
2377 	int			scan_offset = 0;
2378 	char		last_char;
2379 
2380 	/* are we at the end? */
2381 	if (!*fmt)
2382 	{
2383 		end_position = fmt;
2384 		return end_position;
2385 	}
2386 
2387 	/* not at the end */
2388 	while (fmt[scan_offset] == '%' && fmt[scan_offset + 1])
2389 	{
2390 		/*
2391 		 * there is no delimiter, skip to the next delimiter if we're reading
2392 		 * a number and then something that is not a number "9:15pm", we might
2393 		 * be able to recover with the strtol end pointer. Go for the next
2394 		 * percent sign
2395 		 */
2396 		scan_offset += 2;
2397 	}
2398 	next_percent = strchr(fmt + scan_offset, '%');
2399 	if (next_percent)
2400 	{
2401 		/*
2402 		 * we don't want to allocate extra memory, so we temporarily set the
2403 		 * '%' sign to '\0' and call strstr However since we allow whitespace
2404 		 * to float around everything, we have to shorten the pattern until we
2405 		 * reach a non-whitespace character
2406 		 */
2407 
2408 		subst_location = next_percent;
2409 		while (*(subst_location - 1) == ' ' && subst_location - 1 > fmt + scan_offset)
2410 			subst_location--;
2411 		last_char = *subst_location;
2412 		*subst_location = '\0';
2413 
2414 		/*
2415 		 * the haystack is the str and the needle is the original fmt but it
2416 		 * ends at the position where the next percent sign would be
2417 		 */
2418 
2419 		/*
2420 		 * There is one special case. Imagine: str = " 2", fmt = "%d %...",
2421 		 * since we want to allow blanks as "dynamic" padding we have to
2422 		 * accept this. Now, we are called with a fmt of " %..." and look for
2423 		 * " " in str. We find it at the first position and never read the
2424 		 * 2...
2425 		 */
2426 		while (*str == ' ')
2427 			str++;
2428 		end_position = strstr(str, fmt + scan_offset);
2429 		*subst_location = last_char;
2430 	}
2431 	else
2432 	{
2433 		/*
2434 		 * there is no other percent sign. So everything up to the end has to
2435 		 * match.
2436 		 */
2437 		end_position = str + strlen(str);
2438 	}
2439 	if (!end_position)
2440 	{
2441 		/*
2442 		 * maybe we have the following case:
2443 		 *
2444 		 * str = "4:15am" fmt = "%M:%S %p"
2445 		 *
2446 		 * at this place we could have
2447 		 *
2448 		 * str = "15am" fmt = " %p"
2449 		 *
2450 		 * and have set fmt to " " because overwrote the % sign with a NULL
2451 		 *
2452 		 * In this case where we would have to match a space but can't find
2453 		 * it, set end_position to the end of the string
2454 		 */
2455 		if ((fmt + scan_offset)[0] == ' ' && fmt + scan_offset + 1 == subst_location)
2456 			end_position = str + strlen(str);
2457 	}
2458 	return end_position;
2459 }
2460 
2461 static int
pgtypes_defmt_scan(union un_fmt_comb * scan_val,int scan_type,char ** pstr,char * pfmt)2462 pgtypes_defmt_scan(union un_fmt_comb *scan_val, int scan_type, char **pstr, char *pfmt)
2463 {
2464 	/*
2465 	 * scan everything between pstr and pstr_end. This is not including the
2466 	 * last character so we might set it to '\0' for the parsing
2467 	 */
2468 
2469 	char		last_char;
2470 	int			err = 0;
2471 	char	   *pstr_end;
2472 	char	   *strtol_end = NULL;
2473 
2474 	while (**pstr == ' ')
2475 		pstr++;
2476 	pstr_end = find_end_token(*pstr, pfmt);
2477 	if (!pstr_end)
2478 	{
2479 		/* there was an error, no match */
2480 		return 1;
2481 	}
2482 	last_char = *pstr_end;
2483 	*pstr_end = '\0';
2484 
2485 	switch (scan_type)
2486 	{
2487 		case PGTYPES_TYPE_UINT:
2488 
2489 			/*
2490 			 * numbers may be blank-padded, this is the only deviation from
2491 			 * the fmt-string we accept
2492 			 */
2493 			while (**pstr == ' ')
2494 				(*pstr)++;
2495 			errno = 0;
2496 			scan_val->uint_val = (unsigned int) strtol(*pstr, &strtol_end, 10);
2497 			if (errno)
2498 				err = 1;
2499 			break;
2500 		case PGTYPES_TYPE_UINT_LONG:
2501 			while (**pstr == ' ')
2502 				(*pstr)++;
2503 			errno = 0;
2504 			scan_val->luint_val = (unsigned long int) strtol(*pstr, &strtol_end, 10);
2505 			if (errno)
2506 				err = 1;
2507 			break;
2508 		case PGTYPES_TYPE_STRING_MALLOCED:
2509 			scan_val->str_val = pgtypes_strdup(*pstr);
2510 			if (scan_val->str_val == NULL)
2511 				err = 1;
2512 			break;
2513 	}
2514 	if (strtol_end && *strtol_end)
2515 		*pstr = strtol_end;
2516 	else
2517 		*pstr = pstr_end;
2518 	*pstr_end = last_char;
2519 	return err;
2520 }
2521 
2522 /* XXX range checking */
2523 int
PGTYPEStimestamp_defmt_scan(char ** str,char * fmt,timestamp * d,int * year,int * month,int * day,int * hour,int * minute,int * second,int * tz)2524 PGTYPEStimestamp_defmt_scan(char **str, char *fmt, timestamp * d,
2525 							int *year, int *month, int *day,
2526 							int *hour, int *minute, int *second,
2527 							int *tz)
2528 {
2529 	union un_fmt_comb scan_val;
2530 	int			scan_type;
2531 
2532 	char	   *pstr,
2533 			   *pfmt,
2534 			   *tmp;
2535 	int			err = 1;
2536 	unsigned int j;
2537 	struct tm	tm;
2538 
2539 	pfmt = fmt;
2540 	pstr = *str;
2541 
2542 	while (*pfmt)
2543 	{
2544 		err = 0;
2545 		while (*pfmt == ' ')
2546 			pfmt++;
2547 		while (*pstr == ' ')
2548 			pstr++;
2549 		if (*pfmt != '%')
2550 		{
2551 			if (*pfmt == *pstr)
2552 			{
2553 				pfmt++;
2554 				pstr++;
2555 			}
2556 			else
2557 			{
2558 				/* Error: no match */
2559 				err = 1;
2560 				return err;
2561 			}
2562 			continue;
2563 		}
2564 		/* here *pfmt equals '%' */
2565 		pfmt++;
2566 		switch (*pfmt)
2567 		{
2568 			case 'a':
2569 				pfmt++;
2570 
2571 				/*
2572 				 * we parse the day and see if it is a week day but we do not
2573 				 * check if the week day really matches the date
2574 				 */
2575 				err = 1;
2576 				j = 0;
2577 				while (pgtypes_date_weekdays_short[j])
2578 				{
2579 					if (strncmp(pgtypes_date_weekdays_short[j], pstr,
2580 								strlen(pgtypes_date_weekdays_short[j])) == 0)
2581 					{
2582 						/* found it */
2583 						err = 0;
2584 						pstr += strlen(pgtypes_date_weekdays_short[j]);
2585 						break;
2586 					}
2587 					j++;
2588 				}
2589 				break;
2590 			case 'A':
2591 				/* see note above */
2592 				pfmt++;
2593 				err = 1;
2594 				j = 0;
2595 				while (days[j])
2596 				{
2597 					if (strncmp(days[j], pstr, strlen(days[j])) == 0)
2598 					{
2599 						/* found it */
2600 						err = 0;
2601 						pstr += strlen(days[j]);
2602 						break;
2603 					}
2604 					j++;
2605 				}
2606 				break;
2607 			case 'b':
2608 			case 'h':
2609 				pfmt++;
2610 				err = 1;
2611 				j = 0;
2612 				while (months[j])
2613 				{
2614 					if (strncmp(months[j], pstr, strlen(months[j])) == 0)
2615 					{
2616 						/* found it */
2617 						err = 0;
2618 						pstr += strlen(months[j]);
2619 						*month = j + 1;
2620 						break;
2621 					}
2622 					j++;
2623 				}
2624 				break;
2625 			case 'B':
2626 				/* see note above */
2627 				pfmt++;
2628 				err = 1;
2629 				j = 0;
2630 				while (pgtypes_date_months[j])
2631 				{
2632 					if (strncmp(pgtypes_date_months[j], pstr, strlen(pgtypes_date_months[j])) == 0)
2633 					{
2634 						/* found it */
2635 						err = 0;
2636 						pstr += strlen(pgtypes_date_months[j]);
2637 						*month = j + 1;
2638 						break;
2639 					}
2640 					j++;
2641 				}
2642 				break;
2643 			case 'c':
2644 				/* XXX */
2645 				break;
2646 			case 'C':
2647 				pfmt++;
2648 				scan_type = PGTYPES_TYPE_UINT;
2649 				err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
2650 				*year = scan_val.uint_val * 100;
2651 				break;
2652 			case 'd':
2653 			case 'e':
2654 				pfmt++;
2655 				scan_type = PGTYPES_TYPE_UINT;
2656 				err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
2657 				*day = scan_val.uint_val;
2658 				break;
2659 			case 'D':
2660 
2661 				/*
2662 				 * we have to concatenate the strings in order to be able to
2663 				 * find the end of the substitution
2664 				 */
2665 				pfmt++;
2666 				tmp = pgtypes_alloc(strlen("%m/%d/%y") + strlen(pstr) + 1);
2667 				strcpy(tmp, "%m/%d/%y");
2668 				strcat(tmp, pfmt);
2669 				err = PGTYPEStimestamp_defmt_scan(&pstr, tmp, d, year, month, day, hour, minute, second, tz);
2670 				free(tmp);
2671 				return err;
2672 			case 'm':
2673 				pfmt++;
2674 				scan_type = PGTYPES_TYPE_UINT;
2675 				err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
2676 				*month = scan_val.uint_val;
2677 				break;
2678 			case 'y':
2679 			case 'g':			/* XXX difference to y (ISO) */
2680 				pfmt++;
2681 				scan_type = PGTYPES_TYPE_UINT;
2682 				err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
2683 				if (*year < 0)
2684 				{
2685 					/* not yet set */
2686 					*year = scan_val.uint_val;
2687 				}
2688 				else
2689 					*year += scan_val.uint_val;
2690 				if (*year < 100)
2691 					*year += 1900;
2692 				break;
2693 			case 'G':
2694 				/* XXX difference to %V (ISO) */
2695 				pfmt++;
2696 				scan_type = PGTYPES_TYPE_UINT;
2697 				err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
2698 				*year = scan_val.uint_val;
2699 				break;
2700 			case 'H':
2701 			case 'I':
2702 			case 'k':
2703 			case 'l':
2704 				pfmt++;
2705 				scan_type = PGTYPES_TYPE_UINT;
2706 				err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
2707 				*hour += scan_val.uint_val;
2708 				break;
2709 			case 'j':
2710 				pfmt++;
2711 				scan_type = PGTYPES_TYPE_UINT;
2712 				err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
2713 
2714 				/*
2715 				 * XXX what should we do with that? We could say that it's
2716 				 * sufficient if we have the year and the day within the year
2717 				 * to get at least a specific day.
2718 				 */
2719 				break;
2720 			case 'M':
2721 				pfmt++;
2722 				scan_type = PGTYPES_TYPE_UINT;
2723 				err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
2724 				*minute = scan_val.uint_val;
2725 				break;
2726 			case 'n':
2727 				pfmt++;
2728 				if (*pstr == '\n')
2729 					pstr++;
2730 				else
2731 					err = 1;
2732 				break;
2733 			case 'p':
2734 				err = 1;
2735 				pfmt++;
2736 				if (strncmp(pstr, "am", 2) == 0)
2737 				{
2738 					*hour += 0;
2739 					err = 0;
2740 					pstr += 2;
2741 				}
2742 				if (strncmp(pstr, "a.m.", 4) == 0)
2743 				{
2744 					*hour += 0;
2745 					err = 0;
2746 					pstr += 4;
2747 				}
2748 				if (strncmp(pstr, "pm", 2) == 0)
2749 				{
2750 					*hour += 12;
2751 					err = 0;
2752 					pstr += 2;
2753 				}
2754 				if (strncmp(pstr, "p.m.", 4) == 0)
2755 				{
2756 					*hour += 12;
2757 					err = 0;
2758 					pstr += 4;
2759 				}
2760 				break;
2761 			case 'P':
2762 				err = 1;
2763 				pfmt++;
2764 				if (strncmp(pstr, "AM", 2) == 0)
2765 				{
2766 					*hour += 0;
2767 					err = 0;
2768 					pstr += 2;
2769 				}
2770 				if (strncmp(pstr, "A.M.", 4) == 0)
2771 				{
2772 					*hour += 0;
2773 					err = 0;
2774 					pstr += 4;
2775 				}
2776 				if (strncmp(pstr, "PM", 2) == 0)
2777 				{
2778 					*hour += 12;
2779 					err = 0;
2780 					pstr += 2;
2781 				}
2782 				if (strncmp(pstr, "P.M.", 4) == 0)
2783 				{
2784 					*hour += 12;
2785 					err = 0;
2786 					pstr += 4;
2787 				}
2788 				break;
2789 			case 'r':
2790 				pfmt++;
2791 				tmp = pgtypes_alloc(strlen("%I:%M:%S %p") + strlen(pstr) + 1);
2792 				strcpy(tmp, "%I:%M:%S %p");
2793 				strcat(tmp, pfmt);
2794 				err = PGTYPEStimestamp_defmt_scan(&pstr, tmp, d, year, month, day, hour, minute, second, tz);
2795 				free(tmp);
2796 				return err;
2797 			case 'R':
2798 				pfmt++;
2799 				tmp = pgtypes_alloc(strlen("%H:%M") + strlen(pstr) + 1);
2800 				strcpy(tmp, "%H:%M");
2801 				strcat(tmp, pfmt);
2802 				err = PGTYPEStimestamp_defmt_scan(&pstr, tmp, d, year, month, day, hour, minute, second, tz);
2803 				free(tmp);
2804 				return err;
2805 			case 's':
2806 				pfmt++;
2807 				scan_type = PGTYPES_TYPE_UINT_LONG;
2808 				err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
2809 				/* number of seconds in scan_val.luint_val */
2810 				{
2811 					struct tm  *tms;
2812 					time_t		et = (time_t) scan_val.luint_val;
2813 
2814 					tms = gmtime(&et);
2815 
2816 					if (tms)
2817 					{
2818 						*year = tms->tm_year + 1900;
2819 						*month = tms->tm_mon + 1;
2820 						*day = tms->tm_mday;
2821 						*hour = tms->tm_hour;
2822 						*minute = tms->tm_min;
2823 						*second = tms->tm_sec;
2824 					}
2825 					else
2826 						err = 1;
2827 				}
2828 				break;
2829 			case 'S':
2830 				pfmt++;
2831 				scan_type = PGTYPES_TYPE_UINT;
2832 				err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
2833 				*second = scan_val.uint_val;
2834 				break;
2835 			case 't':
2836 				pfmt++;
2837 				if (*pstr == '\t')
2838 					pstr++;
2839 				else
2840 					err = 1;
2841 				break;
2842 			case 'T':
2843 				pfmt++;
2844 				tmp = pgtypes_alloc(strlen("%H:%M:%S") + strlen(pstr) + 1);
2845 				strcpy(tmp, "%H:%M:%S");
2846 				strcat(tmp, pfmt);
2847 				err = PGTYPEStimestamp_defmt_scan(&pstr, tmp, d, year, month, day, hour, minute, second, tz);
2848 				free(tmp);
2849 				return err;
2850 			case 'u':
2851 				pfmt++;
2852 				scan_type = PGTYPES_TYPE_UINT;
2853 				err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
2854 				if (scan_val.uint_val < 1 || scan_val.uint_val > 7)
2855 					err = 1;
2856 				break;
2857 			case 'U':
2858 				pfmt++;
2859 				scan_type = PGTYPES_TYPE_UINT;
2860 				err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
2861 				if (scan_val.uint_val > 53)
2862 					err = 1;
2863 				break;
2864 			case 'V':
2865 				pfmt++;
2866 				scan_type = PGTYPES_TYPE_UINT;
2867 				err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
2868 				if (scan_val.uint_val < 1 || scan_val.uint_val > 53)
2869 					err = 1;
2870 				break;
2871 			case 'w':
2872 				pfmt++;
2873 				scan_type = PGTYPES_TYPE_UINT;
2874 				err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
2875 				if (scan_val.uint_val > 6)
2876 					err = 1;
2877 				break;
2878 			case 'W':
2879 				pfmt++;
2880 				scan_type = PGTYPES_TYPE_UINT;
2881 				err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
2882 				if (scan_val.uint_val > 53)
2883 					err = 1;
2884 				break;
2885 			case 'x':
2886 			case 'X':
2887 				/* XXX */
2888 				break;
2889 			case 'Y':
2890 				pfmt++;
2891 				scan_type = PGTYPES_TYPE_UINT;
2892 				err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
2893 				*year = scan_val.uint_val;
2894 				break;
2895 			case 'z':
2896 				pfmt++;
2897 				scan_type = PGTYPES_TYPE_STRING_MALLOCED;
2898 				err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
2899 				if (!err)
2900 				{
2901 					err = DecodeTimezone(scan_val.str_val, tz);
2902 					free(scan_val.str_val);
2903 				}
2904 				break;
2905 			case 'Z':
2906 				pfmt++;
2907 				scan_type = PGTYPES_TYPE_STRING_MALLOCED;
2908 				err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
2909 				if (!err)
2910 				{
2911 					/*
2912 					 * XXX use DecodeSpecial instead?  Do we need strcasecmp
2913 					 * here?
2914 					 */
2915 					err = 1;
2916 					for (j = 0; j < szdatetktbl; j++)
2917 					{
2918 						if ((datetktbl[j].type == TZ || datetktbl[j].type == DTZ) &&
2919 							pg_strcasecmp(datetktbl[j].token,
2920 										  scan_val.str_val) == 0)
2921 						{
2922 							*tz = -datetktbl[j].value;
2923 							err = 0;
2924 							break;
2925 						}
2926 					}
2927 					free(scan_val.str_val);
2928 				}
2929 				break;
2930 			case '+':
2931 				/* XXX */
2932 				break;
2933 			case '%':
2934 				pfmt++;
2935 				if (*pstr == '%')
2936 					pstr++;
2937 				else
2938 					err = 1;
2939 				break;
2940 			default:
2941 				err = 1;
2942 		}
2943 	}
2944 	if (!err)
2945 	{
2946 		if (*second < 0)
2947 			*second = 0;
2948 		if (*minute < 0)
2949 			*minute = 0;
2950 		if (*hour < 0)
2951 			*hour = 0;
2952 		if (*day < 0)
2953 		{
2954 			err = 1;
2955 			*day = 1;
2956 		}
2957 		if (*month < 0)
2958 		{
2959 			err = 1;
2960 			*month = 1;
2961 		}
2962 		if (*year < 0)
2963 		{
2964 			err = 1;
2965 			*year = 1970;
2966 		}
2967 
2968 		if (*second > 59)
2969 		{
2970 			err = 1;
2971 			*second = 0;
2972 		}
2973 		if (*minute > 59)
2974 		{
2975 			err = 1;
2976 			*minute = 0;
2977 		}
2978 		if (*hour > 24 ||		/* test for > 24:00:00 */
2979 			(*hour == 24 && (*minute > 0 || *second > 0)))
2980 		{
2981 			err = 1;
2982 			*hour = 0;
2983 		}
2984 		if (*month > MONTHS_PER_YEAR)
2985 		{
2986 			err = 1;
2987 			*month = 1;
2988 		}
2989 		if (*day > day_tab[isleap(*year)][*month - 1])
2990 		{
2991 			*day = day_tab[isleap(*year)][*month - 1];
2992 			err = 1;
2993 		}
2994 
2995 		tm.tm_sec = *second;
2996 		tm.tm_min = *minute;
2997 		tm.tm_hour = *hour;
2998 		tm.tm_mday = *day;
2999 		tm.tm_mon = *month;
3000 		tm.tm_year = *year;
3001 
3002 		tm2timestamp(&tm, 0, tz, d);
3003 	}
3004 	return err;
3005 }
3006 
3007 /* XXX: 1900 is compiled in as the base for years */
3008