Annotation of embedaddon/php/ext/calendar/julian.c, revision 1.1.1.1
1.1 misho 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: #include <limits.h>
150:
151: #define JULIAN_SDN_OFFSET 32083
152: #define DAYS_PER_5_MONTHS 153
153: #define DAYS_PER_4_YEARS 1461
154:
155: void SdnToJulian(
156: long int sdn,
157: int *pYear,
158: int *pMonth,
159: int *pDay)
160: {
161: int year;
162: int month;
163: int day;
164: long int temp;
165: int dayOfYear;
166:
167: if (sdn <= 0) {
168: goto fail;
169: }
170: /* Check for overflow */
171: if (sdn > (LONG_MAX - JULIAN_SDN_OFFSET * 4 + 1) / 4 || sdn < LONG_MIN / 4) {
172: goto fail;
173: }
174: temp = sdn * 4 + (JULIAN_SDN_OFFSET * 4 - 1);
175:
176: /* Calculate the year and day of year (1 <= dayOfYear <= 366). */
177: {
178: long yearl = temp / DAYS_PER_4_YEARS;
179: if (yearl > INT_MAX || yearl < INT_MIN) {
180: goto fail;
181: }
182: year = (int) yearl;
183: }
184: dayOfYear = (temp % DAYS_PER_4_YEARS) / 4 + 1;
185:
186: /* Calculate the month and day of month. */
187: temp = dayOfYear * 5 - 3;
188: month = temp / DAYS_PER_5_MONTHS;
189: day = (temp % DAYS_PER_5_MONTHS) / 5 + 1;
190:
191: /* Convert to the normal beginning of the year. */
192: if (month < 10) {
193: month += 3;
194: } else {
195: year += 1;
196: month -= 9;
197: }
198:
199: /* Adjust to the B.C./A.D. type numbering. */
200: year -= 4800;
201: if (year <= 0)
202: year--;
203:
204: *pYear = year;
205: *pMonth = month;
206: *pDay = day;
207: return;
208:
209: fail:
210: *pYear = 0;
211: *pMonth = 0;
212: *pDay = 0;
213: }
214:
215: long int JulianToSdn(
216: int inputYear,
217: int inputMonth,
218: int inputDay)
219: {
220: int year;
221: int month;
222:
223: /* check for invalid dates */
224: if (inputYear == 0 || inputYear < -4713 ||
225: inputMonth <= 0 || inputMonth > 12 ||
226: inputDay <= 0 || inputDay > 31) {
227: return (0);
228: }
229: /* check for dates before SDN 1 (Jan 2, 4713 B.C.) */
230: if (inputYear == -4713) {
231: if (inputMonth == 1 && inputDay == 1) {
232: return (0);
233: }
234: }
235: /* Make year always a positive number. */
236: if (inputYear < 0) {
237: year = inputYear + 4801;
238: } else {
239: year = inputYear + 4800;
240: }
241:
242: /* Adjust the start of the year. */
243: if (inputMonth > 2) {
244: month = inputMonth - 3;
245: } else {
246: month = inputMonth + 9;
247: year--;
248: }
249:
250: return ((year * DAYS_PER_4_YEARS) / 4
251: + (month * DAYS_PER_5_MONTHS + 2) / 5
252: + inputDay
253: - JULIAN_SDN_OFFSET);
254: }
255:
256: /*
257: * Local variables:
258: * tab-width: 4
259: * c-basic-offset: 4
260: * End:
261: * vim600: sw=4 ts=4 fdm=marker
262: * vim<600: sw=4 ts=4
263: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>