Import upstream version 1.26
[debian/tar] / gnu / parse-datetime.y
1 %{
2 /* Parse a string into an internal time stamp.
3
4    Copyright (C) 1999-2000, 2002-2011 Free Software Foundation, Inc.
5
6    This program is free software: you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
18
19 /* Originally written by Steven M. Bellovin <smb@research.att.com> while
20    at the University of North Carolina at Chapel Hill.  Later tweaked by
21    a couple of people on Usenet.  Completely overhauled by Rich $alz
22    <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990.
23
24    Modified by Paul Eggert <eggert@twinsun.com> in August 1999 to do
25    the right thing about local DST.  Also modified by Paul Eggert
26    <eggert@cs.ucla.edu> in February 2004 to support
27    nanosecond-resolution time stamps, and in October 2004 to support
28    TZ strings in dates.  */
29
30 /* FIXME: Check for arithmetic overflow in all cases, not just
31    some of them.  */
32
33 #include <config.h>
34
35 #include "parse-datetime.h"
36
37 #include "intprops.h"
38 #include "timespec.h"
39 #include "verify.h"
40
41 /* There's no need to extend the stack, so there's no need to involve
42    alloca.  */
43 #define YYSTACK_USE_ALLOCA 0
44
45 /* Tell Bison how much stack space is needed.  20 should be plenty for
46    this grammar, which is not right recursive.  Beware setting it too
47    high, since that might cause problems on machines whose
48    implementations have lame stack-overflow checking.  */
49 #define YYMAXDEPTH 20
50 #define YYINITDEPTH YYMAXDEPTH
51
52 /* Since the code of parse-datetime.y is not included in the Emacs executable
53    itself, there is no need to #define static in this file.  Even if
54    the code were included in the Emacs executable, it probably
55    wouldn't do any harm to #undef it here; this will only cause
56    problems if we try to write to a static variable, which I don't
57    think this code needs to do.  */
58 #ifdef emacs
59 # undef static
60 #endif
61
62 #include <c-ctype.h>
63 #include <limits.h>
64 #include <stdio.h>
65 #include <stdlib.h>
66 #include <string.h>
67
68 #include "xalloc.h"
69
70 /* Bison's skeleton tests _STDLIB_H, while some stdlib.h headers
71    use _STDLIB_H_ as witness.  Map the latter to the one bison uses.  */
72 /* FIXME: this is temporary.  Remove when we have a mechanism to ensure
73    that the version we're using is fixed, too.  */
74 #ifdef _STDLIB_H_
75 # undef _STDLIB_H
76 # define _STDLIB_H 1
77 #endif
78
79 /* ISDIGIT differs from isdigit, as follows:
80    - Its arg may be any int or unsigned int; it need not be an unsigned char
81      or EOF.
82    - It's typically faster.
83    POSIX says that only '0' through '9' are digits.  Prefer ISDIGIT to
84    isdigit unless it's important to use the locale's definition
85    of `digit' even when the host does not conform to POSIX.  */
86 #define ISDIGIT(c) ((unsigned int) (c) - '0' <= 9)
87
88 /* Shift A right by B bits portably, by dividing A by 2**B and
89    truncating towards minus infinity.  A and B should be free of side
90    effects, and B should be in the range 0 <= B <= INT_BITS - 2, where
91    INT_BITS is the number of useful bits in an int.  GNU code can
92    assume that INT_BITS is at least 32.
93
94    ISO C99 says that A >> B is implementation-defined if A < 0.  Some
95    implementations (e.g., UNICOS 9.0 on a Cray Y-MP EL) don't shift
96    right in the usual way when A < 0, so SHR falls back on division if
97    ordinary A >> B doesn't seem to be the usual signed shift.  */
98 #define SHR(a, b)       \
99   (-1 >> 1 == -1        \
100    ? (a) >> (b)         \
101    : (a) / (1 << (b)) - ((a) % (1 << (b)) < 0))
102
103 #define EPOCH_YEAR 1970
104 #define TM_YEAR_BASE 1900
105
106 #define HOUR(x) ((x) * 60)
107
108 /* long_time_t is a signed integer type that contains all time_t values.  */
109 verify (TYPE_IS_INTEGER (time_t));
110 #if TIME_T_FITS_IN_LONG_INT
111 typedef long int long_time_t;
112 #else
113 typedef time_t long_time_t;
114 #endif
115
116 /* Lots of this code assumes time_t and time_t-like values fit into
117    long_time_t.  */
118 verify (TYPE_MINIMUM (long_time_t) <= TYPE_MINIMUM (time_t)
119         && TYPE_MAXIMUM (time_t) <= TYPE_MAXIMUM (long_time_t));
120
121 /* FIXME: It also assumes that signed integer overflow silently wraps around,
122    but this is not true any more with recent versions of GCC 4.  */
123
124 /* An integer value, and the number of digits in its textual
125    representation.  */
126 typedef struct
127 {
128   bool negative;
129   long int value;
130   size_t digits;
131 } textint;
132
133 /* An entry in the lexical lookup table.  */
134 typedef struct
135 {
136   char const *name;
137   int type;
138   int value;
139 } table;
140
141 /* Meridian: am, pm, or 24-hour style.  */
142 enum { MERam, MERpm, MER24 };
143
144 enum { BILLION = 1000000000, LOG10_BILLION = 9 };
145
146 /* Relative times.  */
147 typedef struct
148 {
149   /* Relative year, month, day, hour, minutes, seconds, and nanoseconds.  */
150   long int year;
151   long int month;
152   long int day;
153   long int hour;
154   long int minutes;
155   long_time_t seconds;
156   long int ns;
157 } relative_time;
158
159 #if HAVE_COMPOUND_LITERALS
160 # define RELATIVE_TIME_0 ((relative_time) { 0, 0, 0, 0, 0, 0, 0 })
161 #else
162 static relative_time const RELATIVE_TIME_0;
163 #endif
164
165 /* Information passed to and from the parser.  */
166 typedef struct
167 {
168   /* The input string remaining to be parsed. */
169   const char *input;
170
171   /* N, if this is the Nth Tuesday.  */
172   long int day_ordinal;
173
174   /* Day of week; Sunday is 0.  */
175   int day_number;
176
177   /* tm_isdst flag for the local zone.  */
178   int local_isdst;
179
180   /* Time zone, in minutes east of UTC.  */
181   long int time_zone;
182
183   /* Style used for time.  */
184   int meridian;
185
186   /* Gregorian year, month, day, hour, minutes, seconds, and nanoseconds.  */
187   textint year;
188   long int month;
189   long int day;
190   long int hour;
191   long int minutes;
192   struct timespec seconds; /* includes nanoseconds */
193
194   /* Relative year, month, day, hour, minutes, seconds, and nanoseconds.  */
195   relative_time rel;
196
197   /* Presence or counts of nonterminals of various flavors parsed so far.  */
198   bool timespec_seen;
199   bool rels_seen;
200   size_t dates_seen;
201   size_t days_seen;
202   size_t local_zones_seen;
203   size_t dsts_seen;
204   size_t times_seen;
205   size_t zones_seen;
206
207   /* Table of local time zone abbrevations, terminated by a null entry.  */
208   table local_time_zone_table[3];
209 } parser_control;
210
211 union YYSTYPE;
212 static int yylex (union YYSTYPE *, parser_control *);
213 static int yyerror (parser_control const *, char const *);
214 static long int time_zone_hhmm (parser_control *, textint, long int);
215
216 /* Extract into *PC any date and time info from a string of digits
217    of the form e.g., YYYYMMDD, YYMMDD, HHMM, HH (and sometimes YYY,
218    YYYY, ...).  */
219 static void
220 digits_to_date_time (parser_control *pc, textint text_int)
221 {
222   if (pc->dates_seen && ! pc->year.digits
223       && ! pc->rels_seen && (pc->times_seen || 2 < text_int.digits))
224     pc->year = text_int;
225   else
226     {
227       if (4 < text_int.digits)
228         {
229           pc->dates_seen++;
230           pc->day = text_int.value % 100;
231           pc->month = (text_int.value / 100) % 100;
232           pc->year.value = text_int.value / 10000;
233           pc->year.digits = text_int.digits - 4;
234         }
235       else
236         {
237           pc->times_seen++;
238           if (text_int.digits <= 2)
239             {
240               pc->hour = text_int.value;
241               pc->minutes = 0;
242             }
243           else
244             {
245               pc->hour = text_int.value / 100;
246               pc->minutes = text_int.value % 100;
247             }
248           pc->seconds.tv_sec = 0;
249           pc->seconds.tv_nsec = 0;
250           pc->meridian = MER24;
251         }
252     }
253 }
254
255 /* Increment PC->rel by FACTOR * REL (FACTOR is 1 or -1).  */
256 static void
257 apply_relative_time (parser_control *pc, relative_time rel, int factor)
258 {
259   pc->rel.ns += factor * rel.ns;
260   pc->rel.seconds += factor * rel.seconds;
261   pc->rel.minutes += factor * rel.minutes;
262   pc->rel.hour += factor * rel.hour;
263   pc->rel.day += factor * rel.day;
264   pc->rel.month += factor * rel.month;
265   pc->rel.year += factor * rel.year;
266   pc->rels_seen = true;
267 }
268
269 /* Set PC-> hour, minutes, seconds and nanoseconds members from arguments.  */
270 static void
271 set_hhmmss (parser_control *pc, long int hour, long int minutes,
272             time_t sec, long int nsec)
273 {
274   pc->hour = hour;
275   pc->minutes = minutes;
276   pc->seconds.tv_sec = sec;
277   pc->seconds.tv_nsec = nsec;
278 }
279
280 %}
281
282 /* We want a reentrant parser, even if the TZ manipulation and the calls to
283    localtime and gmtime are not reentrant.  */
284 %pure-parser
285 %parse-param { parser_control *pc }
286 %lex-param { parser_control *pc }
287
288 /* This grammar has 20 shift/reduce conflicts. */
289 %expect 20
290
291 %union
292 {
293   long int intval;
294   textint textintval;
295   struct timespec timespec;
296   relative_time rel;
297 }
298
299 %token tAGO tDST
300
301 %token tYEAR_UNIT tMONTH_UNIT tHOUR_UNIT tMINUTE_UNIT tSEC_UNIT
302 %token <intval> tDAY_UNIT tDAY_SHIFT
303
304 %token <intval> tDAY tDAYZONE tLOCAL_ZONE tMERIDIAN
305 %token <intval> tMONTH tORDINAL tZONE
306
307 %token <textintval> tSNUMBER tUNUMBER
308 %token <timespec> tSDECIMAL_NUMBER tUDECIMAL_NUMBER
309
310 %type <intval> o_colon_minutes o_merid
311 %type <timespec> seconds signed_seconds unsigned_seconds
312
313 %type <rel> relunit relunit_snumber dayshift
314
315 %%
316
317 spec:
318     timespec
319   | items
320   ;
321
322 timespec:
323     '@' seconds
324       {
325         pc->seconds = $2;
326         pc->timespec_seen = true;
327       }
328   ;
329
330 items:
331     /* empty */
332   | items item
333   ;
334
335 item:
336     time
337       { pc->times_seen++; }
338   | local_zone
339       { pc->local_zones_seen++; }
340   | zone
341       { pc->zones_seen++; }
342   | date
343       { pc->dates_seen++; }
344   | day
345       { pc->days_seen++; }
346   | rel
347   | number
348   | hybrid
349   ;
350
351 time:
352     tUNUMBER tMERIDIAN
353       {
354         set_hhmmss (pc, $1.value, 0, 0, 0);
355         pc->meridian = $2;
356       }
357   | tUNUMBER ':' tUNUMBER o_merid
358       {
359         set_hhmmss (pc, $1.value, $3.value, 0, 0);
360         pc->meridian = $4;
361       }
362   | tUNUMBER ':' tUNUMBER tSNUMBER o_colon_minutes
363       {
364         set_hhmmss (pc, $1.value, $3.value, 0, 0);
365         pc->meridian = MER24;
366         pc->zones_seen++;
367         pc->time_zone = time_zone_hhmm (pc, $4, $5);
368       }
369   | tUNUMBER ':' tUNUMBER ':' unsigned_seconds o_merid
370       {
371         set_hhmmss (pc, $1.value, $3.value, $5.tv_sec, $5.tv_nsec);
372         pc->meridian = $6;
373       }
374   | tUNUMBER ':' tUNUMBER ':' unsigned_seconds tSNUMBER o_colon_minutes
375       {
376         set_hhmmss (pc, $1.value, $3.value, $5.tv_sec, $5.tv_nsec);
377         pc->meridian = MER24;
378         pc->zones_seen++;
379         pc->time_zone = time_zone_hhmm (pc, $6, $7);
380       }
381   ;
382
383 local_zone:
384     tLOCAL_ZONE
385       {
386         pc->local_isdst = $1;
387         pc->dsts_seen += (0 < $1);
388       }
389   | tLOCAL_ZONE tDST
390       {
391         pc->local_isdst = 1;
392         pc->dsts_seen += (0 < $1) + 1;
393       }
394   ;
395
396 zone:
397     tZONE
398       { pc->time_zone = $1; }
399   | tZONE relunit_snumber
400       { pc->time_zone = $1;
401         apply_relative_time (pc, $2, 1); }
402   | tZONE tSNUMBER o_colon_minutes
403       { pc->time_zone = $1 + time_zone_hhmm (pc, $2, $3); }
404   | tDAYZONE
405       { pc->time_zone = $1 + 60; }
406   | tZONE tDST
407       { pc->time_zone = $1 + 60; }
408   ;
409
410 day:
411     tDAY
412       {
413         pc->day_ordinal = 0;
414         pc->day_number = $1;
415       }
416   | tDAY ','
417       {
418         pc->day_ordinal = 0;
419         pc->day_number = $1;
420       }
421   | tORDINAL tDAY
422       {
423         pc->day_ordinal = $1;
424         pc->day_number = $2;
425       }
426   | tUNUMBER tDAY
427       {
428         pc->day_ordinal = $1.value;
429         pc->day_number = $2;
430       }
431   ;
432
433 date:
434     tUNUMBER '/' tUNUMBER
435       {
436         pc->month = $1.value;
437         pc->day = $3.value;
438       }
439   | tUNUMBER '/' tUNUMBER '/' tUNUMBER
440       {
441         /* Interpret as YYYY/MM/DD if the first value has 4 or more digits,
442            otherwise as MM/DD/YY.
443            The goal in recognizing YYYY/MM/DD is solely to support legacy
444            machine-generated dates like those in an RCS log listing.  If
445            you want portability, use the ISO 8601 format.  */
446         if (4 <= $1.digits)
447           {
448             pc->year = $1;
449             pc->month = $3.value;
450             pc->day = $5.value;
451           }
452         else
453           {
454             pc->month = $1.value;
455             pc->day = $3.value;
456             pc->year = $5;
457           }
458       }
459   | tUNUMBER tSNUMBER tSNUMBER
460       {
461         /* ISO 8601 format.  YYYY-MM-DD.  */
462         pc->year = $1;
463         pc->month = -$2.value;
464         pc->day = -$3.value;
465       }
466   | tUNUMBER tMONTH tSNUMBER
467       {
468         /* e.g. 17-JUN-1992.  */
469         pc->day = $1.value;
470         pc->month = $2;
471         pc->year.value = -$3.value;
472         pc->year.digits = $3.digits;
473       }
474   | tMONTH tSNUMBER tSNUMBER
475       {
476         /* e.g. JUN-17-1992.  */
477         pc->month = $1;
478         pc->day = -$2.value;
479         pc->year.value = -$3.value;
480         pc->year.digits = $3.digits;
481       }
482   | tMONTH tUNUMBER
483       {
484         pc->month = $1;
485         pc->day = $2.value;
486       }
487   | tMONTH tUNUMBER ',' tUNUMBER
488       {
489         pc->month = $1;
490         pc->day = $2.value;
491         pc->year = $4;
492       }
493   | tUNUMBER tMONTH
494       {
495         pc->day = $1.value;
496         pc->month = $2;
497       }
498   | tUNUMBER tMONTH tUNUMBER
499       {
500         pc->day = $1.value;
501         pc->month = $2;
502         pc->year = $3;
503       }
504   ;
505
506 rel:
507     relunit tAGO
508       { apply_relative_time (pc, $1, -1); }
509   | relunit
510       { apply_relative_time (pc, $1, 1); }
511   | dayshift
512       { apply_relative_time (pc, $1, 1); }
513   ;
514
515 relunit:
516     tORDINAL tYEAR_UNIT
517       { $$ = RELATIVE_TIME_0; $$.year = $1; }
518   | tUNUMBER tYEAR_UNIT
519       { $$ = RELATIVE_TIME_0; $$.year = $1.value; }
520   | tYEAR_UNIT
521       { $$ = RELATIVE_TIME_0; $$.year = 1; }
522   | tORDINAL tMONTH_UNIT
523       { $$ = RELATIVE_TIME_0; $$.month = $1; }
524   | tUNUMBER tMONTH_UNIT
525       { $$ = RELATIVE_TIME_0; $$.month = $1.value; }
526   | tMONTH_UNIT
527       { $$ = RELATIVE_TIME_0; $$.month = 1; }
528   | tORDINAL tDAY_UNIT
529       { $$ = RELATIVE_TIME_0; $$.day = $1 * $2; }
530   | tUNUMBER tDAY_UNIT
531       { $$ = RELATIVE_TIME_0; $$.day = $1.value * $2; }
532   | tDAY_UNIT
533       { $$ = RELATIVE_TIME_0; $$.day = $1; }
534   | tORDINAL tHOUR_UNIT
535       { $$ = RELATIVE_TIME_0; $$.hour = $1; }
536   | tUNUMBER tHOUR_UNIT
537       { $$ = RELATIVE_TIME_0; $$.hour = $1.value; }
538   | tHOUR_UNIT
539       { $$ = RELATIVE_TIME_0; $$.hour = 1; }
540   | tORDINAL tMINUTE_UNIT
541       { $$ = RELATIVE_TIME_0; $$.minutes = $1; }
542   | tUNUMBER tMINUTE_UNIT
543       { $$ = RELATIVE_TIME_0; $$.minutes = $1.value; }
544   | tMINUTE_UNIT
545       { $$ = RELATIVE_TIME_0; $$.minutes = 1; }
546   | tORDINAL tSEC_UNIT
547       { $$ = RELATIVE_TIME_0; $$.seconds = $1; }
548   | tUNUMBER tSEC_UNIT
549       { $$ = RELATIVE_TIME_0; $$.seconds = $1.value; }
550   | tSDECIMAL_NUMBER tSEC_UNIT
551       { $$ = RELATIVE_TIME_0; $$.seconds = $1.tv_sec; $$.ns = $1.tv_nsec; }
552   | tUDECIMAL_NUMBER tSEC_UNIT
553       { $$ = RELATIVE_TIME_0; $$.seconds = $1.tv_sec; $$.ns = $1.tv_nsec; }
554   | tSEC_UNIT
555       { $$ = RELATIVE_TIME_0; $$.seconds = 1; }
556   | relunit_snumber
557   ;
558
559 relunit_snumber:
560     tSNUMBER tYEAR_UNIT
561       { $$ = RELATIVE_TIME_0; $$.year = $1.value; }
562   | tSNUMBER tMONTH_UNIT
563       { $$ = RELATIVE_TIME_0; $$.month = $1.value; }
564   | tSNUMBER tDAY_UNIT
565       { $$ = RELATIVE_TIME_0; $$.day = $1.value * $2; }
566   | tSNUMBER tHOUR_UNIT
567       { $$ = RELATIVE_TIME_0; $$.hour = $1.value; }
568   | tSNUMBER tMINUTE_UNIT
569       { $$ = RELATIVE_TIME_0; $$.minutes = $1.value; }
570   | tSNUMBER tSEC_UNIT
571       { $$ = RELATIVE_TIME_0; $$.seconds = $1.value; }
572   ;
573
574 dayshift:
575     tDAY_SHIFT
576       { $$ = RELATIVE_TIME_0; $$.day = $1; }
577   ;
578
579 seconds: signed_seconds | unsigned_seconds;
580
581 signed_seconds:
582     tSDECIMAL_NUMBER
583   | tSNUMBER
584       { $$.tv_sec = $1.value; $$.tv_nsec = 0; }
585   ;
586
587 unsigned_seconds:
588     tUDECIMAL_NUMBER
589   | tUNUMBER
590       { $$.tv_sec = $1.value; $$.tv_nsec = 0; }
591   ;
592
593 number:
594     tUNUMBER
595       { digits_to_date_time (pc, $1); }
596   ;
597
598 hybrid:
599     tUNUMBER relunit_snumber
600       {
601         /* Hybrid all-digit and relative offset, so that we accept e.g.,
602            "YYYYMMDD +N days" as well as "YYYYMMDD N days".  */
603         digits_to_date_time (pc, $1);
604         apply_relative_time (pc, $2, 1);
605       }
606   ;
607
608 o_colon_minutes:
609     /* empty */
610       { $$ = -1; }
611   | ':' tUNUMBER
612       { $$ = $2.value; }
613   ;
614
615 o_merid:
616     /* empty */
617       { $$ = MER24; }
618   | tMERIDIAN
619       { $$ = $1; }
620   ;
621
622 %%
623
624 static table const meridian_table[] =
625 {
626   { "AM",   tMERIDIAN, MERam },
627   { "A.M.", tMERIDIAN, MERam },
628   { "PM",   tMERIDIAN, MERpm },
629   { "P.M.", tMERIDIAN, MERpm },
630   { NULL, 0, 0 }
631 };
632
633 static table const dst_table[] =
634 {
635   { "DST", tDST, 0 }
636 };
637
638 static table const month_and_day_table[] =
639 {
640   { "JANUARY",  tMONTH,  1 },
641   { "FEBRUARY", tMONTH,  2 },
642   { "MARCH",    tMONTH,  3 },
643   { "APRIL",    tMONTH,  4 },
644   { "MAY",      tMONTH,  5 },
645   { "JUNE",     tMONTH,  6 },
646   { "JULY",     tMONTH,  7 },
647   { "AUGUST",   tMONTH,  8 },
648   { "SEPTEMBER",tMONTH,  9 },
649   { "SEPT",     tMONTH,  9 },
650   { "OCTOBER",  tMONTH, 10 },
651   { "NOVEMBER", tMONTH, 11 },
652   { "DECEMBER", tMONTH, 12 },
653   { "SUNDAY",   tDAY,    0 },
654   { "MONDAY",   tDAY,    1 },
655   { "TUESDAY",  tDAY,    2 },
656   { "TUES",     tDAY,    2 },
657   { "WEDNESDAY",tDAY,    3 },
658   { "WEDNES",   tDAY,    3 },
659   { "THURSDAY", tDAY,    4 },
660   { "THUR",     tDAY,    4 },
661   { "THURS",    tDAY,    4 },
662   { "FRIDAY",   tDAY,    5 },
663   { "SATURDAY", tDAY,    6 },
664   { NULL, 0, 0 }
665 };
666
667 static table const time_units_table[] =
668 {
669   { "YEAR",     tYEAR_UNIT,      1 },
670   { "MONTH",    tMONTH_UNIT,     1 },
671   { "FORTNIGHT",tDAY_UNIT,      14 },
672   { "WEEK",     tDAY_UNIT,       7 },
673   { "DAY",      tDAY_UNIT,       1 },
674   { "HOUR",     tHOUR_UNIT,      1 },
675   { "MINUTE",   tMINUTE_UNIT,    1 },
676   { "MIN",      tMINUTE_UNIT,    1 },
677   { "SECOND",   tSEC_UNIT,       1 },
678   { "SEC",      tSEC_UNIT,       1 },
679   { NULL, 0, 0 }
680 };
681
682 /* Assorted relative-time words. */
683 static table const relative_time_table[] =
684 {
685   { "TOMORROW", tDAY_SHIFT,      1 },
686   { "YESTERDAY",tDAY_SHIFT,     -1 },
687   { "TODAY",    tDAY_SHIFT,      0 },
688   { "NOW",      tDAY_SHIFT,      0 },
689   { "LAST",     tORDINAL,       -1 },
690   { "THIS",     tORDINAL,        0 },
691   { "NEXT",     tORDINAL,        1 },
692   { "FIRST",    tORDINAL,        1 },
693 /*{ "SECOND",   tORDINAL,        2 }, */
694   { "THIRD",    tORDINAL,        3 },
695   { "FOURTH",   tORDINAL,        4 },
696   { "FIFTH",    tORDINAL,        5 },
697   { "SIXTH",    tORDINAL,        6 },
698   { "SEVENTH",  tORDINAL,        7 },
699   { "EIGHTH",   tORDINAL,        8 },
700   { "NINTH",    tORDINAL,        9 },
701   { "TENTH",    tORDINAL,       10 },
702   { "ELEVENTH", tORDINAL,       11 },
703   { "TWELFTH",  tORDINAL,       12 },
704   { "AGO",      tAGO,            1 },
705   { NULL, 0, 0 }
706 };
707
708 /* The universal time zone table.  These labels can be used even for
709    time stamps that would not otherwise be valid, e.g., GMT time
710    stamps in London during summer.  */
711 static table const universal_time_zone_table[] =
712 {
713   { "GMT",      tZONE,     HOUR ( 0) }, /* Greenwich Mean */
714   { "UT",       tZONE,     HOUR ( 0) }, /* Universal (Coordinated) */
715   { "UTC",      tZONE,     HOUR ( 0) },
716   { NULL, 0, 0 }
717 };
718
719 /* The time zone table.  This table is necessarily incomplete, as time
720    zone abbreviations are ambiguous; e.g. Australians interpret "EST"
721    as Eastern time in Australia, not as US Eastern Standard Time.
722    You cannot rely on parse_datetime to handle arbitrary time zone
723    abbreviations; use numeric abbreviations like `-0500' instead.  */
724 static table const time_zone_table[] =
725 {
726   { "WET",      tZONE,     HOUR ( 0) }, /* Western European */
727   { "WEST",     tDAYZONE,  HOUR ( 0) }, /* Western European Summer */
728   { "BST",      tDAYZONE,  HOUR ( 0) }, /* British Summer */
729   { "ART",      tZONE,    -HOUR ( 3) }, /* Argentina */
730   { "BRT",      tZONE,    -HOUR ( 3) }, /* Brazil */
731   { "BRST",     tDAYZONE, -HOUR ( 3) }, /* Brazil Summer */
732   { "NST",      tZONE,   -(HOUR ( 3) + 30) },   /* Newfoundland Standard */
733   { "NDT",      tDAYZONE,-(HOUR ( 3) + 30) },   /* Newfoundland Daylight */
734   { "AST",      tZONE,    -HOUR ( 4) }, /* Atlantic Standard */
735   { "ADT",      tDAYZONE, -HOUR ( 4) }, /* Atlantic Daylight */
736   { "CLT",      tZONE,    -HOUR ( 4) }, /* Chile */
737   { "CLST",     tDAYZONE, -HOUR ( 4) }, /* Chile Summer */
738   { "EST",      tZONE,    -HOUR ( 5) }, /* Eastern Standard */
739   { "EDT",      tDAYZONE, -HOUR ( 5) }, /* Eastern Daylight */
740   { "CST",      tZONE,    -HOUR ( 6) }, /* Central Standard */
741   { "CDT",      tDAYZONE, -HOUR ( 6) }, /* Central Daylight */
742   { "MST",      tZONE,    -HOUR ( 7) }, /* Mountain Standard */
743   { "MDT",      tDAYZONE, -HOUR ( 7) }, /* Mountain Daylight */
744   { "PST",      tZONE,    -HOUR ( 8) }, /* Pacific Standard */
745   { "PDT",      tDAYZONE, -HOUR ( 8) }, /* Pacific Daylight */
746   { "AKST",     tZONE,    -HOUR ( 9) }, /* Alaska Standard */
747   { "AKDT",     tDAYZONE, -HOUR ( 9) }, /* Alaska Daylight */
748   { "HST",      tZONE,    -HOUR (10) }, /* Hawaii Standard */
749   { "HAST",     tZONE,    -HOUR (10) }, /* Hawaii-Aleutian Standard */
750   { "HADT",     tDAYZONE, -HOUR (10) }, /* Hawaii-Aleutian Daylight */
751   { "SST",      tZONE,    -HOUR (12) }, /* Samoa Standard */
752   { "WAT",      tZONE,     HOUR ( 1) }, /* West Africa */
753   { "CET",      tZONE,     HOUR ( 1) }, /* Central European */
754   { "CEST",     tDAYZONE,  HOUR ( 1) }, /* Central European Summer */
755   { "MET",      tZONE,     HOUR ( 1) }, /* Middle European */
756   { "MEZ",      tZONE,     HOUR ( 1) }, /* Middle European */
757   { "MEST",     tDAYZONE,  HOUR ( 1) }, /* Middle European Summer */
758   { "MESZ",     tDAYZONE,  HOUR ( 1) }, /* Middle European Summer */
759   { "EET",      tZONE,     HOUR ( 2) }, /* Eastern European */
760   { "EEST",     tDAYZONE,  HOUR ( 2) }, /* Eastern European Summer */
761   { "CAT",      tZONE,     HOUR ( 2) }, /* Central Africa */
762   { "SAST",     tZONE,     HOUR ( 2) }, /* South Africa Standard */
763   { "EAT",      tZONE,     HOUR ( 3) }, /* East Africa */
764   { "MSK",      tZONE,     HOUR ( 3) }, /* Moscow */
765   { "MSD",      tDAYZONE,  HOUR ( 3) }, /* Moscow Daylight */
766   { "IST",      tZONE,    (HOUR ( 5) + 30) },   /* India Standard */
767   { "SGT",      tZONE,     HOUR ( 8) }, /* Singapore */
768   { "KST",      tZONE,     HOUR ( 9) }, /* Korea Standard */
769   { "JST",      tZONE,     HOUR ( 9) }, /* Japan Standard */
770   { "GST",      tZONE,     HOUR (10) }, /* Guam Standard */
771   { "NZST",     tZONE,     HOUR (12) }, /* New Zealand Standard */
772   { "NZDT",     tDAYZONE,  HOUR (12) }, /* New Zealand Daylight */
773   { NULL, 0, 0 }
774 };
775
776 /* Military time zone table. */
777 static table const military_table[] =
778 {
779   { "A", tZONE, -HOUR ( 1) },
780   { "B", tZONE, -HOUR ( 2) },
781   { "C", tZONE, -HOUR ( 3) },
782   { "D", tZONE, -HOUR ( 4) },
783   { "E", tZONE, -HOUR ( 5) },
784   { "F", tZONE, -HOUR ( 6) },
785   { "G", tZONE, -HOUR ( 7) },
786   { "H", tZONE, -HOUR ( 8) },
787   { "I", tZONE, -HOUR ( 9) },
788   { "K", tZONE, -HOUR (10) },
789   { "L", tZONE, -HOUR (11) },
790   { "M", tZONE, -HOUR (12) },
791   { "N", tZONE,  HOUR ( 1) },
792   { "O", tZONE,  HOUR ( 2) },
793   { "P", tZONE,  HOUR ( 3) },
794   { "Q", tZONE,  HOUR ( 4) },
795   { "R", tZONE,  HOUR ( 5) },
796   { "S", tZONE,  HOUR ( 6) },
797   { "T", tZONE,  HOUR ( 7) },
798   { "U", tZONE,  HOUR ( 8) },
799   { "V", tZONE,  HOUR ( 9) },
800   { "W", tZONE,  HOUR (10) },
801   { "X", tZONE,  HOUR (11) },
802   { "Y", tZONE,  HOUR (12) },
803   { "Z", tZONE,  HOUR ( 0) },
804   { NULL, 0, 0 }
805 };
806
807 \f
808
809 /* Convert a time zone expressed as HH:MM into an integer count of
810    minutes.  If MM is negative, then S is of the form HHMM and needs
811    to be picked apart; otherwise, S is of the form HH.  As specified in
812    http://www.opengroup.org/susv3xbd/xbd_chap08.html#tag_08_03, allow
813    only valid TZ range, and consider first two digits as hours, if no
814    minutes specified.  */
815
816 static long int
817 time_zone_hhmm (parser_control *pc, textint s, long int mm)
818 {
819   long int n_minutes;
820
821   /* If the length of S is 1 or 2 and no minutes are specified,
822      interpret it as a number of hours.  */
823   if (s.digits <= 2 && mm < 0)
824     s.value *= 100;
825
826   if (mm < 0)
827     n_minutes = (s.value / 100) * 60 + s.value % 100;
828   else
829     n_minutes = s.value * 60 + (s.negative ? -mm : mm);
830
831   /* If the absolute number of minutes is larger than 24 hours,
832      arrange to reject it by incrementing pc->zones_seen.  Thus,
833      we allow only values in the range UTC-24:00 to UTC+24:00.  */
834   if (24 * 60 < abs (n_minutes))
835     pc->zones_seen++;
836
837   return n_minutes;
838 }
839
840 static int
841 to_hour (long int hours, int meridian)
842 {
843   switch (meridian)
844     {
845     default: /* Pacify GCC.  */
846     case MER24:
847       return 0 <= hours && hours < 24 ? hours : -1;
848     case MERam:
849       return 0 < hours && hours < 12 ? hours : hours == 12 ? 0 : -1;
850     case MERpm:
851       return 0 < hours && hours < 12 ? hours + 12 : hours == 12 ? 12 : -1;
852     }
853 }
854
855 static long int
856 to_year (textint textyear)
857 {
858   long int year = textyear.value;
859
860   if (year < 0)
861     year = -year;
862
863   /* XPG4 suggests that years 00-68 map to 2000-2068, and
864      years 69-99 map to 1969-1999.  */
865   else if (textyear.digits == 2)
866     year += year < 69 ? 2000 : 1900;
867
868   return year;
869 }
870
871 static table const *
872 lookup_zone (parser_control const *pc, char const *name)
873 {
874   table const *tp;
875
876   for (tp = universal_time_zone_table; tp->name; tp++)
877     if (strcmp (name, tp->name) == 0)
878       return tp;
879
880   /* Try local zone abbreviations before those in time_zone_table, as
881      the local ones are more likely to be right.  */
882   for (tp = pc->local_time_zone_table; tp->name; tp++)
883     if (strcmp (name, tp->name) == 0)
884       return tp;
885
886   for (tp = time_zone_table; tp->name; tp++)
887     if (strcmp (name, tp->name) == 0)
888       return tp;
889
890   return NULL;
891 }
892
893 #if ! HAVE_TM_GMTOFF
894 /* Yield the difference between *A and *B,
895    measured in seconds, ignoring leap seconds.
896    The body of this function is taken directly from the GNU C Library;
897    see src/strftime.c.  */
898 static long int
899 tm_diff (struct tm const *a, struct tm const *b)
900 {
901   /* Compute intervening leap days correctly even if year is negative.
902      Take care to avoid int overflow in leap day calculations.  */
903   int a4 = SHR (a->tm_year, 2) + SHR (TM_YEAR_BASE, 2) - ! (a->tm_year & 3);
904   int b4 = SHR (b->tm_year, 2) + SHR (TM_YEAR_BASE, 2) - ! (b->tm_year & 3);
905   int a100 = a4 / 25 - (a4 % 25 < 0);
906   int b100 = b4 / 25 - (b4 % 25 < 0);
907   int a400 = SHR (a100, 2);
908   int b400 = SHR (b100, 2);
909   int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
910   long int ayear = a->tm_year;
911   long int years = ayear - b->tm_year;
912   long int days = (365 * years + intervening_leap_days
913                    + (a->tm_yday - b->tm_yday));
914   return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
915                 + (a->tm_min - b->tm_min))
916           + (a->tm_sec - b->tm_sec));
917 }
918 #endif /* ! HAVE_TM_GMTOFF */
919
920 static table const *
921 lookup_word (parser_control const *pc, char *word)
922 {
923   char *p;
924   char *q;
925   size_t wordlen;
926   table const *tp;
927   bool period_found;
928   bool abbrev;
929
930   /* Make it uppercase.  */
931   for (p = word; *p; p++)
932     {
933       unsigned char ch = *p;
934       *p = c_toupper (ch);
935     }
936
937   for (tp = meridian_table; tp->name; tp++)
938     if (strcmp (word, tp->name) == 0)
939       return tp;
940
941   /* See if we have an abbreviation for a month. */
942   wordlen = strlen (word);
943   abbrev = wordlen == 3 || (wordlen == 4 && word[3] == '.');
944
945   for (tp = month_and_day_table; tp->name; tp++)
946     if ((abbrev ? strncmp (word, tp->name, 3) : strcmp (word, tp->name)) == 0)
947       return tp;
948
949   if ((tp = lookup_zone (pc, word)))
950     return tp;
951
952   if (strcmp (word, dst_table[0].name) == 0)
953     return dst_table;
954
955   for (tp = time_units_table; tp->name; tp++)
956     if (strcmp (word, tp->name) == 0)
957       return tp;
958
959   /* Strip off any plural and try the units table again. */
960   if (word[wordlen - 1] == 'S')
961     {
962       word[wordlen - 1] = '\0';
963       for (tp = time_units_table; tp->name; tp++)
964         if (strcmp (word, tp->name) == 0)
965           return tp;
966       word[wordlen - 1] = 'S';  /* For "this" in relative_time_table.  */
967     }
968
969   for (tp = relative_time_table; tp->name; tp++)
970     if (strcmp (word, tp->name) == 0)
971       return tp;
972
973   /* Military time zones. */
974   if (wordlen == 1)
975     for (tp = military_table; tp->name; tp++)
976       if (word[0] == tp->name[0])
977         return tp;
978
979   /* Drop out any periods and try the time zone table again. */
980   for (period_found = false, p = q = word; (*p = *q); q++)
981     if (*q == '.')
982       period_found = true;
983     else
984       p++;
985   if (period_found && (tp = lookup_zone (pc, word)))
986     return tp;
987
988   return NULL;
989 }
990
991 static int
992 yylex (YYSTYPE *lvalp, parser_control *pc)
993 {
994   unsigned char c;
995   size_t count;
996
997   for (;;)
998     {
999       while (c = *pc->input, c_isspace (c))
1000         pc->input++;
1001
1002       if (ISDIGIT (c) || c == '-' || c == '+')
1003         {
1004           char const *p;
1005           int sign;
1006           unsigned long int value;
1007           if (c == '-' || c == '+')
1008             {
1009               sign = c == '-' ? -1 : 1;
1010               while (c = *++pc->input, c_isspace (c))
1011                 continue;
1012               if (! ISDIGIT (c))
1013                 /* skip the '-' sign */
1014                 continue;
1015             }
1016           else
1017             sign = 0;
1018           p = pc->input;
1019           for (value = 0; ; value *= 10)
1020             {
1021               unsigned long int value1 = value + (c - '0');
1022               if (value1 < value)
1023                 return '?';
1024               value = value1;
1025               c = *++p;
1026               if (! ISDIGIT (c))
1027                 break;
1028               if (ULONG_MAX / 10 < value)
1029                 return '?';
1030             }
1031           if ((c == '.' || c == ',') && ISDIGIT (p[1]))
1032             {
1033               time_t s;
1034               int ns;
1035               int digits;
1036               unsigned long int value1;
1037
1038               /* Check for overflow when converting value to time_t.  */
1039               if (sign < 0)
1040                 {
1041                   s = - value;
1042                   if (0 < s)
1043                     return '?';
1044                   value1 = -s;
1045                 }
1046               else
1047                 {
1048                   s = value;
1049                   if (s < 0)
1050                     return '?';
1051                   value1 = s;
1052                 }
1053               if (value != value1)
1054                 return '?';
1055
1056               /* Accumulate fraction, to ns precision.  */
1057               p++;
1058               ns = *p++ - '0';
1059               for (digits = 2; digits <= LOG10_BILLION; digits++)
1060                 {
1061                   ns *= 10;
1062                   if (ISDIGIT (*p))
1063                     ns += *p++ - '0';
1064                 }
1065
1066               /* Skip excess digits, truncating toward -Infinity.  */
1067               if (sign < 0)
1068                 for (; ISDIGIT (*p); p++)
1069                   if (*p != '0')
1070                     {
1071                       ns++;
1072                       break;
1073                     }
1074               while (ISDIGIT (*p))
1075                 p++;
1076
1077               /* Adjust to the timespec convention, which is that
1078                  tv_nsec is always a positive offset even if tv_sec is
1079                  negative.  */
1080               if (sign < 0 && ns)
1081                 {
1082                   s--;
1083                   if (! (s < 0))
1084                     return '?';
1085                   ns = BILLION - ns;
1086                 }
1087
1088               lvalp->timespec.tv_sec = s;
1089               lvalp->timespec.tv_nsec = ns;
1090               pc->input = p;
1091               return sign ? tSDECIMAL_NUMBER : tUDECIMAL_NUMBER;
1092             }
1093           else
1094             {
1095               lvalp->textintval.negative = sign < 0;
1096               if (sign < 0)
1097                 {
1098                   lvalp->textintval.value = - value;
1099                   if (0 < lvalp->textintval.value)
1100                     return '?';
1101                 }
1102               else
1103                 {
1104                   lvalp->textintval.value = value;
1105                   if (lvalp->textintval.value < 0)
1106                     return '?';
1107                 }
1108               lvalp->textintval.digits = p - pc->input;
1109               pc->input = p;
1110               return sign ? tSNUMBER : tUNUMBER;
1111             }
1112         }
1113
1114       if (c_isalpha (c))
1115         {
1116           char buff[20];
1117           char *p = buff;
1118           table const *tp;
1119
1120           do
1121             {
1122               if (p < buff + sizeof buff - 1)
1123                 *p++ = c;
1124               c = *++pc->input;
1125             }
1126           while (c_isalpha (c) || c == '.');
1127
1128           *p = '\0';
1129           tp = lookup_word (pc, buff);
1130           if (! tp)
1131             return '?';
1132           lvalp->intval = tp->value;
1133           return tp->type;
1134         }
1135
1136       if (c != '(')
1137         return *pc->input++;
1138       count = 0;
1139       do
1140         {
1141           c = *pc->input++;
1142           if (c == '\0')
1143             return c;
1144           if (c == '(')
1145             count++;
1146           else if (c == ')')
1147             count--;
1148         }
1149       while (count != 0);
1150     }
1151 }
1152
1153 /* Do nothing if the parser reports an error.  */
1154 static int
1155 yyerror (parser_control const *pc _GL_UNUSED,
1156          char const *s _GL_UNUSED)
1157 {
1158   return 0;
1159 }
1160
1161 /* If *TM0 is the old and *TM1 is the new value of a struct tm after
1162    passing it to mktime, return true if it's OK that mktime returned T.
1163    It's not OK if *TM0 has out-of-range members.  */
1164
1165 static bool
1166 mktime_ok (struct tm const *tm0, struct tm const *tm1, time_t t)
1167 {
1168   if (t == (time_t) -1)
1169     {
1170       /* Guard against falsely reporting an error when parsing a time
1171          stamp that happens to equal (time_t) -1, on a host that
1172          supports such a time stamp.  */
1173       tm1 = localtime (&t);
1174       if (!tm1)
1175         return false;
1176     }
1177
1178   return ! ((tm0->tm_sec ^ tm1->tm_sec)
1179             | (tm0->tm_min ^ tm1->tm_min)
1180             | (tm0->tm_hour ^ tm1->tm_hour)
1181             | (tm0->tm_mday ^ tm1->tm_mday)
1182             | (tm0->tm_mon ^ tm1->tm_mon)
1183             | (tm0->tm_year ^ tm1->tm_year));
1184 }
1185
1186 /* A reasonable upper bound for the size of ordinary TZ strings.
1187    Use heap allocation if TZ's length exceeds this.  */
1188 enum { TZBUFSIZE = 100 };
1189
1190 /* Return a copy of TZ, stored in TZBUF if it fits, and heap-allocated
1191    otherwise.  */
1192 static char *
1193 get_tz (char tzbuf[TZBUFSIZE])
1194 {
1195   char *tz = getenv ("TZ");
1196   if (tz)
1197     {
1198       size_t tzsize = strlen (tz) + 1;
1199       tz = (tzsize <= TZBUFSIZE
1200             ? memcpy (tzbuf, tz, tzsize)
1201             : xmemdup (tz, tzsize));
1202     }
1203   return tz;
1204 }
1205
1206 /* Parse a date/time string, storing the resulting time value into *RESULT.
1207    The string itself is pointed to by P.  Return true if successful.
1208    P can be an incomplete or relative time specification; if so, use
1209    *NOW as the basis for the returned time.  */
1210 bool
1211 parse_datetime (struct timespec *result, char const *p,
1212                 struct timespec const *now)
1213 {
1214   time_t Start;
1215   long int Start_ns;
1216   struct tm const *tmp;
1217   struct tm tm;
1218   struct tm tm0;
1219   parser_control pc;
1220   struct timespec gettime_buffer;
1221   unsigned char c;
1222   bool tz_was_altered = false;
1223   char *tz0 = NULL;
1224   char tz0buf[TZBUFSIZE];
1225   bool ok = true;
1226
1227   if (! now)
1228     {
1229       gettime (&gettime_buffer);
1230       now = &gettime_buffer;
1231     }
1232
1233   Start = now->tv_sec;
1234   Start_ns = now->tv_nsec;
1235
1236   tmp = localtime (&now->tv_sec);
1237   if (! tmp)
1238     return false;
1239
1240   while (c = *p, c_isspace (c))
1241     p++;
1242
1243   if (strncmp (p, "TZ=\"", 4) == 0)
1244     {
1245       char const *tzbase = p + 4;
1246       size_t tzsize = 1;
1247       char const *s;
1248
1249       for (s = tzbase; *s; s++, tzsize++)
1250         if (*s == '\\')
1251           {
1252             s++;
1253             if (! (*s == '\\' || *s == '"'))
1254               break;
1255           }
1256         else if (*s == '"')
1257           {
1258             char *z;
1259             char *tz1;
1260             char tz1buf[TZBUFSIZE];
1261             bool large_tz = TZBUFSIZE < tzsize;
1262             bool setenv_ok;
1263             /* Free tz0, in case this is the 2nd or subsequent time through. */
1264             free (tz0);
1265             tz0 = get_tz (tz0buf);
1266             z = tz1 = large_tz ? xmalloc (tzsize) : tz1buf;
1267             for (s = tzbase; *s != '"'; s++)
1268               *z++ = *(s += *s == '\\');
1269             *z = '\0';
1270             setenv_ok = setenv ("TZ", tz1, 1) == 0;
1271             if (large_tz)
1272               free (tz1);
1273             if (!setenv_ok)
1274               goto fail;
1275             tz_was_altered = true;
1276             p = s + 1;
1277           }
1278     }
1279
1280   /* As documented, be careful to treat the empty string just like
1281      a date string of "0".  Without this, an empty string would be
1282      declared invalid when parsed during a DST transition.  */
1283   if (*p == '\0')
1284     p = "0";
1285
1286   pc.input = p;
1287   pc.year.value = tmp->tm_year;
1288   pc.year.value += TM_YEAR_BASE;
1289   pc.year.digits = 0;
1290   pc.month = tmp->tm_mon + 1;
1291   pc.day = tmp->tm_mday;
1292   pc.hour = tmp->tm_hour;
1293   pc.minutes = tmp->tm_min;
1294   pc.seconds.tv_sec = tmp->tm_sec;
1295   pc.seconds.tv_nsec = Start_ns;
1296   tm.tm_isdst = tmp->tm_isdst;
1297
1298   pc.meridian = MER24;
1299   pc.rel = RELATIVE_TIME_0;
1300   pc.timespec_seen = false;
1301   pc.rels_seen = false;
1302   pc.dates_seen = 0;
1303   pc.days_seen = 0;
1304   pc.times_seen = 0;
1305   pc.local_zones_seen = 0;
1306   pc.dsts_seen = 0;
1307   pc.zones_seen = 0;
1308
1309 #if HAVE_STRUCT_TM_TM_ZONE
1310   pc.local_time_zone_table[0].name = tmp->tm_zone;
1311   pc.local_time_zone_table[0].type = tLOCAL_ZONE;
1312   pc.local_time_zone_table[0].value = tmp->tm_isdst;
1313   pc.local_time_zone_table[1].name = NULL;
1314
1315   /* Probe the names used in the next three calendar quarters, looking
1316      for a tm_isdst different from the one we already have.  */
1317   {
1318     int quarter;
1319     for (quarter = 1; quarter <= 3; quarter++)
1320       {
1321         time_t probe = Start + quarter * (90 * 24 * 60 * 60);
1322         struct tm const *probe_tm = localtime (&probe);
1323         if (probe_tm && probe_tm->tm_zone
1324             && probe_tm->tm_isdst != pc.local_time_zone_table[0].value)
1325           {
1326               {
1327                 pc.local_time_zone_table[1].name = probe_tm->tm_zone;
1328                 pc.local_time_zone_table[1].type = tLOCAL_ZONE;
1329                 pc.local_time_zone_table[1].value = probe_tm->tm_isdst;
1330                 pc.local_time_zone_table[2].name = NULL;
1331               }
1332             break;
1333           }
1334       }
1335   }
1336 #else
1337 #if HAVE_TZNAME
1338   {
1339 # if !HAVE_DECL_TZNAME
1340     extern char *tzname[];
1341 # endif
1342     int i;
1343     for (i = 0; i < 2; i++)
1344       {
1345         pc.local_time_zone_table[i].name = tzname[i];
1346         pc.local_time_zone_table[i].type = tLOCAL_ZONE;
1347         pc.local_time_zone_table[i].value = i;
1348       }
1349     pc.local_time_zone_table[i].name = NULL;
1350   }
1351 #else
1352   pc.local_time_zone_table[0].name = NULL;
1353 #endif
1354 #endif
1355
1356   if (pc.local_time_zone_table[0].name && pc.local_time_zone_table[1].name
1357       && ! strcmp (pc.local_time_zone_table[0].name,
1358                    pc.local_time_zone_table[1].name))
1359     {
1360       /* This locale uses the same abbrevation for standard and
1361          daylight times.  So if we see that abbreviation, we don't
1362          know whether it's daylight time.  */
1363       pc.local_time_zone_table[0].value = -1;
1364       pc.local_time_zone_table[1].name = NULL;
1365     }
1366
1367   if (yyparse (&pc) != 0)
1368     goto fail;
1369
1370   if (pc.timespec_seen)
1371     *result = pc.seconds;
1372   else
1373     {
1374       if (1 < (pc.times_seen | pc.dates_seen | pc.days_seen | pc.dsts_seen
1375                | (pc.local_zones_seen + pc.zones_seen)))
1376         goto fail;
1377
1378       tm.tm_year = to_year (pc.year) - TM_YEAR_BASE;
1379       tm.tm_mon = pc.month - 1;
1380       tm.tm_mday = pc.day;
1381       if (pc.times_seen || (pc.rels_seen && ! pc.dates_seen && ! pc.days_seen))
1382         {
1383           tm.tm_hour = to_hour (pc.hour, pc.meridian);
1384           if (tm.tm_hour < 0)
1385             goto fail;
1386           tm.tm_min = pc.minutes;
1387           tm.tm_sec = pc.seconds.tv_sec;
1388         }
1389       else
1390         {
1391           tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
1392           pc.seconds.tv_nsec = 0;
1393         }
1394
1395       /* Let mktime deduce tm_isdst if we have an absolute time stamp.  */
1396       if (pc.dates_seen | pc.days_seen | pc.times_seen)
1397         tm.tm_isdst = -1;
1398
1399       /* But if the input explicitly specifies local time with or without
1400          DST, give mktime that information.  */
1401       if (pc.local_zones_seen)
1402         tm.tm_isdst = pc.local_isdst;
1403
1404       tm0 = tm;
1405
1406       Start = mktime (&tm);
1407
1408       if (! mktime_ok (&tm0, &tm, Start))
1409         {
1410           if (! pc.zones_seen)
1411             goto fail;
1412           else
1413             {
1414               /* Guard against falsely reporting errors near the time_t
1415                  boundaries when parsing times in other time zones.  For
1416                  example, suppose the input string "1969-12-31 23:00:00 -0100",
1417                  the current time zone is 8 hours ahead of UTC, and the min
1418                  time_t value is 1970-01-01 00:00:00 UTC.  Then the min
1419                  localtime value is 1970-01-01 08:00:00, and mktime will
1420                  therefore fail on 1969-12-31 23:00:00.  To work around the
1421                  problem, set the time zone to 1 hour behind UTC temporarily
1422                  by setting TZ="XXX1:00" and try mktime again.  */
1423
1424               long int time_zone = pc.time_zone;
1425               long int abs_time_zone = time_zone < 0 ? - time_zone : time_zone;
1426               long int abs_time_zone_hour = abs_time_zone / 60;
1427               int abs_time_zone_min = abs_time_zone % 60;
1428               char tz1buf[sizeof "XXX+0:00"
1429                           + sizeof pc.time_zone * CHAR_BIT / 3];
1430               if (!tz_was_altered)
1431                 tz0 = get_tz (tz0buf);
1432               sprintf (tz1buf, "XXX%s%ld:%02d", "-" + (time_zone < 0),
1433                        abs_time_zone_hour, abs_time_zone_min);
1434               if (setenv ("TZ", tz1buf, 1) != 0)
1435                 goto fail;
1436               tz_was_altered = true;
1437               tm = tm0;
1438               Start = mktime (&tm);
1439               if (! mktime_ok (&tm0, &tm, Start))
1440                 goto fail;
1441             }
1442         }
1443
1444       if (pc.days_seen && ! pc.dates_seen)
1445         {
1446           tm.tm_mday += ((pc.day_number - tm.tm_wday + 7) % 7
1447                          + 7 * (pc.day_ordinal
1448                                 - (0 < pc.day_ordinal
1449                                    && tm.tm_wday != pc.day_number)));
1450           tm.tm_isdst = -1;
1451           Start = mktime (&tm);
1452           if (Start == (time_t) -1)
1453             goto fail;
1454         }
1455
1456       /* Add relative date.  */
1457       if (pc.rel.year | pc.rel.month | pc.rel.day)
1458         {
1459           int year = tm.tm_year + pc.rel.year;
1460           int month = tm.tm_mon + pc.rel.month;
1461           int day = tm.tm_mday + pc.rel.day;
1462           if (((year < tm.tm_year) ^ (pc.rel.year < 0))
1463               | ((month < tm.tm_mon) ^ (pc.rel.month < 0))
1464               | ((day < tm.tm_mday) ^ (pc.rel.day < 0)))
1465             goto fail;
1466           tm.tm_year = year;
1467           tm.tm_mon = month;
1468           tm.tm_mday = day;
1469           tm.tm_hour = tm0.tm_hour;
1470           tm.tm_min = tm0.tm_min;
1471           tm.tm_sec = tm0.tm_sec;
1472           tm.tm_isdst = tm0.tm_isdst;
1473           Start = mktime (&tm);
1474           if (Start == (time_t) -1)
1475             goto fail;
1476         }
1477
1478       /* The only "output" of this if-block is an updated Start value,
1479          so this block must follow others that clobber Start.  */
1480       if (pc.zones_seen)
1481         {
1482           long int delta = pc.time_zone * 60;
1483           time_t t1;
1484 #ifdef HAVE_TM_GMTOFF
1485           delta -= tm.tm_gmtoff;
1486 #else
1487           time_t t = Start;
1488           struct tm const *gmt = gmtime (&t);
1489           if (! gmt)
1490             goto fail;
1491           delta -= tm_diff (&tm, gmt);
1492 #endif
1493           t1 = Start - delta;
1494           if ((Start < t1) != (delta < 0))
1495             goto fail;  /* time_t overflow */
1496           Start = t1;
1497         }
1498
1499       /* Add relative hours, minutes, and seconds.  On hosts that support
1500          leap seconds, ignore the possibility of leap seconds; e.g.,
1501          "+ 10 minutes" adds 600 seconds, even if one of them is a
1502          leap second.  Typically this is not what the user wants, but it's
1503          too hard to do it the other way, because the time zone indicator
1504          must be applied before relative times, and if mktime is applied
1505          again the time zone will be lost.  */
1506       {
1507         long int sum_ns = pc.seconds.tv_nsec + pc.rel.ns;
1508         long int normalized_ns = (sum_ns % BILLION + BILLION) % BILLION;
1509         time_t t0 = Start;
1510         long int d1 = 60 * 60 * pc.rel.hour;
1511         time_t t1 = t0 + d1;
1512         long int d2 = 60 * pc.rel.minutes;
1513         time_t t2 = t1 + d2;
1514         long_time_t d3 = pc.rel.seconds;
1515         long_time_t t3 = t2 + d3;
1516         long int d4 = (sum_ns - normalized_ns) / BILLION;
1517         long_time_t t4 = t3 + d4;
1518         time_t t5 = t4;
1519
1520         if ((d1 / (60 * 60) ^ pc.rel.hour)
1521             | (d2 / 60 ^ pc.rel.minutes)
1522             | ((t1 < t0) ^ (d1 < 0))
1523             | ((t2 < t1) ^ (d2 < 0))
1524             | ((t3 < t2) ^ (d3 < 0))
1525             | ((t4 < t3) ^ (d4 < 0))
1526             | (t5 != t4))
1527           goto fail;
1528
1529         result->tv_sec = t5;
1530         result->tv_nsec = normalized_ns;
1531       }
1532     }
1533
1534   goto done;
1535
1536  fail:
1537   ok = false;
1538  done:
1539   if (tz_was_altered)
1540     ok &= (tz0 ? setenv ("TZ", tz0, 1) : unsetenv ("TZ")) == 0;
1541   if (tz0 != tz0buf)
1542     free (tz0);
1543   return ok;
1544 }
1545
1546 #if TEST
1547
1548 int
1549 main (int ac, char **av)
1550 {
1551   char buff[BUFSIZ];
1552
1553   printf ("Enter date, or blank line to exit.\n\t> ");
1554   fflush (stdout);
1555
1556   buff[BUFSIZ - 1] = '\0';
1557   while (fgets (buff, BUFSIZ - 1, stdin) && buff[0])
1558     {
1559       struct timespec d;
1560       struct tm const *tm;
1561       if (! parse_datetime (&d, buff, NULL))
1562         printf ("Bad format - couldn't convert.\n");
1563       else if (! (tm = localtime (&d.tv_sec)))
1564         {
1565           long int sec = d.tv_sec;
1566           printf ("localtime (%ld) failed\n", sec);
1567         }
1568       else
1569         {
1570           int ns = d.tv_nsec;
1571           printf ("%04ld-%02d-%02d %02d:%02d:%02d.%09d\n",
1572                   tm->tm_year + 1900L, tm->tm_mon + 1, tm->tm_mday,
1573                   tm->tm_hour, tm->tm_min, tm->tm_sec, ns);
1574         }
1575       printf ("\t> ");
1576       fflush (stdout);
1577     }
1578   return 0;
1579 }
1580 #endif /* TEST */