1 : /* $selId: julian.c,v 2.0 1995/10/24 01:13:06 lees Exp $
2 : * Copyright 1993-1995, Scott E. Lee, all rights reserved.
3 : * Permission granted to use, copy, modify, distribute and sell so long as
4 : * the above copyright and this permission statement are retained in all
5 : * copies. THERE IS NO WARRANTY - USE AT YOUR OWN RISK.
6 : */
7 :
8 : /**************************************************************************
9 : *
10 : * These are the externally visible components of this file:
11 : *
12 : * void
13 : * SdnToJulian(
14 : * long int sdn,
15 : * int *pYear,
16 : * int *pMonth,
17 : * int *pDay);
18 : *
19 : * Convert a SDN to a Julian calendar date. If the input SDN is less than
20 : * 1, the three output values will all be set to zero, otherwise *pYear
21 : * will be >= -4713 and != 0; *pMonth will be in the range 1 to 12
22 : * inclusive; *pDay will be in the range 1 to 31 inclusive.
23 : *
24 : * long int
25 : * JulianToSdn(
26 : * int inputYear,
27 : * int inputMonth,
28 : * int inputDay);
29 : *
30 : * Convert a Julian calendar date to a SDN. Zero is returned when the
31 : * input date is detected as invalid or out of the supported range. The
32 : * return value will be > 0 for all valid, supported dates, but there are
33 : * some invalid dates that will return a positive value. To verify that a
34 : * date is valid, convert it to SDN and then back and compare with the
35 : * original.
36 : *
37 : * VALID RANGE
38 : *
39 : * 4713 B.C. to at least 10000 A.D.
40 : *
41 : * Although this software can handle dates all the way back to 4713
42 : * B.C., such use may not be meaningful. The calendar was created in
43 : * 46 B.C., but the details did not stabilize until at least 8 A.D.,
44 : * and perhaps as late at the 4th century. Also, the beginning of a
45 : * year varied from one culture to another - not all accepted January
46 : * as the first month.
47 : *
48 : * CALENDAR OVERVIEW
49 : *
50 : * Julias Ceasar created the calendar in 46 B.C. as a modified form of
51 : * the old Roman republican calendar which was based on lunar cycles.
52 : * The new Julian calendar set fixed lengths for the months, abandoning
53 : * the lunar cycle. It also specified that there would be exactly 12
54 : * months per year and 365.25 days per year with every 4th year being a
55 : * leap year.
56 : *
57 : * Note that the current accepted value for the tropical year is
58 : * 365.242199 days, not 365.25. This lead to an 11 day shift in the
59 : * calendar with respect to the seasons by the 16th century when the
60 : * Gregorian calendar was created to replace the Julian calendar.
61 : *
62 : * The difference between the Julian and today's Gregorian calendar is
63 : * that the Gregorian does not make centennial years leap years unless
64 : * they are a multiple of 400, which leads to a year of 365.2425 days.
65 : * In other words, in the Gregorian calendar, 1700, 1800 and 1900 are
66 : * not leap years, but 2000 is. All centennial years are leap years in
67 : * the Julian calendar.
68 : *
69 : * The details are unknown, but the lengths of the months were adjusted
70 : * until they finally stablized in 8 A.D. with their current lengths:
71 : *
72 : * January 31
73 : * February 28/29
74 : * March 31
75 : * April 30
76 : * May 31
77 : * June 30
78 : * Quintilis/July 31
79 : * Sextilis/August 31
80 : * September 30
81 : * October 31
82 : * November 30
83 : * December 31
84 : *
85 : * In the early days of the calendar, the days of the month were not
86 : * numbered as we do today. The numbers ran backwards (decreasing) and
87 : * were counted from the Ides (15th of the month - which in the old
88 : * Roman republican lunar calendar would have been the full moon) or
89 : * from the Nonae (9th day before the Ides) or from the beginning of
90 : * the next month.
91 : *
92 : * In the early years, the beginning of the year varied, sometimes
93 : * based on the ascension of rulers. It was not always the first of
94 : * January.
95 : *
96 : * Also, today's epoch, 1 A.D. or the birth of Jesus Christ, did not
97 : * come into use until several centuries later when Christianity became
98 : * a dominant religion.
99 : *
100 : * ALGORITHMS
101 : *
102 : * The calculations are based on two different cycles: a 4 year cycle
103 : * of leap years and a 5 month cycle of month lengths.
104 : *
105 : * The 5 month cycle is used to account for the varying lengths of
106 : * months. You will notice that the lengths alternate between 30 and
107 : * 31 days, except for three anomalies: both July and August have 31
108 : * days, both December and January have 31, and February is less than
109 : * 30. Starting with March, the lengths are in a cycle of 5 months
110 : * (31, 30, 31, 30, 31):
111 : *
112 : * Mar 31 days \
113 : * Apr 30 days |
114 : * May 31 days > First cycle
115 : * Jun 30 days |
116 : * Jul 31 days /
117 : *
118 : * Aug 31 days \
119 : * Sep 30 days |
120 : * Oct 31 days > Second cycle
121 : * Nov 30 days |
122 : * Dec 31 days /
123 : *
124 : * Jan 31 days \
125 : * Feb 28/9 days |
126 : * > Third cycle (incomplete)
127 : *
128 : * For this reason the calculations (internally) assume that the year
129 : * starts with March 1.
130 : *
131 : * TESTING
132 : *
133 : * This algorithm has been tested from the year 4713 B.C. to 10000 A.D.
134 : * The source code of the verification program is included in this
135 : * package.
136 : *
137 : * REFERENCES
138 : *
139 : * Conversions Between Calendar Date and Julian Day Number by Robert J.
140 : * Tantzen, Communications of the Association for Computing Machinery
141 : * August 1963. (Also published in Collected Algorithms from CACM,
142 : * algorithm number 199). [Note: the published algorithm is for the
143 : * Gregorian calendar, but was adjusted to use the Julian calendar's
144 : * simpler leap year rule.]
145 : *
146 : **************************************************************************/
147 :
148 : #include "sdncal.h"
149 :
150 : #define JULIAN_SDN_OFFSET 32083
151 : #define DAYS_PER_5_MONTHS 153
152 : #define DAYS_PER_4_YEARS 1461
153 :
154 : void SdnToJulian(
155 : long int sdn,
156 : int *pYear,
157 : int *pMonth,
158 : int *pDay)
159 92 : {
160 : int year;
161 : int month;
162 : int day;
163 : long int temp;
164 : int dayOfYear;
165 :
166 92 : if (sdn <= 0) {
167 3 : *pYear = 0;
168 3 : *pMonth = 0;
169 3 : *pDay = 0;
170 3 : return;
171 : }
172 89 : temp = (sdn + JULIAN_SDN_OFFSET) * 4 - 1;
173 :
174 : /* Calculate the year and day of year (1 <= dayOfYear <= 366). */
175 89 : year = temp / DAYS_PER_4_YEARS;
176 89 : dayOfYear = (temp % DAYS_PER_4_YEARS) / 4 + 1;
177 :
178 : /* Calculate the month and day of month. */
179 89 : temp = dayOfYear * 5 - 3;
180 89 : month = temp / DAYS_PER_5_MONTHS;
181 89 : day = (temp % DAYS_PER_5_MONTHS) / 5 + 1;
182 :
183 : /* Convert to the normal beginning of the year. */
184 89 : if (month < 10) {
185 75 : month += 3;
186 : } else {
187 14 : year += 1;
188 14 : month -= 9;
189 : }
190 :
191 : /* Adjust to the B.C./A.D. type numbering. */
192 89 : year -= 4800;
193 89 : if (year <= 0)
194 0 : year--;
195 :
196 89 : *pYear = year;
197 89 : *pMonth = month;
198 89 : *pDay = day;
199 : }
200 :
201 : long int JulianToSdn(
202 : int inputYear,
203 : int inputMonth,
204 : int inputDay)
205 6 : {
206 : int year;
207 : int month;
208 :
209 : /* check for invalid dates */
210 6 : if (inputYear == 0 || inputYear < -4713 ||
211 : inputMonth <= 0 || inputMonth > 12 ||
212 : inputDay <= 0 || inputDay > 31) {
213 1 : return (0);
214 : }
215 : /* check for dates before SDN 1 (Jan 2, 4713 B.C.) */
216 5 : if (inputYear == -4713) {
217 0 : if (inputMonth == 1 && inputDay == 1) {
218 0 : return (0);
219 : }
220 : }
221 : /* Make year always a positive number. */
222 5 : if (inputYear < 0) {
223 0 : year = inputYear + 4801;
224 : } else {
225 5 : year = inputYear + 4800;
226 : }
227 :
228 : /* Adjust the start of the year. */
229 5 : if (inputMonth > 2) {
230 2 : month = inputMonth - 3;
231 : } else {
232 3 : month = inputMonth + 9;
233 3 : year--;
234 : }
235 :
236 5 : return ((year * DAYS_PER_4_YEARS) / 4
237 : + (month * DAYS_PER_5_MONTHS + 2) / 5
238 : + inputDay
239 : - JULIAN_SDN_OFFSET);
240 : }
241 :
242 : /*
243 : * Local variables:
244 : * tab-width: 4
245 : * c-basic-offset: 4
246 : * End:
247 : * vim600: sw=4 ts=4 fdm=marker
248 : * vim<600: sw=4 ts=4
249 : */
|