GGGGRRRREEEEGGGG((((1111)))) UUUUNNNNIIIIXXXX 5555....0000 ((((llllooooccccaaaallll)))) GGGGRRRREEEEGGGG((((1111)))) NNNNAAAAMMMMEEEE greg - compute details of Gregorian calendar SSSSYYYYNNNNTTTTAAAAXXXX ggggrrrreeeegggg YYYYeeeeaaaarrrr MMMMoooonnnntttthhhh DDDDaaaayyyyOOOOffffMMMMoooonnnntttthhhh [[[[DDDDaaaayyyyOOOOffffWWWWeeeeeeeekkkk WWWWeeeeeeeekkkkOOOOffffMMMMoooonnnntttthhhh DDDDaaaayyyyOOOOffffYYYYeeeeaaaarrrr JJJJuuuulllliiiiaaaannnnDDDDaaaayyyy]]]] SSSSYYYYNNNNOOOOPPPPSSSSIIIISSSS _G_r_e_g provides calendar information. It approximates the functionality of unix cal except that the information is provided in a way that is appropriate for use in other programs rather than visual display. The internal function "gregorian" is designed to be used as a component of other programs. DDDDEEEESSSSCCCCRRRRIIIIPPPPTTTTIIIIOOOONNNN The program is invertible in the sense of a logic programming predicate. That is, inputs with positive values are checked for consistency; missing inputs (indicated by otherwise illegal value 0) are given the correct positive value if possible. If all the output is correct, the program will exit with 0. If the input cannot be reconciled, the program will exit with 1. If the input leaves the output indeterminate, the program will exit with 2. If the C implementation cannot support the calculation because of arithmetic precision, the program will exit with 3. PPPPAAAARRRRAAAAMMMMEEEETTTTEEEERRRRSSSS There are seven related inputs. Inputs 1-3 are required. If inputs 4-7 are omitted, zero is assumed for each. The _Y_e_a_r is an integer >= _1_5_8_2 The _M_o_n_t_h is an integer between _1 and _1_2. The _D_a_y_O_f_M_o_n_t_h is an integer between _1 and _2_8, _2_9, _3_0 or _3_1 depending on the month. The _D_a_y_O_f_W_e_e_k is an integer between _1 and _7 corresponding to _S_u_n_d_a_y, _M_o_n_d_a_y, ... _S_a_t_u_r_d_a_y. It is the column position of the date in the conventional monthly calendar tableau. The _W_e_e_k_O_f_M_o_n_t_h is an integer between _1 and _6 corresponding to weeks in the calendar month. It is the row position of Page 1 (printed 3/10/86) GGGGRRRREEEEGGGG((((1111)))) UUUUNNNNIIIIXXXX 5555....0000 ((((llllooooccccaaaallll)))) GGGGRRRREEEEGGGG((((1111)))) the date in the conventional monthly calendar tableau. The first of the month is always in week _1. The _D_a_y_O_f_Y_e_a_r is an integer between _1 and _3_6_5 or _3_6_6 The _J_u_l_i_a_n_D_a_y is an integer >= _2_2_9_9_1_6_1, corresponding to _1_5 _O_c_t_o_b_e_r, _1_5_8_2. It measures the time in days from 1 Jan 4713 BC (Julian calendar). Each julian day starts at noon, GMT of the corresponding day of the Gregorian calendar. Astronomers express the relation between julian day j and date d as dd.5/mm/yyyy = j.0 where both "day"s are real numbers. dd.5 is noon of day dd. j.0 is the beginning of julian day j. Page 2 (printed 3/10/86) GGGGRRRREEEEGGGG((((1111)))) UUUUNNNNIIIIXXXX 5555....0000 ((((llllooooccccaaaallll)))) GGGGRRRREEEEGGGG((((1111)))) There are four patterns of input for the seven parameters that can possibly give a correct result. They are given below. P signifies positive integer (an input). ? signifies either 0 (an unknown) or a positive integer (an input). P P P ? -- year P ? P ? -- month of year P ? ? ? -- day of month ? ? P ? -- day of week ? ? P ? -- week of month ? P ? ? -- day of year ? ? ? P -- julian day FFFFIIIILLLLEEEESSSS none MMMMEEEETTTTHHHHOOOODDDD The Gregorian Calendar was adopted starting October 15, 1582 (September 14, 1752 in Britain and her colonies). Dates prior to adoption were in the Julian Calendar system (no relation to julian days). Dates before the conversion are denoted OS (old system); dates after the conversion are denoted NS (new system). This program will extrapolate Gregorian dates back to 1 AD although it will issue a warning (inconsistent) for dates prior to the adoption of the Gregorian calendar. 1 BC OS immediately preceded 1 AD OS (no year 0) so the algorithms are invalid, even for extrapolation, prior to 1 AD. The algorithms, some from the references below, are tableless. The collection given here is valid from January 1, 1 AD NS. The algorithms, which depend on a number of _a_d _h_o_c functions over integers, are cryptic but the alternative of using tables does not help much. The notation is C. Logical values are to be interpreted as 1 == true and 0 == false. Where it is supposed that the names of the functions are not sufficiently mnemonic, an italic comment is appended. The code in gregorian.c is algebraically simplified where possible when the functions below are back substituted into other defining formulas. More than one version is given for some formulas. LeapsBefore(y) == (y-1)/4 - (y-1)/100 + (y-1)/400 _l_e_a_p _y_e_a_r_s _b_e_t_w_e_e_n _1 _A_D _a_n_d _y_e_a_r _y Leap(y) == LeapsBefore(y+1) - LeapsBefore(y) Leap(y) == y%400 == 0 || (y%100 != 0 && y%4 == 0) StonesNumber(y, yd) == (yd + (yd>59+Leap(y))*(2-Leap(y)) + 91)*100 DaysInYearBefore(m, y) == 3055*(m+2)/100 - 91 - (m>2)*(2-Leap(y)) Page 3 (printed 3/10/86) GGGGRRRREEEEGGGG((((1111)))) UUUUNNNNIIIIXXXX 5555....0000 ((((llllooooccccaaaallll)))) GGGGRRRREEEEGGGG((((1111)))) DayOfYear(y, m, d) == DaysInYearBefore(m, y) + d MonthOfYear(y, yd) == StonesNumber(y, yd)/3055 - 2 DayOfMonth(y, yd) == StonesNumber(y, yd)%3055/100 + 1 DaysInYear(y) == 365 + Leap(y) DaysInYear(y) == DaysInYearBefore(13, y) DaysInMonth(m, y) == ((m == 2) ? 28+Leap(y) : 30+(m==1 || m%5%3 != 1)) DaysInMonth(m, y) == DaysInYearBefore(m+1, y) - DaysInYearBefore(m, y) JulianDaysB4(y) == (y-1)*365 + LeapsBefore(y) + 1721425 JulianDay(y, m, d) == JulianDaysBefore(y) + DayOfYear(y, m, d) YearOf(jd) = 1 + (jd-=(17214256), jd-=(jd+1)/146097, jd+=(jd+1)/36524, jd-(jd+1)/1461)/365 _y_e_a_r _i_n _w_h_i_c_h _j_u_l_i_a_n _d_a_y _j_d _o_c_c_u_r_s DayOf(jd) == jd - JulianDaysBefore(YearOf(jd)) _g_i_v_e_n _t_h_e _j_u_l_i_a_n _d_a_y _j_d, _d_a_y _o_f _y_e_a_r _f_r_o_m _1 _J_a_n WeekDay(jd) = (jd+1)%7+1 _S_u_n_d_a_y = _1, _e_t_c. Week(dm, dw) = (13 + dm - dw)/7 _w_e_e_k _o_f _m_o_n_t_h _f_r_o_m _d_a_y _o_f _m_o_n_t_h _a_n_d _d_a_y _o_f _w_e_e_k LLLLIIIIMMMMIIIITTTTSSSS Inputs are converted by _a_t_o_i which does not check for non- digits. The julian day is, by definition, bounded from below by 2299161 (15 October, 1582). The program will fail for implementations of C with _s_i_z_e_o_f (_l_o_n_g _i_n_t) < _4. There is no practical upper limit on year or julian day. The program extrapolates backward correctly to January 1, 1 AD NS but reports the input is "inconsistent" prior to October 15, 1582. SSSSEEEEEEEE AAAALLLLSSSSOOOO 1. Any almanac, under calendar, perpetual. (Note the World Almanac (1985, 1986) gives a julian day incorrect by one). 2. Any encyclopedia, under calendar. 3. The Astronomical Ephemeris (any year) 3. CAL(1). The information supplied by greg corresponds to cal starting September 14, 1752 AD. 4. Elmore, Perpetual Calendar, Am.J.Phys.44,3 (May 1976) pp 482-3. Page 4 (printed 3/10/86) GGGGRRRREEEEGGGG((((1111)))) UUUUNNNNIIIIXXXX 5555....0000 ((((llllooooccccaaaallll)))) GGGGRRRREEEEGGGG((((1111)))) 5. Fliegel & Van Flandern, A Machine Algorithm for Processing Calendar Dates, (letter to the editor) CACM 11,10 (October 1968) pg. 657. 6. Stone, Tableless Date Conversion. Algorithm 398. Collected Algorithms from the CACM (rcvd Jan 1970) and a Remark by Robertson (rcvd Dec 1970). 7. Tantzen, Conversions Between Calendar Date and Julian Day Number, Algorithm 199. Collected Algorithms from the CACM (August 1963). 8. Uspensky & Heaslet, Elementary Number Theory, McGraw- Hill, (1939) p.206-221. Page 5 (printed 3/10/86)