source: trunk/src/oleaut32/parsedt.cpp@ 631

Last change on this file since 631 was 631, checked in by sandervl, 26 years ago

Created (WINE Port of OLEAUT32)

File size: 30.4 KB
Line 
1/*
2PostgreSQL Data Base Management System (formerly known as Postgres, then
3as Postgres95).
4
5Copyright (c) 1994-7 Regents of the University of California
6
7Permission to use, copy, modify, and distribute this software and its
8documentation for any purpose, without fee, and without a written agreement
9is hereby granted, provided that the above copyright notice and this
10paragraph and the following two paragraphs appear in all copies.
11
12IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
13DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
14LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
15DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE
16POSSIBILITY OF SUCH DAMAGE.
17
18THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
19INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
20AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO
22PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23*/
24
25/*-------------------------------------------------------------------------
26 *
27 * dt.c--
28 * Functions for the built-in type "dt".
29 *
30 * Copyright (c) 1994, Regents of the University of California
31 *
32 *
33 *-------------------------------------------------------------------------
34 */
35#include <time.h>
36#include <stdio.h>
37#include <ctype.h>
38#include <math.h>
39#include <string.h>
40#include <sys/types.h>
41#include <errno.h>
42#include <limits.h>
43#include <sys/timeb.h>
44
45#include "parsedt.h"
46
47static datetkn *datebsearch(char *key, datetkn *base, unsigned int nel);
48static int DecodeDate(char *str, int fmask, int *tmask, struct tm * tm);
49static int DecodeNumber(int flen, char *field,
50 int fmask, int *tmask, struct tm * tm, double *fsec);
51static int DecodeNumberField(int len, char *str,
52 int fmask, int *tmask, struct tm * tm, double *fsec);
53static int DecodeSpecial(int field, char *lowtoken, int *val);
54static int DecodeTime(char *str, int fmask, int *tmask,
55 struct tm * tm, double *fsec);
56static int DecodeTimezone(char *str, int *tzp);
57
58#define USE_DATE_CACHE 1
59#define ROUND_ALL 0
60
61int mdays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0};
62
63char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
64"Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL};
65
66char *days[] = {"Sunday", "Monday", "Tuesday", "Wednesday",
67"Thursday", "Friday", "Saturday", NULL};
68
69
70#define UTIME_MINYEAR (1901)
71#define UTIME_MINMONTH (12)
72#define UTIME_MINDAY (14)
73#define UTIME_MAXYEAR (2038)
74#define UTIME_MAXMONTH (01)
75#define UTIME_MAXDAY (18)
76
77#define IS_VALID_UTIME(y,m,d) (((y > UTIME_MINYEAR) \
78 || ((y == UTIME_MINYEAR) && ((m > UTIME_MINMONTH) \
79 || ((m == UTIME_MINMONTH) && (d >= UTIME_MINDAY))))) \
80 && ((y < UTIME_MAXYEAR) \
81 || ((y == UTIME_MAXYEAR) && ((m < UTIME_MAXMONTH) \
82 || ((m == UTIME_MAXMONTH) && (d <= UTIME_MAXDAY))))))
83
84
85int DateStyle = 0;
86bool EuroDates= 0;
87int CTimeZone= 0;
88
89
90/*****************************************************************************
91 * PRIVATE ROUTINES *
92 *****************************************************************************/
93
94/* definitions for squeezing values into "value" */
95#define ABS_SIGNBIT (char) 0200
96#define VALMASK (char) 0177
97#define NEG(n) ((n)|ABS_SIGNBIT)
98#define SIGNEDCHAR(c) ((c)&ABS_SIGNBIT? -((c)&VALMASK): (c))
99#define FROMVAL(tp) (-SIGNEDCHAR((tp)->value) * 10) /* uncompress */
100#define TOVAL(tp, v) ((tp)->value = ((v) < 0? NEG((-(v))/10): (v)/10))
101
102/*
103 * to keep this table reasonably small, we divide the lexval for TZ and DTZ
104 * entries by 10 and truncate the text field at MAXTOKLEN characters.
105 * the text field is not guaranteed to be NULL-terminated.
106 */
107static datetkn datetktbl[] = {
108/* text token lexval */
109 {EARLY, RESERV, DTK_EARLY}, /* "-infinity" reserved for "early time" */
110 {"acsst", DTZ, 63}, /* Cent. Australia */
111 {"acst", TZ, 57}, /* Cent. Australia */
112 {DA_D, ADBC, AD}, /* "ad" for years >= 0 */
113 {"abstime", IGNOREFIELD, 0}, /* "abstime" for pre-v6.1 "Invalid
114 * Abstime" */
115 {"adt", DTZ, NEG(18)}, /* Atlantic Daylight Time */
116 {"aesst", DTZ, 66}, /* E. Australia */
117 {"aest", TZ, 60}, /* Australia Eastern Std Time */
118 {"ahst", TZ, 60}, /* Alaska-Hawaii Std Time */
119 {"allballs", RESERV, DTK_ZULU}, /* 00:00:00 */
120 {"am", AMPM, AM},
121 {"apr", MONTH, 4},
122 {"april", MONTH, 4},
123 {"ast", TZ, NEG(24)}, /* Atlantic Std Time (Canada) */
124 {"at", IGNOREFIELD, 0}, /* "at" (throwaway) */
125 {"aug", MONTH, 8},
126 {"august", MONTH, 8},
127 {"awsst", DTZ, 54}, /* W. Australia */
128 {"awst", TZ, 48}, /* W. Australia */
129 {DB_C, ADBC, BC}, /* "bc" for years < 0 */
130 {"bst", TZ, 6}, /* British Summer Time */
131 {"bt", TZ, 18}, /* Baghdad Time */
132 {"cadt", DTZ, 63}, /* Central Australian DST */
133 {"cast", TZ, 57}, /* Central Australian ST */
134 {"cat", TZ, NEG(60)}, /* Central Alaska Time */
135 {"cct", TZ, 48}, /* China Coast */
136 {"cdt", DTZ, NEG(30)}, /* Central Daylight Time */
137 {"cet", TZ, 6}, /* Central European Time */
138 {"cetdst", DTZ, 12}, /* Central European Dayl.Time */
139 {"cst", TZ, NEG(36)}, /* Central Standard Time */
140 {DCURRENT, RESERV, DTK_CURRENT}, /* "current" is always now */
141 {"dec", MONTH, 12},
142 {"december", MONTH, 12},
143 {"dnt", TZ, 6}, /* Dansk Normal Tid */
144 {"dow", RESERV, DTK_DOW}, /* day of week */
145 {"doy", RESERV, DTK_DOY}, /* day of year */
146 {"dst", DTZMOD, 6},
147 {"east", TZ, NEG(60)}, /* East Australian Std Time */
148 {"edt", DTZ, NEG(24)}, /* Eastern Daylight Time */
149 {"eet", TZ, 12}, /* East. Europe, USSR Zone 1 */
150 {"eetdst", DTZ, 18}, /* Eastern Europe */
151 {EPOCH, RESERV, DTK_EPOCH}, /* "epoch" reserved for system epoch time */
152#if USE_AUSTRALIAN_RULES
153 {"est", TZ, 60}, /* Australia Eastern Std Time */
154#else
155 {"est", TZ, NEG(30)}, /* Eastern Standard Time */
156#endif
157 {"feb", MONTH, 2},
158 {"february", MONTH, 2},
159 {"fri", DOW, 5},
160 {"friday", DOW, 5},
161 {"fst", TZ, 6}, /* French Summer Time */
162 {"fwt", DTZ, 12}, /* French Winter Time */
163 {"gmt", TZ, 0}, /* Greenwish Mean Time */
164 {"gst", TZ, 60}, /* Guam Std Time, USSR Zone 9 */
165 {"hdt", DTZ, NEG(54)}, /* Hawaii/Alaska */
166 {"hmt", DTZ, 18}, /* Hellas ? ? */
167 {"hst", TZ, NEG(60)}, /* Hawaii Std Time */
168 {"idle", TZ, 72}, /* Intl. Date Line, East */
169 {"idlw", TZ, NEG(72)}, /* Intl. Date Line,, est */
170 {LATE, RESERV, DTK_LATE}, /* "infinity" reserved for "late time" */
171 {INVALID, RESERV, DTK_INVALID}, /* "invalid" reserved for invalid
172 * time */
173 {"ist", TZ, 12}, /* Israel */
174 {"it", TZ, 22}, /* Iran Time */
175 {"jan", MONTH, 1},
176 {"january", MONTH, 1},
177 {"jst", TZ, 54}, /* Japan Std Time,USSR Zone 8 */
178 {"jt", TZ, 45}, /* Java Time */
179 {"jul", MONTH, 7},
180 {"july", MONTH, 7},
181 {"jun", MONTH, 6},
182 {"june", MONTH, 6},
183 {"kst", TZ, 54}, /* Korea Standard Time */
184 {"ligt", TZ, 60}, /* From Melbourne, Australia */
185 {"mar", MONTH, 3},
186 {"march", MONTH, 3},
187 {"may", MONTH, 5},
188 {"mdt", DTZ, NEG(36)}, /* Mountain Daylight Time */
189 {"mest", DTZ, 12}, /* Middle Europe Summer Time */
190 {"met", TZ, 6}, /* Middle Europe Time */
191 {"metdst", DTZ, 12}, /* Middle Europe Daylight Time */
192 {"mewt", TZ, 6}, /* Middle Europe Winter Time */
193 {"mez", TZ, 6}, /* Middle Europe Zone */
194 {"mon", DOW, 1},
195 {"monday", DOW, 1},
196 {"mst", TZ, NEG(42)}, /* Mountain Standard Time */
197 {"mt", TZ, 51}, /* Moluccas Time */
198 {"ndt", DTZ, NEG(15)}, /* Nfld. Daylight Time */
199 {"nft", TZ, NEG(21)}, /* Newfoundland Standard Time */
200 {"nor", TZ, 6}, /* Norway Standard Time */
201 {"nov", MONTH, 11},
202 {"november", MONTH, 11},
203 {NOW, RESERV, DTK_NOW}, /* current transaction time */
204 {"nst", TZ, NEG(21)}, /* Nfld. Standard Time */
205 {"nt", TZ, NEG(66)}, /* Nome Time */
206 {"nzdt", DTZ, 78}, /* New Zealand Daylight Time */
207 {"nzst", TZ, 72}, /* New Zealand Standard Time */
208 {"nzt", TZ, 72}, /* New Zealand Time */
209 {"oct", MONTH, 10},
210 {"october", MONTH, 10},
211 {"on", IGNOREFIELD, 0}, /* "on" (throwaway) */
212 {"pdt", DTZ, NEG(42)}, /* Pacific Daylight Time */
213 {"pm", AMPM, PM},
214 {"pst", TZ, NEG(48)}, /* Pacific Standard Time */
215 {"sadt", DTZ, 63}, /* S. Australian Dayl. Time */
216 {"sast", TZ, 57}, /* South Australian Std Time */
217 {"sat", DOW, 6},
218 {"saturday", DOW, 6},
219 {"sep", MONTH, 9},
220 {"sept", MONTH, 9},
221 {"september", MONTH, 9},
222 {"set", TZ, NEG(6)}, /* Seychelles Time ?? */
223 {"sst", DTZ, 12}, /* Swedish Summer Time */
224 {"sun", DOW, 0},
225 {"sunday", DOW, 0},
226 {"swt", TZ, 6}, /* Swedish Winter Time */
227 {"thu", DOW, 4},
228 {"thur", DOW, 4},
229 {"thurs", DOW, 4},
230 {"thursday", DOW, 4},
231 {TODAY, RESERV, DTK_TODAY}, /* midnight */
232 {TOMORROW, RESERV, DTK_TOMORROW}, /* tomorrow midnight */
233 {"tue", DOW, 2},
234 {"tues", DOW, 2},
235 {"tuesday", DOW, 2},
236 {"undefined", RESERV, DTK_INVALID}, /* "undefined" pre-v6.1 invalid
237 * time */
238 {"ut", TZ, 0},
239 {"utc", TZ, 0},
240 {"wadt", DTZ, 48}, /* West Australian DST */
241 {"wast", TZ, 42}, /* West Australian Std Time */
242 {"wat", TZ, NEG(6)}, /* West Africa Time */
243 {"wdt", DTZ, 54}, /* West Australian DST */
244 {"wed", DOW, 3},
245 {"wednesday", DOW, 3},
246 {"weds", DOW, 3},
247 {"wet", TZ, 0}, /* Western Europe */
248 {"wetdst", DTZ, 6}, /* Western Europe */
249 {"wst", TZ, 48}, /* West Australian Std Time */
250 {"ydt", DTZ, NEG(48)}, /* Yukon Daylight Time */
251 {YESTERDAY, RESERV, DTK_YESTERDAY}, /* yesterday midnight */
252 {"yst", TZ, NEG(54)}, /* Yukon Standard Time */
253 {"zp4", TZ, NEG(24)}, /* GMT +4 hours. */
254 {"zp5", TZ, NEG(30)}, /* GMT +5 hours. */
255 {"zp6", TZ, NEG(36)}, /* GMT +6 hours. */
256 {"z", RESERV, DTK_ZULU}, /* 00:00:00 */
257 {ZULU, RESERV, DTK_ZULU}, /* 00:00:00 */
258};
259
260static unsigned int szdatetktbl = sizeof datetktbl / sizeof datetktbl[0];
261
262
263
264#if USE_DATE_CACHE
265datetkn *datecache[MAXDATEFIELDS] = {NULL};
266
267datetkn *deltacache[MAXDATEFIELDS] = {NULL};
268
269#endif
270
271
272/*
273 * Calendar time to Julian date conversions.
274 * Julian date is commonly used in astronomical applications,
275 * since it is numerically accurate and computationally simple.
276 * The algorithms here will accurately convert between Julian day
277 * and calendar date for all non-negative Julian days
278 * (i.e. from Nov 23, -4713 on).
279 *
280 * Ref: Explanatory Supplement to the Astronomical Almanac, 1992.
281 * University Science Books, 20 Edgehill Rd. Mill Valley CA 94941.
282 *
283 * Use the algorithm by Henry Fliegel, a former NASA/JPL colleague
284 * now at Aerospace Corp. (hi, Henry!)
285 *
286 * These routines will be used by other date/time packages - tgl 97/02/25
287 */
288
289/* Set the minimum year to one greater than the year of the first valid day
290 * to avoid having to check year and day both. - tgl 97/05/08
291 */
292
293#define JULIAN_MINYEAR (-4713)
294#define JULIAN_MINMONTH (11)
295#define JULIAN_MINDAY (23)
296
297#define IS_VALID_JULIAN(y,m,d) ((y > JULIAN_MINYEAR) \
298 || ((y == JULIAN_MINYEAR) && ((m > JULIAN_MINMONTH) \
299 || ((m == JULIAN_MINMONTH) && (d >= JULIAN_MINDAY)))))
300
301int
302date2j(int y, int m, int d)
303{
304 int m12 = (m - 14) / 12;
305
306 return ((1461 * (y + 4800 + m12)) / 4 + (367 * (m - 2 - 12 * (m12))) / 12
307 - (3 * ((y + 4900 + m12) / 100)) / 4 + d - 32075);
308} /* date2j() */
309
310void
311j2date(int jd, int *year, int *month, int *day)
312{
313 int j,
314 y,
315 m,
316 d;
317
318 int i,
319 l,
320 n;
321
322 l = jd + 68569;
323 n = (4 * l) / 146097;
324 l -= (146097 * n + 3) / 4;
325 i = (4000 * (l + 1)) / 1461001;
326 l += 31 - (1461 * i) / 4;
327 j = (80 * l) / 2447;
328 d = l - (2447 * j) / 80;
329 l = j / 11;
330 m = (j + 2) - (12 * l);
331 y = 100 * (n - 49) + i + l;
332
333 *year = y;
334 *month = m;
335 *day = d;
336 return;
337} /* j2date() */
338
339
340
341
342/*
343 * parse and convert date in timestr (the normal interface)
344 *
345 * Returns the number of seconds since epoch (J2000)
346 */
347
348/* ParseDateTime()
349 * Break string into tokens based on a date/time context.
350 */
351int
352ParseDateTime(char *timestr, char *lowstr,
353 char **field, int *ftype, int maxfields, int *numfields)
354{
355 int nf = 0;
356 char *cp = timestr;
357 char *lp = lowstr;
358
359#ifdef DATEDEBUG
360 printf("ParseDateTime- input string is %s\n", timestr);
361#endif
362 /* outer loop through fields */
363 while (*cp != '\0')
364 {
365 field[nf] = lp;
366
367 /* leading digit? then date or time */
368 if (isdigit(*cp) || (*cp == '.'))
369 {
370 *lp++ = *cp++;
371 while (isdigit(*cp))
372 *lp++ = *cp++;
373 /* time field? */
374 if (*cp == ':')
375 {
376 ftype[nf] = DTK_TIME;
377 while (isdigit(*cp) || (*cp == ':') || (*cp == '.'))
378 *lp++ = *cp++;
379
380 }
381 /* date field? allow embedded text month */
382 else if ((*cp == '-') || (*cp == '/') || (*cp == '.'))
383 {
384 ftype[nf] = DTK_DATE;
385 while (isalnum(*cp) || (*cp == '-') || (*cp == '/') || (*cp == '.'))
386 *lp++ = tolower(*cp++);
387
388 }
389
390 /*
391 * otherwise, number only and will determine year, month, or
392 * day later
393 */
394 else
395 ftype[nf] = DTK_NUMBER;
396
397 }
398
399 /*
400 * text? then date string, month, day of week, special, or
401 * timezone
402 */
403 else if (isalpha(*cp))
404 {
405 ftype[nf] = DTK_STRING;
406 *lp++ = tolower(*cp++);
407 while (isalpha(*cp))
408 *lp++ = tolower(*cp++);
409
410 /* full date string with leading text month? */
411 if ((*cp == '-') || (*cp == '/') || (*cp == '.'))
412 {
413 ftype[nf] = DTK_DATE;
414 while (isdigit(*cp) || (*cp == '-') || (*cp == '/') || (*cp == '.'))
415 *lp++ = tolower(*cp++);
416 }
417
418 /* skip leading spaces */
419 }
420 else if (isspace(*cp))
421 {
422 cp++;
423 continue;
424
425 /* sign? then special or numeric timezone */
426 }
427 else if ((*cp == '+') || (*cp == '-'))
428 {
429 *lp++ = *cp++;
430 /* soak up leading whitespace */
431 while (isspace(*cp))
432 cp++;
433 /* numeric timezone? */
434 if (isdigit(*cp))
435 {
436 ftype[nf] = DTK_TZ;
437 *lp++ = *cp++;
438 while (isdigit(*cp) || (*cp == ':'))
439 *lp++ = *cp++;
440
441 /* special? */
442 }
443 else if (isalpha(*cp))
444 {
445 ftype[nf] = DTK_SPECIAL;
446 *lp++ = tolower(*cp++);
447 while (isalpha(*cp))
448 *lp++ = tolower(*cp++);
449
450 /* otherwise something wrong... */
451 }
452 else
453 return -1;
454
455 /* ignore punctuation but use as delimiter */
456 }
457 else if (ispunct(*cp))
458 {
459 cp++;
460 continue;
461
462 }
463 else
464 return -1;
465
466 /* force in a delimiter */
467 *lp++ = '\0';
468 nf++;
469 if (nf > MAXDATEFIELDS)
470 return -1;
471#ifdef DATEDEBUG
472 printf("ParseDateTime- set field[%d] to %s type %d\n", (nf - 1), field[nf - 1], ftype[nf - 1]);
473#endif
474 }
475
476 *numfields = nf;
477
478 return 0;
479} /* ParseDateTime() */
480
481
482/* DecodeDateTime()
483 * Interpret previously parsed fields for general date and time.
484 * Return 0 if full date, 1 if only time, and -1 if problems.
485 * External format(s):
486 * "<weekday> <month>-<day>-<year> <hour>:<minute>:<second>"
487 * "Fri Feb-7-1997 15:23:27"
488 * "Feb-7-1997 15:23:27"
489 * "2-7-1997 15:23:27"
490 * "1997-2-7 15:23:27"
491 * "1997.038 15:23:27" (day of year 1-366)
492 * Also supports input in compact time:
493 * "970207 152327"
494 * "97038 152327"
495 *
496 * Use the system-provided functions to get the current time zone
497 * if not specified in the input string.
498 * If the date is outside the time_t system-supported time range,
499 * then assume GMT time zone. - tgl 97/05/27
500 */
501int
502DecodeDateTime(char **field, int *ftype, int nf,
503 int *dtype, struct tm * tm, double *fsec, int *tzp)
504{
505 int fmask = 0,
506 tmask,
507 type;
508 int i;
509 int flen,
510 val;
511 int mer = HR24;
512 int bc = FALSE;
513
514 *dtype = DTK_DATE;
515 tm->tm_hour = 0;
516 tm->tm_min = 0;
517 tm->tm_sec = 0;
518 *fsec = 0;
519 tm->tm_isdst = -1; /* don't know daylight savings time status
520 * apriori */
521 if (tzp != NULL)
522 *tzp = 0;
523
524 for (i = 0; i < nf; i++)
525 {
526#ifdef DATEDEBUG
527 printf("DecodeDateTime- field[%d] is %s (type %d)\n", i, field[i], ftype[i]);
528#endif
529 switch (ftype[i])
530 {
531 case DTK_DATE:
532 if (DecodeDate(field[i], fmask, &tmask, tm) != 0)
533 return -1;
534 break;
535
536 case DTK_TIME:
537 if (DecodeTime(field[i], fmask, &tmask, tm, fsec) != 0)
538 return -1;
539
540 /*
541 * check upper limit on hours; other limits checked in
542 * DecodeTime()
543 */
544 if (tm->tm_hour > 23)
545 return -1;
546 break;
547
548 case DTK_TZ:
549 if (tzp == NULL)
550 return -1;
551 if (DecodeTimezone(field[i], tzp) != 0)
552 return -1;
553 tmask = DTK_M(TZ);
554 break;
555
556 case DTK_NUMBER:
557 flen = strlen(field[i]);
558
559 if (flen > 4)
560 {
561 if (DecodeNumberField(flen, field[i], fmask, &tmask, tm, fsec) != 0)
562 return -1;
563
564 }
565 else
566 {
567 if (DecodeNumber(flen, field[i], fmask, &tmask, tm, fsec) != 0)
568 return -1;
569 }
570 break;
571
572 case DTK_STRING:
573 case DTK_SPECIAL:
574 type = DecodeSpecial(i, field[i], &val);
575#ifdef DATEDEBUG
576 printf("DecodeDateTime- special field[%d] %s type=%d value=%d\n", i, field[i], type, val);
577#endif
578 if (type == IGNOREFIELD)
579 continue;
580
581 tmask = DTK_M(type);
582 switch (type)
583 {
584 case RESERV:
585#ifdef DATEDEBUG
586 printf("DecodeDateTime- RESERV field %s value is %d\n", field[i], val);
587#endif
588 switch (val)
589 {
590
591 default:
592 *dtype = val;
593 }
594
595 break;
596
597 case MONTH:
598#ifdef DATEDEBUG
599 printf("DecodeDateTime- month field %s value is %d\n", field[i], val);
600#endif
601 tm->tm_mon = val;
602 break;
603
604 /*
605 * daylight savings time modifier (solves "MET
606 * DST" syntax)
607 */
608 case DTZMOD:
609 tmask |= DTK_M(DTZ);
610 tm->tm_isdst = 1;
611 if (tzp == NULL)
612 return -1;
613 *tzp += val * 60;
614 break;
615
616 case DTZ:
617
618 /*
619 * set mask for TZ here _or_ check for DTZ later
620 * when getting default timezone
621 */
622 tmask |= DTK_M(TZ);
623 tm->tm_isdst = 1;
624 if (tzp == NULL)
625 return -1;
626 *tzp = val * 60;
627 break;
628
629 case TZ:
630 tm->tm_isdst = 0;
631 if (tzp == NULL)
632 return -1;
633 *tzp = val * 60;
634 break;
635
636 case IGNOREFIELD:
637 break;
638
639 case AMPM:
640 mer = val;
641 break;
642
643 case ADBC:
644 bc = (val == BC);
645 break;
646
647 case DOW:
648 tm->tm_wday = val;
649 break;
650
651 default:
652 return -1;
653 }
654 break;
655
656 default:
657 return -1;
658 }
659
660#ifdef DATEDEBUG
661 printf("DecodeDateTime- field[%d] %s (%08x/%08x) value is %d\n",
662 i, field[i], fmask, tmask, val);
663#endif
664
665 if (tmask & fmask)
666 return -1;
667 fmask |= tmask;
668 }
669
670 /* there is no year zero in AD/BC notation; i.e. "1 BC" == year 0 */
671 if (bc)
672 tm->tm_year = -(tm->tm_year - 1);
673
674 if ((mer != HR24) && (tm->tm_hour > 12))
675 return -1;
676 if ((mer == AM) && (tm->tm_hour == 12))
677 tm->tm_hour = 0;
678 else if ((mer == PM) && (tm->tm_hour != 12))
679 tm->tm_hour += 12;
680
681#ifdef DATEDEBUG
682 printf("DecodeDateTime- mask %08x (%08x)", fmask, DTK_DATE_M);
683 printf(" set y%04d m%02d d%02d", tm->tm_year, tm->tm_mon, tm->tm_mday);
684 printf(" %02d:%02d:%02d\n", tm->tm_hour, tm->tm_min, tm->tm_sec);
685#endif
686
687 if ((*dtype == DTK_DATE) && ((fmask & DTK_DATE_M) != DTK_DATE_M))
688 return ((fmask & DTK_TIME_M) == DTK_TIME_M) ? 1 : -1;
689
690 /* timezone not specified? then find local timezone if possible */
691 if ((*dtype == DTK_DATE) && ((fmask & DTK_DATE_M) == DTK_DATE_M)
692 && (tzp != NULL) && (!(fmask & DTK_M(TZ))))
693 {
694
695 /*
696 * daylight savings time modifier but no standard timezone? then
697 * error
698 */
699 if (fmask & DTK_M(DTZMOD))
700 return -1;
701
702 if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday))
703 {
704#ifdef USE_POSIX_TIME
705 tm->tm_year -= 1900;
706 tm->tm_mon -= 1;
707 tm->tm_isdst = -1;
708 mktime(tm);
709 tm->tm_year += 1900;
710 tm->tm_mon += 1;
711
712#ifdef HAVE_INT_TIMEZONE
713 *tzp = ((tm->tm_isdst > 0) ? (timezone - 3600) : timezone);
714
715#else /* !HAVE_INT_TIMEZONE */
716 *tzp = -(tm->tm_gmtoff); /* tm_gmtoff is Sun/DEC-ism */
717#endif
718
719#else /* !USE_POSIX_TIME */
720 *tzp = CTimeZone;
721#endif
722 }
723 else
724 {
725 tm->tm_isdst = 0;
726 *tzp = 0;
727 }
728 }
729
730 return 0;
731} /* DecodeDateTime() */
732
733
734/* DecodeTimeOnly()
735 * Interpret parsed string as time fields only.
736 */
737int
738DecodeTimeOnly(char **field, int *ftype, int nf, int *dtype, struct tm * tm, double *fsec)
739{
740 int fmask,
741 tmask,
742 type;
743 int i;
744 int flen,
745 val;
746 int mer = HR24;
747
748 *dtype = DTK_TIME;
749 tm->tm_hour = 0;
750 tm->tm_min = 0;
751 tm->tm_sec = 0;
752 tm->tm_isdst = -1; /* don't know daylight savings time status
753 * apriori */
754 *fsec = 0;
755
756 fmask = DTK_DATE_M;
757
758 for (i = 0; i < nf; i++)
759 {
760#ifdef DATEDEBUG
761 printf("DecodeTimeOnly- field[%d] is %s (type %d)\n", i, field[i], ftype[i]);
762#endif
763 switch (ftype[i])
764 {
765 case DTK_TIME:
766 if (DecodeTime(field[i], fmask, &tmask, tm, fsec) != 0)
767 return -1;
768 break;
769
770 case DTK_NUMBER:
771 flen = strlen(field[i]);
772
773 if (DecodeNumberField(flen, field[i], fmask, &tmask, tm, fsec) != 0)
774 return -1;
775 break;
776
777 case DTK_STRING:
778 case DTK_SPECIAL:
779 type = DecodeSpecial(i, field[i], &val);
780#ifdef DATEDEBUG
781 printf("DecodeTimeOnly- special field[%d] %s type=%d value=%d\n", i, field[i], type, val);
782#endif
783 if (type == IGNOREFIELD)
784 continue;
785
786 tmask = DTK_M(type);
787 switch (type)
788 {
789 case RESERV:
790#ifdef DATEDEBUG
791 printf("DecodeTimeOnly- RESERV field %s value is %d\n", field[i], val);
792#endif
793 switch (val)
794 {
795
796 default:
797 return -1;
798 }
799
800 break;
801
802 case IGNOREFIELD:
803 break;
804
805 case AMPM:
806 mer = val;
807 break;
808
809 default:
810 return -1;
811 }
812 break;
813
814 default:
815 return -1;
816 }
817
818 if (tmask & fmask)
819 return -1;
820 fmask |= tmask;
821
822#ifdef DATEDEBUG
823 printf("DecodeTimeOnly- field[%d] %s value is %d\n", i, field[i], val);
824#endif
825 }
826
827#ifdef DATEDEBUG
828 printf("DecodeTimeOnly- mask %08x (%08x)", fmask, DTK_TIME_M);
829 printf(" %02d:%02d:%02d (%f)\n", tm->tm_hour, tm->tm_min, tm->tm_sec, *fsec);
830#endif
831
832 if ((mer != HR24) && (tm->tm_hour > 12))
833 return -1;
834 if ((mer == AM) && (tm->tm_hour == 12))
835 tm->tm_hour = 0;
836 else if ((mer == PM) && (tm->tm_hour != 12))
837 tm->tm_hour += 12;
838
839 if ((fmask & DTK_TIME_M) != DTK_TIME_M)
840 return -1;
841
842 return 0;
843} /* DecodeTimeOnly() */
844
845
846/* DecodeDate()
847 * Decode date string which includes delimiters.
848 * Insist on a complete set of fields.
849 */
850static int
851DecodeDate(char *str, int fmask, int *tmask, struct tm * tm)
852{
853 double fsec;
854
855 int nf = 0;
856 int i,
857 len;
858 int type,
859 val,
860 dmask = 0;
861 char *field[MAXDATEFIELDS];
862
863 /* parse this string... */
864 while ((*str != '\0') && (nf < MAXDATEFIELDS))
865 {
866 /* skip field separators */
867 while (!isalnum(*str))
868 str++;
869
870 field[nf] = str;
871 if (isdigit(*str))
872 {
873 while (isdigit(*str))
874 str++;
875 }
876 else if (isalpha(*str))
877 {
878 while (isalpha(*str))
879 str++;
880 }
881
882 if (*str != '\0')
883 *str++ = '\0';
884 nf++;
885 }
886
887 /* don't allow too many fields */
888 if (nf > 3)
889 return -1;
890
891 *tmask = 0;
892
893 /* look first for text fields, since that will be unambiguous month */
894 for (i = 0; i < nf; i++)
895 {
896 if (isalpha(*field[i]))
897 {
898 type = DecodeSpecial(i, field[i], &val);
899 if (type == IGNOREFIELD)
900 continue;
901
902 dmask = DTK_M(type);
903 switch (type)
904 {
905 case MONTH:
906#ifdef DATEDEBUG
907 printf("DecodeDate- month field %s value is %d\n", field[i], val);
908#endif
909 tm->tm_mon = val;
910 break;
911
912 default:
913#ifdef DATEDEBUG
914 printf("DecodeDate- illegal field %s value is %d\n", field[i], val);
915#endif
916 return -1;
917 }
918 if (fmask & dmask)
919 return -1;
920
921 fmask |= dmask;
922 *tmask |= dmask;
923
924 /* mark this field as being completed */
925 field[i] = NULL;
926 }
927 }
928
929 /* now pick up remaining numeric fields */
930 for (i = 0; i < nf; i++)
931 {
932 if (field[i] == NULL)
933 continue;
934
935 if ((len = strlen(field[i])) <= 0)
936 return -1;
937
938 if (DecodeNumber(len, field[i], fmask, &dmask, tm, &fsec) != 0)
939 return -1;
940
941 if (fmask & dmask)
942 return -1;
943
944 fmask |= dmask;
945 *tmask |= dmask;
946 }
947
948 return 0;
949} /* DecodeDate() */
950
951
952/* DecodeTime()
953 * Decode time string which includes delimiters.
954 * Only check the lower limit on hours, since this same code
955 * can be used to represent time spans.
956 */
957static int
958DecodeTime(char *str, int fmask, int *tmask, struct tm * tm, double *fsec)
959{
960 char *cp;
961
962 *tmask = DTK_TIME_M;
963
964 tm->tm_hour = strtol(str, &cp, 10);
965 if (*cp != ':')
966 return -1;
967 str = cp + 1;
968 tm->tm_min = strtol(str, &cp, 10);
969 if (*cp == '\0')
970 {
971 tm->tm_sec = 0;
972 *fsec = 0;
973
974 }
975 else if (*cp != ':')
976 {
977 return -1;
978
979 }
980 else
981 {
982 str = cp + 1;
983 tm->tm_sec = strtol(str, &cp, 10);
984 if (*cp == '\0')
985 *fsec = 0;
986 else if (*cp == '.')
987 {
988 str = cp;
989 *fsec = strtod(str, &cp);
990 if (cp == str)
991 return -1;
992 }
993 else
994 return -1;
995 }
996
997 /* do a sanity check */
998 if ((tm->tm_hour < 0)
999 || (tm->tm_min < 0) || (tm->tm_min > 59)
1000 || (tm->tm_sec < 0) || (tm->tm_sec > 59))
1001 return -1;
1002
1003 return 0;
1004} /* DecodeTime() */
1005
1006
1007/* DecodeNumber()
1008 * Interpret numeric field as a date value in context.
1009 */
1010static int
1011DecodeNumber(int flen, char *str, int fmask, int *tmask, struct tm * tm, double *fsec)
1012{
1013 int val;
1014 char *cp;
1015
1016 *tmask = 0;
1017
1018 val = strtol(str, &cp, 10);
1019 if (cp == str)
1020 return -1;
1021 if (*cp == '.')
1022 {
1023 *fsec = strtod(cp, &cp);
1024 if (*cp != '\0')
1025 return -1;
1026 }
1027
1028#ifdef DATEDEBUG
1029 printf("DecodeNumber- %s is %d fmask=%08x tmask=%08x\n", str, val, fmask, *tmask);
1030#endif
1031
1032 /* enough digits to be unequivocal year? */
1033 if (flen == 4)
1034 {
1035#ifdef DATEDEBUG
1036 printf("DecodeNumber- match %d (%s) as year\n", val, str);
1037#endif
1038 *tmask = DTK_M(YEAR);
1039
1040 /* already have a year? then see if we can substitute... */
1041 if (fmask & DTK_M(YEAR))
1042 {
1043 if ((!(fmask & DTK_M(DAY)))
1044 && ((tm->tm_year >= 1) && (tm->tm_year <= 31)))
1045 {
1046#ifdef DATEDEBUG
1047 printf("DecodeNumber- misidentified year previously; swap with day %d\n", tm->tm_mday);
1048#endif
1049 tm->tm_mday = tm->tm_year;
1050 *tmask = DTK_M(DAY);
1051 }
1052 }
1053
1054 tm->tm_year = val;
1055
1056 /* special case day of year? */
1057 }
1058 else if ((flen == 3) && (fmask & DTK_M(YEAR))
1059 && ((val >= 1) && (val <= 366)))
1060 {
1061 *tmask = (DTK_M(DOY) | DTK_M(MONTH) | DTK_M(DAY));
1062 tm->tm_yday = val;
1063 j2date((date2j(tm->tm_year, 1, 1) + tm->tm_yday - 1),
1064 &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
1065
1066 /* already have year? then could be month */
1067 }
1068 else if ((fmask & DTK_M(YEAR)) && (!(fmask & DTK_M(MONTH)))
1069 && ((val >= 1) && (val <= 12)))
1070 {
1071#ifdef DATEDEBUG
1072 printf("DecodeNumber- match %d (%s) as month\n", val, str);
1073#endif
1074 *tmask = DTK_M(MONTH);
1075 tm->tm_mon = val;
1076
1077 /* no year and EuroDates enabled? then could be day */
1078 }
1079 else if ((EuroDates || (fmask & DTK_M(MONTH)))
1080 && (!(fmask & DTK_M(YEAR)) && !(fmask & DTK_M(DAY)))
1081 && ((val >= 1) && (val <= 31)))
1082 {
1083#ifdef DATEDEBUG
1084 printf("DecodeNumber- match %d (%s) as day\n", val, str);
1085#endif
1086 *tmask = DTK_M(DAY);
1087 tm->tm_mday = val;
1088
1089 }
1090 else if ((!(fmask & DTK_M(MONTH)))
1091 && ((val >= 1) && (val <= 12)))
1092 {
1093#ifdef DATEDEBUG
1094 printf("DecodeNumber- (2) match %d (%s) as month\n", val, str);
1095#endif
1096 *tmask = DTK_M(MONTH);
1097 tm->tm_mon = val;
1098
1099 }
1100 else if ((!(fmask & DTK_M(DAY)))
1101 && ((val >= 1) && (val <= 31)))
1102 {
1103#ifdef DATEDEBUG
1104 printf("DecodeNumber- (2) match %d (%s) as day\n", val, str);
1105#endif
1106 *tmask = DTK_M(DAY);
1107 tm->tm_mday = val;
1108
1109 }
1110 else if (!(fmask & DTK_M(YEAR)))
1111 {
1112#ifdef DATEDEBUG
1113 printf("DecodeNumber- (2) match %d (%s) as year\n", val, str);
1114#endif
1115 *tmask = DTK_M(YEAR);
1116 tm->tm_year = val;
1117 if (tm->tm_year < 70)
1118 tm->tm_year += 2000;
1119 else if (tm->tm_year < 100)
1120 tm->tm_year += 1900;
1121
1122 }
1123 else
1124 return -1;
1125
1126 return 0;
1127} /* DecodeNumber() */
1128
1129
1130/* DecodeNumberField()
1131 * Interpret numeric string as a concatenated date field.
1132 */
1133static int
1134DecodeNumberField(int len, char *str, int fmask, int *tmask, struct tm * tm, double *fsec)
1135{
1136 char *cp;
1137
1138 /* yyyymmdd? */
1139 if (len == 8)
1140 {
1141#ifdef DATEDEBUG
1142 printf("DecodeNumberField- %s is 8 character date fmask=%08x tmask=%08x\n", str, fmask, *tmask);
1143#endif
1144
1145 *tmask = DTK_DATE_M;
1146
1147 tm->tm_mday = atoi(str + 6);
1148 *(str + 6) = '\0';
1149 tm->tm_mon = atoi(str + 4);
1150 *(str + 4) = '\0';
1151 tm->tm_year = atoi(str + 0);
1152
1153 /* yymmdd or hhmmss? */
1154 }
1155 else if (len == 6)
1156 {
1157#ifdef DATEDEBUG
1158 printf("DecodeNumberField- %s is 6 characters fmask=%08x tmask=%08x\n", str, fmask, *tmask);
1159#endif
1160 if (fmask & DTK_DATE_M)
1161 {
1162#ifdef DATEDEBUG
1163 printf("DecodeNumberField- %s is time field fmask=%08x tmask=%08x\n", str, fmask, *tmask);
1164#endif
1165 *tmask = DTK_TIME_M;
1166 tm->tm_sec = atoi(str + 4);
1167 *(str + 4) = '\0';
1168 tm->tm_min = atoi(str + 2);
1169 *(str + 2) = '\0';
1170 tm->tm_hour = atoi(str + 0);
1171
1172 }
1173 else
1174 {
1175#ifdef DATEDEBUG
1176 printf("DecodeNumberField- %s is date field fmask=%08x tmask=%08x\n", str, fmask, *tmask);
1177#endif
1178 *tmask = DTK_DATE_M;
1179 tm->tm_mday = atoi(str + 4);
1180 *(str + 4) = '\0';
1181 tm->tm_mon = atoi(str + 2);
1182 *(str + 2) = '\0';
1183 tm->tm_year = atoi(str + 0);
1184 }
1185
1186 }
1187 else if (strchr(str, '.') != NULL)
1188 {
1189#ifdef DATEDEBUG
1190 printf("DecodeNumberField- %s is time field fmask=%08x tmask=%08x\n", str, fmask, *tmask);
1191#endif
1192 *tmask = DTK_TIME_M;
1193 tm->tm_sec = strtod((str + 4), &cp);
1194 if (cp == (str + 4))
1195 return -1;
1196 if (*cp == '.')
1197 *fsec = strtod(cp, NULL);
1198 *(str + 4) = '\0';
1199 tm->tm_min = strtod((str + 2), &cp);
1200 *(str + 2) = '\0';
1201 tm->tm_hour = strtod((str + 0), &cp);
1202
1203 }
1204 else
1205 return -1;
1206
1207 return 0;
1208} /* DecodeNumberField() */
1209
1210
1211/* DecodeTimezone()
1212 * Interpret string as a numeric timezone.
1213 */
1214static int
1215DecodeTimezone(char *str, int *tzp)
1216{
1217 int tz;
1218 int hr,
1219 min;
1220 char *cp;
1221 int len;
1222
1223 /* assume leading character is "+" or "-" */
1224 hr = strtol((str + 1), &cp, 10);
1225
1226 /* explicit delimiter? */
1227 if (*cp == ':')
1228 {
1229 min = strtol((cp + 1), &cp, 10);
1230
1231 /* otherwise, might have run things together... */
1232 }
1233 else if ((*cp == '\0') && ((len = strlen(str)) > 3))
1234 {
1235 min = strtol((str + len - 2), &cp, 10);
1236 *(str + len - 2) = '\0';
1237 hr = strtol((str + 1), &cp, 10);
1238
1239 }
1240 else
1241 min = 0;
1242
1243 tz = (hr * 60 + min) * 60;
1244 if (*str == '-')
1245 tz = -tz;
1246
1247 *tzp = -tz;
1248 return *cp != '\0';
1249} /* DecodeTimezone() */
1250
1251
1252/* DecodeSpecial()
1253 * Decode text string using lookup table.
1254 * Implement a cache lookup since it is likely that dates
1255 * will be related in format.
1256 */
1257static int
1258DecodeSpecial(int field, char *lowtoken, int *val)
1259{
1260 int type;
1261 datetkn *tp;
1262
1263#if USE_DATE_CACHE
1264 if ((datecache[field] != NULL)
1265 && (strncmp(lowtoken, datecache[field]->token, TOKMAXLEN) == 0))
1266 tp = datecache[field];
1267 else
1268 {
1269#endif
1270 tp = datebsearch(lowtoken, datetktbl, szdatetktbl);
1271#if USE_DATE_CACHE
1272 }
1273 datecache[field] = tp;
1274#endif
1275 if (tp == NULL)
1276 {
1277 type = IGNOREFIELD;
1278 *val = 0;
1279 }
1280 else
1281 {
1282 type = tp->type;
1283 switch (type)
1284 {
1285 case TZ:
1286 case DTZ:
1287 case DTZMOD:
1288 *val = FROMVAL(tp);
1289 break;
1290
1291 default:
1292 *val = tp->value;
1293 break;
1294 }
1295 }
1296
1297 return type;
1298} /* DecodeSpecial() */
1299
1300
1301
1302/* datebsearch()
1303 * Binary search -- from Knuth (6.2.1) Algorithm B. Special case like this
1304 * is WAY faster than the generic bsearch().
1305 */
1306static datetkn *
1307datebsearch(char *key, datetkn *base, unsigned int nel)
1308{
1309 datetkn *last = base + nel - 1,
1310 *position;
1311 int result;
1312
1313 while (last >= base)
1314 {
1315 position = base + ((last - base) >> 1);
1316 result = key[0] - position->token[0];
1317 if (result == 0)
1318 {
1319 result = strncmp(key, position->token, TOKMAXLEN);
1320 if (result == 0)
1321 return position;
1322 }
1323 if (result < 0)
1324 last = position - 1;
1325 else
1326 base = position + 1;
1327 }
1328 return NULL;
1329}
1330
1331
1332
Note: See TracBrowser for help on using the repository browser.