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 int
EncodeDateOnly(struct tm * tm,int style,char * str,bool EuroDates)675 EncodeDateOnly(struct tm *tm, int style, char *str, bool EuroDates)
676 {
677 	if (tm->tm_mon < 1 || tm->tm_mon > MONTHS_PER_YEAR)
678 		return -1;
679 
680 	switch (style)
681 	{
682 		case USE_ISO_DATES:
683 			/* compatible with ISO date formats */
684 			if (tm->tm_year > 0)
685 				sprintf(str, "%04d-%02d-%02d",
686 						tm->tm_year, tm->tm_mon, tm->tm_mday);
687 			else
688 				sprintf(str, "%04d-%02d-%02d %s",
689 						-(tm->tm_year - 1), tm->tm_mon, tm->tm_mday, "BC");
690 			break;
691 
692 		case USE_SQL_DATES:
693 			/* compatible with Oracle/Ingres date formats */
694 			if (EuroDates)
695 				sprintf(str, "%02d/%02d", tm->tm_mday, tm->tm_mon);
696 			else
697 				sprintf(str, "%02d/%02d", tm->tm_mon, tm->tm_mday);
698 			if (tm->tm_year > 0)
699 				sprintf(str + 5, "/%04d", tm->tm_year);
700 			else
701 				sprintf(str + 5, "/%04d %s", -(tm->tm_year - 1), "BC");
702 			break;
703 
704 		case USE_GERMAN_DATES:
705 			/* German-style date format */
706 			sprintf(str, "%02d.%02d", tm->tm_mday, tm->tm_mon);
707 			if (tm->tm_year > 0)
708 				sprintf(str + 5, ".%04d", tm->tm_year);
709 			else
710 				sprintf(str + 5, ".%04d %s", -(tm->tm_year - 1), "BC");
711 			break;
712 
713 		case USE_POSTGRES_DATES:
714 		default:
715 			/* traditional date-only style for Postgres */
716 			if (EuroDates)
717 				sprintf(str, "%02d-%02d", tm->tm_mday, tm->tm_mon);
718 			else
719 				sprintf(str, "%02d-%02d", tm->tm_mon, tm->tm_mday);
720 			if (tm->tm_year > 0)
721 				sprintf(str + 5, "-%04d", tm->tm_year);
722 			else
723 				sprintf(str + 5, "-%04d %s", -(tm->tm_year - 1), "BC");
724 			break;
725 	}
726 
727 	return TRUE;
728 }								/* EncodeDateOnly() */
729 
730 void
TrimTrailingZeros(char * str)731 TrimTrailingZeros(char *str)
732 {
733 	int			len = strlen(str);
734 
735 	/* chop off trailing zeros... but leave at least 2 fractional digits */
736 	while (*(str + len - 1) == '0' && *(str + len - 3) != '.')
737 	{
738 		len--;
739 		*(str + len) = '\0';
740 	}
741 }
742 
743 /* EncodeDateTime()
744  * Encode date and time interpreted as local time.
745  *
746  * tm and fsec are the value to encode, print_tz determines whether to include
747  * a time zone (the difference between timestamp and timestamptz types), tz is
748  * the numeric time zone offset, tzn is the textual time zone, which if
749  * specified will be used instead of tz by some styles, style is the date
750  * style, str is where to write the output.
751  *
752  * Supported date styles:
753  *	Postgres - day mon hh:mm:ss yyyy tz
754  *	SQL - mm/dd/yyyy hh:mm:ss.ss tz
755  *	ISO - yyyy-mm-dd hh:mm:ss+/-tz
756  *	German - dd.mm.yyyy hh:mm:ss tz
757  * Variants (affects order of month and day for Postgres and SQL styles):
758  *	US - mm/dd/yyyy
759  *	European - dd/mm/yyyy
760  */
761 int
EncodeDateTime(struct tm * tm,fsec_t fsec,bool print_tz,int tz,const char * tzn,int style,char * str,bool EuroDates)762 EncodeDateTime(struct tm *tm, fsec_t fsec, bool print_tz, int tz, const char *tzn, int style, char *str, bool EuroDates)
763 {
764 	int			day,
765 				hour,
766 				min;
767 
768 	/*
769 	 * Negative tm_isdst means we have no valid time zone translation.
770 	 */
771 	if (tm->tm_isdst < 0)
772 		print_tz = false;
773 
774 	switch (style)
775 	{
776 		case USE_ISO_DATES:
777 			/* Compatible with ISO-8601 date formats */
778 
779 			sprintf(str, "%04d-%02d-%02d %02d:%02d",
780 					(tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1),
781 					tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min);
782 
783 			/*
784 			 * Print fractional seconds if any.  The field widths here should
785 			 * be at least equal to MAX_TIMESTAMP_PRECISION.
786 			 */
787 			if (fsec != 0)
788 			{
789 				sprintf(str + strlen(str), ":%02d.%06d", tm->tm_sec, fsec);
790 				TrimTrailingZeros(str);
791 			}
792 			else
793 				sprintf(str + strlen(str), ":%02d", tm->tm_sec);
794 
795 			if (tm->tm_year <= 0)
796 				sprintf(str + strlen(str), " BC");
797 
798 			if (print_tz)
799 			{
800 				hour = -(tz / SECS_PER_HOUR);
801 				min = (abs(tz) / MINS_PER_HOUR) % MINS_PER_HOUR;
802 				if (min != 0)
803 					sprintf(str + strlen(str), "%+03d:%02d", hour, min);
804 				else
805 					sprintf(str + strlen(str), "%+03d", hour);
806 			}
807 			break;
808 
809 		case USE_SQL_DATES:
810 			/* Compatible with Oracle/Ingres date formats */
811 
812 			if (EuroDates)
813 				sprintf(str, "%02d/%02d", tm->tm_mday, tm->tm_mon);
814 			else
815 				sprintf(str, "%02d/%02d", tm->tm_mon, tm->tm_mday);
816 
817 			sprintf(str + 5, "/%04d %02d:%02d",
818 					(tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1),
819 					tm->tm_hour, tm->tm_min);
820 
821 			/*
822 			 * Print fractional seconds if any.  The field widths here should
823 			 * be at least equal to MAX_TIMESTAMP_PRECISION.
824 			 */
825 			if (fsec != 0)
826 			{
827 				sprintf(str + strlen(str), ":%02d.%06d", tm->tm_sec, fsec);
828 				TrimTrailingZeros(str);
829 			}
830 			else
831 				sprintf(str + strlen(str), ":%02d", tm->tm_sec);
832 
833 			if (tm->tm_year <= 0)
834 				sprintf(str + strlen(str), " BC");
835 
836 			/*
837 			 * Note: the uses of %.*s in this function would be risky if the
838 			 * timezone names ever contain non-ASCII characters.  However, all
839 			 * TZ abbreviations in the IANA database are plain ASCII.
840 			 */
841 
842 			if (print_tz)
843 			{
844 				if (tzn)
845 					sprintf(str + strlen(str), " %.*s", MAXTZLEN, tzn);
846 				else
847 				{
848 					hour = -(tz / SECS_PER_HOUR);
849 					min = (abs(tz) / MINS_PER_HOUR) % MINS_PER_HOUR;
850 					if (min != 0)
851 						sprintf(str + strlen(str), "%+03d:%02d", hour, min);
852 					else
853 						sprintf(str + strlen(str), "%+03d", hour);
854 				}
855 			}
856 			break;
857 
858 		case USE_GERMAN_DATES:
859 			/* German variant on European style */
860 
861 			sprintf(str, "%02d.%02d", tm->tm_mday, tm->tm_mon);
862 
863 			sprintf(str + 5, ".%04d %02d:%02d",
864 					(tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1),
865 					tm->tm_hour, tm->tm_min);
866 
867 			/*
868 			 * Print fractional seconds if any.  The field widths here should
869 			 * be at least equal to MAX_TIMESTAMP_PRECISION.
870 			 */
871 			if (fsec != 0)
872 			{
873 				sprintf(str + strlen(str), ":%02d.%06d", tm->tm_sec, fsec);
874 				TrimTrailingZeros(str);
875 			}
876 			else
877 				sprintf(str + strlen(str), ":%02d", tm->tm_sec);
878 
879 			if (tm->tm_year <= 0)
880 				sprintf(str + strlen(str), " BC");
881 
882 			if (print_tz)
883 			{
884 				if (tzn)
885 					sprintf(str + strlen(str), " %.*s", MAXTZLEN, tzn);
886 				else
887 				{
888 					hour = -(tz / SECS_PER_HOUR);
889 					min = (abs(tz) / MINS_PER_HOUR) % MINS_PER_HOUR;
890 					if (min != 0)
891 						sprintf(str + strlen(str), "%+03d:%02d", hour, min);
892 					else
893 						sprintf(str + strlen(str), "%+03d", hour);
894 				}
895 			}
896 			break;
897 
898 		case USE_POSTGRES_DATES:
899 		default:
900 			/* Backward-compatible with traditional Postgres abstime dates */
901 
902 			day = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
903 			tm->tm_wday = (int) ((day + date2j(2000, 1, 1) + 1) % 7);
904 
905 			memcpy(str, days[tm->tm_wday], 3);
906 			strcpy(str + 3, " ");
907 
908 			if (EuroDates)
909 				sprintf(str + 4, "%02d %3s", tm->tm_mday, months[tm->tm_mon - 1]);
910 			else
911 				sprintf(str + 4, "%3s %02d", months[tm->tm_mon - 1], tm->tm_mday);
912 
913 			sprintf(str + 10, " %02d:%02d", tm->tm_hour, tm->tm_min);
914 
915 			/*
916 			 * Print fractional seconds if any.  The field widths here should
917 			 * be at least equal to MAX_TIMESTAMP_PRECISION.
918 			 */
919 			if (fsec != 0)
920 			{
921 				sprintf(str + strlen(str), ":%02d.%06d", tm->tm_sec, fsec);
922 				TrimTrailingZeros(str);
923 			}
924 			else
925 				sprintf(str + strlen(str), ":%02d", tm->tm_sec);
926 
927 			sprintf(str + strlen(str), " %04d",
928 					(tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1));
929 			if (tm->tm_year <= 0)
930 				sprintf(str + strlen(str), " BC");
931 
932 			if (print_tz)
933 			{
934 				if (tzn)
935 					sprintf(str + strlen(str), " %.*s", MAXTZLEN, tzn);
936 				else
937 				{
938 					/*
939 					 * We have a time zone, but no string version. Use the
940 					 * numeric form, but be sure to include a leading space to
941 					 * avoid formatting something which would be rejected by
942 					 * the date/time parser later. - thomas 2001-10-19
943 					 */
944 					hour = -(tz / SECS_PER_HOUR);
945 					min = (abs(tz) / MINS_PER_HOUR) % MINS_PER_HOUR;
946 					if (min != 0)
947 						sprintf(str + strlen(str), " %+03d:%02d", hour, min);
948 					else
949 						sprintf(str + strlen(str), " %+03d", hour);
950 				}
951 			}
952 			break;
953 	}
954 
955 	return TRUE;
956 }								/* EncodeDateTime() */
957 
958 int
GetEpochTime(struct tm * tm)959 GetEpochTime(struct tm *tm)
960 {
961 	struct tm  *t0;
962 	time_t		epoch = 0;
963 
964 	t0 = gmtime(&epoch);
965 
966 	if (t0)
967 	{
968 		tm->tm_year = t0->tm_year + 1900;
969 		tm->tm_mon = t0->tm_mon + 1;
970 		tm->tm_mday = t0->tm_mday;
971 		tm->tm_hour = t0->tm_hour;
972 		tm->tm_min = t0->tm_min;
973 		tm->tm_sec = t0->tm_sec;
974 
975 		return 0;
976 	}
977 
978 	return -1;
979 }								/* GetEpochTime() */
980 
981 static void
abstime2tm(AbsoluteTime _time,int * tzp,struct tm * tm,char ** tzn)982 abstime2tm(AbsoluteTime _time, int *tzp, struct tm *tm, char **tzn)
983 {
984 	time_t		time = (time_t) _time;
985 	struct tm  *tx;
986 
987 	errno = 0;
988 	if (tzp != NULL)
989 		tx = localtime((time_t *) &time);
990 	else
991 		tx = gmtime((time_t *) &time);
992 
993 	if (!tx)
994 	{
995 		errno = PGTYPES_TS_BAD_TIMESTAMP;
996 		return;
997 	}
998 
999 	tm->tm_year = tx->tm_year + 1900;
1000 	tm->tm_mon = tx->tm_mon + 1;
1001 	tm->tm_mday = tx->tm_mday;
1002 	tm->tm_hour = tx->tm_hour;
1003 	tm->tm_min = tx->tm_min;
1004 	tm->tm_sec = tx->tm_sec;
1005 	tm->tm_isdst = tx->tm_isdst;
1006 
1007 #if defined(HAVE_TM_ZONE)
1008 	tm->tm_gmtoff = tx->tm_gmtoff;
1009 	tm->tm_zone = tx->tm_zone;
1010 
1011 	if (tzp != NULL)
1012 	{
1013 		/*
1014 		 * We have a brute force time zone per SQL99? Then use it without
1015 		 * change since we have already rotated to the time zone.
1016 		 */
1017 		*tzp = -tm->tm_gmtoff;	/* tm_gmtoff is Sun/DEC-ism */
1018 
1019 		/*
1020 		 * FreeBSD man pages indicate that this should work - tgl 97/04/23
1021 		 */
1022 		if (tzn != NULL)
1023 		{
1024 			/*
1025 			 * Copy no more than MAXTZLEN bytes of timezone to tzn, in case it
1026 			 * contains an error message, which doesn't fit in the buffer
1027 			 */
1028 			StrNCpy(*tzn, tm->tm_zone, MAXTZLEN + 1);
1029 			if (strlen(tm->tm_zone) > MAXTZLEN)
1030 				tm->tm_isdst = -1;
1031 		}
1032 	}
1033 	else
1034 		tm->tm_isdst = -1;
1035 #elif defined(HAVE_INT_TIMEZONE)
1036 	if (tzp != NULL)
1037 	{
1038 		*tzp = (tm->tm_isdst > 0) ? TIMEZONE_GLOBAL - SECS_PER_HOUR : TIMEZONE_GLOBAL;
1039 
1040 		if (tzn != NULL)
1041 		{
1042 			/*
1043 			 * Copy no more than MAXTZLEN bytes of timezone to tzn, in case it
1044 			 * contains an error message, which doesn't fit in the buffer
1045 			 */
1046 			StrNCpy(*tzn, TZNAME_GLOBAL[tm->tm_isdst], MAXTZLEN + 1);
1047 			if (strlen(TZNAME_GLOBAL[tm->tm_isdst]) > MAXTZLEN)
1048 				tm->tm_isdst = -1;
1049 		}
1050 	}
1051 	else
1052 		tm->tm_isdst = -1;
1053 #else							/* not (HAVE_TM_ZONE || HAVE_INT_TIMEZONE) */
1054 	if (tzp != NULL)
1055 	{
1056 		/* default to UTC */
1057 		*tzp = 0;
1058 		if (tzn != NULL)
1059 			*tzn = NULL;
1060 	}
1061 	else
1062 		tm->tm_isdst = -1;
1063 #endif
1064 }
1065 
1066 void
GetCurrentDateTime(struct tm * tm)1067 GetCurrentDateTime(struct tm *tm)
1068 {
1069 	int			tz;
1070 
1071 	abstime2tm(time(NULL), &tz, tm, NULL);
1072 }
1073 
1074 void
dt2time(double jd,int * hour,int * min,int * sec,fsec_t * fsec)1075 dt2time(double jd, int *hour, int *min, int *sec, fsec_t *fsec)
1076 {
1077 	int64		time;
1078 
1079 	time = jd;
1080 	*hour = time / USECS_PER_HOUR;
1081 	time -= (*hour) * USECS_PER_HOUR;
1082 	*min = time / USECS_PER_MINUTE;
1083 	time -= (*min) * USECS_PER_MINUTE;
1084 	*sec = time / USECS_PER_SEC;
1085 	*fsec = time - (*sec * USECS_PER_SEC);
1086 }								/* dt2time() */
1087 
1088 
1089 
1090 /* DecodeNumberField()
1091  * Interpret numeric string as a concatenated date or time field.
1092  * Use the context of previously decoded fields to help with
1093  * the interpretation.
1094  */
1095 static int
DecodeNumberField(int len,char * str,int fmask,int * tmask,struct tm * tm,fsec_t * fsec,int * is2digits)1096 DecodeNumberField(int len, char *str, int fmask,
1097 				  int *tmask, struct tm *tm, fsec_t *fsec, int *is2digits)
1098 {
1099 	char	   *cp;
1100 
1101 	/*
1102 	 * Have a decimal point? Then this is a date or something with a seconds
1103 	 * field...
1104 	 */
1105 	if ((cp = strchr(str, '.')) != NULL)
1106 	{
1107 		char		fstr[7];
1108 		int			i;
1109 
1110 		cp++;
1111 
1112 		/*
1113 		 * OK, we have at most six digits to care about. Let's construct a
1114 		 * string with those digits, zero-padded on the right, and then do the
1115 		 * conversion to an integer.
1116 		 *
1117 		 * XXX This truncates the seventh digit, unlike rounding it as the
1118 		 * backend does.
1119 		 */
1120 		for (i = 0; i < 6; i++)
1121 			fstr[i] = *cp != '\0' ? *cp++ : '0';
1122 		fstr[i] = '\0';
1123 		*fsec = strtol(fstr, NULL, 10);
1124 		*cp = '\0';
1125 		len = strlen(str);
1126 	}
1127 	/* No decimal point and no complete date yet? */
1128 	else if ((fmask & DTK_DATE_M) != DTK_DATE_M)
1129 	{
1130 		/* yyyymmdd? */
1131 		if (len == 8)
1132 		{
1133 			*tmask = DTK_DATE_M;
1134 
1135 			tm->tm_mday = atoi(str + 6);
1136 			*(str + 6) = '\0';
1137 			tm->tm_mon = atoi(str + 4);
1138 			*(str + 4) = '\0';
1139 			tm->tm_year = atoi(str + 0);
1140 
1141 			return DTK_DATE;
1142 		}
1143 		/* yymmdd? */
1144 		else if (len == 6)
1145 		{
1146 			*tmask = DTK_DATE_M;
1147 			tm->tm_mday = atoi(str + 4);
1148 			*(str + 4) = '\0';
1149 			tm->tm_mon = atoi(str + 2);
1150 			*(str + 2) = '\0';
1151 			tm->tm_year = atoi(str + 0);
1152 			*is2digits = TRUE;
1153 
1154 			return DTK_DATE;
1155 		}
1156 		/* yyddd? */
1157 		else if (len == 5)
1158 		{
1159 			*tmask = DTK_DATE_M;
1160 			tm->tm_mday = atoi(str + 2);
1161 			*(str + 2) = '\0';
1162 			tm->tm_mon = 1;
1163 			tm->tm_year = atoi(str + 0);
1164 			*is2digits = TRUE;
1165 
1166 			return DTK_DATE;
1167 		}
1168 	}
1169 
1170 	/* not all time fields are specified? */
1171 	if ((fmask & DTK_TIME_M) != DTK_TIME_M)
1172 	{
1173 		/* hhmmss */
1174 		if (len == 6)
1175 		{
1176 			*tmask = DTK_TIME_M;
1177 			tm->tm_sec = atoi(str + 4);
1178 			*(str + 4) = '\0';
1179 			tm->tm_min = atoi(str + 2);
1180 			*(str + 2) = '\0';
1181 			tm->tm_hour = atoi(str + 0);
1182 
1183 			return DTK_TIME;
1184 		}
1185 		/* hhmm? */
1186 		else if (len == 4)
1187 		{
1188 			*tmask = DTK_TIME_M;
1189 			tm->tm_sec = 0;
1190 			tm->tm_min = atoi(str + 2);
1191 			*(str + 2) = '\0';
1192 			tm->tm_hour = atoi(str + 0);
1193 
1194 			return DTK_TIME;
1195 		}
1196 	}
1197 
1198 	return -1;
1199 }								/* DecodeNumberField() */
1200 
1201 
1202 /* DecodeNumber()
1203  * Interpret plain numeric field as a date value in context.
1204  */
1205 static int
DecodeNumber(int flen,char * str,int fmask,int * tmask,struct tm * tm,fsec_t * fsec,int * is2digits,bool EuroDates)1206 DecodeNumber(int flen, char *str, int fmask,
1207 			 int *tmask, struct tm *tm, fsec_t *fsec, int *is2digits, bool EuroDates)
1208 {
1209 	int			val;
1210 	char	   *cp;
1211 
1212 	*tmask = 0;
1213 
1214 	val = strtol(str, &cp, 10);
1215 	if (cp == str)
1216 		return -1;
1217 
1218 	if (*cp == '.')
1219 	{
1220 		/*
1221 		 * More than two digits? Then could be a date or a run-together time:
1222 		 * 2001.360 20011225 040506.789
1223 		 */
1224 		if (cp - str > 2)
1225 			return DecodeNumberField(flen, str, (fmask | DTK_DATE_M),
1226 									 tmask, tm, fsec, is2digits);
1227 
1228 		*fsec = strtod(cp, &cp);
1229 		if (*cp != '\0')
1230 			return -1;
1231 	}
1232 	else if (*cp != '\0')
1233 		return -1;
1234 
1235 	/* Special case day of year? */
1236 	if (flen == 3 && (fmask & DTK_M(YEAR)) && val >= 1 && val <= 366)
1237 	{
1238 		*tmask = (DTK_M(DOY) | DTK_M(MONTH) | DTK_M(DAY));
1239 		tm->tm_yday = val;
1240 		j2date(date2j(tm->tm_year, 1, 1) + tm->tm_yday - 1,
1241 			   &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
1242 	}
1243 
1244 	/***
1245 	 * Enough digits to be unequivocal year? Used to test for 4 digits or
1246 	 * more, but we now test first for a three-digit doy so anything
1247 	 * bigger than two digits had better be an explicit year.
1248 	 * - thomas 1999-01-09
1249 	 * Back to requiring a 4 digit year. We accept a two digit
1250 	 * year farther down. - thomas 2000-03-28
1251 	 ***/
1252 	else if (flen >= 4)
1253 	{
1254 		*tmask = DTK_M(YEAR);
1255 
1256 		/* already have a year? then see if we can substitute... */
1257 		if ((fmask & DTK_M(YEAR)) && !(fmask & DTK_M(DAY)) &&
1258 			tm->tm_year >= 1 && tm->tm_year <= 31)
1259 		{
1260 			tm->tm_mday = tm->tm_year;
1261 			*tmask = DTK_M(DAY);
1262 		}
1263 
1264 		tm->tm_year = val;
1265 	}
1266 
1267 	/* already have year? then could be month */
1268 	else if ((fmask & DTK_M(YEAR)) && !(fmask & DTK_M(MONTH)) && val >= 1 && val <= MONTHS_PER_YEAR)
1269 	{
1270 		*tmask = DTK_M(MONTH);
1271 		tm->tm_mon = val;
1272 	}
1273 	/* no year and EuroDates enabled? then could be day */
1274 	else if ((EuroDates || (fmask & DTK_M(MONTH))) &&
1275 			 !(fmask & DTK_M(YEAR)) && !(fmask & DTK_M(DAY)) &&
1276 			 val >= 1 && val <= 31)
1277 	{
1278 		*tmask = DTK_M(DAY);
1279 		tm->tm_mday = val;
1280 	}
1281 	else if (!(fmask & DTK_M(MONTH)) && val >= 1 && val <= MONTHS_PER_YEAR)
1282 	{
1283 		*tmask = DTK_M(MONTH);
1284 		tm->tm_mon = val;
1285 	}
1286 	else if (!(fmask & DTK_M(DAY)) && val >= 1 && val <= 31)
1287 	{
1288 		*tmask = DTK_M(DAY);
1289 		tm->tm_mday = val;
1290 	}
1291 
1292 	/*
1293 	 * Check for 2 or 4 or more digits, but currently we reach here only if
1294 	 * two digits. - thomas 2000-03-28
1295 	 */
1296 	else if (!(fmask & DTK_M(YEAR)) && (flen >= 4 || flen == 2))
1297 	{
1298 		*tmask = DTK_M(YEAR);
1299 		tm->tm_year = val;
1300 
1301 		/* adjust ONLY if exactly two digits... */
1302 		*is2digits = (flen == 2);
1303 	}
1304 	else
1305 		return -1;
1306 
1307 	return 0;
1308 }								/* DecodeNumber() */
1309 
1310 /* DecodeDate()
1311  * Decode date string which includes delimiters.
1312  * Insist on a complete set of fields.
1313  */
1314 static int
DecodeDate(char * str,int fmask,int * tmask,struct tm * tm,bool EuroDates)1315 DecodeDate(char *str, int fmask, int *tmask, struct tm *tm, bool EuroDates)
1316 {
1317 	fsec_t		fsec;
1318 
1319 	int			nf = 0;
1320 	int			i,
1321 				len;
1322 	int			bc = FALSE;
1323 	int			is2digits = FALSE;
1324 	int			type,
1325 				val,
1326 				dmask = 0;
1327 	char	   *field[MAXDATEFIELDS];
1328 
1329 	/* parse this string... */
1330 	while (*str != '\0' && nf < MAXDATEFIELDS)
1331 	{
1332 		/* skip field separators */
1333 		while (!isalnum((unsigned char) *str))
1334 			str++;
1335 
1336 		field[nf] = str;
1337 		if (isdigit((unsigned char) *str))
1338 		{
1339 			while (isdigit((unsigned char) *str))
1340 				str++;
1341 		}
1342 		else if (isalpha((unsigned char) *str))
1343 		{
1344 			while (isalpha((unsigned char) *str))
1345 				str++;
1346 		}
1347 
1348 		/* Just get rid of any non-digit, non-alpha characters... */
1349 		if (*str != '\0')
1350 			*str++ = '\0';
1351 		nf++;
1352 	}
1353 
1354 #if 0
1355 	/* don't allow too many fields */
1356 	if (nf > 3)
1357 		return -1;
1358 #endif
1359 
1360 	*tmask = 0;
1361 
1362 	/* look first for text fields, since that will be unambiguous month */
1363 	for (i = 0; i < nf; i++)
1364 	{
1365 		if (isalpha((unsigned char) *field[i]))
1366 		{
1367 			type = DecodeSpecial(i, field[i], &val);
1368 			if (type == IGNORE_DTF)
1369 				continue;
1370 
1371 			dmask = DTK_M(type);
1372 			switch (type)
1373 			{
1374 				case MONTH:
1375 					tm->tm_mon = val;
1376 					break;
1377 
1378 				case ADBC:
1379 					bc = (val == BC);
1380 					break;
1381 
1382 				default:
1383 					return -1;
1384 			}
1385 			if (fmask & dmask)
1386 				return -1;
1387 
1388 			fmask |= dmask;
1389 			*tmask |= dmask;
1390 
1391 			/* mark this field as being completed */
1392 			field[i] = NULL;
1393 		}
1394 	}
1395 
1396 	/* now pick up remaining numeric fields */
1397 	for (i = 0; i < nf; i++)
1398 	{
1399 		if (field[i] == NULL)
1400 			continue;
1401 
1402 		if ((len = strlen(field[i])) <= 0)
1403 			return -1;
1404 
1405 		if (DecodeNumber(len, field[i], fmask, &dmask, tm, &fsec, &is2digits, EuroDates) != 0)
1406 			return -1;
1407 
1408 		if (fmask & dmask)
1409 			return -1;
1410 
1411 		fmask |= dmask;
1412 		*tmask |= dmask;
1413 	}
1414 
1415 	if ((fmask & ~(DTK_M(DOY) | DTK_M(TZ))) != DTK_DATE_M)
1416 		return -1;
1417 
1418 	/* there is no year zero in AD/BC notation; i.e. "1 BC" == year 0 */
1419 	if (bc)
1420 	{
1421 		if (tm->tm_year > 0)
1422 			tm->tm_year = -(tm->tm_year - 1);
1423 		else
1424 			return -1;
1425 	}
1426 	else if (is2digits)
1427 	{
1428 		if (tm->tm_year < 70)
1429 			tm->tm_year += 2000;
1430 		else if (tm->tm_year < 100)
1431 			tm->tm_year += 1900;
1432 	}
1433 
1434 	return 0;
1435 }								/* DecodeDate() */
1436 
1437 
1438 /* DecodeTime()
1439  * Decode time string which includes delimiters.
1440  * Only check the lower limit on hours, since this same code
1441  *	can be used to represent time spans.
1442  */
1443 int
DecodeTime(char * str,int * tmask,struct tm * tm,fsec_t * fsec)1444 DecodeTime(char *str, int *tmask, struct tm *tm, fsec_t *fsec)
1445 {
1446 	char	   *cp;
1447 
1448 	*tmask = DTK_TIME_M;
1449 
1450 	tm->tm_hour = strtol(str, &cp, 10);
1451 	if (*cp != ':')
1452 		return -1;
1453 	str = cp + 1;
1454 	tm->tm_min = strtol(str, &cp, 10);
1455 	if (*cp == '\0')
1456 	{
1457 		tm->tm_sec = 0;
1458 		*fsec = 0;
1459 	}
1460 	else if (*cp != ':')
1461 		return -1;
1462 	else
1463 	{
1464 		str = cp + 1;
1465 		tm->tm_sec = strtol(str, &cp, 10);
1466 		if (*cp == '\0')
1467 			*fsec = 0;
1468 		else if (*cp == '.')
1469 		{
1470 			char		fstr[7];
1471 			int			i;
1472 
1473 			cp++;
1474 
1475 			/*
1476 			 * OK, we have at most six digits to care about. Let's construct a
1477 			 * string with those digits, zero-padded on the right, and then do
1478 			 * the conversion to an integer.
1479 			 *
1480 			 * XXX This truncates the seventh digit, unlike rounding it as the
1481 			 * backend does.
1482 			 */
1483 			for (i = 0; i < 6; i++)
1484 				fstr[i] = *cp != '\0' ? *cp++ : '0';
1485 			fstr[i] = '\0';
1486 			*fsec = strtol(fstr, &cp, 10);
1487 			if (*cp != '\0')
1488 				return -1;
1489 		}
1490 		else
1491 			return -1;
1492 	}
1493 
1494 	/* do a sanity check */
1495 	if (tm->tm_hour < 0 || tm->tm_min < 0 || tm->tm_min > 59 ||
1496 		tm->tm_sec < 0 || tm->tm_sec > 59 || *fsec >= USECS_PER_SEC)
1497 		return -1;
1498 
1499 	return 0;
1500 }								/* DecodeTime() */
1501 
1502 /* DecodeTimezone()
1503  * Interpret string as a numeric timezone.
1504  *
1505  * Note: we allow timezone offsets up to 13:59.  There are places that
1506  * use +1300 summer time.
1507  */
1508 static int
DecodeTimezone(char * str,int * tzp)1509 DecodeTimezone(char *str, int *tzp)
1510 {
1511 	int			tz;
1512 	int			hr,
1513 				min;
1514 	char	   *cp;
1515 	int			len;
1516 
1517 	/* assume leading character is "+" or "-" */
1518 	hr = strtol(str + 1, &cp, 10);
1519 
1520 	/* explicit delimiter? */
1521 	if (*cp == ':')
1522 		min = strtol(cp + 1, &cp, 10);
1523 	/* otherwise, might have run things together... */
1524 	else if (*cp == '\0' && (len = strlen(str)) > 3)
1525 	{
1526 		min = strtol(str + len - 2, &cp, 10);
1527 		if (min < 0 || min >= 60)
1528 			return -1;
1529 
1530 		*(str + len - 2) = '\0';
1531 		hr = strtol(str + 1, &cp, 10);
1532 		if (hr < 0 || hr > 13)
1533 			return -1;
1534 	}
1535 	else
1536 		min = 0;
1537 
1538 	tz = (hr * MINS_PER_HOUR + min) * SECS_PER_MINUTE;
1539 	if (*str == '-')
1540 		tz = -tz;
1541 
1542 	*tzp = -tz;
1543 	return *cp != '\0';
1544 }								/* DecodeTimezone() */
1545 
1546 
1547 /* DecodePosixTimezone()
1548  * Interpret string as a POSIX-compatible timezone:
1549  *	PST-hh:mm
1550  *	PST+h
1551  * - thomas 2000-03-15
1552  */
1553 static int
DecodePosixTimezone(char * str,int * tzp)1554 DecodePosixTimezone(char *str, int *tzp)
1555 {
1556 	int			val,
1557 				tz;
1558 	int			type;
1559 	char	   *cp;
1560 	char		delim;
1561 
1562 	cp = str;
1563 	while (*cp != '\0' && isalpha((unsigned char) *cp))
1564 		cp++;
1565 
1566 	if (DecodeTimezone(cp, &tz) != 0)
1567 		return -1;
1568 
1569 	delim = *cp;
1570 	*cp = '\0';
1571 	type = DecodeSpecial(MAXDATEFIELDS - 1, str, &val);
1572 	*cp = delim;
1573 
1574 	switch (type)
1575 	{
1576 		case DTZ:
1577 		case TZ:
1578 			*tzp = -(val + tz);
1579 			break;
1580 
1581 		default:
1582 			return -1;
1583 	}
1584 
1585 	return 0;
1586 }								/* DecodePosixTimezone() */
1587 
1588 /* ParseDateTime()
1589  * Break string into tokens based on a date/time context.
1590  * Several field types are assigned:
1591  *	DTK_NUMBER - digits and (possibly) a decimal point
1592  *	DTK_DATE - digits and two delimiters, or digits and text
1593  *	DTK_TIME - digits, colon delimiters, and possibly a decimal point
1594  *	DTK_STRING - text (no digits)
1595  *	DTK_SPECIAL - leading "+" or "-" followed by text
1596  *	DTK_TZ - leading "+" or "-" followed by digits
1597  * Note that some field types can hold unexpected items:
1598  *	DTK_NUMBER can hold date fields (yy.ddd)
1599  *	DTK_STRING can hold months (January) and time zones (PST)
1600  *	DTK_DATE can hold Posix time zones (GMT-8)
1601  *
1602  * The "lowstr" work buffer must have at least strlen(timestr) + MAXDATEFIELDS
1603  * bytes of space.  On output, field[] entries will point into it.
1604  * The field[] and ftype[] arrays must have at least MAXDATEFIELDS entries.
1605  */
1606 int
ParseDateTime(char * timestr,char * lowstr,char ** field,int * ftype,int * numfields,char ** endstr)1607 ParseDateTime(char *timestr, char *lowstr,
1608 			  char **field, int *ftype, int *numfields, char **endstr)
1609 {
1610 	int			nf = 0;
1611 	char	   *lp = lowstr;
1612 
1613 	*endstr = timestr;
1614 	/* outer loop through fields */
1615 	while (*(*endstr) != '\0')
1616 	{
1617 		/* Record start of current field */
1618 		if (nf >= MAXDATEFIELDS)
1619 			return -1;
1620 		field[nf] = lp;
1621 
1622 		/* leading digit? then date or time */
1623 		if (isdigit((unsigned char) *(*endstr)))
1624 		{
1625 			*lp++ = *(*endstr)++;
1626 			while (isdigit((unsigned char) *(*endstr)))
1627 				*lp++ = *(*endstr)++;
1628 
1629 			/* time field? */
1630 			if (*(*endstr) == ':')
1631 			{
1632 				ftype[nf] = DTK_TIME;
1633 				*lp++ = *(*endstr)++;
1634 				while (isdigit((unsigned char) *(*endstr)) ||
1635 					   (*(*endstr) == ':') || (*(*endstr) == '.'))
1636 					*lp++ = *(*endstr)++;
1637 			}
1638 			/* date field? allow embedded text month */
1639 			else if (*(*endstr) == '-' || *(*endstr) == '/' || *(*endstr) == '.')
1640 			{
1641 				/* save delimiting character to use later */
1642 				char	   *dp = (*endstr);
1643 
1644 				*lp++ = *(*endstr)++;
1645 				/* second field is all digits? then no embedded text month */
1646 				if (isdigit((unsigned char) *(*endstr)))
1647 				{
1648 					ftype[nf] = (*dp == '.') ? DTK_NUMBER : DTK_DATE;
1649 					while (isdigit((unsigned char) *(*endstr)))
1650 						*lp++ = *(*endstr)++;
1651 
1652 					/*
1653 					 * insist that the delimiters match to get a three-field
1654 					 * date.
1655 					 */
1656 					if (*(*endstr) == *dp)
1657 					{
1658 						ftype[nf] = DTK_DATE;
1659 						*lp++ = *(*endstr)++;
1660 						while (isdigit((unsigned char) *(*endstr)) || (*(*endstr) == *dp))
1661 							*lp++ = *(*endstr)++;
1662 					}
1663 				}
1664 				else
1665 				{
1666 					ftype[nf] = DTK_DATE;
1667 					while (isalnum((unsigned char) *(*endstr)) || (*(*endstr) == *dp))
1668 						*lp++ = pg_tolower((unsigned char) *(*endstr)++);
1669 				}
1670 			}
1671 
1672 			/*
1673 			 * otherwise, number only and will determine year, month, day, or
1674 			 * concatenated fields later...
1675 			 */
1676 			else
1677 				ftype[nf] = DTK_NUMBER;
1678 		}
1679 		/* Leading decimal point? Then fractional seconds... */
1680 		else if (*(*endstr) == '.')
1681 		{
1682 			*lp++ = *(*endstr)++;
1683 			while (isdigit((unsigned char) *(*endstr)))
1684 				*lp++ = *(*endstr)++;
1685 
1686 			ftype[nf] = DTK_NUMBER;
1687 		}
1688 
1689 		/*
1690 		 * text? then date string, month, day of week, special, or timezone
1691 		 */
1692 		else if (isalpha((unsigned char) *(*endstr)))
1693 		{
1694 			ftype[nf] = DTK_STRING;
1695 			*lp++ = pg_tolower((unsigned char) *(*endstr)++);
1696 			while (isalpha((unsigned char) *(*endstr)))
1697 				*lp++ = pg_tolower((unsigned char) *(*endstr)++);
1698 
1699 			/*
1700 			 * Full date string with leading text month? Could also be a POSIX
1701 			 * time zone...
1702 			 */
1703 			if (*(*endstr) == '-' || *(*endstr) == '/' || *(*endstr) == '.')
1704 			{
1705 				char	   *dp = (*endstr);
1706 
1707 				ftype[nf] = DTK_DATE;
1708 				*lp++ = *(*endstr)++;
1709 				while (isdigit((unsigned char) *(*endstr)) || *(*endstr) == *dp)
1710 					*lp++ = *(*endstr)++;
1711 			}
1712 		}
1713 		/* skip leading spaces */
1714 		else if (isspace((unsigned char) *(*endstr)))
1715 		{
1716 			(*endstr)++;
1717 			continue;
1718 		}
1719 		/* sign? then special or numeric timezone */
1720 		else if (*(*endstr) == '+' || *(*endstr) == '-')
1721 		{
1722 			*lp++ = *(*endstr)++;
1723 			/* soak up leading whitespace */
1724 			while (isspace((unsigned char) *(*endstr)))
1725 				(*endstr)++;
1726 			/* numeric timezone? */
1727 			if (isdigit((unsigned char) *(*endstr)))
1728 			{
1729 				ftype[nf] = DTK_TZ;
1730 				*lp++ = *(*endstr)++;
1731 				while (isdigit((unsigned char) *(*endstr)) ||
1732 					   (*(*endstr) == ':') || (*(*endstr) == '.'))
1733 					*lp++ = *(*endstr)++;
1734 			}
1735 			/* special? */
1736 			else if (isalpha((unsigned char) *(*endstr)))
1737 			{
1738 				ftype[nf] = DTK_SPECIAL;
1739 				*lp++ = pg_tolower((unsigned char) *(*endstr)++);
1740 				while (isalpha((unsigned char) *(*endstr)))
1741 					*lp++ = pg_tolower((unsigned char) *(*endstr)++);
1742 			}
1743 			/* otherwise something wrong... */
1744 			else
1745 				return -1;
1746 		}
1747 		/* ignore punctuation but use as delimiter */
1748 		else if (ispunct((unsigned char) *(*endstr)))
1749 		{
1750 			(*endstr)++;
1751 			continue;
1752 
1753 		}
1754 		/* otherwise, something is not right... */
1755 		else
1756 			return -1;
1757 
1758 		/* force in a delimiter after each field */
1759 		*lp++ = '\0';
1760 		nf++;
1761 	}
1762 
1763 	*numfields = nf;
1764 
1765 	return 0;
1766 }								/* ParseDateTime() */
1767 
1768 
1769 /* DecodeDateTime()
1770  * Interpret previously parsed fields for general date and time.
1771  * Return 0 if full date, 1 if only time, and -1 if problems.
1772  *		External format(s):
1773  *				"<weekday> <month>-<day>-<year> <hour>:<minute>:<second>"
1774  *				"Fri Feb-7-1997 15:23:27"
1775  *				"Feb-7-1997 15:23:27"
1776  *				"2-7-1997 15:23:27"
1777  *				"1997-2-7 15:23:27"
1778  *				"1997.038 15:23:27"		(day of year 1-366)
1779  *		Also supports input in compact time:
1780  *				"970207 152327"
1781  *				"97038 152327"
1782  *				"20011225T040506.789-07"
1783  *
1784  * Use the system-provided functions to get the current time zone
1785  *	if not specified in the input string.
1786  * If the date is outside the time_t system-supported time range,
1787  *	then assume UTC time zone. - thomas 1997-05-27
1788  */
1789 int
DecodeDateTime(char ** field,int * ftype,int nf,int * dtype,struct tm * tm,fsec_t * fsec,bool EuroDates)1790 DecodeDateTime(char **field, int *ftype, int nf,
1791 			   int *dtype, struct tm *tm, fsec_t *fsec, bool EuroDates)
1792 {
1793 	int			fmask = 0,
1794 				tmask,
1795 				type;
1796 	int			ptype = 0;		/* "prefix type" for ISO y2001m02d04 format */
1797 	int			i;
1798 	int			val;
1799 	int			mer = HR24;
1800 	int			haveTextMonth = FALSE;
1801 	int			is2digits = FALSE;
1802 	int			bc = FALSE;
1803 	int			t = 0;
1804 	int		   *tzp = &t;
1805 
1806 	/***
1807 	 * We'll insist on at least all of the date fields, but initialize the
1808 	 * remaining fields in case they are not set later...
1809 	 ***/
1810 	*dtype = DTK_DATE;
1811 	tm->tm_hour = 0;
1812 	tm->tm_min = 0;
1813 	tm->tm_sec = 0;
1814 	*fsec = 0;
1815 	/* don't know daylight savings time status apriori */
1816 	tm->tm_isdst = -1;
1817 	if (tzp != NULL)
1818 		*tzp = 0;
1819 
1820 	for (i = 0; i < nf; i++)
1821 	{
1822 		switch (ftype[i])
1823 		{
1824 			case DTK_DATE:
1825 				/***
1826 				 * Integral julian day with attached time zone?
1827 				 * All other forms with JD will be separated into
1828 				 * distinct fields, so we handle just this case here.
1829 				 ***/
1830 				if (ptype == DTK_JULIAN)
1831 				{
1832 					char	   *cp;
1833 					int			val;
1834 
1835 					if (tzp == NULL)
1836 						return -1;
1837 
1838 					val = strtol(field[i], &cp, 10);
1839 					if (*cp != '-')
1840 						return -1;
1841 
1842 					j2date(val, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
1843 					/* Get the time zone from the end of the string */
1844 					if (DecodeTimezone(cp, tzp) != 0)
1845 						return -1;
1846 
1847 					tmask = DTK_DATE_M | DTK_TIME_M | DTK_M(TZ);
1848 					ptype = 0;
1849 					break;
1850 				}
1851 				/***
1852 				 * Already have a date? Then this might be a POSIX time
1853 				 * zone with an embedded dash (e.g. "PST-3" == "EST") or
1854 				 * a run-together time with trailing time zone (e.g. hhmmss-zz).
1855 				 * - thomas 2001-12-25
1856 				 ***/
1857 				else if (((fmask & DTK_DATE_M) == DTK_DATE_M)
1858 						 || (ptype != 0))
1859 				{
1860 					/* No time zone accepted? Then quit... */
1861 					if (tzp == NULL)
1862 						return -1;
1863 
1864 					if (isdigit((unsigned char) *field[i]) || ptype != 0)
1865 					{
1866 						char	   *cp;
1867 
1868 						if (ptype != 0)
1869 						{
1870 							/* Sanity check; should not fail this test */
1871 							if (ptype != DTK_TIME)
1872 								return -1;
1873 							ptype = 0;
1874 						}
1875 
1876 						/*
1877 						 * Starts with a digit but we already have a time
1878 						 * field? Then we are in trouble with a date and time
1879 						 * already...
1880 						 */
1881 						if ((fmask & DTK_TIME_M) == DTK_TIME_M)
1882 							return -1;
1883 
1884 						if ((cp = strchr(field[i], '-')) == NULL)
1885 							return -1;
1886 
1887 						/* Get the time zone from the end of the string */
1888 						if (DecodeTimezone(cp, tzp) != 0)
1889 							return -1;
1890 						*cp = '\0';
1891 
1892 						/*
1893 						 * Then read the rest of the field as a concatenated
1894 						 * time
1895 						 */
1896 						if ((ftype[i] = DecodeNumberField(strlen(field[i]), field[i], fmask,
1897 														  &tmask, tm, fsec, &is2digits)) < 0)
1898 							return -1;
1899 
1900 						/*
1901 						 * modify tmask after returning from
1902 						 * DecodeNumberField()
1903 						 */
1904 						tmask |= DTK_M(TZ);
1905 					}
1906 					else
1907 					{
1908 						if (DecodePosixTimezone(field[i], tzp) != 0)
1909 							return -1;
1910 
1911 						ftype[i] = DTK_TZ;
1912 						tmask = DTK_M(TZ);
1913 					}
1914 				}
1915 				else if (DecodeDate(field[i], fmask, &tmask, tm, EuroDates) != 0)
1916 					return -1;
1917 				break;
1918 
1919 			case DTK_TIME:
1920 				if (DecodeTime(field[i], &tmask, tm, fsec) != 0)
1921 					return -1;
1922 
1923 				/*
1924 				 * Check upper limit on hours; other limits checked in
1925 				 * DecodeTime()
1926 				 */
1927 				/* test for > 24:00:00 */
1928 				if (tm->tm_hour > 24 ||
1929 					(tm->tm_hour == 24 && (tm->tm_min > 0 || tm->tm_sec > 0)))
1930 					return -1;
1931 				break;
1932 
1933 			case DTK_TZ:
1934 				{
1935 					int			tz;
1936 
1937 					if (tzp == NULL)
1938 						return -1;
1939 
1940 					if (DecodeTimezone(field[i], &tz) != 0)
1941 						return -1;
1942 
1943 					/*
1944 					 * Already have a time zone? Then maybe this is the second
1945 					 * field of a POSIX time: EST+3 (equivalent to PST)
1946 					 */
1947 					if (i > 0 && (fmask & DTK_M(TZ)) != 0 &&
1948 						ftype[i - 1] == DTK_TZ &&
1949 						isalpha((unsigned char) *field[i - 1]))
1950 					{
1951 						*tzp -= tz;
1952 						tmask = 0;
1953 					}
1954 					else
1955 					{
1956 						*tzp = tz;
1957 						tmask = DTK_M(TZ);
1958 					}
1959 				}
1960 				break;
1961 
1962 			case DTK_NUMBER:
1963 
1964 				/*
1965 				 * Was this an "ISO date" with embedded field labels? An
1966 				 * example is "y2001m02d04" - thomas 2001-02-04
1967 				 */
1968 				if (ptype != 0)
1969 				{
1970 					char	   *cp;
1971 					int			val;
1972 
1973 					val = strtol(field[i], &cp, 10);
1974 
1975 					/*
1976 					 * only a few kinds are allowed to have an embedded
1977 					 * decimal
1978 					 */
1979 					if (*cp == '.')
1980 						switch (ptype)
1981 						{
1982 							case DTK_JULIAN:
1983 							case DTK_TIME:
1984 							case DTK_SECOND:
1985 								break;
1986 							default:
1987 								return 1;
1988 								break;
1989 						}
1990 					else if (*cp != '\0')
1991 						return -1;
1992 
1993 					switch (ptype)
1994 					{
1995 						case DTK_YEAR:
1996 							tm->tm_year = val;
1997 							tmask = DTK_M(YEAR);
1998 							break;
1999 
2000 						case DTK_MONTH:
2001 
2002 							/*
2003 							 * already have a month and hour? then assume
2004 							 * minutes
2005 							 */
2006 							if ((fmask & DTK_M(MONTH)) != 0 &&
2007 								(fmask & DTK_M(HOUR)) != 0)
2008 							{
2009 								tm->tm_min = val;
2010 								tmask = DTK_M(MINUTE);
2011 							}
2012 							else
2013 							{
2014 								tm->tm_mon = val;
2015 								tmask = DTK_M(MONTH);
2016 							}
2017 							break;
2018 
2019 						case DTK_DAY:
2020 							tm->tm_mday = val;
2021 							tmask = DTK_M(DAY);
2022 							break;
2023 
2024 						case DTK_HOUR:
2025 							tm->tm_hour = val;
2026 							tmask = DTK_M(HOUR);
2027 							break;
2028 
2029 						case DTK_MINUTE:
2030 							tm->tm_min = val;
2031 							tmask = DTK_M(MINUTE);
2032 							break;
2033 
2034 						case DTK_SECOND:
2035 							tm->tm_sec = val;
2036 							tmask = DTK_M(SECOND);
2037 							if (*cp == '.')
2038 							{
2039 								double		frac;
2040 
2041 								frac = strtod(cp, &cp);
2042 								if (*cp != '\0')
2043 									return -1;
2044 								*fsec = frac * 1000000;
2045 							}
2046 							break;
2047 
2048 						case DTK_TZ:
2049 							tmask = DTK_M(TZ);
2050 							if (DecodeTimezone(field[i], tzp) != 0)
2051 								return -1;
2052 							break;
2053 
2054 						case DTK_JULIAN:
2055 							/***
2056 							 * previous field was a label for "julian date"?
2057 							 ***/
2058 							tmask = DTK_DATE_M;
2059 							j2date(val, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
2060 							/* fractional Julian Day? */
2061 							if (*cp == '.')
2062 							{
2063 								double		time;
2064 
2065 								time = strtod(cp, &cp);
2066 								if (*cp != '\0')
2067 									return -1;
2068 
2069 								tmask |= DTK_TIME_M;
2070 								dt2time((time * USECS_PER_DAY), &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec);
2071 							}
2072 							break;
2073 
2074 						case DTK_TIME:
2075 							/* previous field was "t" for ISO time */
2076 							if ((ftype[i] = DecodeNumberField(strlen(field[i]), field[i], (fmask | DTK_DATE_M),
2077 															  &tmask, tm, fsec, &is2digits)) < 0)
2078 								return -1;
2079 
2080 							if (tmask != DTK_TIME_M)
2081 								return -1;
2082 							break;
2083 
2084 						default:
2085 							return -1;
2086 							break;
2087 					}
2088 
2089 					ptype = 0;
2090 					*dtype = DTK_DATE;
2091 				}
2092 				else
2093 				{
2094 					char	   *cp;
2095 					int			flen;
2096 
2097 					flen = strlen(field[i]);
2098 					cp = strchr(field[i], '.');
2099 
2100 					/* Embedded decimal and no date yet? */
2101 					if (cp != NULL && !(fmask & DTK_DATE_M))
2102 					{
2103 						if (DecodeDate(field[i], fmask, &tmask, tm, EuroDates) != 0)
2104 							return -1;
2105 					}
2106 					/* embedded decimal and several digits before? */
2107 					else if (cp != NULL && flen - strlen(cp) > 2)
2108 					{
2109 						/*
2110 						 * Interpret as a concatenated date or time Set the
2111 						 * type field to allow decoding other fields later.
2112 						 * Example: 20011223 or 040506
2113 						 */
2114 						if ((ftype[i] = DecodeNumberField(flen, field[i], fmask,
2115 														  &tmask, tm, fsec, &is2digits)) < 0)
2116 							return -1;
2117 					}
2118 					else if (flen > 4)
2119 					{
2120 						if ((ftype[i] = DecodeNumberField(flen, field[i], fmask,
2121 														  &tmask, tm, fsec, &is2digits)) < 0)
2122 							return -1;
2123 					}
2124 					/* otherwise it is a single date/time field... */
2125 					else if (DecodeNumber(flen, field[i], fmask,
2126 										  &tmask, tm, fsec, &is2digits, EuroDates) != 0)
2127 						return -1;
2128 				}
2129 				break;
2130 
2131 			case DTK_STRING:
2132 			case DTK_SPECIAL:
2133 				type = DecodeSpecial(i, field[i], &val);
2134 				if (type == IGNORE_DTF)
2135 					continue;
2136 
2137 				tmask = DTK_M(type);
2138 				switch (type)
2139 				{
2140 					case RESERV:
2141 						switch (val)
2142 						{
2143 							case DTK_NOW:
2144 								tmask = (DTK_DATE_M | DTK_TIME_M | DTK_M(TZ));
2145 								*dtype = DTK_DATE;
2146 								GetCurrentDateTime(tm);
2147 								break;
2148 
2149 							case DTK_YESTERDAY:
2150 								tmask = DTK_DATE_M;
2151 								*dtype = DTK_DATE;
2152 								GetCurrentDateTime(tm);
2153 								j2date(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - 1,
2154 									   &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
2155 								tm->tm_hour = 0;
2156 								tm->tm_min = 0;
2157 								tm->tm_sec = 0;
2158 								break;
2159 
2160 							case DTK_TODAY:
2161 								tmask = DTK_DATE_M;
2162 								*dtype = DTK_DATE;
2163 								GetCurrentDateTime(tm);
2164 								tm->tm_hour = 0;
2165 								tm->tm_min = 0;
2166 								tm->tm_sec = 0;
2167 								break;
2168 
2169 							case DTK_TOMORROW:
2170 								tmask = DTK_DATE_M;
2171 								*dtype = DTK_DATE;
2172 								GetCurrentDateTime(tm);
2173 								j2date(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) + 1,
2174 									   &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
2175 								tm->tm_hour = 0;
2176 								tm->tm_min = 0;
2177 								tm->tm_sec = 0;
2178 								break;
2179 
2180 							case DTK_ZULU:
2181 								tmask = (DTK_TIME_M | DTK_M(TZ));
2182 								*dtype = DTK_DATE;
2183 								tm->tm_hour = 0;
2184 								tm->tm_min = 0;
2185 								tm->tm_sec = 0;
2186 								if (tzp != NULL)
2187 									*tzp = 0;
2188 								break;
2189 
2190 							default:
2191 								*dtype = val;
2192 						}
2193 
2194 						break;
2195 
2196 					case MONTH:
2197 
2198 						/*
2199 						 * already have a (numeric) month? then see if we can
2200 						 * substitute...
2201 						 */
2202 						if ((fmask & DTK_M(MONTH)) && !haveTextMonth &&
2203 							!(fmask & DTK_M(DAY)) && tm->tm_mon >= 1 && tm->tm_mon <= 31)
2204 						{
2205 							tm->tm_mday = tm->tm_mon;
2206 							tmask = DTK_M(DAY);
2207 						}
2208 						haveTextMonth = TRUE;
2209 						tm->tm_mon = val;
2210 						break;
2211 
2212 					case DTZMOD:
2213 
2214 						/*
2215 						 * daylight savings time modifier (solves "MET DST"
2216 						 * syntax)
2217 						 */
2218 						tmask |= DTK_M(DTZ);
2219 						tm->tm_isdst = 1;
2220 						if (tzp == NULL)
2221 							return -1;
2222 						*tzp -= val;
2223 						break;
2224 
2225 					case DTZ:
2226 
2227 						/*
2228 						 * set mask for TZ here _or_ check for DTZ later when
2229 						 * getting default timezone
2230 						 */
2231 						tmask |= DTK_M(TZ);
2232 						tm->tm_isdst = 1;
2233 						if (tzp == NULL)
2234 							return -1;
2235 						*tzp = -val;
2236 						ftype[i] = DTK_TZ;
2237 						break;
2238 
2239 					case TZ:
2240 						tm->tm_isdst = 0;
2241 						if (tzp == NULL)
2242 							return -1;
2243 						*tzp = -val;
2244 						ftype[i] = DTK_TZ;
2245 						break;
2246 
2247 					case IGNORE_DTF:
2248 						break;
2249 
2250 					case AMPM:
2251 						mer = val;
2252 						break;
2253 
2254 					case ADBC:
2255 						bc = (val == BC);
2256 						break;
2257 
2258 					case DOW:
2259 						tm->tm_wday = val;
2260 						break;
2261 
2262 					case UNITS:
2263 						tmask = 0;
2264 						ptype = val;
2265 						break;
2266 
2267 					case ISOTIME:
2268 
2269 						/*
2270 						 * This is a filler field "t" indicating that the next
2271 						 * field is time. Try to verify that this is sensible.
2272 						 */
2273 						tmask = 0;
2274 
2275 						/* No preceding date? Then quit... */
2276 						if ((fmask & DTK_DATE_M) != DTK_DATE_M)
2277 							return -1;
2278 
2279 						/***
2280 						 * We will need one of the following fields:
2281 						 *	DTK_NUMBER should be hhmmss.fff
2282 						 *	DTK_TIME should be hh:mm:ss.fff
2283 						 *	DTK_DATE should be hhmmss-zz
2284 						 ***/
2285 						if (i >= nf - 1 ||
2286 							(ftype[i + 1] != DTK_NUMBER &&
2287 							 ftype[i + 1] != DTK_TIME &&
2288 							 ftype[i + 1] != DTK_DATE))
2289 							return -1;
2290 
2291 						ptype = val;
2292 						break;
2293 
2294 					default:
2295 						return -1;
2296 				}
2297 				break;
2298 
2299 			default:
2300 				return -1;
2301 		}
2302 
2303 		if (tmask & fmask)
2304 			return -1;
2305 		fmask |= tmask;
2306 	}
2307 
2308 	/* there is no year zero in AD/BC notation; i.e. "1 BC" == year 0 */
2309 	if (bc)
2310 	{
2311 		if (tm->tm_year > 0)
2312 			tm->tm_year = -(tm->tm_year - 1);
2313 		else
2314 			return -1;
2315 	}
2316 	else if (is2digits)
2317 	{
2318 		if (tm->tm_year < 70)
2319 			tm->tm_year += 2000;
2320 		else if (tm->tm_year < 100)
2321 			tm->tm_year += 1900;
2322 	}
2323 
2324 	if (mer != HR24 && tm->tm_hour > 12)
2325 		return -1;
2326 	if (mer == AM && tm->tm_hour == 12)
2327 		tm->tm_hour = 0;
2328 	else if (mer == PM && tm->tm_hour != 12)
2329 		tm->tm_hour += 12;
2330 
2331 	/* do additional checking for full date specs... */
2332 	if (*dtype == DTK_DATE)
2333 	{
2334 		if ((fmask & DTK_DATE_M) != DTK_DATE_M)
2335 			return ((fmask & DTK_TIME_M) == DTK_TIME_M) ? 1 : -1;
2336 
2337 		/*
2338 		 * check for valid day of month, now that we know for sure the month
2339 		 * and year...
2340 		 */
2341 		if (tm->tm_mday < 1 || tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1])
2342 			return -1;
2343 
2344 		/*
2345 		 * backend tried to find local timezone here but we don't use the
2346 		 * result afterwards anyway so we only check for this error: daylight
2347 		 * savings time modifier but no standard timezone?
2348 		 */
2349 		if ((fmask & DTK_DATE_M) == DTK_DATE_M && tzp != NULL && !(fmask & DTK_M(TZ)) && (fmask & DTK_M(DTZMOD)))
2350 			return -1;
2351 	}
2352 
2353 	return 0;
2354 }								/* DecodeDateTime() */
2355 
2356 /* Function works as follows:
2357  *
2358  *
2359  * */
2360 
2361 static char *
find_end_token(char * str,char * fmt)2362 find_end_token(char *str, char *fmt)
2363 {
2364 	/*
2365 	 * str: here is28the day12the hour fmt: here is%dthe day%hthe hour
2366 	 *
2367 	 * we extract the 28, we read the percent sign and the type "d" then this
2368 	 * functions gets called as find_end_token("28the day12the hour", "the
2369 	 * day%hthehour")
2370 	 *
2371 	 * fmt points to "the day%hthehour", next_percent points to %hthehour and
2372 	 * we have to find a match for everything between these positions ("the
2373 	 * day"). We look for "the day" in str and know that the pattern we are
2374 	 * about to scan ends where this string starts (right after the "28")
2375 	 *
2376 	 * At the end, *fmt is '\0' and *str isn't. end_position then is
2377 	 * unchanged.
2378 	 */
2379 	char	   *end_position = NULL;
2380 	char	   *next_percent,
2381 			   *subst_location = NULL;
2382 	int			scan_offset = 0;
2383 	char		last_char;
2384 
2385 	/* are we at the end? */
2386 	if (!*fmt)
2387 	{
2388 		end_position = fmt;
2389 		return end_position;
2390 	}
2391 
2392 	/* not at the end */
2393 	while (fmt[scan_offset] == '%' && fmt[scan_offset + 1])
2394 	{
2395 		/*
2396 		 * there is no delimiter, skip to the next delimiter if we're reading
2397 		 * a number and then something that is not a number "9:15pm", we might
2398 		 * be able to recover with the strtol end pointer. Go for the next
2399 		 * percent sign
2400 		 */
2401 		scan_offset += 2;
2402 	}
2403 	next_percent = strchr(fmt + scan_offset, '%');
2404 	if (next_percent)
2405 	{
2406 		/*
2407 		 * we don't want to allocate extra memory, so we temporarily set the
2408 		 * '%' sign to '\0' and call strstr However since we allow whitespace
2409 		 * to float around everything, we have to shorten the pattern until we
2410 		 * reach a non-whitespace character
2411 		 */
2412 
2413 		subst_location = next_percent;
2414 		while (*(subst_location - 1) == ' ' && subst_location - 1 > fmt + scan_offset)
2415 			subst_location--;
2416 		last_char = *subst_location;
2417 		*subst_location = '\0';
2418 
2419 		/*
2420 		 * the haystack is the str and the needle is the original fmt but it
2421 		 * ends at the position where the next percent sign would be
2422 		 */
2423 
2424 		/*
2425 		 * There is one special case. Imagine: str = " 2", fmt = "%d %...",
2426 		 * since we want to allow blanks as "dynamic" padding we have to
2427 		 * accept this. Now, we are called with a fmt of " %..." and look for
2428 		 * " " in str. We find it at the first position and never read the
2429 		 * 2...
2430 		 */
2431 		while (*str == ' ')
2432 			str++;
2433 		end_position = strstr(str, fmt + scan_offset);
2434 		*subst_location = last_char;
2435 	}
2436 	else
2437 	{
2438 		/*
2439 		 * there is no other percent sign. So everything up to the end has to
2440 		 * match.
2441 		 */
2442 		end_position = str + strlen(str);
2443 	}
2444 	if (!end_position)
2445 	{
2446 		/*
2447 		 * maybe we have the following case:
2448 		 *
2449 		 * str = "4:15am" fmt = "%M:%S %p"
2450 		 *
2451 		 * at this place we could have
2452 		 *
2453 		 * str = "15am" fmt = " %p"
2454 		 *
2455 		 * and have set fmt to " " because overwrote the % sign with a NULL
2456 		 *
2457 		 * In this case where we would have to match a space but can't find
2458 		 * it, set end_position to the end of the string
2459 		 */
2460 		if ((fmt + scan_offset)[0] == ' ' && fmt + scan_offset + 1 == subst_location)
2461 			end_position = str + strlen(str);
2462 	}
2463 	return end_position;
2464 }
2465 
2466 static int
pgtypes_defmt_scan(union un_fmt_comb * scan_val,int scan_type,char ** pstr,char * pfmt)2467 pgtypes_defmt_scan(union un_fmt_comb *scan_val, int scan_type, char **pstr, char *pfmt)
2468 {
2469 	/*
2470 	 * scan everything between pstr and pstr_end. This is not including the
2471 	 * last character so we might set it to '\0' for the parsing
2472 	 */
2473 
2474 	char		last_char;
2475 	int			err = 0;
2476 	char	   *pstr_end;
2477 	char	   *strtol_end = NULL;
2478 
2479 	while (**pstr == ' ')
2480 		pstr++;
2481 	pstr_end = find_end_token(*pstr, pfmt);
2482 	if (!pstr_end)
2483 	{
2484 		/* there was an error, no match */
2485 		return 1;
2486 	}
2487 	last_char = *pstr_end;
2488 	*pstr_end = '\0';
2489 
2490 	switch (scan_type)
2491 	{
2492 		case PGTYPES_TYPE_UINT:
2493 
2494 			/*
2495 			 * numbers may be blank-padded, this is the only deviation from
2496 			 * the fmt-string we accept
2497 			 */
2498 			while (**pstr == ' ')
2499 				(*pstr)++;
2500 			errno = 0;
2501 			scan_val->uint_val = (unsigned int) strtol(*pstr, &strtol_end, 10);
2502 			if (errno)
2503 				err = 1;
2504 			break;
2505 		case PGTYPES_TYPE_UINT_LONG:
2506 			while (**pstr == ' ')
2507 				(*pstr)++;
2508 			errno = 0;
2509 			scan_val->luint_val = (unsigned long int) strtol(*pstr, &strtol_end, 10);
2510 			if (errno)
2511 				err = 1;
2512 			break;
2513 		case PGTYPES_TYPE_STRING_MALLOCED:
2514 			scan_val->str_val = pgtypes_strdup(*pstr);
2515 			if (scan_val->str_val == NULL)
2516 				err = 1;
2517 			break;
2518 	}
2519 	if (strtol_end && *strtol_end)
2520 		*pstr = strtol_end;
2521 	else
2522 		*pstr = pstr_end;
2523 	*pstr_end = last_char;
2524 	return err;
2525 }
2526 
2527 /* XXX range checking */
2528 int
PGTYPEStimestamp_defmt_scan(char ** str,char * fmt,timestamp * d,int * year,int * month,int * day,int * hour,int * minute,int * second,int * tz)2529 PGTYPEStimestamp_defmt_scan(char **str, char *fmt, timestamp * d,
2530 							int *year, int *month, int *day,
2531 							int *hour, int *minute, int *second,
2532 							int *tz)
2533 {
2534 	union un_fmt_comb scan_val;
2535 	int			scan_type;
2536 
2537 	char	   *pstr,
2538 			   *pfmt,
2539 			   *tmp;
2540 	int			err = 1;
2541 	unsigned int j;
2542 	struct tm	tm;
2543 
2544 	pfmt = fmt;
2545 	pstr = *str;
2546 
2547 	while (*pfmt)
2548 	{
2549 		err = 0;
2550 		while (*pfmt == ' ')
2551 			pfmt++;
2552 		while (*pstr == ' ')
2553 			pstr++;
2554 		if (*pfmt != '%')
2555 		{
2556 			if (*pfmt == *pstr)
2557 			{
2558 				pfmt++;
2559 				pstr++;
2560 			}
2561 			else
2562 			{
2563 				/* Error: no match */
2564 				err = 1;
2565 				return err;
2566 			}
2567 			continue;
2568 		}
2569 		/* here *pfmt equals '%' */
2570 		pfmt++;
2571 		switch (*pfmt)
2572 		{
2573 			case 'a':
2574 				pfmt++;
2575 
2576 				/*
2577 				 * we parse the day and see if it is a week day but we do not
2578 				 * check if the week day really matches the date
2579 				 */
2580 				err = 1;
2581 				j = 0;
2582 				while (pgtypes_date_weekdays_short[j])
2583 				{
2584 					if (strncmp(pgtypes_date_weekdays_short[j], pstr,
2585 								strlen(pgtypes_date_weekdays_short[j])) == 0)
2586 					{
2587 						/* found it */
2588 						err = 0;
2589 						pstr += strlen(pgtypes_date_weekdays_short[j]);
2590 						break;
2591 					}
2592 					j++;
2593 				}
2594 				break;
2595 			case 'A':
2596 				/* see note above */
2597 				pfmt++;
2598 				err = 1;
2599 				j = 0;
2600 				while (days[j])
2601 				{
2602 					if (strncmp(days[j], pstr, strlen(days[j])) == 0)
2603 					{
2604 						/* found it */
2605 						err = 0;
2606 						pstr += strlen(days[j]);
2607 						break;
2608 					}
2609 					j++;
2610 				}
2611 				break;
2612 			case 'b':
2613 			case 'h':
2614 				pfmt++;
2615 				err = 1;
2616 				j = 0;
2617 				while (months[j])
2618 				{
2619 					if (strncmp(months[j], pstr, strlen(months[j])) == 0)
2620 					{
2621 						/* found it */
2622 						err = 0;
2623 						pstr += strlen(months[j]);
2624 						*month = j + 1;
2625 						break;
2626 					}
2627 					j++;
2628 				}
2629 				break;
2630 			case 'B':
2631 				/* see note above */
2632 				pfmt++;
2633 				err = 1;
2634 				j = 0;
2635 				while (pgtypes_date_months[j])
2636 				{
2637 					if (strncmp(pgtypes_date_months[j], pstr, strlen(pgtypes_date_months[j])) == 0)
2638 					{
2639 						/* found it */
2640 						err = 0;
2641 						pstr += strlen(pgtypes_date_months[j]);
2642 						*month = j + 1;
2643 						break;
2644 					}
2645 					j++;
2646 				}
2647 				break;
2648 			case 'c':
2649 				/* XXX */
2650 				break;
2651 			case 'C':
2652 				pfmt++;
2653 				scan_type = PGTYPES_TYPE_UINT;
2654 				err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
2655 				*year = scan_val.uint_val * 100;
2656 				break;
2657 			case 'd':
2658 			case 'e':
2659 				pfmt++;
2660 				scan_type = PGTYPES_TYPE_UINT;
2661 				err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
2662 				*day = scan_val.uint_val;
2663 				break;
2664 			case 'D':
2665 
2666 				/*
2667 				 * we have to concatenate the strings in order to be able to
2668 				 * find the end of the substitution
2669 				 */
2670 				pfmt++;
2671 				tmp = pgtypes_alloc(strlen("%m/%d/%y") + strlen(pstr) + 1);
2672 				strcpy(tmp, "%m/%d/%y");
2673 				strcat(tmp, pfmt);
2674 				err = PGTYPEStimestamp_defmt_scan(&pstr, tmp, d, year, month, day, hour, minute, second, tz);
2675 				free(tmp);
2676 				return err;
2677 			case 'm':
2678 				pfmt++;
2679 				scan_type = PGTYPES_TYPE_UINT;
2680 				err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
2681 				*month = scan_val.uint_val;
2682 				break;
2683 			case 'y':
2684 			case 'g':			/* XXX difference to y (ISO) */
2685 				pfmt++;
2686 				scan_type = PGTYPES_TYPE_UINT;
2687 				err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
2688 				if (*year < 0)
2689 				{
2690 					/* not yet set */
2691 					*year = scan_val.uint_val;
2692 				}
2693 				else
2694 					*year += scan_val.uint_val;
2695 				if (*year < 100)
2696 					*year += 1900;
2697 				break;
2698 			case 'G':
2699 				/* XXX difference to %V (ISO) */
2700 				pfmt++;
2701 				scan_type = PGTYPES_TYPE_UINT;
2702 				err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
2703 				*year = scan_val.uint_val;
2704 				break;
2705 			case 'H':
2706 			case 'I':
2707 			case 'k':
2708 			case 'l':
2709 				pfmt++;
2710 				scan_type = PGTYPES_TYPE_UINT;
2711 				err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
2712 				*hour += scan_val.uint_val;
2713 				break;
2714 			case 'j':
2715 				pfmt++;
2716 				scan_type = PGTYPES_TYPE_UINT;
2717 				err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
2718 
2719 				/*
2720 				 * XXX what should we do with that? We could say that it's
2721 				 * sufficient if we have the year and the day within the year
2722 				 * to get at least a specific day.
2723 				 */
2724 				break;
2725 			case 'M':
2726 				pfmt++;
2727 				scan_type = PGTYPES_TYPE_UINT;
2728 				err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
2729 				*minute = scan_val.uint_val;
2730 				break;
2731 			case 'n':
2732 				pfmt++;
2733 				if (*pstr == '\n')
2734 					pstr++;
2735 				else
2736 					err = 1;
2737 				break;
2738 			case 'p':
2739 				err = 1;
2740 				pfmt++;
2741 				if (strncmp(pstr, "am", 2) == 0)
2742 				{
2743 					*hour += 0;
2744 					err = 0;
2745 					pstr += 2;
2746 				}
2747 				if (strncmp(pstr, "a.m.", 4) == 0)
2748 				{
2749 					*hour += 0;
2750 					err = 0;
2751 					pstr += 4;
2752 				}
2753 				if (strncmp(pstr, "pm", 2) == 0)
2754 				{
2755 					*hour += 12;
2756 					err = 0;
2757 					pstr += 2;
2758 				}
2759 				if (strncmp(pstr, "p.m.", 4) == 0)
2760 				{
2761 					*hour += 12;
2762 					err = 0;
2763 					pstr += 4;
2764 				}
2765 				break;
2766 			case 'P':
2767 				err = 1;
2768 				pfmt++;
2769 				if (strncmp(pstr, "AM", 2) == 0)
2770 				{
2771 					*hour += 0;
2772 					err = 0;
2773 					pstr += 2;
2774 				}
2775 				if (strncmp(pstr, "A.M.", 4) == 0)
2776 				{
2777 					*hour += 0;
2778 					err = 0;
2779 					pstr += 4;
2780 				}
2781 				if (strncmp(pstr, "PM", 2) == 0)
2782 				{
2783 					*hour += 12;
2784 					err = 0;
2785 					pstr += 2;
2786 				}
2787 				if (strncmp(pstr, "P.M.", 4) == 0)
2788 				{
2789 					*hour += 12;
2790 					err = 0;
2791 					pstr += 4;
2792 				}
2793 				break;
2794 			case 'r':
2795 				pfmt++;
2796 				tmp = pgtypes_alloc(strlen("%I:%M:%S %p") + strlen(pstr) + 1);
2797 				strcpy(tmp, "%I:%M:%S %p");
2798 				strcat(tmp, pfmt);
2799 				err = PGTYPEStimestamp_defmt_scan(&pstr, tmp, d, year, month, day, hour, minute, second, tz);
2800 				free(tmp);
2801 				return err;
2802 			case 'R':
2803 				pfmt++;
2804 				tmp = pgtypes_alloc(strlen("%H:%M") + strlen(pstr) + 1);
2805 				strcpy(tmp, "%H:%M");
2806 				strcat(tmp, pfmt);
2807 				err = PGTYPEStimestamp_defmt_scan(&pstr, tmp, d, year, month, day, hour, minute, second, tz);
2808 				free(tmp);
2809 				return err;
2810 			case 's':
2811 				pfmt++;
2812 				scan_type = PGTYPES_TYPE_UINT_LONG;
2813 				err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
2814 				/* number of seconds in scan_val.luint_val */
2815 				{
2816 					struct tm  *tms;
2817 					time_t		et = (time_t) scan_val.luint_val;
2818 
2819 					tms = gmtime(&et);
2820 
2821 					if (tms)
2822 					{
2823 						*year = tms->tm_year + 1900;
2824 						*month = tms->tm_mon + 1;
2825 						*day = tms->tm_mday;
2826 						*hour = tms->tm_hour;
2827 						*minute = tms->tm_min;
2828 						*second = tms->tm_sec;
2829 					}
2830 					else
2831 						err = 1;
2832 				}
2833 				break;
2834 			case 'S':
2835 				pfmt++;
2836 				scan_type = PGTYPES_TYPE_UINT;
2837 				err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
2838 				*second = scan_val.uint_val;
2839 				break;
2840 			case 't':
2841 				pfmt++;
2842 				if (*pstr == '\t')
2843 					pstr++;
2844 				else
2845 					err = 1;
2846 				break;
2847 			case 'T':
2848 				pfmt++;
2849 				tmp = pgtypes_alloc(strlen("%H:%M:%S") + strlen(pstr) + 1);
2850 				strcpy(tmp, "%H:%M:%S");
2851 				strcat(tmp, pfmt);
2852 				err = PGTYPEStimestamp_defmt_scan(&pstr, tmp, d, year, month, day, hour, minute, second, tz);
2853 				free(tmp);
2854 				return err;
2855 			case 'u':
2856 				pfmt++;
2857 				scan_type = PGTYPES_TYPE_UINT;
2858 				err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
2859 				if (scan_val.uint_val < 1 || scan_val.uint_val > 7)
2860 					err = 1;
2861 				break;
2862 			case 'U':
2863 				pfmt++;
2864 				scan_type = PGTYPES_TYPE_UINT;
2865 				err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
2866 				if (scan_val.uint_val > 53)
2867 					err = 1;
2868 				break;
2869 			case 'V':
2870 				pfmt++;
2871 				scan_type = PGTYPES_TYPE_UINT;
2872 				err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
2873 				if (scan_val.uint_val < 1 || scan_val.uint_val > 53)
2874 					err = 1;
2875 				break;
2876 			case 'w':
2877 				pfmt++;
2878 				scan_type = PGTYPES_TYPE_UINT;
2879 				err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
2880 				if (scan_val.uint_val > 6)
2881 					err = 1;
2882 				break;
2883 			case 'W':
2884 				pfmt++;
2885 				scan_type = PGTYPES_TYPE_UINT;
2886 				err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
2887 				if (scan_val.uint_val > 53)
2888 					err = 1;
2889 				break;
2890 			case 'x':
2891 			case 'X':
2892 				/* XXX */
2893 				break;
2894 			case 'Y':
2895 				pfmt++;
2896 				scan_type = PGTYPES_TYPE_UINT;
2897 				err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
2898 				*year = scan_val.uint_val;
2899 				break;
2900 			case 'z':
2901 				pfmt++;
2902 				scan_type = PGTYPES_TYPE_STRING_MALLOCED;
2903 				err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
2904 				if (!err)
2905 				{
2906 					err = DecodeTimezone(scan_val.str_val, tz);
2907 					free(scan_val.str_val);
2908 				}
2909 				break;
2910 			case 'Z':
2911 				pfmt++;
2912 				scan_type = PGTYPES_TYPE_STRING_MALLOCED;
2913 				err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
2914 				if (!err)
2915 				{
2916 					/*
2917 					 * XXX use DecodeSpecial instead?  Do we need strcasecmp
2918 					 * here?
2919 					 */
2920 					err = 1;
2921 					for (j = 0; j < szdatetktbl; j++)
2922 					{
2923 						if ((datetktbl[j].type == TZ || datetktbl[j].type == DTZ) &&
2924 							pg_strcasecmp(datetktbl[j].token,
2925 										  scan_val.str_val) == 0)
2926 						{
2927 							*tz = -datetktbl[j].value;
2928 							err = 0;
2929 							break;
2930 						}
2931 					}
2932 					free(scan_val.str_val);
2933 				}
2934 				break;
2935 			case '+':
2936 				/* XXX */
2937 				break;
2938 			case '%':
2939 				pfmt++;
2940 				if (*pstr == '%')
2941 					pstr++;
2942 				else
2943 					err = 1;
2944 				break;
2945 			default:
2946 				err = 1;
2947 		}
2948 	}
2949 	if (!err)
2950 	{
2951 		if (*second < 0)
2952 			*second = 0;
2953 		if (*minute < 0)
2954 			*minute = 0;
2955 		if (*hour < 0)
2956 			*hour = 0;
2957 		if (*day < 0)
2958 		{
2959 			err = 1;
2960 			*day = 1;
2961 		}
2962 		if (*month < 0)
2963 		{
2964 			err = 1;
2965 			*month = 1;
2966 		}
2967 		if (*year < 0)
2968 		{
2969 			err = 1;
2970 			*year = 1970;
2971 		}
2972 
2973 		if (*second > 59)
2974 		{
2975 			err = 1;
2976 			*second = 0;
2977 		}
2978 		if (*minute > 59)
2979 		{
2980 			err = 1;
2981 			*minute = 0;
2982 		}
2983 		if (*hour > 24 ||		/* test for > 24:00:00 */
2984 			(*hour == 24 && (*minute > 0 || *second > 0)))
2985 		{
2986 			err = 1;
2987 			*hour = 0;
2988 		}
2989 		if (*month > MONTHS_PER_YEAR)
2990 		{
2991 			err = 1;
2992 			*month = 1;
2993 		}
2994 		if (*day > day_tab[isleap(*year)][*month - 1])
2995 		{
2996 			*day = day_tab[isleap(*year)][*month - 1];
2997 			err = 1;
2998 		}
2999 
3000 		tm.tm_sec = *second;
3001 		tm.tm_min = *minute;
3002 		tm.tm_hour = *hour;
3003 		tm.tm_mday = *day;
3004 		tm.tm_mon = *month;
3005 		tm.tm_year = *year;
3006 
3007 		tm2timestamp(&tm, 0, tz, d);
3008 	}
3009 	return err;
3010 }
3011 
3012 /* XXX: 1900 is compiled in as the base for years */
3013