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