[3ae31e9] | 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
|
---|