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;
7 ** send any email to Rich.
9 ** This grammar has 10 shift/reduce conflicts.
11 ** This code is in the public domain and has no copyright.
13 /* SUPPRESS 287 on yaccpar_sccsid *//* Unused static variable */
14 /* SUPPRESS 288 on yyerrlab *//* Label unused */
24 /* Since the code of getdate.y is not included in the Emacs executable
25 itself, there is no need to #define static in this file. Even if
26 the code were included in the Emacs executable, it probably
27 wouldn't do any harm to #undef it here; this will only cause
28 problems if we try to write to a static variable, which I don't
29 think this code needs to do. */
37 #if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII))
38 # define IN_CTYPE_DOMAIN(c) 1
40 # define IN_CTYPE_DOMAIN(c) isascii(c)
43 #define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c))
44 #define ISALPHA(c) (IN_CTYPE_DOMAIN (c) && isalpha (c))
45 #define ISUPPER(c) (IN_CTYPE_DOMAIN (c) && isupper (c))
46 #define ISDIGIT_LOCALE(c) (IN_CTYPE_DOMAIN (c) && isdigit (c))
48 /* ISDIGIT differs from ISDIGIT_LOCALE, as follows:
49 - Its arg may be any int or unsigned int; it need not be an unsigned char.
50 - It's guaranteed to evaluate its argument exactly once.
51 - It's typically faster.
52 Posix 1003.2-1992 section 2.5.2.1 page 50 lines 1556-1558 says that
53 only '0' through '9' are digits. Prefer ISDIGIT to ISDIGIT_LOCALE unless
54 it's important to use the locale's definition of `digit' even when the
55 host does not conform to Posix. */
56 #define ISDIGIT(c) ((unsigned) (c) - '0' <= 9)
62 #include <sys/types.h>
63 #ifdef TIME_WITH_SYS_TIME
67 #ifdef HAVE_SYS_TIME_H
75 #undef timezone /* needed for sgi */
78 #if defined (HAVE_SYS_TIMEB_H)
79 #include <sys/timeb.h>
82 /* get_date uses the obsolete `struct timeb' in its interface! FIXME.
83 Since some systems don't have it, we define it here;
84 callers must do likewise. */
87 time_t time; /* Seconds since the epoch */
88 unsigned short millitm; /* Field not used */
89 short timezone; /* Minutes west of GMT */
90 short dstflag; /* Field not used */
92 #endif /* defined (HAVE_SYS_TIMEB_H) */
94 #endif /* defined (vms) */
96 #if defined (STDC_HEADERS) || defined (USG)
100 /* Some old versions of bison generate parsers that use bcopy.
101 That loses on systems that don't provide the function, so we have
102 to redefine it here. */
103 #if !defined (HAVE_BCOPY) && defined (HAVE_MEMCPY) && !defined (bcopy)
104 #define bcopy(from, to, len) memcpy ((to), (from), (len))
107 extern struct tm *gmtime ();
108 extern struct tm *localtime ();
110 /* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc),
111 as well as gratuitiously global symbol names, so we can have multiple
112 yacc generated parsers in the same program. Note that these are only
113 the variables produced by yacc. If other parser generators (bison,
114 byacc, etc) produce additional global names that conflict at link time,
115 then those parser generators need to be fixed instead of adding those
116 names to this list. */
118 #define yymaxdepth gd_maxdepth
119 #define yyparse gd_parse
121 #define yyerror gd_error
122 #define yylval gd_lval
123 #define yychar gd_char
124 #define yydebug gd_debug
125 #define yypact gd_pact
132 #define yyexca gd_exca
133 #define yyerrflag gd_errflag
134 #define yynerrs gd_nerrs
138 #define yy_yys gd_yys
139 #define yystate gd_state
142 #define yy_yyv gd_yyv
144 #define yylloc gd_lloc
145 #define yyreds gd_reds /* With YYDEBUG defined */
146 #define yytoks gd_toks /* With YYDEBUG defined */
147 #define yylhs gd_yylhs
148 #define yylen gd_yylen
149 #define yydefred gd_yydefred
150 #define yydgoto gd_yydgoto
151 #define yysindex gd_yysindex
152 #define yyrindex gd_yyrindex
153 #define yygindex gd_yygindex
154 #define yytable gd_yytable
155 #define yycheck gd_yycheck
158 static int yyerror ();
161 #define DOOMSDAY 2038
162 #define HOUR(x) ((time_t)(x) * 60)
163 #define SECSPERDAY (24L * 60L * 60L)
165 #define MAX_BUFF_LEN 128 /* size of buffer to read the date into */
168 ** An entry in the lexical lookup table.
170 typedef struct _TABLE {
178 ** Daylight-savings mode: on, off, or not yet known.
180 typedef enum _DSTMODE {
181 DSTon, DSToff, DSTmaybe
185 ** Meridian: am, pm, or 24-hour style.
187 typedef enum _MERIDIAN {
193 ** Global variables. We could get rid of most of these by using a good
194 ** union as the yacc stack. (This routine was originally written before
195 ** yacc had the %union construct.) Maybe someday; right now we only use
196 ** the %union very rarely.
198 static char *yyInput;
199 static DSTMODE yyDSTmode;
200 static time_t yyDayOrdinal;
201 static time_t yyDayNumber;
202 static int yyHaveDate;
203 static int yyHaveDay;
204 static int yyHaveRel;
205 static int yyHaveTime;
206 static int yyHaveZone;
207 static time_t yyTimezone;
209 static time_t yyHour;
210 static time_t yyMinutes;
211 static time_t yyMonth;
212 static time_t yySeconds;
213 static time_t yyYear;
214 static MERIDIAN yyMeridian;
215 static time_t yyRelMonth;
216 static time_t yyRelSeconds;
222 enum _MERIDIAN Meridian;
225 %token tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT
226 %token tSEC_UNIT tSNUMBER tUNUMBER tZONE tDST
228 %type <Number> tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT
229 %type <Number> tSEC_UNIT tSNUMBER tUNUMBER tZONE
230 %type <Meridian> tMERIDIAN o_merid
256 time : tUNUMBER tMERIDIAN {
262 | tUNUMBER ':' tUNUMBER o_merid {
268 | tUNUMBER ':' tUNUMBER tSNUMBER {
273 yyTimezone = - ($4 % 100 + ($4 / 100) * 60);
275 | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid {
281 | tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER {
287 yyTimezone = - ($6 % 100 + ($6 / 100) * 60);
320 date : tUNUMBER '/' tUNUMBER {
324 | tUNUMBER '/' tUNUMBER '/' tUNUMBER {
325 /* Interpret as YYYY/MM/DD if $1 >= 1000, otherwise as MM/DD/YY.
326 The goal in recognizing YYYY/MM/DD is solely to support legacy
327 machine-generated dates like those in an RCS log listing. If
328 you want portability, use the ISO 8601 format. */
342 | tUNUMBER tSNUMBER tSNUMBER {
343 /* ISO 8601 format. yyyy-mm-dd. */
348 | tUNUMBER tMONTH tSNUMBER {
349 /* e.g. 17-JUN-1992. */
358 | tMONTH tUNUMBER ',' tUNUMBER {
367 | tUNUMBER tMONTH tUNUMBER {
375 yyRelSeconds = -yyRelSeconds;
376 yyRelMonth = -yyRelMonth;
381 relunit : tUNUMBER tMINUTE_UNIT {
382 yyRelSeconds += $1 * $2 * 60L;
384 | tSNUMBER tMINUTE_UNIT {
385 yyRelSeconds += $1 * $2 * 60L;
388 yyRelSeconds += $1 * 60L;
390 | tSNUMBER tSEC_UNIT {
393 | tUNUMBER tSEC_UNIT {
399 | tSNUMBER tMONTH_UNIT {
400 yyRelMonth += $1 * $2;
402 | tUNUMBER tMONTH_UNIT {
403 yyRelMonth += $1 * $2;
411 if (yyHaveTime && yyHaveDate && !yyHaveRel)
417 yyMonth= ($1/100)%100;
428 yyMinutes = $1 % 100;
437 o_merid : /* NULL */ {
447 /* Month and day table. */
448 static TABLE const MonthDayTable[] = {
449 { "january", tMONTH, 1 },
450 { "february", tMONTH, 2 },
451 { "march", tMONTH, 3 },
452 { "april", tMONTH, 4 },
453 { "may", tMONTH, 5 },
454 { "june", tMONTH, 6 },
455 { "july", tMONTH, 7 },
456 { "august", tMONTH, 8 },
457 { "september", tMONTH, 9 },
458 { "sept", tMONTH, 9 },
459 { "october", tMONTH, 10 },
460 { "november", tMONTH, 11 },
461 { "december", tMONTH, 12 },
462 { "sunday", tDAY, 0 },
463 { "monday", tDAY, 1 },
464 { "tuesday", tDAY, 2 },
466 { "wednesday", tDAY, 3 },
467 { "wednes", tDAY, 3 },
468 { "thursday", tDAY, 4 },
470 { "thurs", tDAY, 4 },
471 { "friday", tDAY, 5 },
472 { "saturday", tDAY, 6 },
476 /* Time units table. */
477 static TABLE const UnitsTable[] = {
478 { "year", tMONTH_UNIT, 12 },
479 { "month", tMONTH_UNIT, 1 },
480 { "fortnight", tMINUTE_UNIT, 14 * 24 * 60 },
481 { "week", tMINUTE_UNIT, 7 * 24 * 60 },
482 { "day", tMINUTE_UNIT, 1 * 24 * 60 },
483 { "hour", tMINUTE_UNIT, 60 },
484 { "minute", tMINUTE_UNIT, 1 },
485 { "min", tMINUTE_UNIT, 1 },
486 { "second", tSEC_UNIT, 1 },
487 { "sec", tSEC_UNIT, 1 },
491 /* Assorted relative-time words. */
492 static TABLE const OtherTable[] = {
493 { "tomorrow", tMINUTE_UNIT, 1 * 24 * 60 },
494 { "yesterday", tMINUTE_UNIT, -1 * 24 * 60 },
495 { "today", tMINUTE_UNIT, 0 },
496 { "now", tMINUTE_UNIT, 0 },
497 { "last", tUNUMBER, -1 },
498 { "this", tMINUTE_UNIT, 0 },
499 { "next", tUNUMBER, 2 },
500 { "first", tUNUMBER, 1 },
501 /* { "second", tUNUMBER, 2 }, */
502 { "third", tUNUMBER, 3 },
503 { "fourth", tUNUMBER, 4 },
504 { "fifth", tUNUMBER, 5 },
505 { "sixth", tUNUMBER, 6 },
506 { "seventh", tUNUMBER, 7 },
507 { "eighth", tUNUMBER, 8 },
508 { "ninth", tUNUMBER, 9 },
509 { "tenth", tUNUMBER, 10 },
510 { "eleventh", tUNUMBER, 11 },
511 { "twelfth", tUNUMBER, 12 },
516 /* The timezone table. */
517 /* Some of these are commented out because a time_t can't store a float. */
518 static TABLE const TimezoneTable[] = {
519 { "gmt", tZONE, HOUR ( 0) }, /* Greenwich Mean */
520 { "ut", tZONE, HOUR ( 0) }, /* Universal (Coordinated) */
521 { "utc", tZONE, HOUR ( 0) },
522 { "wet", tZONE, HOUR ( 0) }, /* Western European */
523 { "bst", tDAYZONE, HOUR ( 0) }, /* British Summer */
524 { "wat", tZONE, HOUR ( 1) }, /* West Africa */
525 { "at", tZONE, HOUR ( 2) }, /* Azores */
527 /* For completeness. BST is also British Summer, and GST is
528 * also Guam Standard. */
529 { "bst", tZONE, HOUR ( 3) }, /* Brazil Standard */
530 { "gst", tZONE, HOUR ( 3) }, /* Greenland Standard */
533 { "nft", tZONE, HOUR (3.5) }, /* Newfoundland */
534 { "nst", tZONE, HOUR (3.5) }, /* Newfoundland Standard */
535 { "ndt", tDAYZONE, HOUR (3.5) }, /* Newfoundland Daylight */
537 { "ast", tZONE, HOUR ( 4) }, /* Atlantic Standard */
538 { "adt", tDAYZONE, HOUR ( 4) }, /* Atlantic Daylight */
539 { "est", tZONE, HOUR ( 5) }, /* Eastern Standard */
540 { "edt", tDAYZONE, HOUR ( 5) }, /* Eastern Daylight */
541 { "cst", tZONE, HOUR ( 6) }, /* Central Standard */
542 { "cdt", tDAYZONE, HOUR ( 6) }, /* Central Daylight */
543 { "mst", tZONE, HOUR ( 7) }, /* Mountain Standard */
544 { "mdt", tDAYZONE, HOUR ( 7) }, /* Mountain Daylight */
545 { "pst", tZONE, HOUR ( 8) }, /* Pacific Standard */
546 { "pdt", tDAYZONE, HOUR ( 8) }, /* Pacific Daylight */
547 { "yst", tZONE, HOUR ( 9) }, /* Yukon Standard */
548 { "ydt", tDAYZONE, HOUR ( 9) }, /* Yukon Daylight */
549 { "hst", tZONE, HOUR (10) }, /* Hawaii Standard */
550 { "hdt", tDAYZONE, HOUR (10) }, /* Hawaii Daylight */
551 { "cat", tZONE, HOUR (10) }, /* Central Alaska */
552 { "ahst", tZONE, HOUR (10) }, /* Alaska-Hawaii Standard */
553 { "nt", tZONE, HOUR (11) }, /* Nome */
554 { "idlw", tZONE, HOUR (12) }, /* International Date Line West */
555 { "cet", tZONE, -HOUR (1) }, /* Central European */
556 { "met", tZONE, -HOUR (1) }, /* Middle European */
557 { "mewt", tZONE, -HOUR (1) }, /* Middle European Winter */
558 { "mest", tDAYZONE, -HOUR (1) }, /* Middle European Summer */
559 { "mesz", tDAYZONE, -HOUR (1) }, /* Middle European Summer */
560 { "swt", tZONE, -HOUR (1) }, /* Swedish Winter */
561 { "sst", tDAYZONE, -HOUR (1) }, /* Swedish Summer */
562 { "fwt", tZONE, -HOUR (1) }, /* French Winter */
563 { "fst", tDAYZONE, -HOUR (1) }, /* French Summer */
564 { "eet", tZONE, -HOUR (2) }, /* Eastern Europe, USSR Zone 1 */
565 { "bt", tZONE, -HOUR (3) }, /* Baghdad, USSR Zone 2 */
567 { "it", tZONE, -HOUR (3.5) },/* Iran */
569 { "zp4", tZONE, -HOUR (4) }, /* USSR Zone 3 */
570 { "zp5", tZONE, -HOUR (5) }, /* USSR Zone 4 */
572 { "ist", tZONE, -HOUR (5.5) },/* Indian Standard */
574 { "zp6", tZONE, -HOUR (6) }, /* USSR Zone 5 */
576 /* For completeness. NST is also Newfoundland Standard, and SST is
577 * also Swedish Summer. */
578 { "nst", tZONE, -HOUR (6.5) },/* North Sumatra */
579 { "sst", tZONE, -HOUR (7) }, /* South Sumatra, USSR Zone 6 */
581 { "wast", tZONE, -HOUR (7) }, /* West Australian Standard */
582 { "wadt", tDAYZONE, -HOUR (7) }, /* West Australian Daylight */
584 { "jt", tZONE, -HOUR (7.5) },/* Java (3pm in Cronusland!) */
586 { "cct", tZONE, -HOUR (8) }, /* China Coast, USSR Zone 7 */
587 { "jst", tZONE, -HOUR (9) }, /* Japan Standard, USSR Zone 8 */
589 { "cast", tZONE, -HOUR (9.5) },/* Central Australian Standard */
590 { "cadt", tDAYZONE, -HOUR (9.5) },/* Central Australian Daylight */
592 { "east", tZONE, -HOUR (10) }, /* Eastern Australian Standard */
593 { "eadt", tDAYZONE, -HOUR (10) }, /* Eastern Australian Daylight */
594 { "gst", tZONE, -HOUR (10) }, /* Guam Standard, USSR Zone 9 */
595 { "nzt", tZONE, -HOUR (12) }, /* New Zealand */
596 { "nzst", tZONE, -HOUR (12) }, /* New Zealand Standard */
597 { "nzdt", tDAYZONE, -HOUR (12) }, /* New Zealand Daylight */
598 { "idle", tZONE, -HOUR (12) }, /* International Date Line East */
602 /* Military timezone table. */
603 static TABLE const MilitaryTable[] = {
604 { "a", tZONE, HOUR ( 1) },
605 { "b", tZONE, HOUR ( 2) },
606 { "c", tZONE, HOUR ( 3) },
607 { "d", tZONE, HOUR ( 4) },
608 { "e", tZONE, HOUR ( 5) },
609 { "f", tZONE, HOUR ( 6) },
610 { "g", tZONE, HOUR ( 7) },
611 { "h", tZONE, HOUR ( 8) },
612 { "i", tZONE, HOUR ( 9) },
613 { "k", tZONE, HOUR ( 10) },
614 { "l", tZONE, HOUR ( 11) },
615 { "m", tZONE, HOUR ( 12) },
616 { "n", tZONE, HOUR (- 1) },
617 { "o", tZONE, HOUR (- 2) },
618 { "p", tZONE, HOUR (- 3) },
619 { "q", tZONE, HOUR (- 4) },
620 { "r", tZONE, HOUR (- 5) },
621 { "s", tZONE, HOUR (- 6) },
622 { "t", tZONE, HOUR (- 7) },
623 { "u", tZONE, HOUR (- 8) },
624 { "v", tZONE, HOUR (- 9) },
625 { "w", tZONE, HOUR (-10) },
626 { "x", tZONE, HOUR (-11) },
627 { "y", tZONE, HOUR (-12) },
628 { "z", tZONE, HOUR ( 0) },
645 ToSeconds (Hours, Minutes, Seconds, Meridian)
651 if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59)
655 if (Hours < 0 || Hours > 23)
657 return (Hours * 60L + Minutes) * 60L + Seconds;
659 if (Hours < 1 || Hours > 12)
663 return (Hours * 60L + Minutes) * 60L + Seconds;
665 if (Hours < 1 || Hours > 12)
669 return ((Hours + 12) * 60L + Minutes) * 60L + Seconds;
678 Convert (Month, Day, Year, Hours, Minutes, Seconds, Meridian, DSTmode)
688 static int DaysInMonth[12] = {
689 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
697 if (Year < DOOMSDAY-2000)
701 DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0)
703 if (Year < EPOCH || Year > DOOMSDAY
704 || Month < 1 || Month > 12
705 /* Lint fluff: "conversion from long may lose accuracy" */
706 || Day < 1 || Day > DaysInMonth[(int)--Month])
709 for (Julian = Day - 1, i = 0; i < Month; i++)
710 Julian += DaysInMonth[i];
711 for (i = EPOCH; i < Year; i++)
712 Julian += 365 + (i % 4 == 0);
713 Julian *= SECSPERDAY;
714 Julian += yyTimezone * 60L;
715 if ((tod = ToSeconds (Hours, Minutes, Seconds, Meridian)) < 0)
719 || (DSTmode == DSTmaybe && localtime (&Julian)->tm_isdst))
726 DSTcorrect (Start, Future)
733 StartDay = (localtime (&Start)->tm_hour + 1) % 24;
734 FutureDay = (localtime (&Future)->tm_hour + 1) % 24;
735 return (Future - Start) + (StartDay - FutureDay) * 60L * 60L;
740 RelativeDate (Start, DayOrdinal, DayNumber)
749 tm = localtime (&now);
750 now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7);
751 now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1);
752 return DSTcorrect (Start, now);
757 RelativeMonth (Start, RelMonth)
767 tm = localtime (&Start);
768 Month = 12 * (1900 + tm->tm_year) + tm->tm_mon + RelMonth;
770 Month = Month % 12 + 1;
771 return DSTcorrect (Start,
772 Convert (Month, (time_t)tm->tm_mday, Year,
773 (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
784 register const TABLE *tp;
788 /* Make it lowercase. */
789 for (p = buff; *p; p++)
793 if (strcmp (buff, "am") == 0 || strcmp (buff, "a.m.") == 0) {
794 yylval.Meridian = MERam;
797 if (strcmp (buff, "pm") == 0 || strcmp (buff, "p.m.") == 0) {
798 yylval.Meridian = MERpm;
802 /* See if we have an abbreviation for a month. */
803 if (strlen (buff) == 3)
805 else if (strlen (buff) == 4 && buff[3] == '.') {
812 for (tp = MonthDayTable; tp->name; tp++) {
814 if (strncmp (buff, tp->name, 3) == 0) {
815 yylval.Number = tp->value;
819 else if (strcmp (buff, tp->name) == 0) {
820 yylval.Number = tp->value;
825 for (tp = TimezoneTable; tp->name; tp++)
826 if (strcmp (buff, tp->name) == 0) {
827 yylval.Number = tp->value;
831 if (strcmp (buff, "dst") == 0)
834 for (tp = UnitsTable; tp->name; tp++)
835 if (strcmp (buff, tp->name) == 0) {
836 yylval.Number = tp->value;
840 /* Strip off any plural and try the units table again. */
841 i = strlen (buff) - 1;
842 if (buff[i] == 's') {
844 for (tp = UnitsTable; tp->name; tp++)
845 if (strcmp (buff, tp->name) == 0) {
846 yylval.Number = tp->value;
849 buff[i] = 's'; /* Put back for "this" in OtherTable. */
852 for (tp = OtherTable; tp->name; tp++)
853 if (strcmp (buff, tp->name) == 0) {
854 yylval.Number = tp->value;
858 /* Military timezones. */
859 if (buff[1] == '\0' && ISALPHA (*buff)) {
860 for (tp = MilitaryTable; tp->name; tp++)
861 if (strcmp (buff, tp->name) == 0) {
862 yylval.Number = tp->value;
867 /* Drop out any periods and try the timezone table again. */
868 for (i = 0, p = q = buff; *q; q++)
875 for (tp = TimezoneTable; tp->name; tp++)
876 if (strcmp (buff, tp->name) == 0) {
877 yylval.Number = tp->value;
895 while (ISSPACE (*yyInput))
898 if (ISDIGIT (c = *yyInput) || c == '-' || c == '+') {
899 if (c == '-' || c == '+') {
900 sign = c == '-' ? -1 : 1;
901 if (!ISDIGIT (*++yyInput))
902 /* skip the '-' sign */
907 for (yylval.Number = 0; ISDIGIT (c = *yyInput++); )
908 yylval.Number = 10 * yylval.Number + c - '0';
911 yylval.Number = -yylval.Number;
912 return sign ? tSNUMBER : tUNUMBER;
915 for (p = buff; (c = *yyInput++, ISALPHA (c)) || c == '.'; )
916 if (p < &buff[sizeof buff - 1])
920 return LookupWord (buff);
937 #define TM_YEAR_ORIGIN 1900
939 /* Yield A - B, measured in seconds. */
944 int ay = a->tm_year + (TM_YEAR_ORIGIN - 1);
945 int by = b->tm_year + (TM_YEAR_ORIGIN - 1);
947 /* difference in day of year */
948 a->tm_yday - b->tm_yday
949 /* + intervening leap days */
950 + ((ay >> 2) - (by >> 2))
952 + ((ay/100 >> 2) - (by/100 >> 2))
953 /* + difference in years * 365 */
954 + (long)(ay-by) * 365
956 return (60*(60*(24*days + (a->tm_hour - b->tm_hour))
957 + (a->tm_min - b->tm_min))
958 + (a->tm_sec - b->tm_sec));
974 (void)time (&ftz.time);
976 if (! (tm = gmtime (&ftz.time)))
978 gmt = *tm; /* Make a copy, in case localtime modifies *tm. */
980 if (! (tm = localtime (&ftz.time)))
983 ftz.timezone = difftm (&gmt, tm) / 60;
988 tm = localtime (&now->time);
989 yyYear = tm->tm_year;
990 yyMonth = tm->tm_mon + 1;
992 yyTimezone = now->timezone;
993 yyDSTmode = DSTmaybe;
1007 || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1)
1010 if (yyHaveDate || yyHaveTime || yyHaveDay) {
1011 Start = Convert (yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds,
1012 yyMeridian, yyDSTmode);
1019 Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec;
1022 Start += yyRelSeconds;
1023 Start += RelativeMonth (Start, yyRelMonth);
1025 if (yyHaveDay && !yyHaveDate) {
1026 tod = RelativeDate (Start, yyDayOrdinal, yyDayNumber);
1030 /* Have to do *something* with a legitimate -1 so it's distinguishable
1031 * from the error return value. (Alternately could set errno on error.) */
1032 return Start == -1 ? 0 : Start;
1044 char buff[MAX_BUFF_LEN + 1];
1047 (void)printf ("Enter date, or blank line to exit.\n\t> ");
1048 (void)fflush (stdout);
1050 buff[MAX_BUFF_LEN] = 0;
1051 while (fgets (buff, MAX_BUFF_LEN, stdin) && buff[0]) {
1052 d = get_date (buff, (struct timeb *)NULL);
1054 (void)printf ("Bad format - couldn't convert.\n");
1056 (void)printf ("%s", ctime (&d));
1057 (void)printf ("\t> ");
1058 (void)fflush (stdout);
1063 #endif /* defined (TEST) */