1 | /************************************************************************/
|
---|
2 | /* Program: greg */
|
---|
3 | /* Purpose: compute and verify information for Gregorian calendar */
|
---|
4 | /* Copyright: W. M. McKeeman 1986. This program may be used or */
|
---|
5 | /* modified for any purpose so long as this copyright */
|
---|
6 | /* notice is incorporated in the resulting source code. */
|
---|
7 | /* Compile: Use cc -Os -DMAIN -o greg greg.c to compile with main */
|
---|
8 | /* delete the -DMAIN to compile as a function only. */
|
---|
9 | /* Input: year, month, day */
|
---|
10 | /* day of month week & year, week of month, julian day. */
|
---|
11 | /* input values are zero (meaning "to be computed") or */
|
---|
12 | /* positive integers (meaning "to be checked and used") */
|
---|
13 | /* Output: consistent positive values for input: */
|
---|
14 | /* return 0 if all output is valid, */
|
---|
15 | /* return 1 if input is inconsistent, */
|
---|
16 | /* return 2 if input is incomplete, */
|
---|
17 | /* return 3 if int or long int is too short. */
|
---|
18 | /* Example: */
|
---|
19 | /* y = 1985; m = 12; d = 10; wd = 0; wk = 0; yd = 0; jd = 0; */
|
---|
20 | /* greg(&y, &m, &d, &wd, &wk, &yd, &jd) returns 0 and leaves: */
|
---|
21 | /* y = 1985; m = 12; d = 10; wd = 3; wk = 2; yd = 344; jd = 2446410; */
|
---|
22 | /* Method: tableless. see man page */
|
---|
23 | /************************************************************************/
|
---|
24 |
|
---|
25 | #include "stdio.h"
|
---|
26 |
|
---|
27 | #define SUCCESS 0
|
---|
28 | #define INCONS 1
|
---|
29 | #define INCOMP 2
|
---|
30 | #define SYSFAIL 3
|
---|
31 |
|
---|
32 | #define Defined(e) ((e) != 0)
|
---|
33 |
|
---|
34 | #define MakeCon(v1, v2) \
|
---|
35 | {if (Defined(v1) && (v1) != (v2)) return(INCONS); else (v1) = (v2);}
|
---|
36 |
|
---|
37 | #define LeapsB4(y) (((y)-1)/4 - ((y)-1)/100 + ((y)-1)/400)
|
---|
38 |
|
---|
39 | #define AD0001Jan00 1721425L
|
---|
40 | #define AD1582Oct15 2299161L
|
---|
41 | #define AD14699Nov15 7090078L
|
---|
42 |
|
---|
43 | int
|
---|
44 | greg(year, month, day0month, day0week, week0month, day0year, julianDay)
|
---|
45 | int *year, *month, *day0month, *day0week, *week0month, *day0year;
|
---|
46 | long int *julianDay; /* 7 significant digits */
|
---|
47 | {
|
---|
48 | int d, w, m, y, ly, leaps;
|
---|
49 | long int td, jd;
|
---|
50 |
|
---|
51 | if Defined(*julianDay) {
|
---|
52 |
|
---|
53 | jd = *julianDay;
|
---|
54 |
|
---|
55 | if (jd <= AD0001Jan00)
|
---|
56 | return(INCONS);
|
---|
57 |
|
---|
58 | td = jd - AD0001Jan00 - 1;
|
---|
59 | y = 1 + (td -= (td+1)/146097, td += (td+1)/36524, td-(td+1)/1461)/365;
|
---|
60 | MakeCon(*year, y);
|
---|
61 | d = jd - ((y-1)*365 + LeapsB4(y) + AD0001Jan00);
|
---|
62 | MakeCon(*day0year, d);
|
---|
63 | }
|
---|
64 |
|
---|
65 | if (!Defined(*year))
|
---|
66 | return(INCOMP);
|
---|
67 | else
|
---|
68 | y = *year;
|
---|
69 |
|
---|
70 | leaps = LeapsB4(y);
|
---|
71 | ly = y%400 == 0 || (y%100 != 0 && y%4 == 0);
|
---|
72 |
|
---|
73 | if (!Defined(*day0year)) {
|
---|
74 | if (!Defined(*month)) return(INCOMP);
|
---|
75 | if (!Defined(*day0month)) {
|
---|
76 | if (!Defined(*day0week)||!Defined(*week0month))return(INCOMP);
|
---|
77 | *day0month = 7*(*week0month-1) + *day0week -
|
---|
78 | (y+leaps+3055L*(*month+2)/100-84-(*month>2)*(2-ly))%7;
|
---|
79 | }
|
---|
80 | *day0year = 3055L*(*month+2)/100 - 91 + *day0month - (*month>2)*(2-ly);
|
---|
81 | }
|
---|
82 |
|
---|
83 | td = (*day0year + (*day0year>59+ly)*(2-ly) + 91)*100L;
|
---|
84 | m = td/3055 - 2;
|
---|
85 | MakeCon(*month, m);
|
---|
86 | d = td%3055/100 + 1;
|
---|
87 | MakeCon(*day0month, d);
|
---|
88 |
|
---|
89 | jd = AD0001Jan00 + (y-1)*365 + LeapsB4(y) + *day0year;
|
---|
90 | MakeCon(*julianDay, jd);
|
---|
91 | w = (jd+1)%7 + 1;
|
---|
92 | MakeCon(*day0week, w);
|
---|
93 | w = (13 + *day0month - *day0week)/7;
|
---|
94 | MakeCon(*week0month, w);
|
---|
95 |
|
---|
96 | return(*month) > 12 || *julianDay < AD1582Oct15 || *day0month >
|
---|
97 | (*month == 2 ? 28+ly : 30+(*month == 1 || *month%5%3 != 1));
|
---|
98 | }
|
---|
99 |
|
---|
100 | #ifdef MAIN
|
---|
101 |
|
---|
102 | main(argc, argv) /* driver for greg */
|
---|
103 | int argc; char *argv[];
|
---|
104 | {
|
---|
105 | int r, i, p[7];
|
---|
106 | long int jd; /* 7 significant digits */
|
---|
107 |
|
---|
108 | if (sizeof (long int) < 4 || sizeof (int) < 2) r = SYSFAIL;
|
---|
109 | else if (argc > 8) r = INCONS; /* too many inputs */
|
---|
110 | else if (argc < 4) r = INCOMP; /* need y m d at least */
|
---|
111 | else {
|
---|
112 | r = SUCCESS;
|
---|
113 | for (i=1;i<=6;i++) {
|
---|
114 | p[i] = i < argc ? atoi(argv[i]) : 0;
|
---|
115 | if (p[i] < 0) r = INCONS; /* no negative input */
|
---|
116 | }
|
---|
117 | jd = argc == 8 ? atol(argv[7]) : 0L; /* julian day is (long) */
|
---|
118 | if (r != INCONS)
|
---|
119 | r = greg(&p[1], &p[2], &p[3], &p[4], &p[5], &p[6], &jd);
|
---|
120 | }
|
---|
121 |
|
---|
122 | switch (r) {
|
---|
123 |
|
---|
124 | case INCONS:
|
---|
125 | puts("greg: input does not describe a valid gregorian date");
|
---|
126 |
|
---|
127 | case SUCCESS:
|
---|
128 | printf("%d %d %d %d %d %d %ld\n", p[1],p[2],p[3],p[4],p[5],p[6],jd);
|
---|
129 | break;
|
---|
130 |
|
---|
131 | case INCOMP:
|
---|
132 | puts("greg: insufficient information");
|
---|
133 | puts("usage: greg year month day [day0week week0month day0year jd]");
|
---|
134 | break;
|
---|
135 |
|
---|
136 | case SYSFAIL:
|
---|
137 | puts("greg: insufficient precision in either (int) or (long int)");
|
---|
138 | break;
|
---|
139 | }
|
---|
140 | exit(r);
|
---|
141 | }
|
---|
142 |
|
---|
143 | #endif
|
---|