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))
47 /* ISDIGIT differs from ISDIGIT_LOCALE, as follows:
48 - Its arg may be any int or unsigned int; it need not be an unsigned char.
49 - It's guaranteed to evaluate its argument exactly once.
50 - It's typically faster.
51 Posix 1003.2-1992 section 2.5.2.1 page 50 lines 1556-1558 says that
52 only '0' through '9' are digits. Prefer ISDIGIT to ISDIGIT_LOCALE unless
53 it's important to use the locale's definition of `digit' even when the
54 host does not conform to Posix. */
55 #define ISDIGIT(c) ((unsigned) (c) - '0' <= 9)
61 #include <sys/types.h>
62 #ifdef TIME_WITH_SYS_TIME
66 #ifdef HAVE_SYS_TIME_H
74 #undef timezone /* needed for sgi */
77 #if defined (HAVE_SYS_TIMEB_H)
78 #include <sys/timeb.h>
81 /* get_date uses the obsolete `struct timeb' in its interface! FIXME.
82 Since some systems don't have it, we define it here;
83 callers must do likewise. */
86 time_t time; /* Seconds since the epoch */
87 unsigned short millitm; /* Field not used */
88 short timezone; /* Minutes west of GMT */
89 short dstflag; /* Field not used */
91 #endif /* defined (HAVE_SYS_TIMEB_H) */
93 #endif /* defined (vms) */
95 #if defined (STDC_HEADERS) || defined (USG)
99 /* Some old versions of bison generate parsers that use bcopy.
100 That loses on systems that don't provide the function, so we have
101 to redefine it here. */
102 #if !defined (HAVE_BCOPY) && defined (HAVE_MEMCPY) && !defined (bcopy)
103 #define bcopy(from, to, len) memcpy ((to), (from), (len))
106 extern struct tm *gmtime ();
107 extern struct tm *localtime ();
109 /* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc),
110 as well as gratuitiously global symbol names, so we can have multiple
111 yacc generated parsers in the same program. Note that these are only
112 the variables produced by yacc. If other parser generators (bison,
113 byacc, etc) produce additional global names that conflict at link time,
114 then those parser generators need to be fixed instead of adding those
115 names to this list. */
117 #define yymaxdepth gd_maxdepth
118 #define yyparse gd_parse
120 #define yyerror gd_error
121 #define yylval gd_lval
122 #define yychar gd_char
123 #define yydebug gd_debug
124 #define yypact gd_pact
131 #define yyexca gd_exca
132 #define yyerrflag gd_errflag
133 #define yynerrs gd_nerrs
137 #define yy_yys gd_yys
138 #define yystate gd_state
141 #define yy_yyv gd_yyv
143 #define yylloc gd_lloc
144 #define yyreds gd_reds /* With YYDEBUG defined */
145 #define yytoks gd_toks /* With YYDEBUG defined */
146 #define yylhs gd_yylhs
147 #define yylen gd_yylen
148 #define yydefred gd_yydefred
149 #define yydgoto gd_yydgoto
150 #define yysindex gd_yysindex
151 #define yyrindex gd_yyrindex
152 #define yygindex gd_yygindex
153 #define yytable gd_yytable
154 #define yycheck gd_yycheck
157 static int yyerror ();
160 #define DOOMSDAY 2038
161 #define HOUR(x) ((time_t)(x) * 60)
162 #define SECSPERDAY (24L * 60L * 60L)
164 #define MAX_BUFF_LEN 128 /* size of buffer to read the date into */
167 ** An entry in the lexical lookup table.
169 typedef struct _TABLE {
177 ** Daylight-savings mode: on, off, or not yet known.
179 typedef enum _DSTMODE {
180 DSTon, DSToff, DSTmaybe
184 ** Meridian: am, pm, or 24-hour style.
186 typedef enum _MERIDIAN {
192 ** Global variables. We could get rid of most of these by using a good
193 ** union as the yacc stack. (This routine was originally written before
194 ** yacc had the %union construct.) Maybe someday; right now we only use
195 ** the %union very rarely.
197 static char *yyInput;
198 static DSTMODE yyDSTmode;
199 static time_t yyDayOrdinal;
200 static time_t yyDayNumber;
201 static int yyHaveDate;
202 static int yyHaveDay;
203 static int yyHaveRel;
204 static int yyHaveTime;
205 static int yyHaveZone;
206 static time_t yyTimezone;
208 static time_t yyHour;
209 static time_t yyMinutes;
210 static time_t yyMonth;
211 static time_t yySeconds;
212 static time_t yyYear;
213 static MERIDIAN yyMeridian;
214 static time_t yyRelMonth;
215 static time_t yyRelSeconds;
221 enum _MERIDIAN Meridian;
224 %token tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT
225 %token tSEC_UNIT tSNUMBER tUNUMBER tZONE tDST
227 %type <Number> tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT
228 %type <Number> tSEC_UNIT tSNUMBER tUNUMBER tZONE
229 %type <Meridian> tMERIDIAN o_merid
255 time : tUNUMBER tMERIDIAN {
261 | tUNUMBER ':' tUNUMBER o_merid {
267 | tUNUMBER ':' tUNUMBER tSNUMBER {
272 yyTimezone = - ($4 % 100 + ($4 / 100) * 60);
274 | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid {
280 | tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER {
286 yyTimezone = - ($6 % 100 + ($6 / 100) * 60);
319 date : tUNUMBER '/' tUNUMBER {
323 | tUNUMBER '/' tUNUMBER '/' tUNUMBER {
324 /* Interpret as YYYY/MM/DD if $1 >= 1000, otherwise as MM/DD/YY.
325 The goal in recognizing YYYY/MM/DD is solely to support legacy
326 machine-generated dates like those in an RCS log listing. If
327 you want portability, use the ISO 8601 format. */
341 | tUNUMBER tSNUMBER tSNUMBER {
342 /* ISO 8601 format. yyyy-mm-dd. */
347 | tUNUMBER tMONTH tSNUMBER {
348 /* e.g. 17-JUN-1992. */
357 | tMONTH tUNUMBER ',' tUNUMBER {
366 | tUNUMBER tMONTH tUNUMBER {
374 yyRelSeconds = -yyRelSeconds;
375 yyRelMonth = -yyRelMonth;
380 relunit : tUNUMBER tMINUTE_UNIT {
381 yyRelSeconds += $1 * $2 * 60L;
383 | tSNUMBER tMINUTE_UNIT {
384 yyRelSeconds += $1 * $2 * 60L;
387 yyRelSeconds += $1 * 60L;
389 | tSNUMBER tSEC_UNIT {
392 | tUNUMBER tSEC_UNIT {
398 | tSNUMBER tMONTH_UNIT {
399 yyRelMonth += $1 * $2;
401 | tUNUMBER tMONTH_UNIT {
402 yyRelMonth += $1 * $2;
410 if (yyHaveTime && yyHaveDate && !yyHaveRel)
416 yyMonth= ($1/100)%100;
427 yyMinutes = $1 % 100;
436 o_merid : /* NULL */ {
446 /* Month and day table. */
447 static TABLE const MonthDayTable[] = {
448 { "january", tMONTH, 1 },
449 { "february", tMONTH, 2 },
450 { "march", tMONTH, 3 },
451 { "april", tMONTH, 4 },
452 { "may", tMONTH, 5 },
453 { "june", tMONTH, 6 },
454 { "july", tMONTH, 7 },
455 { "august", tMONTH, 8 },
456 { "september", tMONTH, 9 },
457 { "sept", tMONTH, 9 },
458 { "october", tMONTH, 10 },
459 { "november", tMONTH, 11 },
460 { "december", tMONTH, 12 },
461 { "sunday", tDAY, 0 },
462 { "monday", tDAY, 1 },
463 { "tuesday", tDAY, 2 },
465 { "wednesday", tDAY, 3 },
466 { "wednes", tDAY, 3 },
467 { "thursday", tDAY, 4 },
469 { "thurs", tDAY, 4 },
470 { "friday", tDAY, 5 },
471 { "saturday", tDAY, 6 },
475 /* Time units table. */
476 static TABLE const UnitsTable[] = {
477 { "year", tMONTH_UNIT, 12 },
478 { "month", tMONTH_UNIT, 1 },
479 { "fortnight", tMINUTE_UNIT, 14 * 24 * 60 },
480 { "week", tMINUTE_UNIT, 7 * 24 * 60 },
481 { "day", tMINUTE_UNIT, 1 * 24 * 60 },
482 { "hour", tMINUTE_UNIT, 60 },
483 { "minute", tMINUTE_UNIT, 1 },
484 { "min", tMINUTE_UNIT, 1 },
485 { "second", tSEC_UNIT, 1 },
486 { "sec", tSEC_UNIT, 1 },
490 /* Assorted relative-time words. */
491 static TABLE const OtherTable[] = {
492 { "tomorrow", tMINUTE_UNIT, 1 * 24 * 60 },
493 { "yesterday", tMINUTE_UNIT, -1 * 24 * 60 },
494 { "today", tMINUTE_UNIT, 0 },
495 { "now", tMINUTE_UNIT, 0 },
496 { "last", tUNUMBER, -1 },
497 { "this", tMINUTE_UNIT, 0 },
498 { "next", tUNUMBER, 2 },
499 { "first", tUNUMBER, 1 },
500 /* { "second", tUNUMBER, 2 }, */
501 { "third", tUNUMBER, 3 },
502 { "fourth", tUNUMBER, 4 },
503 { "fifth", tUNUMBER, 5 },
504 { "sixth", tUNUMBER, 6 },
505 { "seventh", tUNUMBER, 7 },
506 { "eighth", tUNUMBER, 8 },
507 { "ninth", tUNUMBER, 9 },
508 { "tenth", tUNUMBER, 10 },
509 { "eleventh", tUNUMBER, 11 },
510 { "twelfth", tUNUMBER, 12 },
515 /* The timezone table. */
516 /* Some of these are commented out because a time_t can't store a float. */
517 static TABLE const TimezoneTable[] = {
518 { "gmt", tZONE, HOUR ( 0) }, /* Greenwich Mean */
519 { "ut", tZONE, HOUR ( 0) }, /* Universal (Coordinated) */
520 { "utc", tZONE, HOUR ( 0) },
521 { "wet", tZONE, HOUR ( 0) }, /* Western European */
522 { "bst", tDAYZONE, HOUR ( 0) }, /* British Summer */
523 { "wat", tZONE, HOUR ( 1) }, /* West Africa */
524 { "at", tZONE, HOUR ( 2) }, /* Azores */
526 /* For completeness. BST is also British Summer, and GST is
527 * also Guam Standard. */
528 { "bst", tZONE, HOUR ( 3) }, /* Brazil Standard */
529 { "gst", tZONE, HOUR ( 3) }, /* Greenland Standard */
532 { "nft", tZONE, HOUR (3.5) }, /* Newfoundland */
533 { "nst", tZONE, HOUR (3.5) }, /* Newfoundland Standard */
534 { "ndt", tDAYZONE, HOUR (3.5) }, /* Newfoundland Daylight */
536 { "ast", tZONE, HOUR ( 4) }, /* Atlantic Standard */
537 { "adt", tDAYZONE, HOUR ( 4) }, /* Atlantic Daylight */
538 { "est", tZONE, HOUR ( 5) }, /* Eastern Standard */
539 { "edt", tDAYZONE, HOUR ( 5) }, /* Eastern Daylight */
540 { "cst", tZONE, HOUR ( 6) }, /* Central Standard */
541 { "cdt", tDAYZONE, HOUR ( 6) }, /* Central Daylight */
542 { "mst", tZONE, HOUR ( 7) }, /* Mountain Standard */
543 { "mdt", tDAYZONE, HOUR ( 7) }, /* Mountain Daylight */
544 { "pst", tZONE, HOUR ( 8) }, /* Pacific Standard */
545 { "pdt", tDAYZONE, HOUR ( 8) }, /* Pacific Daylight */
546 { "yst", tZONE, HOUR ( 9) }, /* Yukon Standard */
547 { "ydt", tDAYZONE, HOUR ( 9) }, /* Yukon Daylight */
548 { "hst", tZONE, HOUR (10) }, /* Hawaii Standard */
549 { "hdt", tDAYZONE, HOUR (10) }, /* Hawaii Daylight */
550 { "cat", tZONE, HOUR (10) }, /* Central Alaska */
551 { "ahst", tZONE, HOUR (10) }, /* Alaska-Hawaii Standard */
552 { "nt", tZONE, HOUR (11) }, /* Nome */
553 { "idlw", tZONE, HOUR (12) }, /* International Date Line West */
554 { "cet", tZONE, -HOUR (1) }, /* Central European */
555 { "met", tZONE, -HOUR (1) }, /* Middle European */
556 { "mewt", tZONE, -HOUR (1) }, /* Middle European Winter */
557 { "mest", tDAYZONE, -HOUR (1) }, /* Middle European Summer */
558 { "mesz", tDAYZONE, -HOUR (1) }, /* Middle European Summer */
559 { "swt", tZONE, -HOUR (1) }, /* Swedish Winter */
560 { "sst", tDAYZONE, -HOUR (1) }, /* Swedish Summer */
561 { "fwt", tZONE, -HOUR (1) }, /* French Winter */
562 { "fst", tDAYZONE, -HOUR (1) }, /* French Summer */
563 { "eet", tZONE, -HOUR (2) }, /* Eastern Europe, USSR Zone 1 */
564 { "bt", tZONE, -HOUR (3) }, /* Baghdad, USSR Zone 2 */
566 { "it", tZONE, -HOUR (3.5) },/* Iran */
568 { "zp4", tZONE, -HOUR (4) }, /* USSR Zone 3 */
569 { "zp5", tZONE, -HOUR (5) }, /* USSR Zone 4 */
571 { "ist", tZONE, -HOUR (5.5) },/* Indian Standard */
573 { "zp6", tZONE, -HOUR (6) }, /* USSR Zone 5 */
575 /* For completeness. NST is also Newfoundland Standard, and SST is
576 * also Swedish Summer. */
577 { "nst", tZONE, -HOUR (6.5) },/* North Sumatra */
578 { "sst", tZONE, -HOUR (7) }, /* South Sumatra, USSR Zone 6 */
580 { "wast", tZONE, -HOUR (7) }, /* West Australian Standard */
581 { "wadt", tDAYZONE, -HOUR (7) }, /* West Australian Daylight */
583 { "jt", tZONE, -HOUR (7.5) },/* Java (3pm in Cronusland!) */
585 { "cct", tZONE, -HOUR (8) }, /* China Coast, USSR Zone 7 */
586 { "jst", tZONE, -HOUR (9) }, /* Japan Standard, USSR Zone 8 */
588 { "cast", tZONE, -HOUR (9.5) },/* Central Australian Standard */
589 { "cadt", tDAYZONE, -HOUR (9.5) },/* Central Australian Daylight */
591 { "east", tZONE, -HOUR (10) }, /* Eastern Australian Standard */
592 { "eadt", tDAYZONE, -HOUR (10) }, /* Eastern Australian Daylight */
593 { "gst", tZONE, -HOUR (10) }, /* Guam Standard, USSR Zone 9 */
594 { "nzt", tZONE, -HOUR (12) }, /* New Zealand */
595 { "nzst", tZONE, -HOUR (12) }, /* New Zealand Standard */
596 { "nzdt", tDAYZONE, -HOUR (12) }, /* New Zealand Daylight */
597 { "idle", tZONE, -HOUR (12) }, /* International Date Line East */
601 /* Military timezone table. */
602 static TABLE const MilitaryTable[] = {
603 { "a", tZONE, HOUR ( 1) },
604 { "b", tZONE, HOUR ( 2) },
605 { "c", tZONE, HOUR ( 3) },
606 { "d", tZONE, HOUR ( 4) },
607 { "e", tZONE, HOUR ( 5) },
608 { "f", tZONE, HOUR ( 6) },
609 { "g", tZONE, HOUR ( 7) },
610 { "h", tZONE, HOUR ( 8) },
611 { "i", tZONE, HOUR ( 9) },
612 { "k", tZONE, HOUR ( 10) },
613 { "l", tZONE, HOUR ( 11) },
614 { "m", tZONE, HOUR ( 12) },
615 { "n", tZONE, HOUR (- 1) },
616 { "o", tZONE, HOUR (- 2) },
617 { "p", tZONE, HOUR (- 3) },
618 { "q", tZONE, HOUR (- 4) },
619 { "r", tZONE, HOUR (- 5) },
620 { "s", tZONE, HOUR (- 6) },
621 { "t", tZONE, HOUR (- 7) },
622 { "u", tZONE, HOUR (- 8) },
623 { "v", tZONE, HOUR (- 9) },
624 { "w", tZONE, HOUR (-10) },
625 { "x", tZONE, HOUR (-11) },
626 { "y", tZONE, HOUR (-12) },
627 { "z", tZONE, HOUR ( 0) },
644 ToSeconds (Hours, Minutes, Seconds, Meridian)
650 if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59)
654 if (Hours < 0 || Hours > 23)
656 return (Hours * 60L + Minutes) * 60L + Seconds;
658 if (Hours < 1 || Hours > 12)
662 return (Hours * 60L + Minutes) * 60L + Seconds;
664 if (Hours < 1 || Hours > 12)
668 return ((Hours + 12) * 60L + Minutes) * 60L + Seconds;
677 Convert (Month, Day, Year, Hours, Minutes, Seconds, Meridian, DSTmode)
687 static int DaysInMonth[12] = {
688 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
696 if (Year < DOOMSDAY-2000)
700 DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0)
702 if (Year < EPOCH || Year > DOOMSDAY
703 || Month < 1 || Month > 12
704 /* Lint fluff: "conversion from long may lose accuracy" */
705 || Day < 1 || Day > DaysInMonth[(int)--Month])
708 for (Julian = Day - 1, i = 0; i < Month; i++)
709 Julian += DaysInMonth[i];
710 for (i = EPOCH; i < Year; i++)
711 Julian += 365 + (i % 4 == 0);
712 Julian *= SECSPERDAY;
713 Julian += yyTimezone * 60L;
714 if ((tod = ToSeconds (Hours, Minutes, Seconds, Meridian)) < 0)
718 || (DSTmode == DSTmaybe && localtime (&Julian)->tm_isdst))
725 DSTcorrect (Start, Future)
732 StartDay = (localtime (&Start)->tm_hour + 1) % 24;
733 FutureDay = (localtime (&Future)->tm_hour + 1) % 24;
734 return (Future - Start) + (StartDay - FutureDay) * 60L * 60L;
739 RelativeDate (Start, DayOrdinal, DayNumber)
748 tm = localtime (&now);
749 now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7);
750 now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1);
751 return DSTcorrect (Start, now);
756 RelativeMonth (Start, RelMonth)
766 tm = localtime (&Start);
767 Month = 12 * (1900 + tm->tm_year) + tm->tm_mon + RelMonth;
769 Month = Month % 12 + 1;
770 return DSTcorrect (Start,
771 Convert (Month, (time_t)tm->tm_mday, Year,
772 (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
783 register const TABLE *tp;
787 /* Make it lowercase. */
788 for (p = buff; *p; p++)
792 if (strcmp (buff, "am") == 0 || strcmp (buff, "a.m.") == 0) {
793 yylval.Meridian = MERam;
796 if (strcmp (buff, "pm") == 0 || strcmp (buff, "p.m.") == 0) {
797 yylval.Meridian = MERpm;
801 /* See if we have an abbreviation for a month. */
802 if (strlen (buff) == 3)
804 else if (strlen (buff) == 4 && buff[3] == '.') {
811 for (tp = MonthDayTable; tp->name; tp++) {
813 if (strncmp (buff, tp->name, 3) == 0) {
814 yylval.Number = tp->value;
818 else if (strcmp (buff, tp->name) == 0) {
819 yylval.Number = tp->value;
824 for (tp = TimezoneTable; tp->name; tp++)
825 if (strcmp (buff, tp->name) == 0) {
826 yylval.Number = tp->value;
830 if (strcmp (buff, "dst") == 0)
833 for (tp = UnitsTable; tp->name; tp++)
834 if (strcmp (buff, tp->name) == 0) {
835 yylval.Number = tp->value;
839 /* Strip off any plural and try the units table again. */
840 i = strlen (buff) - 1;
841 if (buff[i] == 's') {
843 for (tp = UnitsTable; tp->name; tp++)
844 if (strcmp (buff, tp->name) == 0) {
845 yylval.Number = tp->value;
848 buff[i] = 's'; /* Put back for "this" in OtherTable. */
851 for (tp = OtherTable; tp->name; tp++)
852 if (strcmp (buff, tp->name) == 0) {
853 yylval.Number = tp->value;
857 /* Military timezones. */
858 if (buff[1] == '\0' && ISALPHA (*buff)) {
859 for (tp = MilitaryTable; tp->name; tp++)
860 if (strcmp (buff, tp->name) == 0) {
861 yylval.Number = tp->value;
866 /* Drop out any periods and try the timezone table again. */
867 for (i = 0, p = q = buff; *q; q++)
874 for (tp = TimezoneTable; tp->name; tp++)
875 if (strcmp (buff, tp->name) == 0) {
876 yylval.Number = tp->value;
894 while (ISSPACE (*yyInput))
897 if (ISDIGIT (c = *yyInput) || c == '-' || c == '+') {
898 if (c == '-' || c == '+') {
899 sign = c == '-' ? -1 : 1;
900 if (!ISDIGIT (*++yyInput))
901 /* skip the '-' sign */
906 for (yylval.Number = 0; ISDIGIT (c = *yyInput++); )
907 yylval.Number = 10 * yylval.Number + c - '0';
910 yylval.Number = -yylval.Number;
911 return sign ? tSNUMBER : tUNUMBER;
914 for (p = buff; (c = *yyInput++, ISALPHA (c)) || c == '.'; )
915 if (p < &buff[sizeof buff - 1])
919 return LookupWord (buff);
936 #define TM_YEAR_ORIGIN 1900
938 /* Yield A - B, measured in seconds. */
943 int ay = a->tm_year + (TM_YEAR_ORIGIN - 1);
944 int by = b->tm_year + (TM_YEAR_ORIGIN - 1);
946 /* difference in day of year */
947 a->tm_yday - b->tm_yday
948 /* + intervening leap days */
949 + ((ay >> 2) - (by >> 2))
951 + ((ay/100 >> 2) - (by/100 >> 2))
952 /* + difference in years * 365 */
953 + (long)(ay-by) * 365
955 return (60*(60*(24*days + (a->tm_hour - b->tm_hour))
956 + (a->tm_min - b->tm_min))
957 + (a->tm_sec - b->tm_sec));
973 (void)time (&ftz.time);
975 if (! (tm = gmtime (&ftz.time)))
977 gmt = *tm; /* Make a copy, in case localtime modifies *tm. */
979 if (! (tm = localtime (&ftz.time)))
982 ftz.timezone = difftm (&gmt, tm) / 60;
987 tm = localtime (&now->time);
988 yyYear = tm->tm_year;
989 yyMonth = tm->tm_mon + 1;
991 yyTimezone = now->timezone;
992 yyDSTmode = DSTmaybe;
1006 || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1)
1009 if (yyHaveDate || yyHaveTime || yyHaveDay) {
1010 Start = Convert (yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds,
1011 yyMeridian, yyDSTmode);
1018 Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec;
1021 Start += yyRelSeconds;
1022 Start += RelativeMonth (Start, yyRelMonth);
1024 if (yyHaveDay && !yyHaveDate) {
1025 tod = RelativeDate (Start, yyDayOrdinal, yyDayNumber);
1029 /* Have to do *something* with a legitimate -1 so it's distinguishable
1030 * from the error return value. (Alternately could set errno on error.) */
1031 return Start == -1 ? 0 : Start;
1043 char buff[MAX_BUFF_LEN + 1];
1046 (void)printf ("Enter date, or blank line to exit.\n\t> ");
1047 (void)fflush (stdout);
1049 buff[MAX_BUFF_LEN] = 0;
1050 while (fgets (buff, MAX_BUFF_LEN, stdin) && buff[0]) {
1051 d = get_date (buff, (struct timeb *)NULL);
1053 (void)printf ("Bad format - couldn't convert.\n");
1055 (void)printf ("%s", ctime (&d));
1056 (void)printf ("\t> ");
1057 (void)fflush (stdout);
1062 #endif /* defined (TEST) */