3 ** Originally written by Steven M. Bellovin <smb@research.att.com> while
4 ** at the University of North Carolina at Chapel Hill. Later tweaked by
5 ** a couple of people on Usenet. Completely overhauled by Rich $alz
6 ** <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990.
8 ** This code is in the public domain and has no copyright.
13 # ifdef FORCE_ALLOCA_H
18 /* Since the code of getdate.y is not included in the Emacs executable
19 itself, there is no need to #define static in this file. Even if
20 the code were included in the Emacs executable, it probably
21 wouldn't do any harm to #undef it here; this will only cause
22 problems if we try to write to a static variable, which I don't
23 think this code needs to do. */
31 #if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII))
32 # define IN_CTYPE_DOMAIN(c) 1
34 # define IN_CTYPE_DOMAIN(c) isascii(c)
37 #define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c))
38 #define ISALPHA(c) (IN_CTYPE_DOMAIN (c) && isalpha (c))
39 #define ISUPPER(c) (IN_CTYPE_DOMAIN (c) && isupper (c))
40 #define ISDIGIT_LOCALE(c) (IN_CTYPE_DOMAIN (c) && isdigit (c))
42 /* ISDIGIT differs from ISDIGIT_LOCALE, as follows:
43 - Its arg may be any int or unsigned int; it need not be an unsigned char.
44 - It's guaranteed to evaluate its argument exactly once.
45 - It's typically faster.
46 Posix 1003.2-1992 section 2.5.2.1 page 50 lines 1556-1558 says that
47 only '0' through '9' are digits. Prefer ISDIGIT to ISDIGIT_LOCALE unless
48 it's important to use the locale's definition of `digit' even when the
49 host does not conform to Posix. */
50 #define ISDIGIT(c) ((unsigned) (c) - '0' <= 9)
52 #if defined (STDC_HEADERS) || defined (USG)
56 #if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7)
57 # define __attribute__(x)
60 #ifndef ATTRIBUTE_UNUSED
61 # define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
64 /* Some old versions of bison generate parsers that use bcopy.
65 That loses on systems that don't provide the function, so we have
66 to redefine it here. */
67 #if !defined (HAVE_BCOPY) && defined (HAVE_MEMCPY) && !defined (bcopy)
68 # define bcopy(from, to, len) memcpy ((to), (from), (len))
71 /* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc),
72 as well as gratuitiously global symbol names, so we can have multiple
73 yacc generated parsers in the same program. Note that these are only
74 the variables produced by yacc. If other parser generators (bison,
75 byacc, etc) produce additional global names that conflict at link time,
76 then those parser generators need to be fixed instead of adding those
77 names to this list. */
79 #define yymaxdepth gd_maxdepth
80 #define yyparse gd_parse
82 #define yyerror gd_error
83 #define yylval gd_lval
84 #define yychar gd_char
85 #define yydebug gd_debug
86 #define yypact gd_pact
93 #define yyexca gd_exca
94 #define yyerrflag gd_errflag
95 #define yynerrs gd_nerrs
100 #define yystate gd_state
103 #define yy_yyv gd_yyv
105 #define yylloc gd_lloc
106 #define yyreds gd_reds /* With YYDEBUG defined */
107 #define yytoks gd_toks /* With YYDEBUG defined */
108 #define yylhs gd_yylhs
109 #define yylen gd_yylen
110 #define yydefred gd_yydefred
111 #define yydgoto gd_yydgoto
112 #define yysindex gd_yysindex
113 #define yyrindex gd_yyrindex
114 #define yygindex gd_yygindex
115 #define yytable gd_yytable
116 #define yycheck gd_yycheck
119 static int yyerror ();
122 #define HOUR(x) ((x) * 60)
124 #define MAX_BUFF_LEN 128 /* size of buffer to read the date into */
127 ** An entry in the lexical lookup table.
129 typedef
struct _TABLE
{
137 ** Meridian: am, pm, or 24-hour style.
139 typedef
enum _MERIDIAN
{
145 ** Global variables. We could get rid of most of these by using a good
146 ** union as the yacc stack. (This routine was originally written before
147 ** yacc had the %union construct.) Maybe someday; right now we only use
148 ** the %union very rarely.
150 static const char *yyInput
;
151 static int yyDayOrdinal
;
152 static int yyDayNumber
;
153 static int yyHaveDate
;
154 static int yyHaveDay
;
155 static int yyHaveRel
;
156 static int yyHaveTime
;
157 static int yyHaveZone
;
158 static int yyTimezone
;
161 static int yyMinutes
;
163 static int yySeconds
;
165 static MERIDIAN yyMeridian
;
167 static int yyRelHour
;
168 static int yyRelMinutes
;
169 static int yyRelMonth
;
170 static int yyRelSeconds
;
171 static int yyRelYear
;
175 /* This grammar has 13 shift/reduce conflicts. */
180 enum _MERIDIAN Meridian
;
183 %token tAGO tDAY tDAY_UNIT tDAYZONE tDST tHOUR_UNIT tID
184 %token tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT
185 %token tSEC_UNIT tSNUMBER tUNUMBER tYEAR_UNIT tZONE
187 %type
<Number
> tDAY tDAY_UNIT tDAYZONE tHOUR_UNIT tMINUTE_UNIT
188 %type
<Number
> tMONTH tMONTH_UNIT
189 %type
<Number
> tSEC_UNIT tSNUMBER tUNUMBER tYEAR_UNIT tZONE
190 %type
<Meridian
> tMERIDIAN o_merid
216 time
: tUNUMBER tMERIDIAN
{
222 | tUNUMBER
':' tUNUMBER o_merid
{
228 | tUNUMBER
':' tUNUMBER tSNUMBER
{
234 ?
-$4 %
100 + (-$4 / 100) * 60
235 : - ($4 %
100 + ($4 / 100) * 60));
237 | tUNUMBER
':' tUNUMBER
':' tUNUMBER o_merid
{
243 | tUNUMBER
':' tUNUMBER
':' tUNUMBER tSNUMBER
{
250 ?
-$6 %
100 + (-$6 / 100) * 60
251 : - ($6 %
100 + ($6 / 100) * 60));
259 yyTimezone
= $1 - 60;
263 yyTimezone
= $1 - 60;
281 date
: tUNUMBER
'/' tUNUMBER
{
285 | tUNUMBER
'/' tUNUMBER
'/' tUNUMBER
{
286 /* Interpret as YYYY/MM/DD if $1 >= 1000, otherwise as MM/DD/YY.
287 The goal in recognizing YYYY/MM/DD is solely to support legacy
288 machine-generated dates like those in an RCS log listing. If
289 you want portability, use the ISO 8601 format. */
303 | tUNUMBER tSNUMBER tSNUMBER
{
304 /* ISO 8601 format. yyyy-mm-dd. */
309 | tUNUMBER tMONTH tSNUMBER
{
310 /* e.g. 17-JUN-1992. */
319 | tMONTH tUNUMBER
',' tUNUMBER
{
328 | tUNUMBER tMONTH tUNUMBER
{
336 yyRelSeconds
= -yyRelSeconds
;
337 yyRelMinutes
= -yyRelMinutes
;
338 yyRelHour
= -yyRelHour
;
339 yyRelDay
= -yyRelDay
;
340 yyRelMonth
= -yyRelMonth
;
341 yyRelYear
= -yyRelYear
;
346 relunit
: tUNUMBER tYEAR_UNIT
{
347 yyRelYear
+= $1 * $2;
349 | tSNUMBER tYEAR_UNIT
{
350 yyRelYear
+= $1 * $2;
355 | tUNUMBER tMONTH_UNIT
{
356 yyRelMonth
+= $1 * $2;
358 | tSNUMBER tMONTH_UNIT
{
359 yyRelMonth
+= $1 * $2;
364 | tUNUMBER tDAY_UNIT
{
367 | tSNUMBER tDAY_UNIT
{
373 | tUNUMBER tHOUR_UNIT
{
374 yyRelHour
+= $1 * $2;
376 | tSNUMBER tHOUR_UNIT
{
377 yyRelHour
+= $1 * $2;
382 | tUNUMBER tMINUTE_UNIT
{
383 yyRelMinutes
+= $1 * $2;
385 | tSNUMBER tMINUTE_UNIT
{
386 yyRelMinutes
+= $1 * $2;
391 | tUNUMBER tSEC_UNIT
{
392 yyRelSeconds
+= $1 * $2;
394 | tSNUMBER tSEC_UNIT
{
395 yyRelSeconds
+= $1 * $2;
404 if
(yyHaveTime
&& yyHaveDate
&& !yyHaveRel
)
412 yyMonth
= ($1/100)%
100;
426 yyMinutes
= $1 %
100;
447 /* Include this file down here because bison inserts code above which
448 may define-away `const'. We want the prototype for get_date to have
449 the same signature as the function definition does. */
452 extern
struct tm
*gmtime
();
453 extern
struct tm
*localtime
();
454 extern
time_t mktime
();
456 /* Month and day table. */
457 static TABLE
const MonthDayTable
[] = {
458 { "january", tMONTH
, 1 },
459 { "february", tMONTH
, 2 },
460 { "march", tMONTH
, 3 },
461 { "april", tMONTH
, 4 },
462 { "may", tMONTH
, 5 },
463 { "june", tMONTH
, 6 },
464 { "july", tMONTH
, 7 },
465 { "august", tMONTH
, 8 },
466 { "september", tMONTH
, 9 },
467 { "sept", tMONTH
, 9 },
468 { "october", tMONTH
, 10 },
469 { "november", tMONTH
, 11 },
470 { "december", tMONTH
, 12 },
471 { "sunday", tDAY
, 0 },
472 { "monday", tDAY
, 1 },
473 { "tuesday", tDAY
, 2 },
475 { "wednesday", tDAY
, 3 },
476 { "wednes", tDAY
, 3 },
477 { "thursday", tDAY
, 4 },
479 { "thurs", tDAY
, 4 },
480 { "friday", tDAY
, 5 },
481 { "saturday", tDAY
, 6 },
485 /* Time units table. */
486 static TABLE
const UnitsTable
[] = {
487 { "year", tYEAR_UNIT
, 1 },
488 { "month", tMONTH_UNIT
, 1 },
489 { "fortnight", tDAY_UNIT
, 14 },
490 { "week", tDAY_UNIT
, 7 },
491 { "day", tDAY_UNIT
, 1 },
492 { "hour", tHOUR_UNIT
, 1 },
493 { "minute", tMINUTE_UNIT
, 1 },
494 { "min", tMINUTE_UNIT
, 1 },
495 { "second", tSEC_UNIT
, 1 },
496 { "sec", tSEC_UNIT
, 1 },
500 /* Assorted relative-time words. */
501 static TABLE
const OtherTable
[] = {
502 { "tomorrow", tMINUTE_UNIT
, 1 * 24 * 60 },
503 { "yesterday", tMINUTE_UNIT
, -1 * 24 * 60 },
504 { "today", tMINUTE_UNIT
, 0 },
505 { "now", tMINUTE_UNIT
, 0 },
506 { "last", tUNUMBER
, -1 },
507 { "this", tMINUTE_UNIT
, 0 },
508 { "next", tUNUMBER
, 1 },
509 { "first", tUNUMBER
, 1 },
510 /* { "second", tUNUMBER, 2 }, */
511 { "third", tUNUMBER
, 3 },
512 { "fourth", tUNUMBER
, 4 },
513 { "fifth", tUNUMBER
, 5 },
514 { "sixth", tUNUMBER
, 6 },
515 { "seventh", tUNUMBER
, 7 },
516 { "eighth", tUNUMBER
, 8 },
517 { "ninth", tUNUMBER
, 9 },
518 { "tenth", tUNUMBER
, 10 },
519 { "eleventh", tUNUMBER
, 11 },
520 { "twelfth", tUNUMBER
, 12 },
525 /* The timezone table. */
526 static TABLE
const TimezoneTable
[] = {
527 { "gmt", tZONE
, HOUR
( 0) }, /* Greenwich Mean */
528 { "ut", tZONE
, HOUR
( 0) }, /* Universal (Coordinated) */
529 { "utc", tZONE
, HOUR
( 0) },
530 { "wet", tZONE
, HOUR
( 0) }, /* Western European */
531 { "bst", tDAYZONE
, HOUR
( 0) }, /* British Summer */
532 { "wat", tZONE
, HOUR
( 1) }, /* West Africa */
533 { "at", tZONE
, HOUR
( 2) }, /* Azores */
535 /* For completeness. BST is also British Summer, and GST is
536 * also Guam Standard. */
537 { "bst", tZONE
, HOUR
( 3) }, /* Brazil Standard */
538 { "gst", tZONE
, HOUR
( 3) }, /* Greenland Standard */
541 { "nft", tZONE
, HOUR
(3.5) }, /* Newfoundland */
542 { "nst", tZONE
, HOUR
(3.5) }, /* Newfoundland Standard */
543 { "ndt", tDAYZONE
, HOUR
(3.5) }, /* Newfoundland Daylight */
545 { "ast", tZONE
, HOUR
( 4) }, /* Atlantic Standard */
546 { "adt", tDAYZONE
, HOUR
( 4) }, /* Atlantic Daylight */
547 { "est", tZONE
, HOUR
( 5) }, /* Eastern Standard */
548 { "edt", tDAYZONE
, HOUR
( 5) }, /* Eastern Daylight */
549 { "cst", tZONE
, HOUR
( 6) }, /* Central Standard */
550 { "cdt", tDAYZONE
, HOUR
( 6) }, /* Central Daylight */
551 { "mst", tZONE
, HOUR
( 7) }, /* Mountain Standard */
552 { "mdt", tDAYZONE
, HOUR
( 7) }, /* Mountain Daylight */
553 { "pst", tZONE
, HOUR
( 8) }, /* Pacific Standard */
554 { "pdt", tDAYZONE
, HOUR
( 8) }, /* Pacific Daylight */
555 { "yst", tZONE
, HOUR
( 9) }, /* Yukon Standard */
556 { "ydt", tDAYZONE
, HOUR
( 9) }, /* Yukon Daylight */
557 { "hst", tZONE
, HOUR
(10) }, /* Hawaii Standard */
558 { "hdt", tDAYZONE
, HOUR
(10) }, /* Hawaii Daylight */
559 { "cat", tZONE
, HOUR
(10) }, /* Central Alaska */
560 { "ahst", tZONE
, HOUR
(10) }, /* Alaska-Hawaii Standard */
561 { "nt", tZONE
, HOUR
(11) }, /* Nome */
562 { "idlw", tZONE
, HOUR
(12) }, /* International Date Line West */
563 { "cet", tZONE
, -HOUR
(1) }, /* Central European */
564 { "met", tZONE
, -HOUR
(1) }, /* Middle European */
565 { "mewt", tZONE
, -HOUR
(1) }, /* Middle European Winter */
566 { "mest", tDAYZONE
, -HOUR
(1) }, /* Middle European Summer */
567 { "mesz", tDAYZONE
, -HOUR
(1) }, /* Middle European Summer */
568 { "swt", tZONE
, -HOUR
(1) }, /* Swedish Winter */
569 { "sst", tDAYZONE
, -HOUR
(1) }, /* Swedish Summer */
570 { "fwt", tZONE
, -HOUR
(1) }, /* French Winter */
571 { "fst", tDAYZONE
, -HOUR
(1) }, /* French Summer */
572 { "eet", tZONE
, -HOUR
(2) }, /* Eastern Europe, USSR Zone 1 */
573 { "bt", tZONE
, -HOUR
(3) }, /* Baghdad, USSR Zone 2 */
575 { "it", tZONE
, -HOUR
(3.5) },/* Iran */
577 { "zp4", tZONE
, -HOUR
(4) }, /* USSR Zone 3 */
578 { "zp5", tZONE
, -HOUR
(5) }, /* USSR Zone 4 */
580 { "ist", tZONE
, -HOUR
(5.5) },/* Indian Standard */
582 { "zp6", tZONE
, -HOUR
(6) }, /* USSR Zone 5 */
584 /* For completeness. NST is also Newfoundland Standard, and SST is
585 * also Swedish Summer. */
586 { "nst", tZONE
, -HOUR
(6.5) },/* North Sumatra */
587 { "sst", tZONE
, -HOUR
(7) }, /* South Sumatra, USSR Zone 6 */
589 { "wast", tZONE
, -HOUR
(7) }, /* West Australian Standard */
590 { "wadt", tDAYZONE
, -HOUR
(7) }, /* West Australian Daylight */
592 { "jt", tZONE
, -HOUR
(7.5) },/* Java (3pm in Cronusland!) */
594 { "cct", tZONE
, -HOUR
(8) }, /* China Coast, USSR Zone 7 */
595 { "jst", tZONE
, -HOUR
(9) }, /* Japan Standard, USSR Zone 8 */
597 { "cast", tZONE
, -HOUR
(9.5) },/* Central Australian Standard */
598 { "cadt", tDAYZONE
, -HOUR
(9.5) },/* Central Australian Daylight */
600 { "east", tZONE
, -HOUR
(10) }, /* Eastern Australian Standard */
601 { "eadt", tDAYZONE
, -HOUR
(10) }, /* Eastern Australian Daylight */
602 { "gst", tZONE
, -HOUR
(10) }, /* Guam Standard, USSR Zone 9 */
603 { "nzt", tZONE
, -HOUR
(12) }, /* New Zealand */
604 { "nzst", tZONE
, -HOUR
(12) }, /* New Zealand Standard */
605 { "nzdt", tDAYZONE
, -HOUR
(12) }, /* New Zealand Daylight */
606 { "idle", tZONE
, -HOUR
(12) }, /* International Date Line East */
610 /* Military timezone table. */
611 static TABLE
const MilitaryTable
[] = {
612 { "a", tZONE
, HOUR
( 1) },
613 { "b", tZONE
, HOUR
( 2) },
614 { "c", tZONE
, HOUR
( 3) },
615 { "d", tZONE
, HOUR
( 4) },
616 { "e", tZONE
, HOUR
( 5) },
617 { "f", tZONE
, HOUR
( 6) },
618 { "g", tZONE
, HOUR
( 7) },
619 { "h", tZONE
, HOUR
( 8) },
620 { "i", tZONE
, HOUR
( 9) },
621 { "k", tZONE
, HOUR
( 10) },
622 { "l", tZONE
, HOUR
( 11) },
623 { "m", tZONE
, HOUR
( 12) },
624 { "n", tZONE
, HOUR
(- 1) },
625 { "o", tZONE
, HOUR
(- 2) },
626 { "p", tZONE
, HOUR
(- 3) },
627 { "q", tZONE
, HOUR
(- 4) },
628 { "r", tZONE
, HOUR
(- 5) },
629 { "s", tZONE
, HOUR
(- 6) },
630 { "t", tZONE
, HOUR
(- 7) },
631 { "u", tZONE
, HOUR
(- 8) },
632 { "v", tZONE
, HOUR
(- 9) },
633 { "w", tZONE
, HOUR
(-10) },
634 { "x", tZONE
, HOUR
(-11) },
635 { "y", tZONE
, HOUR
(-12) },
636 { "z", tZONE
, HOUR
( 0) },
646 char *s ATTRIBUTE_UNUSED
;
652 ToHour
(Hours
, Meridian
)
659 if
(Hours
< 0 || Hours
> 23)
663 if
(Hours
< 1 || Hours
> 12)
669 if
(Hours
< 1 || Hours
> 12)
687 /* XPG4 suggests that years 00-68 map to 2000-2068, and
688 years 69-99 map to 1969-1999. */
703 register
const TABLE
*tp
;
707 /* Make it lowercase. */
708 for
(p
= buff
; *p
; p
++)
712 if
(strcmp
(buff
, "am") == 0 || strcmp
(buff
, "a.m.") == 0)
714 yylval.Meridian
= MERam
;
717 if
(strcmp
(buff
, "pm") == 0 || strcmp
(buff
, "p.m.") == 0)
719 yylval.Meridian
= MERpm
;
723 /* See if we have an abbreviation for a month. */
724 if
(strlen
(buff
) == 3)
726 else if
(strlen
(buff
) == 4 && buff
[3] == '.')
734 for
(tp
= MonthDayTable
; tp
->name
; tp
++)
738 if
(strncmp
(buff
, tp
->name
, 3) == 0)
740 yylval.Number
= tp
->value
;
744 else if
(strcmp
(buff
, tp
->name
) == 0)
746 yylval.Number
= tp
->value
;
751 for
(tp
= TimezoneTable
; tp
->name
; tp
++)
752 if
(strcmp
(buff
, tp
->name
) == 0)
754 yylval.Number
= tp
->value
;
758 if
(strcmp
(buff
, "dst") == 0)
761 for
(tp
= UnitsTable
; tp
->name
; tp
++)
762 if
(strcmp
(buff
, tp
->name
) == 0)
764 yylval.Number
= tp
->value
;
768 /* Strip off any plural and try the units table again. */
769 i
= strlen
(buff
) - 1;
773 for
(tp
= UnitsTable
; tp
->name
; tp
++)
774 if
(strcmp
(buff
, tp
->name
) == 0)
776 yylval.Number
= tp
->value
;
779 buff
[i
] = 's'; /* Put back for "this" in OtherTable. */
782 for
(tp
= OtherTable
; tp
->name
; tp
++)
783 if
(strcmp
(buff
, tp
->name
) == 0)
785 yylval.Number
= tp
->value
;
789 /* Military timezones. */
790 if
(buff
[1] == '\0' && ISALPHA
(*buff
))
792 for
(tp
= MilitaryTable
; tp
->name
; tp
++)
793 if
(strcmp
(buff
, tp
->name
) == 0)
795 yylval.Number
= tp
->value
;
800 /* Drop out any periods and try the timezone table again. */
801 for
(i
= 0, p
= q
= buff
; *q
; q
++)
808 for
(tp
= TimezoneTable
; tp
->name
; tp
++)
809 if
(strcmp
(buff
, tp
->name
) == 0)
811 yylval.Number
= tp
->value
;
829 while
(ISSPACE
(*yyInput
))
832 if
(ISDIGIT
(c
= *yyInput
) || c
== '-' || c
== '+')
834 if
(c
== '-' || c
== '+')
836 sign
= c
== '-' ?
-1 : 1;
837 if
(!ISDIGIT
(*++yyInput
))
838 /* skip the '-' sign */
843 for
(yylval.Number
= 0; ISDIGIT
(c
= *yyInput
++);)
844 yylval.Number
= 10 * yylval.Number
+ c
- '0';
847 yylval.Number
= -yylval.Number
;
848 return sign ? tSNUMBER
: tUNUMBER
;
852 for
(p
= buff
; (c
= *yyInput
++, ISALPHA
(c
)) || c
== '.';)
853 if
(p
< &buff
[sizeof buff
- 1])
857 return LookupWord
(buff
);
876 #define TM_YEAR_ORIGIN 1900
878 /* Yield A - B, measured in seconds. */
883 int ay
= a
->tm_year
+ (TM_YEAR_ORIGIN
- 1);
884 int by
= b
->tm_year
+ (TM_YEAR_ORIGIN
- 1);
886 /* difference in day of year */
887 a
->tm_yday
- b
->tm_yday
888 /* + intervening leap days */
889 + ((ay
>> 2) - (by
>> 2))
890 - (ay
/ 100 - by
/ 100)
891 + ((ay
/ 100 >> 2) - (by
/ 100 >> 2))
892 /* + difference in years * 365 */
893 + (long) (ay
- by
) * 365
895 return
(60 * (60 * (24 * days
+ (a
->tm_hour
- b
->tm_hour
))
896 + (a
->tm_min
- b
->tm_min
))
897 + (a
->tm_sec
- b
->tm_sec
));
901 get_date
(const char *p
, const time_t *now
)
903 struct tm tm
, tm0
, *tmp
;
907 Start
= now ?
*now
: time
((time_t *) NULL
);
908 tmp
= localtime
(&Start
);
909 yyYear
= tmp
->tm_year
+ TM_YEAR_ORIGIN
;
910 yyMonth
= tmp
->tm_mon
+ 1;
911 yyDay
= tmp
->tm_mday
;
912 yyHour
= tmp
->tm_hour
;
913 yyMinutes
= tmp
->tm_min
;
914 yySeconds
= tmp
->tm_sec
;
929 || yyHaveTime
> 1 || yyHaveZone
> 1 || yyHaveDate
> 1 || yyHaveDay
> 1)
932 tm.tm_year
= ToYear
(yyYear
) - TM_YEAR_ORIGIN
+ yyRelYear
;
933 tm.tm_mon
= yyMonth
- 1 + yyRelMonth
;
934 tm.tm_mday
= yyDay
+ yyRelDay
;
935 if
(yyHaveTime ||
(yyHaveRel
&& !yyHaveDate
&& !yyHaveDay
))
937 tm.tm_hour
= ToHour
(yyHour
, yyMeridian
);
940 tm.tm_min
= yyMinutes
;
941 tm.tm_sec
= yySeconds
;
945 tm.tm_hour
= tm.tm_min
= tm.tm_sec
= 0;
947 tm.tm_hour
+= yyRelHour
;
948 tm.tm_min
+= yyRelMinutes
;
949 tm.tm_sec
+= yyRelSeconds
;
953 Start
= mktime
(&tm
);
955 if
(Start
== (time_t) -1)
958 /* Guard against falsely reporting errors near the time_t boundaries
959 when parsing times in other time zones. For example, if the min
960 time_t value is 1970-01-01 00:00:00 UTC and we are 8 hours ahead
961 of UTC, then the min localtime value is 1970-01-01 08:00:00; if
962 we apply mktime to 1970-01-01 00:00:00 we will get an error, so
963 we apply mktime to 1970-01-02 08:00:00 instead and adjust the time
964 zone by 24 hours to compensate. This algorithm assumes that
965 there is no DST transition within a day of the time_t boundaries. */
969 if
(tm.tm_year
<= EPOCH
- TM_YEAR_ORIGIN
)
972 yyTimezone
-= 24 * 60;
977 yyTimezone
+= 24 * 60;
979 Start
= mktime
(&tm
);
982 if
(Start
== (time_t) -1)
986 if
(yyHaveDay
&& !yyHaveDate
)
988 tm.tm_mday
+= ((yyDayNumber
- tm.tm_wday
+ 7) %
7
989 + 7 * (yyDayOrdinal
- (0 < yyDayOrdinal
)));
990 Start
= mktime
(&tm
);
991 if
(Start
== (time_t) -1)
997 long delta
= yyTimezone
* 60L + difftm
(&tm
, gmtime
(&Start
));
998 if
((Start
+ delta
< Start
) != (delta
< 0))
999 return
-1; /* time_t overflow */
1014 char buff
[MAX_BUFF_LEN
+ 1];
1017 (void) printf
("Enter date, or blank line to exit.\n\t> ");
1018 (void) fflush
(stdout
);
1020 buff
[MAX_BUFF_LEN
] = 0;
1021 while
(fgets
(buff
, MAX_BUFF_LEN
, stdin
) && buff
[0])
1023 d
= get_date
(buff
, (time_t *) NULL
);
1025 (void) printf
("Bad format - couldn't convert.\n");
1027 (void) printf
("%s", ctime
(&d
));
1028 (void) printf
("\t> ");
1029 (void) fflush
(stdout
);
1034 #endif /* defined (TEST) */