2 * Copyright (c) 1997 Wolfgang Helbig
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * $FreeBSD: src/lib/libcalendar/calendar.c,v 1.3 1999/08/28 00:04:03 peter Exp $
36 * For each month tabulate the number of days elapsed in a year before the
37 * month. This assumes the internal date representation, where a year
38 * starts on March 1st. So we don't need a special table for leap years.
39 * But we do need a special table for the year 1582, since 10 days are
40 * deleted in October. This is month1s for the switch from Julian to
43 static int const month1[] =
44 {0, 31, 61, 92, 122, 153, 184, 214, 245, 275, 306, 337};
45 /* M A M J J A S O N D J */
46 static int const month1s[]=
47 {0, 31, 61, 92, 122, 153, 184, 214, 235, 265, 296, 327};
49 typedef struct date date;
51 /* The last day of Julian calendar, in internal and ndays representation */
52 static int nswitch; /* The last day of Julian calendar */
53 static date jiswitch = {1582, 7, 3};
55 static date *date2idt(date *idt, date *dt);
56 static date *idt2date(date *dt, date *idt);
57 static int ndaysji(date *idt);
58 static int ndaysgi(date *idt);
59 static int firstweek(int year);
62 * Compute the Julian date from the number of days elapsed since
63 * March 1st of year zero.
66 jdate(int ndays, date *dt)
68 date idt; /* Internal date representation */
69 int r; /* hold the rest of days */
72 * Compute the year by starting with an approximation not smaller
73 * than the answer and using linear search for the greatest
74 * year which does not begin after ndays.
79 while ((r = ndaysji(&idt)) > ndays)
83 * Set r to the days left in the year and compute the month by
84 * linear search as the largest month that does not begin after r
88 for (idt.m = 11; month1[idt.m] > r; idt.m--)
91 /* Compute the days left in the month */
92 idt.d = r - month1[idt.m];
94 /* return external representation of the date */
95 return (idt2date(dt, &idt));
99 * Return the number of days since March 1st of the year zero.
100 * The date is given according to Julian calendar.
105 date idt; /* Internal date representation */
107 if (date2idt(&idt, dt) == NULL)
110 return (ndaysji(&idt));
114 * Same as above, where the Julian date is given in internal notation.
115 * This formula shows the beauty of this notation.
121 return (idt->d + month1[idt->m] + idt->y * 365 + idt->y / 4);
125 * Compute the date according to the Gregorian calendar from the number of
126 * days since March 1st, year zero. The date computed will be Julian if it
127 * is older than 1582-10-05. This is the reverse of the function ndaysg().
130 gdate(int ndays, date *dt)
132 int const *montht; /* month-table */
133 date idt; /* for internal date representation */
134 int r; /* holds the rest of days */
137 * Compute the year by starting with an approximation not smaller
138 * than the answer and search linearly for the greatest year not
139 * starting after ndays.
144 while ((r = ndaysgi(&idt)) > ndays)
148 * Set ndays to the number of days left and compute by linear
149 * search the greatest month which does not start after ndays. We
150 * use the table month1 which provides for each month the number
151 * of days that elapsed in the year before that month. Here the
152 * year 1582 is special, as 10 days are left out in October to
153 * resynchronize the calendar with the earth's orbit. October 4th
154 * 1582 is followed by October 15th 1582. We use the "switch"
155 * table month1s for this year.
163 for (idt.m = 11; montht[idt.m] > ndays; idt.m--)
166 idt.d = ndays - montht[idt.m]; /* the rest is the day in month */
168 /* Advance ten days deleted from October if after switch in Oct 1582 */
169 if (idt.y == jiswitch.y && idt.m == jiswitch.m && jiswitch.d < idt.d)
172 /* return external representation of found date */
173 return (idt2date(dt, &idt));
177 * Return the number of days since March 1st of the year zero. The date is
178 * assumed Gregorian if younger than 1582-10-04 and Julian otherwise. This
179 * is the reverse of gdate.
184 date idt; /* Internal date representation */
186 if (date2idt(&idt, dt) == NULL)
188 return (ndaysgi(&idt));
192 * Same as above, but with the Gregorian date given in internal
198 int nd; /* Number of days--return value */
200 /* Cache nswitch if not already done */
202 nswitch = ndaysji(&jiswitch);
205 * Assume Julian calendar and adapt to Gregorian if necessary, i. e.
206 * younger than nswitch. Gregori deleted
207 * the ten days from Oct 5th to Oct 14th 1582.
208 * Thereafter years which are multiples of 100 and not multiples
209 * of 400 were not leap years anymore.
210 * This makes the average length of a year
211 * 365d +.25d - .01d + .0025d = 365.2425d. But the tropical
212 * year measures 365.2422d. So in 10000/3 years we are
213 * again one day ahead of the earth. Sigh :-)
214 * (d is the average length of a day and tropical year is the
215 * time from one spring point to the next.)
217 if ((nd = ndaysji(idt)) == -1)
220 nd = (nd - 10 - (idt->y - 1600) / 100 + (idt->y - 1600) / 400);
221 else if (nd > nswitch)
227 * Compute the week number from the number of days since March 1st year 0.
228 * The weeks are numbered per year starting with 1. If the first
229 * week of a year includes at least four days of that year it is week 1,
230 * otherwise it gets the number of the last week of the previous year.
231 * The variable y will be filled with the year that contains the greater
238 int fw; /* 1st day of week 1 of previous, this and
241 for (*y = dt.y + 1; nd < (fw = firstweek(*y)); (*y)--)
243 return ((nd - fw) / 7 + 1);
246 /* return the first day of week 1 of year y */
253 idt.y = y - 1; /* internal representation of y-1-1 */
259 * If more than 3 days of this week are in the preceding year, the
260 * next week is week 1 (and the next monday is the answer),
261 * otherwise this week is week 1 and the last monday is the
264 if ((wd = weekday(nd)) > 3)
265 return (nd - wd + 7);
270 /* return the weekday (Mo = 0 .. Su = 6) */
274 date dmondaygi = {1997, 8, 16}; /* Internal repr. of 1997-11-17 */
275 static int nmonday; /* ... which is a monday */
277 /* Cache the daynumber of one monday */
279 nmonday = ndaysgi(&dmondaygi);
281 /* return (nd - nmonday) modulo 7 which is the weekday */
282 nd = (nd - nmonday) % 7;
290 * Convert a date to internal date representation: The year starts on
291 * March 1st, month and day numbering start at zero. E. g. March 1st of
292 * year zero is written as y=0, m=0, d=0.
295 date2idt(date *idt, date *dt)
306 if (idt->m < 0 || idt->m > 11 || idt->y < 0)
312 /* Reverse of date2idt */
314 idt2date(date *dt, date *idt)