This source file includes following definitions.
- time_overflow
- to_uchar
- _GL_ATTRIBUTE_FORMAT
- debugging
- digits_to_date_time
- apply_relative_time
- set_hhmmss
- str_days
- time_zone_str
- debug_print_current_time
- print_rel_part
- debug_print_relative_time
- time_zone_hhmm
- to_hour
- tm_year_str
- to_tm_year
- lookup_zone
- tm_diff
- lookup_word
- yylex
- yyerror
- mktime_ok
- debug_strfdatetime
- debug_strfdate
- debug_strftime
- debug_mktime_not_ok
- parse_datetime_body
- parse_datetime2
- parse_datetime
- main
1 %{
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 #include <config.h>
35
36 #include "parse-datetime.h"
37
38 #include "idx.h"
39 #include "intprops.h"
40 #include "timespec.h"
41 #include "verify.h"
42 #include "strftime.h"
43
44
45
46 #define YYSTACK_USE_ALLOCA 0
47
48
49
50
51
52 #define YYMAXDEPTH 20
53 #define YYINITDEPTH YYMAXDEPTH
54
55
56
57
58
59
60
61 #ifdef emacs
62 # undef static
63 #endif
64
65 #include <inttypes.h>
66 #include <c-ctype.h>
67 #include <stdarg.h>
68 #include <stdio.h>
69 #include <stdlib.h>
70 #include <string.h>
71
72 #include "gettext.h"
73
74 #define _(str) gettext (str)
75
76
77
78
79
80 #ifdef _STDLIB_H_
81 # undef _STDLIB_H
82 # define _STDLIB_H 1
83 #endif
84
85
86
87
88
89
90
91
92
93
94
95 #define SHR(a, b) \
96 (-1 >> 1 == -1 \
97 ? (a) >> (b) \
98 : (a) / (1 << (b)) - ((a) % (1 << (b)) < 0))
99
100 #define HOUR(x) (60 * 60 * (x))
101
102 #define STREQ(a, b) (strcmp (a, b) == 0)
103
104
105
106
107 verify (TYPE_IS_INTEGER (time_t));
108 verify (!TYPE_SIGNED (time_t) || INTMAX_MIN <= TYPE_MINIMUM (time_t));
109 verify (TYPE_MAXIMUM (time_t) <= INTMAX_MAX);
110
111
112 static bool
113 time_overflow (intmax_t n)
114 {
115 return ! ((TYPE_SIGNED (time_t) ? TYPE_MINIMUM (time_t) <= n : 0 <= n)
116 && n <= TYPE_MAXIMUM (time_t));
117 }
118
119
120
121
122 static unsigned char to_uchar (char ch) { return ch; }
123
124 static void _GL_ATTRIBUTE_FORMAT ((__printf__, 1, 2))
125 dbg_printf (char const *msg, ...)
126 {
127 va_list args;
128
129 fputs ("date: ", stderr);
130
131 va_start (args, msg);
132 vfprintf (stderr, msg, args);
133 va_end (args);
134 }
135
136
137
138
139 typedef struct
140 {
141 bool negative;
142 intmax_t value;
143 idx_t digits;
144 } textint;
145
146
147 typedef struct
148 {
149 char const *name;
150 int type;
151 int value;
152 } table;
153
154
155 enum { MERam, MERpm, MER24 };
156
157
158 enum { DBGBUFSIZE = 100 };
159
160 enum { BILLION = 1000000000, LOG10_BILLION = 9 };
161
162
163 typedef struct
164 {
165
166 intmax_t year;
167 intmax_t month;
168 intmax_t day;
169 intmax_t hour;
170 intmax_t minutes;
171 intmax_t seconds;
172 int ns;
173 } relative_time;
174
175 #if HAVE_COMPOUND_LITERALS
176 # define RELATIVE_TIME_0 ((relative_time) { 0, 0, 0, 0, 0, 0, 0 })
177 #else
178 static relative_time const RELATIVE_TIME_0;
179 #endif
180
181
182 typedef struct
183 {
184
185 const char *input;
186
187
188 intmax_t day_ordinal;
189
190
191 int day_number;
192
193
194 int local_isdst;
195
196
197 int time_zone;
198
199
200 int meridian;
201
202
203 textint year;
204 intmax_t month;
205 intmax_t day;
206 intmax_t hour;
207 intmax_t minutes;
208 struct timespec seconds;
209
210
211 relative_time rel;
212
213
214 bool timespec_seen;
215 bool rels_seen;
216 idx_t dates_seen;
217 idx_t days_seen;
218 idx_t local_zones_seen;
219 idx_t dsts_seen;
220 idx_t times_seen;
221 idx_t zones_seen;
222 bool year_seen;
223
224 #ifdef GNULIB_PARSE_DATETIME2
225
226 bool parse_datetime_debug;
227 #endif
228
229
230 bool debug_dates_seen;
231 bool debug_days_seen;
232 bool debug_local_zones_seen;
233 bool debug_times_seen;
234 bool debug_zones_seen;
235 bool debug_year_seen;
236
237
238 bool debug_ordinal_day_seen;
239
240
241 table local_time_zone_table[3];
242 } parser_control;
243
244 static bool
245 debugging (parser_control const *pc)
246 {
247 #ifdef GNULIB_PARSE_DATETIME2
248 return pc->parse_datetime_debug;
249 #else
250 return false;
251 #endif
252 }
253
254 union YYSTYPE;
255 static int yylex (union YYSTYPE *, parser_control *);
256 static int yyerror (parser_control const *, char const *);
257 static bool time_zone_hhmm (parser_control *, textint, intmax_t);
258
259
260
261
262 static void
263 digits_to_date_time (parser_control *pc, textint text_int)
264 {
265 if (pc->dates_seen && ! pc->year.digits
266 && ! pc->rels_seen && (pc->times_seen || 2 < text_int.digits))
267 {
268 pc->year_seen = true;
269 pc->year = text_int;
270 }
271 else
272 {
273 if (4 < text_int.digits)
274 {
275 pc->dates_seen++;
276 pc->day = text_int.value % 100;
277 pc->month = (text_int.value / 100) % 100;
278 pc->year.value = text_int.value / 10000;
279 pc->year.digits = text_int.digits - 4;
280 }
281 else
282 {
283 pc->times_seen++;
284 if (text_int.digits <= 2)
285 {
286 pc->hour = text_int.value;
287 pc->minutes = 0;
288 }
289 else
290 {
291 pc->hour = text_int.value / 100;
292 pc->minutes = text_int.value % 100;
293 }
294 pc->seconds.tv_sec = 0;
295 pc->seconds.tv_nsec = 0;
296 pc->meridian = MER24;
297 }
298 }
299 }
300
301
302
303 static bool
304 apply_relative_time (parser_control *pc, relative_time rel, int factor)
305 {
306 if (factor < 0
307 ? (INT_SUBTRACT_WRAPV (pc->rel.ns, rel.ns, &pc->rel.ns)
308 | INT_SUBTRACT_WRAPV (pc->rel.seconds, rel.seconds, &pc->rel.seconds)
309 | INT_SUBTRACT_WRAPV (pc->rel.minutes, rel.minutes, &pc->rel.minutes)
310 | INT_SUBTRACT_WRAPV (pc->rel.hour, rel.hour, &pc->rel.hour)
311 | INT_SUBTRACT_WRAPV (pc->rel.day, rel.day, &pc->rel.day)
312 | INT_SUBTRACT_WRAPV (pc->rel.month, rel.month, &pc->rel.month)
313 | INT_SUBTRACT_WRAPV (pc->rel.year, rel.year, &pc->rel.year))
314 : (INT_ADD_WRAPV (pc->rel.ns, rel.ns, &pc->rel.ns)
315 | INT_ADD_WRAPV (pc->rel.seconds, rel.seconds, &pc->rel.seconds)
316 | INT_ADD_WRAPV (pc->rel.minutes, rel.minutes, &pc->rel.minutes)
317 | INT_ADD_WRAPV (pc->rel.hour, rel.hour, &pc->rel.hour)
318 | INT_ADD_WRAPV (pc->rel.day, rel.day, &pc->rel.day)
319 | INT_ADD_WRAPV (pc->rel.month, rel.month, &pc->rel.month)
320 | INT_ADD_WRAPV (pc->rel.year, rel.year, &pc->rel.year)))
321 return false;
322 pc->rels_seen = true;
323 return true;
324 }
325
326
327 static void
328 set_hhmmss (parser_control *pc, intmax_t hour, intmax_t minutes,
329 time_t sec, int nsec)
330 {
331 pc->hour = hour;
332 pc->minutes = minutes;
333 pc->seconds.tv_sec = sec;
334 pc->seconds.tv_nsec = nsec;
335 }
336
337
338
339 static const char *
340 str_days (parser_control *pc, char *buffer, int n)
341 {
342
343 static char const ordinal_values[][11] = {
344 "last",
345 "this",
346 "next/first",
347 "(SECOND)",
348 "third",
349 "fourth",
350 "fifth",
351 "sixth",
352 "seventh",
353 "eight",
354 "ninth",
355 "tenth",
356 "eleventh",
357 "twelfth"
358 };
359
360 static char const days_values[][4] = {
361 "Sun",
362 "Mon",
363 "Tue",
364 "Wed",
365 "Thu",
366 "Fri",
367 "Sat"
368 };
369
370 int len;
371
372
373
374 if (pc->debug_ordinal_day_seen)
375 {
376
377 len = (-1 <= pc->day_ordinal && pc->day_ordinal <= 12
378 ? snprintf (buffer, n, "%s", ordinal_values[pc->day_ordinal + 1])
379 : snprintf (buffer, n, "%"PRIdMAX, pc->day_ordinal));
380 }
381 else
382 {
383 buffer[0] = '\0';
384 len = 0;
385 }
386
387
388 if (0 <= pc->day_number && pc->day_number <= 6 && 0 <= len && len < n)
389 snprintf (buffer + len, n - len, &" %s"[len == 0],
390 days_values[pc->day_number]);
391 else
392 {
393
394 }
395 return buffer;
396 }
397
398
399
400 enum { TIME_ZONE_BUFSIZE = INT_STRLEN_BOUND (intmax_t) + sizeof ":MM:SS" } ;
401
402 static char const *
403 time_zone_str (int time_zone, char time_zone_buf[TIME_ZONE_BUFSIZE])
404 {
405 char *p = time_zone_buf;
406 char sign = time_zone < 0 ? '-' : '+';
407 int hour = abs (time_zone / (60 * 60));
408 p += sprintf (time_zone_buf, "%c%02d", sign, hour);
409 int offset_from_hour = abs (time_zone % (60 * 60));
410 if (offset_from_hour != 0)
411 {
412 int mm = offset_from_hour / 60;
413 int ss = offset_from_hour % 60;
414 *p++ = ':';
415 *p++ = '0' + mm / 10;
416 *p++ = '0' + mm % 10;
417 if (ss)
418 {
419 *p++ = ':';
420 *p++ = '0' + ss / 10;
421 *p++ = '0' + ss % 10;
422 }
423 *p = '\0';
424 }
425 return time_zone_buf;
426 }
427
428
429
430
431 static void
432 debug_print_current_time (char const *item, parser_control *pc)
433 {
434 bool space = false;
435
436 if (!debugging (pc))
437 return;
438
439
440 dbg_printf (_("parsed %s part: "), item);
441
442 if (pc->dates_seen && !pc->debug_dates_seen)
443 {
444
445 fprintf (stderr, "(Y-M-D) %04"PRIdMAX"-%02"PRIdMAX"-%02"PRIdMAX,
446 pc->year.value, pc->month, pc->day);
447 pc->debug_dates_seen = true;
448 space = true;
449 }
450
451 if (pc->year_seen != pc->debug_year_seen)
452 {
453 if (space)
454 fputc (' ', stderr);
455 fprintf (stderr, _("year: %04"PRIdMAX), pc->year.value);
456
457 pc->debug_year_seen = pc->year_seen;
458 space = true;
459 }
460
461 if (pc->times_seen && !pc->debug_times_seen)
462 {
463 intmax_t sec = pc->seconds.tv_sec;
464 fprintf (stderr, &" %02"PRIdMAX":%02"PRIdMAX":%02"PRIdMAX[!space],
465 pc->hour, pc->minutes, sec);
466 if (pc->seconds.tv_nsec != 0)
467 {
468 int nsec = pc->seconds.tv_nsec;
469 fprintf (stderr, ".%09d", nsec);
470 }
471 if (pc->meridian == MERpm)
472 fputs ("pm", stderr);
473
474 pc->debug_times_seen = true;
475 space = true;
476 }
477
478 if (pc->days_seen && !pc->debug_days_seen)
479 {
480 if (space)
481 fputc (' ', stderr);
482 char tmp[DBGBUFSIZE];
483 fprintf (stderr, _("%s (day ordinal=%"PRIdMAX" number=%d)"),
484 str_days (pc, tmp, sizeof tmp),
485 pc->day_ordinal, pc->day_number);
486 pc->debug_days_seen = true;
487 space = true;
488 }
489
490
491
492 if (pc->local_zones_seen && !pc->debug_local_zones_seen)
493 {
494 fprintf (stderr, &" isdst=%d%s"[!space],
495 pc->local_isdst, pc->dsts_seen ? " DST" : "");
496 pc->debug_local_zones_seen = true;
497 space = true;
498 }
499
500 if (pc->zones_seen && !pc->debug_zones_seen)
501 {
502 char time_zone_buf[TIME_ZONE_BUFSIZE];
503 fprintf (stderr, &" UTC%s"[!space],
504 time_zone_str (pc->time_zone, time_zone_buf));
505 pc->debug_zones_seen = true;
506 space = true;
507 }
508
509 if (pc->timespec_seen)
510 {
511 intmax_t sec = pc->seconds.tv_sec;
512 if (space)
513 fputc (' ', stderr);
514 fprintf (stderr, _("number of seconds: %"PRIdMAX), sec);
515 }
516
517 fputc ('\n', stderr);
518 }
519
520
521
522 static bool
523 print_rel_part (bool space, intmax_t val, char const *name)
524 {
525 if (val == 0)
526 return space;
527 fprintf (stderr, &" %+"PRIdMAX" %s"[!space], val, name);
528 return true;
529 }
530
531 static void
532 debug_print_relative_time (char const *item, parser_control const *pc)
533 {
534 bool space = false;
535
536 if (!debugging (pc))
537 return;
538
539
540 dbg_printf (_("parsed %s part: "), item);
541
542 if (pc->rel.year == 0 && pc->rel.month == 0 && pc->rel.day == 0
543 && pc->rel.hour == 0 && pc->rel.minutes == 0 && pc->rel.seconds == 0
544 && pc->rel.ns == 0)
545 {
546
547 fputs (_("today/this/now\n"), stderr);
548 return;
549 }
550
551 space = print_rel_part (space, pc->rel.year, "year(s)");
552 space = print_rel_part (space, pc->rel.month, "month(s)");
553 space = print_rel_part (space, pc->rel.day, "day(s)");
554 space = print_rel_part (space, pc->rel.hour, "hour(s)");
555 space = print_rel_part (space, pc->rel.minutes, "minutes");
556 space = print_rel_part (space, pc->rel.seconds, "seconds");
557 print_rel_part (space, pc->rel.ns, "nanoseconds");
558
559 fputc ('\n', stderr);
560 }
561
562
563
564 %}
565
566
567
568 %define api.pure
569 %parse-param { parser_control *pc }
570 %lex-param { parser_control *pc }
571
572
573 %expect 31
574
575 %union
576 {
577 intmax_t intval;
578 textint textintval;
579 struct timespec timespec;
580 relative_time rel;
581 }
582
583 %token <intval> tAGO
584 %token tDST
585
586 %token tYEAR_UNIT tMONTH_UNIT tHOUR_UNIT tMINUTE_UNIT tSEC_UNIT
587 %token <intval> tDAY_UNIT tDAY_SHIFT
588
589 %token <intval> tDAY tDAYZONE tLOCAL_ZONE tMERIDIAN
590 %token <intval> tMONTH tORDINAL tZONE
591
592 %token <textintval> tSNUMBER tUNUMBER
593 %token <timespec> tSDECIMAL_NUMBER tUDECIMAL_NUMBER
594
595 %type <intval> o_colon_minutes
596 %type <timespec> seconds signed_seconds unsigned_seconds
597
598 %type <rel> relunit relunit_snumber dayshift
599
600 %%
601
602 spec:
603 timespec
604 | items
605 ;
606
607 timespec:
608 '@' seconds
609 {
610 pc->seconds = $2;
611 pc->timespec_seen = true;
612 debug_print_current_time (_("number of seconds"), pc);
613 }
614 ;
615
616 items:
617
618 | items item
619 ;
620
621 item:
622 datetime
623 {
624 pc->times_seen++; pc->dates_seen++;
625 debug_print_current_time (_("datetime"), pc);
626 }
627 | time
628 {
629 pc->times_seen++;
630 debug_print_current_time (_("time"), pc);
631 }
632 | local_zone
633 {
634 pc->local_zones_seen++;
635 debug_print_current_time (_("local_zone"), pc);
636 }
637 | zone
638 {
639 pc->zones_seen++;
640 debug_print_current_time (_("zone"), pc);
641 }
642 | date
643 {
644 pc->dates_seen++;
645 debug_print_current_time (_("date"), pc);
646 }
647 | day
648 {
649 pc->days_seen++;
650 debug_print_current_time (_("day"), pc);
651 }
652 | rel
653 {
654 debug_print_relative_time (_("relative"), pc);
655 }
656 | number
657 {
658 debug_print_current_time (_("number"), pc);
659 }
660 | hybrid
661 {
662 debug_print_relative_time (_("hybrid"), pc);
663 }
664 ;
665
666 datetime:
667 iso_8601_datetime
668 ;
669
670 iso_8601_datetime:
671 iso_8601_date 'T' iso_8601_time
672 ;
673
674 time:
675 tUNUMBER tMERIDIAN
676 {
677 set_hhmmss (pc, $1.value, 0, 0, 0);
678 pc->meridian = $2;
679 }
680 | tUNUMBER ':' tUNUMBER tMERIDIAN
681 {
682 set_hhmmss (pc, $1.value, $3.value, 0, 0);
683 pc->meridian = $4;
684 }
685 | tUNUMBER ':' tUNUMBER ':' unsigned_seconds tMERIDIAN
686 {
687 set_hhmmss (pc, $1.value, $3.value, $5.tv_sec, $5.tv_nsec);
688 pc->meridian = $6;
689 }
690 | iso_8601_time
691 ;
692
693 iso_8601_time:
694 tUNUMBER zone_offset
695 {
696 set_hhmmss (pc, $1.value, 0, 0, 0);
697 pc->meridian = MER24;
698 }
699 | tUNUMBER ':' tUNUMBER o_zone_offset
700 {
701 set_hhmmss (pc, $1.value, $3.value, 0, 0);
702 pc->meridian = MER24;
703 }
704 | tUNUMBER ':' tUNUMBER ':' unsigned_seconds o_zone_offset
705 {
706 set_hhmmss (pc, $1.value, $3.value, $5.tv_sec, $5.tv_nsec);
707 pc->meridian = MER24;
708 }
709 ;
710
711 o_zone_offset:
712
713 | zone_offset
714 ;
715
716 zone_offset:
717 tSNUMBER o_colon_minutes
718 {
719 pc->zones_seen++;
720 if (! time_zone_hhmm (pc, $1, $2)) YYABORT;
721 }
722 ;
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741 local_zone:
742 tLOCAL_ZONE
743 { pc->local_isdst = $1; }
744 | tLOCAL_ZONE tDST
745 {
746 pc->local_isdst = 1;
747 pc->dsts_seen++;
748 }
749 ;
750
751
752
753 zone:
754 tZONE
755 { pc->time_zone = $1; }
756 | 'T'
757 { pc->time_zone = -HOUR (7); }
758 | tZONE relunit_snumber
759 { pc->time_zone = $1;
760 if (! apply_relative_time (pc, $2, 1)) YYABORT;
761 debug_print_relative_time (_("relative"), pc);
762 }
763 | 'T' relunit_snumber
764 { pc->time_zone = -HOUR (7);
765 if (! apply_relative_time (pc, $2, 1)) YYABORT;
766 debug_print_relative_time (_("relative"), pc);
767 }
768 | tZONE tSNUMBER o_colon_minutes
769 { if (! time_zone_hhmm (pc, $2, $3)) YYABORT;
770 if (INT_ADD_WRAPV (pc->time_zone, $1, &pc->time_zone)) YYABORT; }
771 | tDAYZONE
772 { pc->time_zone = $1 + 60 * 60; }
773 | tZONE tDST
774 { pc->time_zone = $1 + 60 * 60; }
775 ;
776
777 day:
778 tDAY
779 {
780 pc->day_ordinal = 0;
781 pc->day_number = $1;
782 }
783 | tDAY ','
784 {
785 pc->day_ordinal = 0;
786 pc->day_number = $1;
787 }
788 | tORDINAL tDAY
789 {
790 pc->day_ordinal = $1;
791 pc->day_number = $2;
792 pc->debug_ordinal_day_seen = true;
793 }
794 | tUNUMBER tDAY
795 {
796 pc->day_ordinal = $1.value;
797 pc->day_number = $2;
798 pc->debug_ordinal_day_seen = true;
799 }
800 ;
801
802 date:
803 tUNUMBER '/' tUNUMBER
804 {
805 pc->month = $1.value;
806 pc->day = $3.value;
807 }
808 | tUNUMBER '/' tUNUMBER '/' tUNUMBER
809 {
810
811
812
813
814
815 if (4 <= $1.digits)
816 {
817 if (debugging (pc))
818 {
819 intmax_t digits = $1.digits;
820 dbg_printf (_("warning: value %"PRIdMAX" has %"PRIdMAX" digits. "
821 "Assuming YYYY/MM/DD\n"),
822 $1.value, digits);
823 }
824
825 pc->year = $1;
826 pc->month = $3.value;
827 pc->day = $5.value;
828 }
829 else
830 {
831 if (debugging (pc))
832 dbg_printf (_("warning: value %"PRIdMAX" has less than 4 digits. "
833 "Assuming MM/DD/YY[YY]\n"),
834 $1.value);
835
836 pc->month = $1.value;
837 pc->day = $3.value;
838 pc->year = $5;
839 }
840 }
841 | tUNUMBER tMONTH tSNUMBER
842 {
843
844 pc->day = $1.value;
845 pc->month = $2;
846 if (INT_SUBTRACT_WRAPV (0, $3.value, &pc->year.value)) YYABORT;
847 pc->year.digits = $3.digits;
848 }
849 | tMONTH tSNUMBER tSNUMBER
850 {
851
852 pc->month = $1;
853 if (INT_SUBTRACT_WRAPV (0, $2.value, &pc->day)) YYABORT;
854 if (INT_SUBTRACT_WRAPV (0, $3.value, &pc->year.value)) YYABORT;
855 pc->year.digits = $3.digits;
856 }
857 | tMONTH tUNUMBER
858 {
859 pc->month = $1;
860 pc->day = $2.value;
861 }
862 | tMONTH tUNUMBER ',' tUNUMBER
863 {
864 pc->month = $1;
865 pc->day = $2.value;
866 pc->year = $4;
867 }
868 | tUNUMBER tMONTH
869 {
870 pc->day = $1.value;
871 pc->month = $2;
872 }
873 | tUNUMBER tMONTH tUNUMBER
874 {
875 pc->day = $1.value;
876 pc->month = $2;
877 pc->year = $3;
878 }
879 | iso_8601_date
880 ;
881
882 iso_8601_date:
883 tUNUMBER tSNUMBER tSNUMBER
884 {
885
886 pc->year = $1;
887 if (INT_SUBTRACT_WRAPV (0, $2.value, &pc->month)) YYABORT;
888 if (INT_SUBTRACT_WRAPV (0, $3.value, &pc->day)) YYABORT;
889 }
890 ;
891
892 rel:
893 relunit tAGO
894 { if (! apply_relative_time (pc, $1, $2)) YYABORT; }
895 | relunit
896 { if (! apply_relative_time (pc, $1, 1)) YYABORT; }
897 | dayshift
898 { if (! apply_relative_time (pc, $1, 1)) YYABORT; }
899 ;
900
901 relunit:
902 tORDINAL tYEAR_UNIT
903 { $$ = RELATIVE_TIME_0; $$.year = $1; }
904 | tUNUMBER tYEAR_UNIT
905 { $$ = RELATIVE_TIME_0; $$.year = $1.value; }
906 | tYEAR_UNIT
907 { $$ = RELATIVE_TIME_0; $$.year = 1; }
908 | tORDINAL tMONTH_UNIT
909 { $$ = RELATIVE_TIME_0; $$.month = $1; }
910 | tUNUMBER tMONTH_UNIT
911 { $$ = RELATIVE_TIME_0; $$.month = $1.value; }
912 | tMONTH_UNIT
913 { $$ = RELATIVE_TIME_0; $$.month = 1; }
914 | tORDINAL tDAY_UNIT
915 { $$ = RELATIVE_TIME_0;
916 if (INT_MULTIPLY_WRAPV ($1, $2, &$$.day)) YYABORT; }
917 | tUNUMBER tDAY_UNIT
918 { $$ = RELATIVE_TIME_0;
919 if (INT_MULTIPLY_WRAPV ($1.value, $2, &$$.day)) YYABORT; }
920 | tDAY_UNIT
921 { $$ = RELATIVE_TIME_0; $$.day = $1; }
922 | tORDINAL tHOUR_UNIT
923 { $$ = RELATIVE_TIME_0; $$.hour = $1; }
924 | tUNUMBER tHOUR_UNIT
925 { $$ = RELATIVE_TIME_0; $$.hour = $1.value; }
926 | tHOUR_UNIT
927 { $$ = RELATIVE_TIME_0; $$.hour = 1; }
928 | tORDINAL tMINUTE_UNIT
929 { $$ = RELATIVE_TIME_0; $$.minutes = $1; }
930 | tUNUMBER tMINUTE_UNIT
931 { $$ = RELATIVE_TIME_0; $$.minutes = $1.value; }
932 | tMINUTE_UNIT
933 { $$ = RELATIVE_TIME_0; $$.minutes = 1; }
934 | tORDINAL tSEC_UNIT
935 { $$ = RELATIVE_TIME_0; $$.seconds = $1; }
936 | tUNUMBER tSEC_UNIT
937 { $$ = RELATIVE_TIME_0; $$.seconds = $1.value; }
938 | tSDECIMAL_NUMBER tSEC_UNIT
939 { $$ = RELATIVE_TIME_0; $$.seconds = $1.tv_sec; $$.ns = $1.tv_nsec; }
940 | tUDECIMAL_NUMBER tSEC_UNIT
941 { $$ = RELATIVE_TIME_0; $$.seconds = $1.tv_sec; $$.ns = $1.tv_nsec; }
942 | tSEC_UNIT
943 { $$ = RELATIVE_TIME_0; $$.seconds = 1; }
944 | relunit_snumber
945 ;
946
947 relunit_snumber:
948 tSNUMBER tYEAR_UNIT
949 { $$ = RELATIVE_TIME_0; $$.year = $1.value; }
950 | tSNUMBER tMONTH_UNIT
951 { $$ = RELATIVE_TIME_0; $$.month = $1.value; }
952 | tSNUMBER tDAY_UNIT
953 { $$ = RELATIVE_TIME_0;
954 if (INT_MULTIPLY_WRAPV ($1.value, $2, &$$.day)) YYABORT; }
955 | tSNUMBER tHOUR_UNIT
956 { $$ = RELATIVE_TIME_0; $$.hour = $1.value; }
957 | tSNUMBER tMINUTE_UNIT
958 { $$ = RELATIVE_TIME_0; $$.minutes = $1.value; }
959 | tSNUMBER tSEC_UNIT
960 { $$ = RELATIVE_TIME_0; $$.seconds = $1.value; }
961 ;
962
963 dayshift:
964 tDAY_SHIFT
965 { $$ = RELATIVE_TIME_0; $$.day = $1; }
966 ;
967
968 seconds: signed_seconds | unsigned_seconds;
969
970 signed_seconds:
971 tSDECIMAL_NUMBER
972 | tSNUMBER
973 { if (time_overflow ($1.value)) YYABORT;
974 $$.tv_sec = $1.value; $$.tv_nsec = 0; }
975 ;
976
977 unsigned_seconds:
978 tUDECIMAL_NUMBER
979 | tUNUMBER
980 { if (time_overflow ($1.value)) YYABORT;
981 $$.tv_sec = $1.value; $$.tv_nsec = 0; }
982 ;
983
984 number:
985 tUNUMBER
986 { digits_to_date_time (pc, $1); }
987 ;
988
989 hybrid:
990 tUNUMBER relunit_snumber
991 {
992
993
994 digits_to_date_time (pc, $1);
995 if (! apply_relative_time (pc, $2, 1)) YYABORT;
996 }
997 ;
998
999 o_colon_minutes:
1000
1001 { $$ = -1; }
1002 | ':' tUNUMBER
1003 { $$ = $2.value; }
1004 ;
1005
1006 %%
1007
1008 static table const meridian_table[] =
1009 {
1010 { "AM", tMERIDIAN, MERam },
1011 { "A.M.", tMERIDIAN, MERam },
1012 { "PM", tMERIDIAN, MERpm },
1013 { "P.M.", tMERIDIAN, MERpm },
1014 { NULL, 0, 0 }
1015 };
1016
1017 static table const dst_table[] =
1018 {
1019 { "DST", tDST, 0 }
1020 };
1021
1022 static table const month_and_day_table[] =
1023 {
1024 { "JANUARY", tMONTH, 1 },
1025 { "FEBRUARY", tMONTH, 2 },
1026 { "MARCH", tMONTH, 3 },
1027 { "APRIL", tMONTH, 4 },
1028 { "MAY", tMONTH, 5 },
1029 { "JUNE", tMONTH, 6 },
1030 { "JULY", tMONTH, 7 },
1031 { "AUGUST", tMONTH, 8 },
1032 { "SEPTEMBER",tMONTH, 9 },
1033 { "SEPT", tMONTH, 9 },
1034 { "OCTOBER", tMONTH, 10 },
1035 { "NOVEMBER", tMONTH, 11 },
1036 { "DECEMBER", tMONTH, 12 },
1037 { "SUNDAY", tDAY, 0 },
1038 { "MONDAY", tDAY, 1 },
1039 { "TUESDAY", tDAY, 2 },
1040 { "TUES", tDAY, 2 },
1041 { "WEDNESDAY",tDAY, 3 },
1042 { "WEDNES", tDAY, 3 },
1043 { "THURSDAY", tDAY, 4 },
1044 { "THUR", tDAY, 4 },
1045 { "THURS", tDAY, 4 },
1046 { "FRIDAY", tDAY, 5 },
1047 { "SATURDAY", tDAY, 6 },
1048 { NULL, 0, 0 }
1049 };
1050
1051 static table const time_units_table[] =
1052 {
1053 { "YEAR", tYEAR_UNIT, 1 },
1054 { "MONTH", tMONTH_UNIT, 1 },
1055 { "FORTNIGHT",tDAY_UNIT, 14 },
1056 { "WEEK", tDAY_UNIT, 7 },
1057 { "DAY", tDAY_UNIT, 1 },
1058 { "HOUR", tHOUR_UNIT, 1 },
1059 { "MINUTE", tMINUTE_UNIT, 1 },
1060 { "MIN", tMINUTE_UNIT, 1 },
1061 { "SECOND", tSEC_UNIT, 1 },
1062 { "SEC", tSEC_UNIT, 1 },
1063 { NULL, 0, 0 }
1064 };
1065
1066
1067 static table const relative_time_table[] =
1068 {
1069 { "TOMORROW", tDAY_SHIFT, 1 },
1070 { "YESTERDAY",tDAY_SHIFT, -1 },
1071 { "TODAY", tDAY_SHIFT, 0 },
1072 { "NOW", tDAY_SHIFT, 0 },
1073 { "LAST", tORDINAL, -1 },
1074 { "THIS", tORDINAL, 0 },
1075 { "NEXT", tORDINAL, 1 },
1076 { "FIRST", tORDINAL, 1 },
1077
1078 { "THIRD", tORDINAL, 3 },
1079 { "FOURTH", tORDINAL, 4 },
1080 { "FIFTH", tORDINAL, 5 },
1081 { "SIXTH", tORDINAL, 6 },
1082 { "SEVENTH", tORDINAL, 7 },
1083 { "EIGHTH", tORDINAL, 8 },
1084 { "NINTH", tORDINAL, 9 },
1085 { "TENTH", tORDINAL, 10 },
1086 { "ELEVENTH", tORDINAL, 11 },
1087 { "TWELFTH", tORDINAL, 12 },
1088 { "AGO", tAGO, -1 },
1089 { "HENCE", tAGO, 1 },
1090 { NULL, 0, 0 }
1091 };
1092
1093
1094
1095
1096 static table const universal_time_zone_table[] =
1097 {
1098 { "GMT", tZONE, HOUR ( 0) },
1099 { "UT", tZONE, HOUR ( 0) },
1100 { "UTC", tZONE, HOUR ( 0) },
1101 { NULL, 0, 0 }
1102 };
1103
1104
1105
1106
1107
1108
1109 static table const time_zone_table[] =
1110 {
1111 { "WET", tZONE, HOUR ( 0) },
1112 { "WEST", tDAYZONE, HOUR ( 0) },
1113 { "BST", tDAYZONE, HOUR ( 0) },
1114 { "ART", tZONE, -HOUR ( 3) },
1115 { "BRT", tZONE, -HOUR ( 3) },
1116 { "BRST", tDAYZONE, -HOUR ( 3) },
1117 { "NST", tZONE, -(HOUR ( 3) + 30 * 60) },
1118 { "NDT", tDAYZONE,-(HOUR ( 3) + 30 * 60) },
1119 { "AST", tZONE, -HOUR ( 4) },
1120 { "ADT", tDAYZONE, -HOUR ( 4) },
1121 { "CLT", tZONE, -HOUR ( 4) },
1122 { "CLST", tDAYZONE, -HOUR ( 4) },
1123 { "EST", tZONE, -HOUR ( 5) },
1124 { "EDT", tDAYZONE, -HOUR ( 5) },
1125 { "CST", tZONE, -HOUR ( 6) },
1126 { "CDT", tDAYZONE, -HOUR ( 6) },
1127 { "MST", tZONE, -HOUR ( 7) },
1128 { "MDT", tDAYZONE, -HOUR ( 7) },
1129 { "PST", tZONE, -HOUR ( 8) },
1130 { "PDT", tDAYZONE, -HOUR ( 8) },
1131 { "AKST", tZONE, -HOUR ( 9) },
1132 { "AKDT", tDAYZONE, -HOUR ( 9) },
1133 { "HST", tZONE, -HOUR (10) },
1134 { "HAST", tZONE, -HOUR (10) },
1135 { "HADT", tDAYZONE, -HOUR (10) },
1136 { "SST", tZONE, -HOUR (12) },
1137 { "WAT", tZONE, HOUR ( 1) },
1138 { "CET", tZONE, HOUR ( 1) },
1139 { "CEST", tDAYZONE, HOUR ( 1) },
1140 { "MET", tZONE, HOUR ( 1) },
1141 { "MEZ", tZONE, HOUR ( 1) },
1142 { "MEST", tDAYZONE, HOUR ( 1) },
1143 { "MESZ", tDAYZONE, HOUR ( 1) },
1144 { "EET", tZONE, HOUR ( 2) },
1145 { "EEST", tDAYZONE, HOUR ( 2) },
1146 { "CAT", tZONE, HOUR ( 2) },
1147 { "SAST", tZONE, HOUR ( 2) },
1148 { "EAT", tZONE, HOUR ( 3) },
1149 { "MSK", tZONE, HOUR ( 3) },
1150 { "MSD", tDAYZONE, HOUR ( 3) },
1151 { "IST", tZONE, (HOUR ( 5) + 30 * 60) },
1152 { "SGT", tZONE, HOUR ( 8) },
1153 { "KST", tZONE, HOUR ( 9) },
1154 { "JST", tZONE, HOUR ( 9) },
1155 { "GST", tZONE, HOUR (10) },
1156 { "NZST", tZONE, HOUR (12) },
1157 { "NZDT", tDAYZONE, HOUR (12) },
1158 { NULL, 0, 0 }
1159 };
1160
1161
1162
1163
1164
1165
1166
1167
1168 static table const military_table[] =
1169 {
1170 { "A", tZONE, HOUR ( 1) },
1171 { "B", tZONE, HOUR ( 2) },
1172 { "C", tZONE, HOUR ( 3) },
1173 { "D", tZONE, HOUR ( 4) },
1174 { "E", tZONE, HOUR ( 5) },
1175 { "F", tZONE, HOUR ( 6) },
1176 { "G", tZONE, HOUR ( 7) },
1177 { "H", tZONE, HOUR ( 8) },
1178 { "I", tZONE, HOUR ( 9) },
1179 { "K", tZONE, HOUR (10) },
1180 { "L", tZONE, HOUR (11) },
1181 { "M", tZONE, HOUR (12) },
1182 { "N", tZONE, -HOUR ( 1) },
1183 { "O", tZONE, -HOUR ( 2) },
1184 { "P", tZONE, -HOUR ( 3) },
1185 { "Q", tZONE, -HOUR ( 4) },
1186 { "R", tZONE, -HOUR ( 5) },
1187 { "S", tZONE, -HOUR ( 6) },
1188 { "T", 'T', 0 },
1189 { "U", tZONE, -HOUR ( 8) },
1190 { "V", tZONE, -HOUR ( 9) },
1191 { "W", tZONE, -HOUR (10) },
1192 { "X", tZONE, -HOUR (11) },
1193 { "Y", tZONE, -HOUR (12) },
1194 { "Z", tZONE, HOUR ( 0) },
1195 { NULL, 0, 0 }
1196 };
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207 static bool
1208 time_zone_hhmm (parser_control *pc, textint s, intmax_t mm)
1209 {
1210 intmax_t n_minutes;
1211 bool overflow = false;
1212
1213
1214
1215 if (s.digits <= 2 && mm < 0)
1216 s.value *= 100;
1217
1218 if (mm < 0)
1219 n_minutes = (s.value / 100) * 60 + s.value % 100;
1220 else
1221 {
1222 overflow |= INT_MULTIPLY_WRAPV (s.value, 60, &n_minutes);
1223 overflow |= (s.negative
1224 ? INT_SUBTRACT_WRAPV (n_minutes, mm, &n_minutes)
1225 : INT_ADD_WRAPV (n_minutes, mm, &n_minutes));
1226 }
1227
1228 if (overflow || ! (-24 * 60 <= n_minutes && n_minutes <= 24 * 60))
1229 return false;
1230 pc->time_zone = n_minutes * 60;
1231 return true;
1232 }
1233
1234 static int
1235 to_hour (intmax_t hours, int meridian)
1236 {
1237 switch (meridian)
1238 {
1239 default:
1240 case MER24:
1241 return 0 <= hours && hours < 24 ? hours : -1;
1242 case MERam:
1243 return 0 < hours && hours < 12 ? hours : hours == 12 ? 0 : -1;
1244 case MERpm:
1245 return 0 < hours && hours < 12 ? hours + 12 : hours == 12 ? 12 : -1;
1246 }
1247 }
1248
1249 enum { TM_YEAR_BASE = 1900 };
1250 enum { TM_YEAR_BUFSIZE = INT_BUFSIZE_BOUND (int) + 1 };
1251
1252
1253
1254
1255 static char const *
1256 tm_year_str (int tm_year, char buf[TM_YEAR_BUFSIZE])
1257 {
1258 verify (TM_YEAR_BASE % 100 == 0);
1259 sprintf (buf, &"-%02d%02d"[-TM_YEAR_BASE <= tm_year],
1260 abs (tm_year / 100 + TM_YEAR_BASE / 100),
1261 abs (tm_year % 100));
1262 return buf;
1263 }
1264
1265
1266
1267
1268 static bool
1269 to_tm_year (textint textyear, bool debug, int *tm_year)
1270 {
1271 intmax_t year = textyear.value;
1272
1273
1274
1275 if (0 <= year && textyear.digits == 2)
1276 {
1277 year += year < 69 ? 2000 : 1900;
1278 if (debug)
1279 dbg_printf (_("warning: adjusting year value %"PRIdMAX
1280 " to %"PRIdMAX"\n"),
1281 textyear.value, year);
1282 }
1283
1284 if (year < 0
1285 ? INT_SUBTRACT_WRAPV (-TM_YEAR_BASE, year, tm_year)
1286 : INT_SUBTRACT_WRAPV (year, TM_YEAR_BASE, tm_year))
1287 {
1288 if (debug)
1289 dbg_printf (_("error: out-of-range year %"PRIdMAX"\n"), year);
1290 return false;
1291 }
1292
1293 return true;
1294 }
1295
1296 static table const * _GL_ATTRIBUTE_PURE
1297 lookup_zone (parser_control const *pc, char const *name)
1298 {
1299 table const *tp;
1300
1301 for (tp = universal_time_zone_table; tp->name; tp++)
1302 if (strcmp (name, tp->name) == 0)
1303 return tp;
1304
1305
1306
1307 for (tp = pc->local_time_zone_table; tp->name; tp++)
1308 if (strcmp (name, tp->name) == 0)
1309 return tp;
1310
1311 for (tp = time_zone_table; tp->name; tp++)
1312 if (strcmp (name, tp->name) == 0)
1313 return tp;
1314
1315 return NULL;
1316 }
1317
1318 #if ! HAVE_TM_GMTOFF
1319
1320
1321
1322
1323 static int
1324 tm_diff (const struct tm *a, const struct tm *b)
1325 {
1326
1327
1328
1329 int a4 = SHR (a->tm_year, 2) + SHR (TM_YEAR_BASE, 2) - ! (a->tm_year & 3);
1330 int b4 = SHR (b->tm_year, 2) + SHR (TM_YEAR_BASE, 2) - ! (b->tm_year & 3);
1331 int a100 = a4 / 25 - (a4 % 25 < 0);
1332 int b100 = b4 / 25 - (b4 % 25 < 0);
1333 int a400 = SHR (a100, 2);
1334 int b400 = SHR (b100, 2);
1335 int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
1336 int years = a->tm_year - b->tm_year;
1337 int days = (365 * years + intervening_leap_days
1338 + (a->tm_yday - b->tm_yday));
1339 return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
1340 + (a->tm_min - b->tm_min))
1341 + (a->tm_sec - b->tm_sec));
1342 }
1343 #endif
1344
1345 static table const *
1346 lookup_word (parser_control const *pc, char *word)
1347 {
1348 char *p;
1349 char *q;
1350 idx_t wordlen;
1351 table const *tp;
1352 bool period_found;
1353 bool abbrev;
1354
1355
1356 for (p = word; *p; p++)
1357 *p = c_toupper (to_uchar (*p));
1358
1359 for (tp = meridian_table; tp->name; tp++)
1360 if (strcmp (word, tp->name) == 0)
1361 return tp;
1362
1363
1364 wordlen = strlen (word);
1365 abbrev = wordlen == 3 || (wordlen == 4 && word[3] == '.');
1366
1367 for (tp = month_and_day_table; tp->name; tp++)
1368 if ((abbrev ? strncmp (word, tp->name, 3) : strcmp (word, tp->name)) == 0)
1369 return tp;
1370
1371 if ((tp = lookup_zone (pc, word)))
1372 return tp;
1373
1374 if (strcmp (word, dst_table[0].name) == 0)
1375 return dst_table;
1376
1377 for (tp = time_units_table; tp->name; tp++)
1378 if (strcmp (word, tp->name) == 0)
1379 return tp;
1380
1381
1382 if (word[wordlen - 1] == 'S')
1383 {
1384 word[wordlen - 1] = '\0';
1385 for (tp = time_units_table; tp->name; tp++)
1386 if (strcmp (word, tp->name) == 0)
1387 return tp;
1388 word[wordlen - 1] = 'S';
1389 }
1390
1391 for (tp = relative_time_table; tp->name; tp++)
1392 if (strcmp (word, tp->name) == 0)
1393 return tp;
1394
1395
1396 if (wordlen == 1)
1397 for (tp = military_table; tp->name; tp++)
1398 if (word[0] == tp->name[0])
1399 return tp;
1400
1401
1402 for (period_found = false, p = q = word; (*p = *q); q++)
1403 if (*q == '.')
1404 period_found = true;
1405 else
1406 p++;
1407 if (period_found && (tp = lookup_zone (pc, word)))
1408 return tp;
1409
1410 return NULL;
1411 }
1412
1413 static int
1414 yylex (union YYSTYPE *lvalp, parser_control *pc)
1415 {
1416 unsigned char c;
1417
1418 for (;;)
1419 {
1420 while (c = *pc->input, c_isspace (c))
1421 pc->input++;
1422
1423 if (c_isdigit (c) || c == '-' || c == '+')
1424 {
1425 char const *p = pc->input;
1426 int sign;
1427 if (c == '-' || c == '+')
1428 {
1429 sign = c == '-' ? -1 : 1;
1430 while (c = *(pc->input = ++p), c_isspace (c))
1431 continue;
1432 if (! c_isdigit (c))
1433
1434 continue;
1435 }
1436 else
1437 sign = 0;
1438
1439 time_t value = 0;
1440 do
1441 {
1442 if (INT_MULTIPLY_WRAPV (value, 10, &value))
1443 return '?';
1444 if (INT_ADD_WRAPV (value, sign < 0 ? '0' - c : c - '0', &value))
1445 return '?';
1446 c = *++p;
1447 }
1448 while (c_isdigit (c));
1449
1450 if ((c == '.' || c == ',') && c_isdigit (p[1]))
1451 {
1452 time_t s = value;
1453 int digits;
1454
1455
1456 p++;
1457 int ns = *p++ - '0';
1458 for (digits = 2; digits <= LOG10_BILLION; digits++)
1459 {
1460 ns *= 10;
1461 if (c_isdigit (*p))
1462 ns += *p++ - '0';
1463 }
1464
1465
1466 if (sign < 0)
1467 for (; c_isdigit (*p); p++)
1468 if (*p != '0')
1469 {
1470 ns++;
1471 break;
1472 }
1473 while (c_isdigit (*p))
1474 p++;
1475
1476
1477
1478
1479 if (sign < 0 && ns)
1480 {
1481 if (INT_SUBTRACT_WRAPV (s, 1, &s))
1482 return '?';
1483 ns = BILLION - ns;
1484 }
1485
1486 lvalp->timespec.tv_sec = s;
1487 lvalp->timespec.tv_nsec = ns;
1488 pc->input = p;
1489 return sign ? tSDECIMAL_NUMBER : tUDECIMAL_NUMBER;
1490 }
1491 else
1492 {
1493 lvalp->textintval.negative = sign < 0;
1494 lvalp->textintval.value = value;
1495 lvalp->textintval.digits = p - pc->input;
1496 pc->input = p;
1497 return sign ? tSNUMBER : tUNUMBER;
1498 }
1499 }
1500
1501 if (c_isalpha (c))
1502 {
1503 char buff[20];
1504 char *p = buff;
1505 table const *tp;
1506
1507 do
1508 {
1509 if (p < buff + sizeof buff - 1)
1510 *p++ = c;
1511 c = *++pc->input;
1512 }
1513 while (c_isalpha (c) || c == '.');
1514
1515 *p = '\0';
1516 tp = lookup_word (pc, buff);
1517 if (! tp)
1518 {
1519 if (debugging (pc))
1520 dbg_printf (_("error: unknown word '%s'\n"), buff);
1521 return '?';
1522 }
1523 lvalp->intval = tp->value;
1524 return tp->type;
1525 }
1526
1527 if (c != '(')
1528 return to_uchar (*pc->input++);
1529
1530 idx_t count = 0;
1531 do
1532 {
1533 c = *pc->input++;
1534 if (c == '\0')
1535 return c;
1536 if (c == '(')
1537 count++;
1538 else if (c == ')')
1539 count--;
1540 }
1541 while (count != 0);
1542 }
1543 }
1544
1545
1546 static int
1547 yyerror (_GL_UNUSED parser_control const *pc,
1548 _GL_UNUSED char const *s)
1549 {
1550 return 0;
1551 }
1552
1553
1554
1555
1556
1557
1558
1559 static bool
1560 mktime_ok (struct tm const *tm0, struct tm const *tm1)
1561 {
1562 if (tm1->tm_wday < 0)
1563 return false;
1564
1565 return ! ((tm0->tm_sec ^ tm1->tm_sec)
1566 | (tm0->tm_min ^ tm1->tm_min)
1567 | (tm0->tm_hour ^ tm1->tm_hour)
1568 | (tm0->tm_mday ^ tm1->tm_mday)
1569 | (tm0->tm_mon ^ tm1->tm_mon)
1570 | (tm0->tm_year ^ tm1->tm_year));
1571 }
1572
1573
1574
1575 static char const *
1576 debug_strfdatetime (struct tm const *tm, parser_control const *pc,
1577 char *buf, int n)
1578 {
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602 int m = nstrftime (buf, n, "(Y-M-D) %Y-%m-%d %H:%M:%S", tm, 0, 0);
1603
1604
1605
1606 if (pc && m < n && pc->zones_seen)
1607 {
1608 int tz = pc->time_zone;
1609
1610
1611 if (pc->local_zones_seen && !pc->zones_seen && 0 < pc->local_isdst)
1612 tz += 60 * 60;
1613
1614 char time_zone_buf[TIME_ZONE_BUFSIZE];
1615 snprintf (&buf[m], n - m, " TZ=%s", time_zone_str (tz, time_zone_buf));
1616 }
1617 return buf;
1618 }
1619
1620 static char const *
1621 debug_strfdate (struct tm const *tm, char *buf, int n)
1622 {
1623 char tm_year_buf[TM_YEAR_BUFSIZE];
1624 snprintf (buf, n, "(Y-M-D) %s-%02d-%02d",
1625 tm_year_str (tm->tm_year, tm_year_buf),
1626 tm->tm_mon + 1, tm->tm_mday);
1627 return buf;
1628 }
1629
1630 static char const *
1631 debug_strftime (struct tm const *tm, char *buf, int n)
1632 {
1633 snprintf (buf, n, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec);
1634 return buf;
1635 }
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649 static void
1650 debug_mktime_not_ok (struct tm const *tm0, struct tm const *tm1,
1651 parser_control const *pc, bool time_zone_seen)
1652 {
1653
1654 char tmp[DBGBUFSIZE];
1655 int i;
1656 const bool eq_sec = (tm0->tm_sec == tm1->tm_sec);
1657 const bool eq_min = (tm0->tm_min == tm1->tm_min);
1658 const bool eq_hour = (tm0->tm_hour == tm1->tm_hour);
1659 const bool eq_mday = (tm0->tm_mday == tm1->tm_mday);
1660 const bool eq_month = (tm0->tm_mon == tm1->tm_mon);
1661 const bool eq_year = (tm0->tm_year == tm1->tm_year);
1662
1663 const bool dst_shift = eq_sec && eq_min && !eq_hour
1664 && eq_mday && eq_month && eq_year;
1665
1666 if (!debugging (pc))
1667 return;
1668
1669 dbg_printf (_("error: invalid date/time value:\n"));
1670 dbg_printf (_(" user provided time: '%s'\n"),
1671 debug_strfdatetime (tm0, pc, tmp, sizeof tmp));
1672 dbg_printf (_(" normalized time: '%s'\n"),
1673 debug_strfdatetime (tm1, pc, tmp, sizeof tmp));
1674
1675
1676 i = snprintf (tmp, sizeof tmp,
1677 " %4s %2s %2s %2s %2s %2s",
1678 eq_year ? "" : "----",
1679 eq_month ? "" : "--",
1680 eq_mday ? "" : "--",
1681 eq_hour ? "" : "--",
1682 eq_min ? "" : "--",
1683 eq_sec ? "" : "--");
1684
1685 if (0 <= i)
1686 {
1687 if (sizeof tmp - 1 < i)
1688 i = sizeof tmp - 1;
1689 while (0 < i && tmp[i - 1] == ' ')
1690 --i;
1691 tmp[i] = '\0';
1692 }
1693 dbg_printf ("%s\n", tmp);
1694
1695 dbg_printf (_(" possible reasons:\n"));
1696 if (dst_shift)
1697 dbg_printf (_(" non-existing due to daylight-saving time;\n"));
1698 if (!eq_mday && !eq_month)
1699 dbg_printf (_(" invalid day/month combination;\n"));
1700 dbg_printf (_(" numeric values overflow;\n"));
1701 dbg_printf (" %s\n", (time_zone_seen ? _("incorrect timezone")
1702 : _("missing timezone")));
1703 }
1704
1705
1706
1707
1708
1709
1710 static bool
1711 parse_datetime_body (struct timespec *result, char const *p,
1712 struct timespec const *now, unsigned int flags,
1713 timezone_t tzdefault, char const *tzstring)
1714 {
1715 struct tm tm;
1716 struct tm tm0;
1717 char time_zone_buf[TIME_ZONE_BUFSIZE];
1718 char dbg_tm[DBGBUFSIZE];
1719 bool ok = false;
1720 char const *input_sentinel = p + strlen (p);
1721 char *tz1alloc = NULL;
1722
1723
1724
1725 enum { TZBUFSIZE = 100 };
1726 char tz1buf[TZBUFSIZE];
1727
1728 struct timespec gettime_buffer;
1729 if (! now)
1730 {
1731 gettime (&gettime_buffer);
1732 now = &gettime_buffer;
1733 }
1734
1735 time_t Start = now->tv_sec;
1736 int Start_ns = now->tv_nsec;
1737
1738 unsigned char c;
1739 while (c = *p, c_isspace (c))
1740 p++;
1741
1742 timezone_t tz = tzdefault;
1743
1744
1745
1746
1747 const relative_time rel_time_0 = RELATIVE_TIME_0;
1748
1749 if (strncmp (p, "TZ=\"", 4) == 0)
1750 {
1751 char const *tzbase = p + 4;
1752 idx_t tzsize = 1;
1753 char const *s;
1754
1755 for (s = tzbase; *s; s++, tzsize++)
1756 if (*s == '\\')
1757 {
1758 s++;
1759 if (! (*s == '\\' || *s == '"'))
1760 break;
1761 }
1762 else if (*s == '"')
1763 {
1764 timezone_t tz1;
1765 char *tz1string = tz1buf;
1766 char *z;
1767 if (TZBUFSIZE < tzsize)
1768 {
1769 tz1alloc = malloc (tzsize);
1770 if (!tz1alloc)
1771 goto fail;
1772 tz1string = tz1alloc;
1773 }
1774 z = tz1string;
1775 for (s = tzbase; *s != '"'; s++)
1776 *z++ = *(s += *s == '\\');
1777 *z = '\0';
1778 tz1 = tzalloc (tz1string);
1779 if (!tz1)
1780 goto fail;
1781 tz = tz1;
1782 tzstring = tz1string;
1783
1784 p = s + 1;
1785 while (c = *p, c_isspace (c))
1786 p++;
1787
1788 break;
1789 }
1790 }
1791
1792 struct tm tmp;
1793 if (! localtime_rz (tz, &now->tv_sec, &tmp))
1794 goto fail;
1795
1796
1797
1798
1799 if (*p == '\0')
1800 p = "0";
1801
1802 parser_control pc;
1803 pc.input = p;
1804 #ifdef GNULIB_PARSE_DATETIME2
1805 pc.parse_datetime_debug = (flags & PARSE_DATETIME_DEBUG) != 0;
1806 #endif
1807 if (INT_ADD_WRAPV (tmp.tm_year, TM_YEAR_BASE, &pc.year.value))
1808 {
1809 if (debugging (&pc))
1810 dbg_printf (_("error: initial year out of range\n"));
1811 goto fail;
1812 }
1813 pc.year.digits = 0;
1814 pc.month = tmp.tm_mon + 1;
1815 pc.day = tmp.tm_mday;
1816 pc.hour = tmp.tm_hour;
1817 pc.minutes = tmp.tm_min;
1818 pc.seconds.tv_sec = tmp.tm_sec;
1819 pc.seconds.tv_nsec = Start_ns;
1820 tm.tm_isdst = tmp.tm_isdst;
1821
1822 pc.meridian = MER24;
1823 pc.rel = rel_time_0;
1824 pc.timespec_seen = false;
1825 pc.rels_seen = false;
1826 pc.dates_seen = 0;
1827 pc.days_seen = 0;
1828 pc.times_seen = 0;
1829 pc.local_zones_seen = 0;
1830 pc.dsts_seen = 0;
1831 pc.zones_seen = 0;
1832 pc.year_seen = false;
1833 pc.debug_dates_seen = false;
1834 pc.debug_days_seen = false;
1835 pc.debug_times_seen = false;
1836 pc.debug_local_zones_seen = false;
1837 pc.debug_zones_seen = false;
1838 pc.debug_year_seen = false;
1839 pc.debug_ordinal_day_seen = false;
1840
1841 #if HAVE_STRUCT_TM_TM_ZONE
1842 pc.local_time_zone_table[0].name = tmp.tm_zone;
1843 pc.local_time_zone_table[0].type = tLOCAL_ZONE;
1844 pc.local_time_zone_table[0].value = tmp.tm_isdst;
1845 pc.local_time_zone_table[1].name = NULL;
1846
1847
1848
1849 {
1850 int quarter;
1851 for (quarter = 1; quarter <= 3; quarter++)
1852 {
1853 time_t probe;
1854 if (INT_ADD_WRAPV (Start, quarter * (90 * 24 * 60 * 60), &probe))
1855 break;
1856 struct tm probe_tm;
1857 if (localtime_rz (tz, &probe, &probe_tm) && probe_tm.tm_zone
1858 && probe_tm.tm_isdst != pc.local_time_zone_table[0].value)
1859 {
1860 {
1861 pc.local_time_zone_table[1].name = probe_tm.tm_zone;
1862 pc.local_time_zone_table[1].type = tLOCAL_ZONE;
1863 pc.local_time_zone_table[1].value = probe_tm.tm_isdst;
1864 pc.local_time_zone_table[2].name = NULL;
1865 }
1866 break;
1867 }
1868 }
1869 }
1870 #else
1871 #if HAVE_TZNAME
1872 {
1873 # if !HAVE_DECL_TZNAME
1874 extern char *tzname[];
1875 # endif
1876 int i;
1877 for (i = 0; i < 2; i++)
1878 {
1879 pc.local_time_zone_table[i].name = tzname[i];
1880 pc.local_time_zone_table[i].type = tLOCAL_ZONE;
1881 pc.local_time_zone_table[i].value = i;
1882 }
1883 pc.local_time_zone_table[i].name = NULL;
1884 }
1885 #else
1886 pc.local_time_zone_table[0].name = NULL;
1887 #endif
1888 #endif
1889
1890 if (pc.local_time_zone_table[0].name && pc.local_time_zone_table[1].name
1891 && ! strcmp (pc.local_time_zone_table[0].name,
1892 pc.local_time_zone_table[1].name))
1893 {
1894
1895
1896
1897 pc.local_time_zone_table[0].value = -1;
1898 pc.local_time_zone_table[1].name = NULL;
1899 }
1900
1901 if (yyparse (&pc) != 0)
1902 {
1903 if (debugging (&pc))
1904 dbg_printf ((input_sentinel <= pc.input
1905 ? _("error: parsing failed\n")
1906 : _("error: parsing failed, stopped at '%s'\n")),
1907 pc.input);
1908 goto fail;
1909 }
1910
1911
1912
1913
1914 if (debugging (&pc))
1915 {
1916 dbg_printf (_("input timezone: "));
1917
1918 if (pc.timespec_seen)
1919 fprintf (stderr, _("'@timespec' - always UTC"));
1920 else if (pc.zones_seen)
1921 fprintf (stderr, _("parsed date/time string"));
1922 else if (tzstring)
1923 {
1924 if (tz != tzdefault)
1925 fprintf (stderr, _("TZ=\"%s\" in date string"), tzstring);
1926 else if (STREQ (tzstring, "UTC0"))
1927 {
1928
1929 fprintf (stderr, _("TZ=\"UTC0\" environment value or -u"));
1930 }
1931 else
1932 fprintf (stderr, _("TZ=\"%s\" environment value"), tzstring);
1933 }
1934 else
1935 fprintf (stderr, _("system default"));
1936
1937
1938
1939
1940 if (pc.local_zones_seen && !pc.zones_seen && 0 < pc.local_isdst)
1941 fprintf (stderr, ", dst");
1942
1943 if (pc.zones_seen)
1944 fprintf (stderr, " (%s)", time_zone_str (pc.time_zone, time_zone_buf));
1945
1946 fputc ('\n', stderr);
1947 }
1948
1949 if (pc.timespec_seen)
1950 *result = pc.seconds;
1951 else
1952 {
1953 if (1 < (pc.times_seen | pc.dates_seen | pc.days_seen | pc.dsts_seen
1954 | (pc.local_zones_seen + pc.zones_seen)))
1955 {
1956 if (debugging (&pc))
1957 {
1958 if (pc.times_seen > 1)
1959 dbg_printf ("error: seen multiple time parts\n");
1960 if (pc.dates_seen > 1)
1961 dbg_printf ("error: seen multiple date parts\n");
1962 if (pc.days_seen > 1)
1963 dbg_printf ("error: seen multiple days parts\n");
1964 if (pc.dsts_seen > 1)
1965 dbg_printf ("error: seen multiple daylight-saving parts\n");
1966 if ((pc.local_zones_seen + pc.zones_seen) > 1)
1967 dbg_printf ("error: seen multiple time-zone parts\n");
1968 }
1969 goto fail;
1970 }
1971
1972 if (! to_tm_year (pc.year, debugging (&pc), &tm.tm_year)
1973 || INT_ADD_WRAPV (pc.month, -1, &tm.tm_mon)
1974 || INT_ADD_WRAPV (pc.day, 0, &tm.tm_mday))
1975 {
1976 if (debugging (&pc))
1977 dbg_printf (_("error: year, month, or day overflow\n"));
1978 goto fail;
1979 }
1980 if (pc.times_seen || (pc.rels_seen && ! pc.dates_seen && ! pc.days_seen))
1981 {
1982 tm.tm_hour = to_hour (pc.hour, pc.meridian);
1983 if (tm.tm_hour < 0)
1984 {
1985 char const *mrd = (pc.meridian == MERam ? "am"
1986 : pc.meridian == MERpm ?"pm" : "");
1987 if (debugging (&pc))
1988 dbg_printf (_("error: invalid hour %"PRIdMAX"%s\n"),
1989 pc.hour, mrd);
1990 goto fail;
1991 }
1992 tm.tm_min = pc.minutes;
1993 tm.tm_sec = pc.seconds.tv_sec;
1994 if (debugging (&pc))
1995 dbg_printf ((pc.times_seen
1996 ? _("using specified time as starting value: '%s'\n")
1997 : _("using current time as starting value: '%s'\n")),
1998 debug_strftime (&tm, dbg_tm, sizeof dbg_tm));
1999 }
2000 else
2001 {
2002 tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
2003 pc.seconds.tv_nsec = 0;
2004 if (debugging (&pc))
2005 dbg_printf ("warning: using midnight as starting time: 00:00:00\n");
2006 }
2007
2008
2009 if (pc.dates_seen | pc.days_seen | pc.times_seen)
2010 tm.tm_isdst = -1;
2011
2012
2013
2014 if (pc.local_zones_seen)
2015 tm.tm_isdst = pc.local_isdst;
2016
2017 tm0.tm_sec = tm.tm_sec;
2018 tm0.tm_min = tm.tm_min;
2019 tm0.tm_hour = tm.tm_hour;
2020 tm0.tm_mday = tm.tm_mday;
2021 tm0.tm_mon = tm.tm_mon;
2022 tm0.tm_year = tm.tm_year;
2023 tm0.tm_isdst = tm.tm_isdst;
2024 tm.tm_wday = -1;
2025
2026 Start = mktime_z (tz, &tm);
2027
2028 if (! mktime_ok (&tm0, &tm))
2029 {
2030 bool repaired = false;
2031 bool time_zone_seen = pc.zones_seen != 0;
2032 if (time_zone_seen)
2033 {
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044 char tz2buf[sizeof "XXX" - 1 + TIME_ZONE_BUFSIZE];
2045 tz2buf[0] = tz2buf[1] = tz2buf[2] = 'X';
2046 time_zone_str (pc.time_zone, &tz2buf[3]);
2047 timezone_t tz2 = tzalloc (tz2buf);
2048 if (!tz2)
2049 {
2050 if (debugging (&pc))
2051 dbg_printf (_("error: tzalloc (\"%s\") failed\n"), tz2buf);
2052 goto fail;
2053 }
2054 tm.tm_sec = tm0.tm_sec;
2055 tm.tm_min = tm0.tm_min;
2056 tm.tm_hour = tm0.tm_hour;
2057 tm.tm_mday = tm0.tm_mday;
2058 tm.tm_mon = tm0.tm_mon;
2059 tm.tm_year = tm0.tm_year;
2060 tm.tm_isdst = tm0.tm_isdst;
2061 tm.tm_wday = -1;
2062 Start = mktime_z (tz2, &tm);
2063 repaired = mktime_ok (&tm0, &tm);
2064 tzfree (tz2);
2065 }
2066
2067 if (! repaired)
2068 {
2069 debug_mktime_not_ok (&tm0, &tm, &pc, time_zone_seen);
2070 goto fail;
2071 }
2072 }
2073
2074 char dbg_ord[DBGBUFSIZE];
2075
2076 if (pc.days_seen && ! pc.dates_seen)
2077 {
2078 intmax_t dayincr;
2079 if (INT_MULTIPLY_WRAPV ((pc.day_ordinal
2080 - (0 < pc.day_ordinal
2081 && tm.tm_wday != pc.day_number)),
2082 7, &dayincr)
2083 || INT_ADD_WRAPV ((pc.day_number - tm.tm_wday + 7) % 7,
2084 dayincr, &dayincr)
2085 || INT_ADD_WRAPV (dayincr, tm.tm_mday, &tm.tm_mday))
2086 Start = -1;
2087 else
2088 {
2089 tm.tm_isdst = -1;
2090 Start = mktime_z (tz, &tm);
2091 }
2092
2093 if (Start == (time_t) -1)
2094 {
2095 if (debugging (&pc))
2096 dbg_printf (_("error: day '%s' "
2097 "(day ordinal=%"PRIdMAX" number=%d) "
2098 "resulted in an invalid date: '%s'\n"),
2099 str_days (&pc, dbg_ord, sizeof dbg_ord),
2100 pc.day_ordinal, pc.day_number,
2101 debug_strfdatetime (&tm, &pc, dbg_tm,
2102 sizeof dbg_tm));
2103 goto fail;
2104 }
2105
2106 if (debugging (&pc))
2107 dbg_printf (_("new start date: '%s' is '%s'\n"),
2108 str_days (&pc, dbg_ord, sizeof dbg_ord),
2109 debug_strfdatetime (&tm, &pc, dbg_tm, sizeof dbg_tm));
2110
2111 }
2112
2113 if (debugging (&pc))
2114 {
2115 if (!pc.dates_seen && !pc.days_seen)
2116 dbg_printf (_("using current date as starting value: '%s'\n"),
2117 debug_strfdate (&tm, dbg_tm, sizeof dbg_tm));
2118
2119 if (pc.days_seen && pc.dates_seen)
2120 dbg_printf (_("warning: day (%s) ignored when explicit dates "
2121 "are given\n"),
2122 str_days (&pc, dbg_ord, sizeof dbg_ord));
2123
2124 dbg_printf (_("starting date/time: '%s'\n"),
2125 debug_strfdatetime (&tm, &pc, dbg_tm, sizeof dbg_tm));
2126 }
2127
2128
2129 if (pc.rel.year | pc.rel.month | pc.rel.day)
2130 {
2131 if (debugging (&pc))
2132 {
2133 if ((pc.rel.year != 0 || pc.rel.month != 0) && tm.tm_mday != 15)
2134 dbg_printf (_("warning: when adding relative months/years, "
2135 "it is recommended to specify the 15th of the "
2136 "months\n"));
2137
2138 if (pc.rel.day != 0 && tm.tm_hour != 12)
2139 dbg_printf (_("warning: when adding relative days, "
2140 "it is recommended to specify noon\n"));
2141 }
2142
2143 int year, month, day;
2144 if (INT_ADD_WRAPV (tm.tm_year, pc.rel.year, &year)
2145 || INT_ADD_WRAPV (tm.tm_mon, pc.rel.month, &month)
2146 || INT_ADD_WRAPV (tm.tm_mday, pc.rel.day, &day))
2147 {
2148 if (debugging (&pc))
2149 dbg_printf (_("error: %s:%d\n"), __FILE__, __LINE__);
2150 goto fail;
2151 }
2152 tm.tm_year = year;
2153 tm.tm_mon = month;
2154 tm.tm_mday = day;
2155 tm.tm_hour = tm0.tm_hour;
2156 tm.tm_min = tm0.tm_min;
2157 tm.tm_sec = tm0.tm_sec;
2158 tm.tm_isdst = tm0.tm_isdst;
2159 Start = mktime_z (tz, &tm);
2160 if (Start == (time_t) -1)
2161 {
2162 if (debugging (&pc))
2163 dbg_printf (_("error: adding relative date resulted "
2164 "in an invalid date: '%s'\n"),
2165 debug_strfdatetime (&tm, &pc, dbg_tm,
2166 sizeof dbg_tm));
2167 goto fail;
2168 }
2169
2170 if (debugging (&pc))
2171 {
2172 dbg_printf (_("after date adjustment "
2173 "(%+"PRIdMAX" years, %+"PRIdMAX" months, "
2174 "%+"PRIdMAX" days),\n"),
2175 pc.rel.year, pc.rel.month, pc.rel.day);
2176 dbg_printf (_(" new date/time = '%s'\n"),
2177 debug_strfdatetime (&tm, &pc, dbg_tm,
2178 sizeof dbg_tm));
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194 if (tm0.tm_isdst != -1 && tm.tm_isdst != tm0.tm_isdst)
2195 dbg_printf (_("warning: daylight saving time changed after "
2196 "date adjustment\n"));
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210 if (pc.rel.day == 0
2211 && (tm.tm_mday != day
2212 || (pc.rel.month == 0 && tm.tm_mon != month)))
2213 {
2214 dbg_printf (_("warning: month/year adjustment resulted in "
2215 "shifted dates:\n"));
2216 char tm_year_buf[TM_YEAR_BUFSIZE];
2217 dbg_printf (_(" adjusted Y M D: %s %02d %02d\n"),
2218 tm_year_str (year, tm_year_buf), month + 1, day);
2219 dbg_printf (_(" normalized Y M D: %s %02d %02d\n"),
2220 tm_year_str (tm.tm_year, tm_year_buf),
2221 tm.tm_mon + 1, tm.tm_mday);
2222 }
2223 }
2224
2225 }
2226
2227
2228
2229 if (pc.zones_seen)
2230 {
2231 bool overflow = false;
2232 #ifdef HAVE_TM_GMTOFF
2233 long int utcoff = tm.tm_gmtoff;
2234 #else
2235 time_t t = Start;
2236 struct tm gmt;
2237 int utcoff = (gmtime_r (&t, &gmt)
2238 ? tm_diff (&tm, &gmt)
2239 : (overflow = true, 0));
2240 #endif
2241 intmax_t delta;
2242 overflow |= INT_SUBTRACT_WRAPV (pc.time_zone, utcoff, &delta);
2243 time_t t1;
2244 overflow |= INT_SUBTRACT_WRAPV (Start, delta, &t1);
2245 if (overflow)
2246 {
2247 if (debugging (&pc))
2248 dbg_printf (_("error: timezone %d caused time_t overflow\n"),
2249 pc.time_zone);
2250 goto fail;
2251 }
2252 Start = t1;
2253 }
2254
2255 if (debugging (&pc))
2256 {
2257 intmax_t Starti = Start;
2258 dbg_printf (_("'%s' = %"PRIdMAX" epoch-seconds\n"),
2259 debug_strfdatetime (&tm, &pc, dbg_tm, sizeof dbg_tm),
2260 Starti);
2261 }
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271 {
2272 intmax_t orig_ns = pc.seconds.tv_nsec;
2273 intmax_t sum_ns = orig_ns + pc.rel.ns;
2274 int normalized_ns = (sum_ns % BILLION + BILLION) % BILLION;
2275 int d4 = (sum_ns - normalized_ns) / BILLION;
2276 intmax_t d1, t1, d2, t2, t3;
2277 time_t t4;
2278 if (INT_MULTIPLY_WRAPV (pc.rel.hour, 60 * 60, &d1)
2279 || INT_ADD_WRAPV (Start, d1, &t1)
2280 || INT_MULTIPLY_WRAPV (pc.rel.minutes, 60, &d2)
2281 || INT_ADD_WRAPV (t1, d2, &t2)
2282 || INT_ADD_WRAPV (t2, pc.rel.seconds, &t3)
2283 || INT_ADD_WRAPV (t3, d4, &t4))
2284 {
2285 if (debugging (&pc))
2286 dbg_printf (_("error: adding relative time caused an "
2287 "overflow\n"));
2288 goto fail;
2289 }
2290
2291 result->tv_sec = t4;
2292 result->tv_nsec = normalized_ns;
2293
2294 if (debugging (&pc)
2295 && (pc.rel.hour | pc.rel.minutes | pc.rel.seconds | pc.rel.ns))
2296 {
2297 dbg_printf (_("after time adjustment (%+"PRIdMAX" hours, "
2298 "%+"PRIdMAX" minutes, "
2299 "%+"PRIdMAX" seconds, %+d ns),\n"),
2300 pc.rel.hour, pc.rel.minutes, pc.rel.seconds,
2301 pc.rel.ns);
2302 intmax_t t4i = t4;
2303 dbg_printf (_(" new time = %"PRIdMAX" epoch-seconds\n"), t4i);
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316 struct tm lmt;
2317 if (tm.tm_isdst != -1 && localtime_rz (tz, &result->tv_sec, &lmt)
2318 && tm.tm_isdst != lmt.tm_isdst)
2319 dbg_printf (_("warning: daylight saving time changed after "
2320 "time adjustment\n"));
2321 }
2322 }
2323 }
2324
2325 if (debugging (&pc))
2326 {
2327
2328 if (! tzstring)
2329 dbg_printf (_("timezone: system default\n"));
2330 else if (STREQ (tzstring, "UTC0"))
2331 dbg_printf (_("timezone: Universal Time\n"));
2332 else
2333 dbg_printf (_("timezone: TZ=\"%s\" environment value\n"), tzstring);
2334
2335 intmax_t sec = result->tv_sec;
2336 int nsec = result->tv_nsec;
2337 dbg_printf (_("final: %"PRIdMAX".%09d (epoch-seconds)\n"),
2338 sec, nsec);
2339
2340 struct tm gmt, lmt;
2341 bool got_utc = !!gmtime_r (&result->tv_sec, &gmt);
2342 if (got_utc)
2343 dbg_printf (_("final: %s (UTC)\n"),
2344 debug_strfdatetime (&gmt, NULL,
2345 dbg_tm, sizeof dbg_tm));
2346 if (localtime_rz (tz, &result->tv_sec, &lmt))
2347 {
2348 #ifdef HAVE_TM_GMTOFF
2349 bool got_utcoff = true;
2350 long int utcoff = lmt.tm_gmtoff;
2351 #else
2352 bool got_utcoff = got_utc;
2353 int utcoff;
2354 if (got_utcoff)
2355 utcoff = tm_diff (&lmt, &gmt);
2356 #endif
2357 if (got_utcoff)
2358 dbg_printf (_("final: %s (UTC%s)\n"),
2359 debug_strfdatetime (&lmt, NULL, dbg_tm, sizeof dbg_tm),
2360 time_zone_str (utcoff, time_zone_buf));
2361 else
2362 dbg_printf (_("final: %s (unknown time zone offset)\n"),
2363 debug_strfdatetime (&lmt, NULL, dbg_tm, sizeof dbg_tm));
2364 }
2365 }
2366
2367 ok = true;
2368
2369 fail:
2370 if (tz != tzdefault)
2371 tzfree (tz);
2372 free (tz1alloc);
2373 return ok;
2374 }
2375
2376 #ifdef GNULIB_PARSE_DATETIME2
2377
2378
2379
2380
2381
2382 bool
2383 parse_datetime2 (struct timespec *result, char const *p,
2384 struct timespec const *now, unsigned int flags,
2385 timezone_t tzdefault, char const *tzstring)
2386 {
2387 return parse_datetime_body (result, p, now, flags, tzdefault, tzstring);
2388 }
2389 #endif
2390
2391
2392
2393 bool
2394 parse_datetime (struct timespec *result, char const *p,
2395 struct timespec const *now)
2396 {
2397 char const *tzstring = getenv ("TZ");
2398 timezone_t tz = tzalloc (tzstring);
2399 if (!tz)
2400 return false;
2401 bool ok = parse_datetime_body (result, p, now, 0, tz, tzstring);
2402 tzfree (tz);
2403 return ok;
2404 }
2405
2406 #if TEST
2407
2408 int
2409 main (int ac, char **av)
2410 {
2411 char buff[BUFSIZ];
2412
2413 printf ("Enter date, or blank line to exit.\n\t> ");
2414 fflush (stdout);
2415
2416 buff[BUFSIZ - 1] = '\0';
2417 while (fgets (buff, BUFSIZ - 1, stdin) && buff[0])
2418 {
2419 struct timespec d;
2420 struct tm const *tm;
2421 if (! parse_datetime (&d, buff, NULL))
2422 printf ("Bad format - couldn't convert.\n");
2423 else if (! (tm = localtime (&d.tv_sec)))
2424 {
2425 intmax_t sec = d.tv_sec;
2426 printf ("localtime (%"PRIdMAX") failed\n", sec);
2427 }
2428 else
2429 {
2430 int ns = d.tv_nsec;
2431 char tm_year_buf[TM_YEAR_BUFSIZE];
2432 printf ("%s-%02d-%02d %02d:%02d:%02d.%09d\n",
2433 tm_year_str (tm->tm_year, tm_year_buf),
2434 tm->tm_mon + 1, tm->tm_mday,
2435 tm->tm_hour, tm->tm_min, tm->tm_sec, ns);
2436 }
2437 printf ("\t> ");
2438 fflush (stdout);
2439 }
2440 return 0;
2441 }
2442 #endif