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 grammar has 10 shift/reduce conflicts.
10 ** This code is in the public domain and has no copyright.
12 /* SUPPRESS 287 on yaccpar_sccsid *//* Unused static variable */
13 /* SUPPRESS 288 on yyerrlab *//* Label unused */
16 #if defined (emacs) || defined (CONFIG_BROKETS)
23 /* Since the code of getdate.y is not included in the Emacs executable
24 itself, there is no need to #define static in this file. Even if
25 the code were included in the Emacs executable, it probably
26 wouldn't do any harm to #undef it here; this will only cause
27 problems if we try to write to a static variable, which I don't
28 think this code needs to do. */
36 /* The code at the top of get_date which figures out the offset of the
37 current time zone checks various CPP symbols to see if special
38 tricks are need, but defaults to using the gettimeofday system call.
39 Include <sys/time.h> if that will be used. */
43 #else /* defined(vms) */
44 # include <sys/types.h>
45 #endif /* !defined(vms) */
48 #if defined (STDC_HEADERS) || defined (USG)
52 /* Some old versions of bison generate parsers that use bcopy.
53 That loses on systems that don't provide the function, so we have
54 to redefine it here. */
55 #if !defined (HAVE_BCOPY) && defined (HAVE_MEMCPY) && !defined (bcopy)
56 #define bcopy(from, to, len) memcpy ((to), (from), (len))
59 #if defined (STDC_HEADERS)
63 /* NOTES on rebuilding getdate.c (particularly for inclusion in CVS
66 We don't want to mess with all the portability hassles of alloca.
67 In particular, most (all?) versions of bison will use alloca in
68 their parser. If bison works on your system (e.g. it should work
69 with gcc), then go ahead and use it, but the more general solution
70 is to use byacc instead of bison, which should generate a portable
71 parser. I played with adding "#define alloca dont_use_alloca", to
72 give an error if the parser generator uses alloca (and thus detect
73 unportable getdate.c's), but that seems to cause as many problems
76 extern
struct tm
*gmtime
();
77 extern
struct tm
*localtime
();
79 #define yyparse getdate_yyparse
80 #define yylex getdate_yylex
81 #define yyerror getdate_yyerror
83 static int yyparse ();
85 static int yyerror ();
88 #define HOUR(x) ((time_t)(x) * 60)
89 #define SECSPERDAY (24L * 60L * 60L)
93 ** An entry in the lexical lookup table.
95 typedef
struct _TABLE
{
103 ** Daylight-savings mode: on, off, or not yet known.
105 typedef
enum _DSTMODE
{
106 DSTon
, DSToff
, DSTmaybe
110 ** Meridian: am, pm, or 24-hour style.
112 typedef
enum _MERIDIAN
{
118 ** Global variables. We could get rid of most of these by using a good
119 ** union as the yacc stack. (This routine was originally written before
120 ** yacc had the %union construct.) Maybe someday; right now we only use
121 ** the %union very rarely.
123 static char *yyInput
;
124 static DSTMODE yyDSTmode
;
125 static time_t yyDayOrdinal
;
126 static time_t yyDayNumber
;
127 static int yyHaveDate
;
128 static int yyHaveDay
;
129 static int yyHaveRel
;
130 static int yyHaveTime
;
131 static int yyHaveZone
;
132 static time_t yyTimezone
;
134 static time_t yyHour
;
135 static time_t yyMinutes
;
136 static time_t yyMonth
;
137 static time_t yySeconds
;
138 static time_t yyYear
;
139 static MERIDIAN yyMeridian
;
140 static time_t yyRelMonth
;
141 static time_t yyRelSeconds
;
147 enum _MERIDIAN Meridian
;
150 %token tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT
151 %token tSEC_UNIT tSNUMBER tUNUMBER tZONE tDST
153 %type
<Number
> tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT
154 %type
<Number
> tSEC_UNIT tSNUMBER tUNUMBER tZONE
155 %type
<Meridian
> tMERIDIAN o_merid
186 cvsstamp: tUNUMBER
'.' tUNUMBER
'.' tUNUMBER
'.' tUNUMBER
'.' tUNUMBER
'.' tUNUMBER
{
188 if
(yyYear
< 100) yyYear
+= 1900;
199 time
: tUNUMBER tMERIDIAN
{
205 | tUNUMBER
':' tUNUMBER o_merid
{
211 | tUNUMBER
':' tUNUMBER tSNUMBER
{
216 yyTimezone
= - ($4 %
100 + ($4 / 100) * 60);
218 | tUNUMBER
':' tUNUMBER
':' tUNUMBER o_merid
{
224 | tUNUMBER
':' tUNUMBER
':' tUNUMBER tSNUMBER
{
230 yyTimezone
= - ($6 %
100 + ($6 / 100) * 60);
263 date
: tUNUMBER
'/' tUNUMBER
{
267 | tUNUMBER
'/' tUNUMBER
'/' tUNUMBER
{
278 | tUNUMBER tSNUMBER tSNUMBER
{
279 /* ISO 8601 format. yyyy-mm-dd. */
284 | tUNUMBER tMONTH tSNUMBER
{
285 /* e.g. 17-JUN-1992. */
294 | tMONTH tUNUMBER
',' tUNUMBER
{
303 | tUNUMBER tMONTH tUNUMBER
{
311 yyRelSeconds
= -yyRelSeconds
;
312 yyRelMonth
= -yyRelMonth
;
317 relunit
: tUNUMBER tMINUTE_UNIT
{
318 yyRelSeconds
+= $1 * $2 * 60L;
320 | tSNUMBER tMINUTE_UNIT
{
321 yyRelSeconds
+= $1 * $2 * 60L;
324 yyRelSeconds
+= $1 * 60L;
326 | tSNUMBER tSEC_UNIT
{
329 | tUNUMBER tSEC_UNIT
{
335 | tSNUMBER tMONTH_UNIT
{
336 yyRelMonth
+= $1 * $2;
338 | tUNUMBER tMONTH_UNIT
{
339 yyRelMonth
+= $1 * $2;
347 if
(yyHaveTime
&& yyHaveDate
&& !yyHaveRel
)
353 yyMonth
= ($1/100)%
100;
364 yyMinutes
= $1 %
100;
373 o_merid
: /* NULL */ {
383 /* Month and day table. */
384 static TABLE
const MonthDayTable
[] = {
385 { "january", tMONTH
, 1 },
386 { "february", tMONTH
, 2 },
387 { "march", tMONTH
, 3 },
388 { "april", tMONTH
, 4 },
389 { "may", tMONTH
, 5 },
390 { "june", tMONTH
, 6 },
391 { "july", tMONTH
, 7 },
392 { "august", tMONTH
, 8 },
393 { "september", tMONTH
, 9 },
394 { "sept", tMONTH
, 9 },
395 { "october", tMONTH
, 10 },
396 { "november", tMONTH
, 11 },
397 { "december", tMONTH
, 12 },
398 { "sunday", tDAY
, 0 },
399 { "monday", tDAY
, 1 },
400 { "tuesday", tDAY
, 2 },
402 { "wednesday", tDAY
, 3 },
403 { "wednes", tDAY
, 3 },
404 { "thursday", tDAY
, 4 },
406 { "thurs", tDAY
, 4 },
407 { "friday", tDAY
, 5 },
408 { "saturday", tDAY
, 6 },
412 /* Time units table. */
413 static TABLE
const UnitsTable
[] = {
414 { "year", tMONTH_UNIT
, 12 },
415 { "month", tMONTH_UNIT
, 1 },
416 { "fortnight", tMINUTE_UNIT
, 14 * 24 * 60 },
417 { "week", tMINUTE_UNIT
, 7 * 24 * 60 },
418 { "day", tMINUTE_UNIT
, 1 * 24 * 60 },
419 { "hour", tMINUTE_UNIT
, 60 },
420 { "minute", tMINUTE_UNIT
, 1 },
421 { "min", tMINUTE_UNIT
, 1 },
422 { "second", tSEC_UNIT
, 1 },
423 { "sec", tSEC_UNIT
, 1 },
427 /* Assorted relative-time words. */
428 static TABLE
const OtherTable
[] = {
429 { "tomorrow", tMINUTE_UNIT
, 1 * 24 * 60 },
430 { "yesterday", tMINUTE_UNIT
, -1 * 24 * 60 },
431 { "today", tMINUTE_UNIT
, 0 },
432 { "now", tMINUTE_UNIT
, 0 },
433 { "last", tUNUMBER
, -1 },
434 { "this", tMINUTE_UNIT
, 0 },
435 { "next", tUNUMBER
, 2 },
436 { "first", tUNUMBER
, 1 },
437 /* { "second", tUNUMBER, 2 }, */
438 { "third", tUNUMBER
, 3 },
439 { "fourth", tUNUMBER
, 4 },
440 { "fifth", tUNUMBER
, 5 },
441 { "sixth", tUNUMBER
, 6 },
442 { "seventh", tUNUMBER
, 7 },
443 { "eighth", tUNUMBER
, 8 },
444 { "ninth", tUNUMBER
, 9 },
445 { "tenth", tUNUMBER
, 10 },
446 { "eleventh", tUNUMBER
, 11 },
447 { "twelfth", tUNUMBER
, 12 },
452 /* The timezone table. */
453 /* Some of these are commented out because a time_t can't store a float. */
454 static TABLE
const TimezoneTable
[] = {
455 { "gmt", tZONE
, HOUR
( 0) }, /* Greenwich Mean */
456 { "ut", tZONE
, HOUR
( 0) }, /* Universal (Coordinated) */
457 { "utc", tZONE
, HOUR
( 0) },
458 { "wet", tZONE
, HOUR
( 0) }, /* Western European */
459 { "bst", tDAYZONE
, HOUR
( 0) }, /* British Summer */
460 { "wat", tZONE
, HOUR
( 1) }, /* West Africa */
461 { "at", tZONE
, HOUR
( 2) }, /* Azores */
463 /* For completeness. BST is also British Summer, and GST is
464 * also Guam Standard. */
465 { "bst", tZONE
, HOUR
( 3) }, /* Brazil Standard */
466 { "gst", tZONE
, HOUR
( 3) }, /* Greenland Standard */
469 { "nft", tZONE
, HOUR
(3.5) }, /* Newfoundland */
470 { "nst", tZONE
, HOUR
(3.5) }, /* Newfoundland Standard */
471 { "ndt", tDAYZONE
, HOUR
(3.5) }, /* Newfoundland Daylight */
473 { "ast", tZONE
, HOUR
( 4) }, /* Atlantic Standard */
474 { "adt", tDAYZONE
, HOUR
( 4) }, /* Atlantic Daylight */
475 { "est", tZONE
, HOUR
( 5) }, /* Eastern Standard */
476 { "edt", tDAYZONE
, HOUR
( 5) }, /* Eastern Daylight */
477 { "cst", tZONE
, HOUR
( 6) }, /* Central Standard */
478 { "cdt", tDAYZONE
, HOUR
( 6) }, /* Central Daylight */
479 { "mst", tZONE
, HOUR
( 7) }, /* Mountain Standard */
480 { "mdt", tDAYZONE
, HOUR
( 7) }, /* Mountain Daylight */
481 { "pst", tZONE
, HOUR
( 8) }, /* Pacific Standard */
482 { "pdt", tDAYZONE
, HOUR
( 8) }, /* Pacific Daylight */
483 { "yst", tZONE
, HOUR
( 9) }, /* Yukon Standard */
484 { "ydt", tDAYZONE
, HOUR
( 9) }, /* Yukon Daylight */
485 { "hst", tZONE
, HOUR
(10) }, /* Hawaii Standard */
486 { "hdt", tDAYZONE
, HOUR
(10) }, /* Hawaii Daylight */
487 { "cat", tZONE
, HOUR
(10) }, /* Central Alaska */
488 { "ahst", tZONE
, HOUR
(10) }, /* Alaska-Hawaii Standard */
489 { "nt", tZONE
, HOUR
(11) }, /* Nome */
490 { "idlw", tZONE
, HOUR
(12) }, /* International Date Line West */
491 { "cet", tZONE
, -HOUR
(1) }, /* Central European */
492 { "met", tZONE
, -HOUR
(1) }, /* Middle European */
493 { "mewt", tZONE
, -HOUR
(1) }, /* Middle European Winter */
494 { "mest", tDAYZONE
, -HOUR
(1) }, /* Middle European Summer */
495 { "swt", tZONE
, -HOUR
(1) }, /* Swedish Winter */
496 { "sst", tDAYZONE
, -HOUR
(1) }, /* Swedish Summer */
497 { "fwt", tZONE
, -HOUR
(1) }, /* French Winter */
498 { "fst", tDAYZONE
, -HOUR
(1) }, /* French Summer */
499 { "eet", tZONE
, -HOUR
(2) }, /* Eastern Europe, USSR Zone 1 */
500 { "bt", tZONE
, -HOUR
(3) }, /* Baghdad, USSR Zone 2 */
502 { "it", tZONE
, -HOUR
(3.5) },/* Iran */
504 { "zp4", tZONE
, -HOUR
(4) }, /* USSR Zone 3 */
505 { "zp5", tZONE
, -HOUR
(5) }, /* USSR Zone 4 */
507 { "ist", tZONE
, -HOUR
(5.5) },/* Indian Standard */
509 { "zp6", tZONE
, -HOUR
(6) }, /* USSR Zone 5 */
511 /* For completeness. NST is also Newfoundland Stanard, and SST is
512 * also Swedish Summer. */
513 { "nst", tZONE
, -HOUR
(6.5) },/* North Sumatra */
514 { "sst", tZONE
, -HOUR
(7) }, /* South Sumatra, USSR Zone 6 */
516 { "wast", tZONE
, -HOUR
(7) }, /* West Australian Standard */
517 { "wadt", tDAYZONE
, -HOUR
(7) }, /* West Australian Daylight */
519 { "jt", tZONE
, -HOUR
(7.5) },/* Java (3pm in Cronusland!) */
521 { "cct", tZONE
, -HOUR
(8) }, /* China Coast, USSR Zone 7 */
522 { "jst", tZONE
, -HOUR
(9) }, /* Japan Standard, USSR Zone 8 */
524 { "cast", tZONE
, -HOUR
(9.5) },/* Central Australian Standard */
525 { "cadt", tDAYZONE
, -HOUR
(9.5) },/* Central Australian Daylight */
527 { "east", tZONE
, -HOUR
(10) }, /* Eastern Australian Standard */
528 { "eadt", tDAYZONE
, -HOUR
(10) }, /* Eastern Australian Daylight */
529 { "gst", tZONE
, -HOUR
(10) }, /* Guam Standard, USSR Zone 9 */
530 { "nzt", tZONE
, -HOUR
(12) }, /* New Zealand */
531 { "nzst", tZONE
, -HOUR
(12) }, /* New Zealand Standard */
532 { "nzdt", tDAYZONE
, -HOUR
(12) }, /* New Zealand Daylight */
533 { "idle", tZONE
, -HOUR
(12) }, /* International Date Line East */
537 /* Military timezone table. */
538 static TABLE
const MilitaryTable
[] = {
539 { "a", tZONE
, HOUR
( 1) },
540 { "b", tZONE
, HOUR
( 2) },
541 { "c", tZONE
, HOUR
( 3) },
542 { "d", tZONE
, HOUR
( 4) },
543 { "e", tZONE
, HOUR
( 5) },
544 { "f", tZONE
, HOUR
( 6) },
545 { "g", tZONE
, HOUR
( 7) },
546 { "h", tZONE
, HOUR
( 8) },
547 { "i", tZONE
, HOUR
( 9) },
548 { "k", tZONE
, HOUR
( 10) },
549 { "l", tZONE
, HOUR
( 11) },
550 { "m", tZONE
, HOUR
( 12) },
551 { "n", tZONE
, HOUR
(- 1) },
552 { "o", tZONE
, HOUR
(- 2) },
553 { "p", tZONE
, HOUR
(- 3) },
554 { "q", tZONE
, HOUR
(- 4) },
555 { "r", tZONE
, HOUR
(- 5) },
556 { "s", tZONE
, HOUR
(- 6) },
557 { "t", tZONE
, HOUR
(- 7) },
558 { "u", tZONE
, HOUR
(- 8) },
559 { "v", tZONE
, HOUR
(- 9) },
560 { "w", tZONE
, HOUR
(-10) },
561 { "x", tZONE
, HOUR
(-11) },
562 { "y", tZONE
, HOUR
(-12) },
563 { "z", tZONE
, HOUR
( 0) },
580 ToSeconds
(Hours
, Minutes
, Seconds
, Meridian
)
586 if
(Minutes
< 0 || Minutes
> 59 || Seconds
< 0 || Seconds
> 59)
590 if
(Hours
< 0 || Hours
> 23)
592 return
(Hours
* 60L + Minutes
) * 60L + Seconds
;
594 if
(Hours
< 1 || Hours
> 12)
598 return
(Hours
* 60L + Minutes
) * 60L + Seconds
;
600 if
(Hours
< 1 || Hours
> 12)
604 return
((Hours
+ 12) * 60L + Minutes
) * 60L + Seconds
;
613 * A negative number, which means to use its absolute value (why?)
614 * A number from 0 to 99, which means a year from 1900 to 1999, or
615 * The actual year (>=100). */
617 Convert
(Month
, Day
, Year
, Hours
, Minutes
, Seconds
, Meridian
, DSTmode
)
627 static int DaysInMonth
[12] = {
628 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
640 DaysInMonth
[1] = Year %
4 == 0 && (Year %
100 != 0 || Year %
400 == 0)
642 /* Checking for 2038 bogusly assumes that time_t is 32 bits. But
643 I'm too lazy to try to check for time_t overflow in another way. */
644 if
(Year
< EPOCH || Year
> 2038
645 || Month
< 1 || Month
> 12
646 /* Lint fluff: "conversion from long may lose accuracy" */
647 || Day
< 1 || Day
> DaysInMonth
[(int)--Month
])
649 * It would be nice to set a global error string here.
650 * "February 30 is not a valid date" is much more informative than
651 * "Can't parse date/time: 100 months" when the user input was
652 * "100 months" and addition resolved that to February 30, for
653 * example. See rcs2-7 in src/sanity.sh for more. */
656 for
(Julian
= Day
- 1, i
= 0; i
< Month
; i
++)
657 Julian
+= DaysInMonth
[i
];
658 for
(i
= EPOCH
; i
< Year
; i
++)
659 Julian
+= 365 + (i %
4 == 0);
660 Julian
*= SECSPERDAY
;
661 Julian
+= yyTimezone
* 60L;
662 if
((tod
= ToSeconds
(Hours
, Minutes
, Seconds
, Meridian
)) < 0)
666 ||
(DSTmode
== DSTmaybe
&& localtime
(&Julian
)->tm_isdst
))
673 DSTcorrect
(Start
, Future
)
680 StartDay
= (localtime
(&Start
)->tm_hour
+ 1) %
24;
681 FutureDay
= (localtime
(&Future
)->tm_hour
+ 1) %
24;
682 return
(Future
- Start
) + (StartDay
- FutureDay
) * 60L * 60L;
687 RelativeDate
(Start
, DayOrdinal
, DayNumber
)
696 tm
= localtime
(&now
);
697 now
+= SECSPERDAY
* ((DayNumber
- tm
->tm_wday
+ 7) %
7);
698 now
+= 7 * SECSPERDAY
* (DayOrdinal
<= 0 ? DayOrdinal
: DayOrdinal
- 1);
699 return DSTcorrect
(Start
, now
);
704 RelativeMonth
(Start
, RelMonth
)
714 tm
= localtime
(&Start
);
715 Month
= 12 * (tm
->tm_year
+ 1900) + tm
->tm_mon
+ RelMonth
;
717 Month
= Month %
12 + 1;
718 return DSTcorrect
(Start
,
719 Convert
(Month
, (time_t)tm
->tm_mday
, Year
,
720 (time_t)tm
->tm_hour
, (time_t)tm
->tm_min
, (time_t)tm
->tm_sec
,
731 register
const TABLE
*tp
;
735 /* Make it lowercase. */
736 for
(p
= buff
; *p
; p
++)
740 if
(strcmp
(buff
, "am") == 0 || strcmp
(buff
, "a.m.") == 0) {
741 yylval.Meridian
= MERam
;
744 if
(strcmp
(buff
, "pm") == 0 || strcmp
(buff
, "p.m.") == 0) {
745 yylval.Meridian
= MERpm
;
749 /* See if we have an abbreviation for a month. */
750 if
(strlen
(buff
) == 3)
752 else if
(strlen
(buff
) == 4 && buff
[3] == '.') {
759 for
(tp
= MonthDayTable
; tp
->name
; tp
++) {
761 if
(strncmp
(buff
, tp
->name
, 3) == 0) {
762 yylval.Number
= tp
->value
;
766 else if
(strcmp
(buff
, tp
->name
) == 0) {
767 yylval.Number
= tp
->value
;
772 for
(tp
= TimezoneTable
; tp
->name
; tp
++)
773 if
(strcmp
(buff
, tp
->name
) == 0) {
774 yylval.Number
= tp
->value
;
778 if
(strcmp
(buff
, "dst") == 0)
781 for
(tp
= UnitsTable
; tp
->name
; tp
++)
782 if
(strcmp
(buff
, tp
->name
) == 0) {
783 yylval.Number
= tp
->value
;
787 /* Strip off any plural and try the units table again. */
788 i
= strlen
(buff
) - 1;
789 if
(buff
[i
] == 's') {
791 for
(tp
= UnitsTable
; tp
->name
; tp
++)
792 if
(strcmp
(buff
, tp
->name
) == 0) {
793 yylval.Number
= tp
->value
;
796 buff
[i
] = 's'; /* Put back for "this" in OtherTable. */
799 for
(tp
= OtherTable
; tp
->name
; tp
++)
800 if
(strcmp
(buff
, tp
->name
) == 0) {
801 yylval.Number
= tp
->value
;
805 /* Military timezones. */
806 if
(buff
[1] == '\0' && isalpha
(*buff
)) {
807 for
(tp
= MilitaryTable
; tp
->name
; tp
++)
808 if
(strcmp
(buff
, tp
->name
) == 0) {
809 yylval.Number
= tp
->value
;
814 /* Drop out any periods and try the timezone table again. */
815 for
(i
= 0, p
= q
= buff
; *q
; q
++)
822 for
(tp
= TimezoneTable
; tp
->name
; tp
++)
823 if
(strcmp
(buff
, tp
->name
) == 0) {
824 yylval.Number
= tp
->value
;
842 while
(isspace
(*yyInput
))
845 if
(isdigit
(c
= *yyInput
) || c
== '-' || c
== '+') {
846 if
(c
== '-' || c
== '+') {
847 sign
= c
== '-' ?
-1 : 1;
848 if
(!isdigit
(*++yyInput
))
849 /* skip the '-' sign */
854 for
(yylval.Number
= 0; isdigit
(c
= *yyInput
++); )
855 yylval.Number
= 10 * yylval.Number
+ c
- '0';
858 yylval.Number
= -yylval.Number
;
859 return sign ? tSNUMBER
: tUNUMBER
;
862 for
(p
= buff
; isalpha
(c
= *yyInput
++) || c
== '.'; )
863 if
(p
< &buff
[sizeof buff
- 1])
867 return LookupWord
(buff
);
884 #define TM_YEAR_ORIGIN 1900
886 /* Yield A - B, measured in seconds. */
891 int ay
= a
->tm_year
+ (TM_YEAR_ORIGIN
- 1);
892 int by
= b
->tm_year
+ (TM_YEAR_ORIGIN
- 1);
894 /* difference in day of year */
895 a
->tm_yday
- b
->tm_yday
896 /* + intervening leap days */
897 + ((ay
>> 2) - (by
>> 2))
899 + ((ay
/100 >> 2) - (by
/100 >> 2))
900 /* + difference in years * 365 */
901 + (long)(ay
-by
) * 365
903 return
(60*(60*(24*days
+ (a
->tm_hour
- b
->tm_hour
))
904 + (a
->tm_min
- b
->tm_min
))
905 + (a
->tm_sec
- b
->tm_sec
));
924 (void)time
(&nowtime
);
926 gmt_ptr
= gmtime
(&nowtime
);
929 /* Make a copy, in case localtime modifies *tm (I think
930 that comment now applies to *gmt_ptr, but I am too
931 lazy to dig into how gmtime and locatime allocate the
932 structures they return pointers to). */
936 if
(! (tm
= localtime
(&nowtime
)))
940 ftz.timezone
= difftm
(&gmt
, tm
) / 60;
942 /* We are on a system like VMS, where the system clock is
943 in local time and the system has no concept of timezones.
944 Hopefully we can fake this out (for the case in which the
945 user specifies no timezone) by just saying the timezone
957 tm
= localtime
(&nowtime
);
958 yyYear
= tm
->tm_year
+ 1900;
959 yyMonth
= tm
->tm_mon
+ 1;
961 yyTimezone
= now
->timezone
;
962 yyDSTmode
= DSTmaybe
;
976 || yyHaveTime
> 1 || yyHaveZone
> 1 || yyHaveDate
> 1 || yyHaveDay
> 1)
979 if
(yyHaveDate || yyHaveTime || yyHaveDay
) {
980 Start
= Convert
(yyMonth
, yyDay
, yyYear
, yyHour
, yyMinutes
, yySeconds
,
981 yyMeridian
, yyDSTmode
);
988 Start
-= ((tm
->tm_hour
* 60L + tm
->tm_min
) * 60L) + tm
->tm_sec
;
991 Start
+= yyRelSeconds
;
992 Start
+= RelativeMonth
(Start
, yyRelMonth
);
994 if
(yyHaveDay
&& !yyHaveDate
) {
995 tod
= RelativeDate
(Start
, yyDayOrdinal
, yyDayNumber
);
999 /* Have to do *something* with a legitimate -1 so it's distinguishable
1000 * from the error return value. (Alternately could set errno on error.) */
1001 return Start
== -1 ?
0 : Start
;
1016 (void)printf
("Enter date, or blank line to exit.\n\t> ");
1017 (void)fflush
(stdout
);
1018 while
(gets
(buff
) && buff
[0]) {
1019 d
= get_date
(buff
, (struct timeb
*)NULL
);
1021 (void)printf
("Bad format - couldn't convert.\n");
1023 (void)printf
("%s", ctime
(&d
));
1024 (void)printf
("\t> ");
1025 (void)fflush
(stdout
);
1030 #endif /* defined(TEST) */