2 PostgreSQL Data Base Management System (formerly known as Postgres, then
5 Copyright (c) 1994-7 Regents of the University of California
7 Permission to use, copy, modify, and distribute this software and its
8 documentation for any purpose, without fee, and without a written agreement
9 is hereby granted, provided that the above copyright notice and this
10 paragraph and the following two paragraphs appear in all copies.
12 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
13 DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
14 LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
15 DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE
16 POSSIBILITY OF SUCH DAMAGE.
18 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
19 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
20 AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21 ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO
22 PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
25 /*-------------------------------------------------------------------------
28 * Functions for the built-in type "dt".
30 * Copyright (c) 1994, Regents of the University of California
36 *-------------------------------------------------------------------------
43 #include <sys/types.h>
46 #include <sys/timeb.h>
50 static datetkn *datebsearch(char *key, datetkn *base, unsigned int nel);
51 static int DecodeDate(char *str, int fmask, int *tmask, struct tm * tm);
52 static int DecodeNumber(int flen, char *field,
53 int fmask, int *tmask, struct tm * tm, double *fsec);
54 static int DecodeNumberField(int len, char *str,
55 int fmask, int *tmask, struct tm * tm, double *fsec);
56 static int DecodeSpecial(int field, char *lowtoken, int *val);
57 static int DecodeTime(char *str, int fmask, int *tmask,
58 struct tm * tm, double *fsec);
59 static int DecodeTimezone(char *str, int *tzp);
61 #define USE_DATE_CACHE 1
64 int mdays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0};
66 char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
67 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL};
69 char *days[] = {"Sunday", "Monday", "Tuesday", "Wednesday",
70 "Thursday", "Friday", "Saturday", NULL};
73 #define UTIME_MINYEAR (1901)
74 #define UTIME_MINMONTH (12)
75 #define UTIME_MINDAY (14)
76 #define UTIME_MAXYEAR (2038)
77 #define UTIME_MAXMONTH (01)
78 #define UTIME_MAXDAY (18)
80 #define IS_VALID_UTIME(y,m,d) (((y > UTIME_MINYEAR) \
81 || ((y == UTIME_MINYEAR) && ((m > UTIME_MINMONTH) \
82 || ((m == UTIME_MINMONTH) && (d >= UTIME_MINDAY))))) \
83 && ((y < UTIME_MAXYEAR) \
84 || ((y == UTIME_MAXYEAR) && ((m < UTIME_MAXMONTH) \
85 || ((m == UTIME_MAXMONTH) && (d <= UTIME_MAXDAY))))))
90 /*****************************************************************************
92 *****************************************************************************/
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))
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.
107 static 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
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 */
123 {"ast", TZ, NEG(24)}, /* Atlantic Std Time (Canada) */
124 {"at", IGNOREFIELD, 0}, /* "at" (throwaway) */
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 */
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 */
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 */
155 {"est", TZ, NEG(30)}, /* Eastern Standard Time */
158 {"february", MONTH, 2},
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
173 {"ist", TZ, 12}, /* Israel */
174 {"it", TZ, 22}, /* Iran Time */
176 {"january", MONTH, 1},
177 {"jst", TZ, 54}, /* Japan Std Time,USSR Zone 8 */
178 {"jt", TZ, 45}, /* Java Time */
183 {"kst", TZ, 54}, /* Korea Standard Time */
184 {"ligt", TZ, 60}, /* From Melbourne, Australia */
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 */
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 */
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 */
210 {"october", MONTH, 10},
211 {"on", IGNOREFIELD, 0}, /* "on" (throwaway) */
212 {"pdt", DTZ, NEG(42)}, /* Pacific Daylight Time */
214 {"pst", TZ, NEG(48)}, /* Pacific Standard Time */
215 {"sadt", DTZ, 63}, /* S. Australian Dayl. Time */
216 {"sast", TZ, 57}, /* South Australian Std Time */
218 {"saturday", DOW, 6},
221 {"september", MONTH, 9},
222 {"set", TZ, NEG(6)}, /* Seychelles Time ?? */
223 {"sst", DTZ, 12}, /* Swedish Summer Time */
226 {"swt", TZ, 6}, /* Swedish Winter Time */
230 {"thursday", DOW, 4},
231 {TODAY, RESERV, DTK_TODAY}, /* midnight */
232 {TOMORROW, RESERV, DTK_TOMORROW}, /* tomorrow midnight */
236 {"undefined", RESERV, DTK_INVALID}, /* "undefined" pre-v6.1 invalid
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 */
245 {"wednesday", 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 */
260 static unsigned int szdatetktbl = sizeof datetktbl / sizeof datetktbl[0];
265 datetkn *datecache[MAXDATEFIELDS] = {NULL};
267 datetkn *deltacache[MAXDATEFIELDS] = {NULL};
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).
280 * Ref: Explanatory Supplement to the Astronomical Almanac, 1992.
281 * University Science Books, 20 Edgehill Rd. Mill Valley CA 94941.
283 * Use the algorithm by Henry Fliegel, a former NASA/JPL colleague
284 * now at Aerospace Corp. (hi, Henry!)
286 * These routines will be used by other date/time packages - tgl 97/02/25
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
293 #define JULIAN_MINYEAR (-4713)
294 #define JULIAN_MINMONTH (11)
295 #define JULIAN_MINDAY (23)
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)))))
302 date2j(int y, int m, int d)
304 int m12 = (m - 14) / 12;
306 return ((1461 * (y + 4800 + m12)) / 4 + (367 * (m - 2 - 12 * (m12))) / 12
307 - (3 * ((y + 4900 + m12) / 100)) / 4 + d - 32075);
311 j2date(int jd, int *year, int *month, int *day)
323 n = (4 * l) / 146097;
324 l -= (146097 * n + 3) / 4;
325 i = (4000 * (l + 1)) / 1461001;
326 l += 31 - (1461 * i) / 4;
328 d = l - (2447 * j) / 80;
330 m = (j + 2) - (12 * l);
331 y = 100 * (n - 49) + i + l;
343 * parse and convert date in timestr (the normal interface)
345 * Returns the number of seconds since epoch (J2000)
349 * Break string into tokens based on a date/time context.
352 ParseDateTime(char *timestr, char *lowstr,
353 char **field, int *ftype, int maxfields, int *numfields)
360 printf("ParseDateTime- input string is %s\n", timestr);
362 /* outer loop through fields */
367 /* leading digit? then date or time */
368 if (isdigit(*cp) || (*cp == '.'))
376 ftype[nf] = DTK_TIME;
377 while (isdigit(*cp) || (*cp == ':') || (*cp == '.'))
381 /* date field? allow embedded text month */
382 else if ((*cp == '-') || (*cp == '/') || (*cp == '.'))
384 ftype[nf] = DTK_DATE;
385 while (isalnum(*cp) || (*cp == '-') || (*cp == '/') || (*cp == '.'))
386 *lp++ = tolower(*cp++);
391 * otherwise, number only and will determine year, month, or
395 ftype[nf] = DTK_NUMBER;
400 * text? then date string, month, day of week, special, or
403 else if (isalpha(*cp))
405 ftype[nf] = DTK_STRING;
406 *lp++ = tolower(*cp++);
408 *lp++ = tolower(*cp++);
410 /* full date string with leading text month? */
411 if ((*cp == '-') || (*cp == '/') || (*cp == '.'))
413 ftype[nf] = DTK_DATE;
414 while (isdigit(*cp) || (*cp == '-') || (*cp == '/') || (*cp == '.'))
415 *lp++ = tolower(*cp++);
418 /* skip leading spaces */
420 else if (isspace(*cp))
425 /* sign? then special or numeric timezone */
427 else if ((*cp == '+') || (*cp == '-'))
430 /* soak up leading whitespace */
433 /* numeric timezone? */
438 while (isdigit(*cp) || (*cp == ':'))
443 else if (isalpha(*cp))
445 ftype[nf] = DTK_SPECIAL;
446 *lp++ = tolower(*cp++);
448 *lp++ = tolower(*cp++);
450 /* otherwise something wrong... */
455 /* ignore punctuation but use as delimiter */
457 else if (ispunct(*cp))
466 /* force in a delimiter */
469 if (nf > MAXDATEFIELDS)
472 printf("ParseDateTime- set field[%d] to %s type %d\n", (nf - 1), field[nf - 1], ftype[nf - 1]);
479 } /* ParseDateTime() */
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:
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
502 DecodeDateTime(char **field, int *ftype, int nf,
503 int *dtype, struct tm * tm, double *fsec, int *tzp)
519 tm->tm_isdst = -1; /* don't know daylight savings time status
524 for (i = 0; i < nf; i++)
527 printf("DecodeDateTime- field[%d] is %s (type %d)\n", i, field[i], ftype[i]);
532 if (DecodeDate(field[i], fmask, &tmask, tm) != 0)
537 if (DecodeTime(field[i], fmask, &tmask, tm, fsec) != 0)
541 * check upper limit on hours; other limits checked in
544 if (tm->tm_hour > 23)
551 if (DecodeTimezone(field[i], tzp) != 0)
557 flen = strlen(field[i]);
561 if (DecodeNumberField(flen, field[i], fmask, &tmask, tm, fsec) != 0)
567 if (DecodeNumber(flen, field[i], fmask, &tmask, tm, fsec) != 0)
574 type = DecodeSpecial(i, field[i], &val);
576 printf("DecodeDateTime- special field[%d] %s type=%d value=%d\n", i, field[i], type, val);
578 if (type == IGNOREFIELD)
586 printf("DecodeDateTime- RESERV field %s value is %d\n", field[i], val);
599 printf("DecodeDateTime- month field %s value is %d\n", field[i], val);
605 * daylight savings time modifier (solves "MET
619 * set mask for TZ here _or_ check for DTZ later
620 * when getting default timezone
661 printf("DecodeDateTime- field[%d] %s (%08x/%08x) value is %d\n",
662 i, field[i], fmask, tmask, val);
670 /* there is no year zero in AD/BC notation; i.e. "1 BC" == year 0 */
672 tm->tm_year = -(tm->tm_year - 1);
674 if ((mer != HR24) && (tm->tm_hour > 12))
676 if ((mer == AM) && (tm->tm_hour == 12))
678 else if ((mer == PM) && (tm->tm_hour != 12))
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);
687 if ((*dtype == DTK_DATE) && ((fmask & DTK_DATE_M) != DTK_DATE_M))
688 return ((fmask & DTK_TIME_M) == DTK_TIME_M) ? 1 : -1;
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))))
696 * daylight savings time modifier but no standard timezone? then
699 if (fmask & DTK_M(DTZMOD))
702 if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday))
704 #ifdef USE_POSIX_TIME
712 #ifdef HAVE_INT_TIMEZONE
713 *tzp = ((tm->tm_isdst > 0) ? (timezone - 3600) : timezone);
715 #else /* !HAVE_INT_TIMEZONE */
716 *tzp = -(tm->tm_gmtoff); /* tm_gmtoff is Sun/DEC-ism */
719 #else /* !USE_POSIX_TIME */
731 } /* DecodeDateTime() */
735 * Interpret parsed string as time fields only.
738 DecodeTimeOnly(char **field, int *ftype, int nf, int *dtype, struct tm * tm, double *fsec)
752 tm->tm_isdst = -1; /* don't know daylight savings time status
758 for (i = 0; i < nf; i++)
761 printf("DecodeTimeOnly- field[%d] is %s (type %d)\n", i, field[i], ftype[i]);
766 if (DecodeTime(field[i], fmask, &tmask, tm, fsec) != 0)
771 flen = strlen(field[i]);
773 if (DecodeNumberField(flen, field[i], fmask, &tmask, tm, fsec) != 0)
779 type = DecodeSpecial(i, field[i], &val);
781 printf("DecodeTimeOnly- special field[%d] %s type=%d value=%d\n", i, field[i], type, val);
783 if (type == IGNOREFIELD)
791 printf("DecodeTimeOnly- RESERV field %s value is %d\n", field[i], val);
823 printf("DecodeTimeOnly- field[%d] %s value is %d\n", i, field[i], val);
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);
832 if ((mer != HR24) && (tm->tm_hour > 12))
834 if ((mer == AM) && (tm->tm_hour == 12))
836 else if ((mer == PM) && (tm->tm_hour != 12))
839 if ((fmask & DTK_TIME_M) != DTK_TIME_M)
843 } /* DecodeTimeOnly() */
847 * Decode date string which includes delimiters.
848 * Insist on a complete set of fields.
851 DecodeDate(char *str, int fmask, int *tmask, struct tm * tm)
861 char *field[MAXDATEFIELDS];
863 /* parse this string... */
864 while ((*str != '\0') && (nf < MAXDATEFIELDS))
866 /* skip field separators */
867 while (!isalnum(*str))
873 while (isdigit(*str))
876 else if (isalpha(*str))
878 while (isalpha(*str))
887 /* don't allow too many fields */
893 /* look first for text fields, since that will be unambiguous month */
894 for (i = 0; i < nf; i++)
896 if (isalpha(*field[i]))
898 type = DecodeSpecial(i, field[i], &val);
899 if (type == IGNOREFIELD)
907 printf("DecodeDate- month field %s value is %d\n", field[i], val);
914 printf("DecodeDate- illegal field %s value is %d\n", field[i], val);
924 /* mark this field as being completed */
929 /* now pick up remaining numeric fields */
930 for (i = 0; i < nf; i++)
932 if (field[i] == NULL)
935 if ((len = strlen(field[i])) <= 0)
938 if (DecodeNumber(len, field[i], fmask, &dmask, tm, &fsec) != 0)
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.
958 DecodeTime(char *str, int fmask, int *tmask, struct tm * tm, double *fsec)
964 tm->tm_hour = strtol(str, &cp, 10);
968 tm->tm_min = strtol(str, &cp, 10);
983 tm->tm_sec = strtol(str, &cp, 10);
989 *fsec = strtod(str, &cp);
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))
1004 } /* DecodeTime() */
1008 * Interpret numeric field as a date value in context.
1011 DecodeNumber(int flen, char *str, int fmask, int *tmask, struct tm * tm, double *fsec)
1018 val = strtol(str, &cp, 10);
1023 *fsec = strtod(cp, &cp);
1029 printf("DecodeNumber- %s is %d fmask=%08x tmask=%08x\n", str, val, fmask, *tmask);
1032 /* enough digits to be unequivocal year? */
1036 printf("DecodeNumber- match %d (%s) as year\n", val, str);
1038 *tmask = DTK_M(YEAR);
1040 /* already have a year? then see if we can substitute... */
1041 if (fmask & DTK_M(YEAR))
1043 if ((!(fmask & DTK_M(DAY)))
1044 && ((tm->tm_year >= 1) && (tm->tm_year <= 31)))
1047 printf("DecodeNumber- misidentified year previously; swap with day %d\n", tm->tm_mday);
1049 tm->tm_mday = tm->tm_year;
1050 *tmask = DTK_M(DAY);
1056 /* special case day of year? */
1058 else if ((flen == 3) && (fmask & DTK_M(YEAR))
1059 && ((val >= 1) && (val <= 366)))
1061 *tmask = (DTK_M(DOY) | DTK_M(MONTH) | DTK_M(DAY));
1063 j2date((date2j(tm->tm_year, 1, 1) + tm->tm_yday - 1),
1064 &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
1066 /* already have year? then could be month */
1068 else if ((fmask & DTK_M(YEAR)) && (!(fmask & DTK_M(MONTH)))
1069 && ((val >= 1) && (val <= 12)))
1072 printf("DecodeNumber- match %d (%s) as month\n", val, str);
1074 *tmask = DTK_M(MONTH);
1077 /* no year and EuroDates enabled? then could be day */
1079 else if ((EuroDates || (fmask & DTK_M(MONTH)))
1080 && (!(fmask & DTK_M(YEAR)) && !(fmask & DTK_M(DAY)))
1081 && ((val >= 1) && (val <= 31)))
1084 printf("DecodeNumber- match %d (%s) as day\n", val, str);
1086 *tmask = DTK_M(DAY);
1090 else if ((!(fmask & DTK_M(MONTH)))
1091 && ((val >= 1) && (val <= 12)))
1094 printf("DecodeNumber- (2) match %d (%s) as month\n", val, str);
1096 *tmask = DTK_M(MONTH);
1100 else if ((!(fmask & DTK_M(DAY)))
1101 && ((val >= 1) && (val <= 31)))
1104 printf("DecodeNumber- (2) match %d (%s) as day\n", val, str);
1106 *tmask = DTK_M(DAY);
1110 else if (!(fmask & DTK_M(YEAR)))
1113 printf("DecodeNumber- (2) match %d (%s) as year\n", val, str);
1115 *tmask = DTK_M(YEAR);
1117 if (tm->tm_year < 70)
1118 tm->tm_year += 2000;
1119 else if (tm->tm_year < 100)
1120 tm->tm_year += 1900;
1127 } /* DecodeNumber() */
1130 /* DecodeNumberField()
1131 * Interpret numeric string as a concatenated date field.
1134 DecodeNumberField(int len, char *str, int fmask, int *tmask, struct tm * tm, double *fsec)
1142 printf("DecodeNumberField- %s is 8 character date fmask=%08x tmask=%08x\n", str, fmask, *tmask);
1145 *tmask = DTK_DATE_M;
1147 tm->tm_mday = atoi(str + 6);
1149 tm->tm_mon = atoi(str + 4);
1151 tm->tm_year = atoi(str + 0);
1153 /* yymmdd or hhmmss? */
1158 printf("DecodeNumberField- %s is 6 characters fmask=%08x tmask=%08x\n", str, fmask, *tmask);
1160 if (fmask & DTK_DATE_M)
1163 printf("DecodeNumberField- %s is time field fmask=%08x tmask=%08x\n", str, fmask, *tmask);
1165 *tmask = DTK_TIME_M;
1166 tm->tm_sec = atoi(str + 4);
1168 tm->tm_min = atoi(str + 2);
1170 tm->tm_hour = atoi(str + 0);
1176 printf("DecodeNumberField- %s is date field fmask=%08x tmask=%08x\n", str, fmask, *tmask);
1178 *tmask = DTK_DATE_M;
1179 tm->tm_mday = atoi(str + 4);
1181 tm->tm_mon = atoi(str + 2);
1183 tm->tm_year = atoi(str + 0);
1187 else if (strchr(str, '.') != NULL)
1190 printf("DecodeNumberField- %s is time field fmask=%08x tmask=%08x\n", str, fmask, *tmask);
1192 *tmask = DTK_TIME_M;
1193 tm->tm_sec = strtod((str + 4), &cp);
1194 if (cp == (str + 4))
1197 *fsec = strtod(cp, NULL);
1199 tm->tm_min = strtod((str + 2), &cp);
1201 tm->tm_hour = strtod((str + 0), &cp);
1208 } /* DecodeNumberField() */
1212 * Interpret string as a numeric timezone.
1215 DecodeTimezone(char *str, int *tzp)
1223 /* assume leading character is "+" or "-" */
1224 hr = strtol((str + 1), &cp, 10);
1226 /* explicit delimiter? */
1229 min = strtol((cp + 1), &cp, 10);
1231 /* otherwise, might have run things together... */
1233 else if ((*cp == '\0') && ((len = strlen(str)) > 3))
1235 min = strtol((str + len - 2), &cp, 10);
1236 *(str + len - 2) = '\0';
1237 hr = strtol((str + 1), &cp, 10);
1243 tz = (hr * 60 + min) * 60;
1249 } /* DecodeTimezone() */
1253 * Decode text string using lookup table.
1254 * Implement a cache lookup since it is likely that dates
1255 * will be related in format.
1258 DecodeSpecial(int field, char *lowtoken, int *val)
1264 if ((datecache[field] != NULL)
1265 && (strncmp(lowtoken, datecache[field]->token, TOKMAXLEN) == 0))
1266 tp = datecache[field];
1270 tp = datebsearch(lowtoken, datetktbl, szdatetktbl);
1273 datecache[field] = tp;
1298 } /* DecodeSpecial() */
1303 * Binary search -- from Knuth (6.2.1) Algorithm B. Special case like this
1304 * is WAY faster than the generic bsearch().
1307 datebsearch(char *key, datetkn *base, unsigned int nel)
1309 datetkn *last = base + nel - 1,
1313 while (last >= base)
1315 position = base + ((last - base) >> 1);
1316 result = key[0] - position->token[0];
1319 result = strncmp(key, position->token, TOKMAXLEN);
1324 last = position - 1;
1326 base = position + 1;