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 $
27 * $DragonFly: src/lib/libcalendar/calendar.c,v 1.2 2003/06/17 04:26:48 dillon Exp $
37 * For each month tabulate the number of days elapsed in a year before the
38 * month. This assumes the internal date representation, where a year
39 * starts on March 1st. So we don't need a special table for leap years.
40 * But we do need a special table for the year 1582, since 10 days are
41 * deleted in October. This is month1s for the switch from Julian to
44 static int const month1
[] =
45 {0, 31, 61, 92, 122, 153, 184, 214, 245, 275, 306, 337};
46 /* M A M J J A S O N D J */
47 static int const month1s
[]=
48 {0, 31, 61, 92, 122, 153, 184, 214, 235, 265, 296, 327};
50 typedef struct date date
;
52 /* The last day of Julian calendar, in internal and ndays representation */
53 static int nswitch
; /* The last day of Julian calendar */
54 static date jiswitch
= {1582, 7, 3};
56 static date
*date2idt(date
*idt
, date
*dt
);
57 static date
*idt2date(date
*dt
, date
*idt
);
58 static int ndaysji(date
*idt
);
59 static int ndaysgi(date
*idt
);
60 static int firstweek(int year
);
63 * Compute the Julian date from the number of days elapsed since
64 * March 1st of year zero.
67 jdate(int ndays
, date
*dt
)
69 date idt
; /* Internal date representation */
70 int r
; /* hold the rest of days */
73 * Compute the year by starting with an approximation not smaller
74 * than the answer and using linear search for the greatest
75 * year which does not begin after ndays.
80 while ((r
= ndaysji(&idt
)) > ndays
)
84 * Set r to the days left in the year and compute the month by
85 * linear search as the largest month that does not begin after r
89 for (idt
.m
= 11; month1
[idt
.m
] > r
; idt
.m
--)
92 /* Compute the days left in the month */
93 idt
.d
= r
- month1
[idt
.m
];
95 /* return external representation of the date */
96 return (idt2date(dt
, &idt
));
100 * Return the number of days since March 1st of the year zero.
101 * The date is given according to Julian calendar.
106 date idt
; /* Internal date representation */
108 if (date2idt(&idt
, dt
) == NULL
)
111 return (ndaysji(&idt
));
115 * Same as above, where the Julian date is given in internal notation.
116 * This formula shows the beauty of this notation.
122 return (idt
->d
+ month1
[idt
->m
] + idt
->y
* 365 + idt
->y
/ 4);
126 * Compute the date according to the Gregorian calendar from the number of
127 * days since March 1st, year zero. The date computed will be Julian if it
128 * is older than 1582-10-05. This is the reverse of the function ndaysg().
131 gdate(int ndays
, date
*dt
)
133 int const *montht
; /* month-table */
134 date idt
; /* for internal date representation */
135 int r
; /* holds the rest of days */
138 * Compute the year by starting with an approximation not smaller
139 * than the answer and search linearly for the greatest year not
140 * starting after ndays.
145 while ((r
= ndaysgi(&idt
)) > ndays
)
149 * Set ndays to the number of days left and compute by linear
150 * search the greatest month which does not start after ndays. We
151 * use the table month1 which provides for each month the number
152 * of days that elapsed in the year before that month. Here the
153 * year 1582 is special, as 10 days are left out in October to
154 * resynchronize the calendar with the earth's orbit. October 4th
155 * 1582 is followed by October 15th 1582. We use the "switch"
156 * table month1s for this year.
164 for (idt
.m
= 11; montht
[idt
.m
] > ndays
; idt
.m
--)
167 idt
.d
= ndays
- montht
[idt
.m
]; /* the rest is the day in month */
169 /* Advance ten days deleted from October if after switch in Oct 1582 */
170 if (idt
.y
== jiswitch
.y
&& idt
.m
== jiswitch
.m
&& jiswitch
.d
< idt
.d
)
173 /* return external representation of found date */
174 return (idt2date(dt
, &idt
));
178 * Return the number of days since March 1st of the year zero. The date is
179 * assumed Gregorian if younger than 1582-10-04 and Julian otherwise. This
180 * is the reverse of gdate.
185 date idt
; /* Internal date representation */
187 if (date2idt(&idt
, dt
) == NULL
)
189 return (ndaysgi(&idt
));
193 * Same as above, but with the Gregorian date given in internal
199 int nd
; /* Number of days--return value */
201 /* Cache nswitch if not already done */
203 nswitch
= ndaysji(&jiswitch
);
206 * Assume Julian calendar and adapt to Gregorian if necessary, i. e.
207 * younger than nswitch. Gregori deleted
208 * the ten days from Oct 5th to Oct 14th 1582.
209 * Thereafter years which are multiples of 100 and not multiples
210 * of 400 were not leap years anymore.
211 * This makes the average length of a year
212 * 365d +.25d - .01d + .0025d = 365.2425d. But the tropical
213 * year measures 365.2422d. So in 10000/3 years we are
214 * again one day ahead of the earth. Sigh :-)
215 * (d is the average length of a day and tropical year is the
216 * time from one spring point to the next.)
218 if ((nd
= ndaysji(idt
)) == -1)
221 nd
= (nd
- 10 - (idt
->y
- 1600) / 100 + (idt
->y
- 1600) / 400);
222 else if (nd
> nswitch
)
228 * Compute the week number from the number of days since March 1st year 0.
229 * The weeks are numbered per year starting with 1. If the first
230 * week of a year includes at least four days of that year it is week 1,
231 * otherwise it gets the number of the last week of the previous year.
232 * The variable y will be filled with the year that contains the greater
239 int fw
; /* 1st day of week 1 of previous, this and
242 for (*y
= dt
.y
+ 1; nd
< (fw
= firstweek(*y
)); (*y
)--)
244 return ((nd
- fw
) / 7 + 1);
247 /* return the first day of week 1 of year y */
254 idt
.y
= y
- 1; /* internal representation of y-1-1 */
260 * If more than 3 days of this week are in the preceding year, the
261 * next week is week 1 (and the next monday is the answer),
262 * otherwise this week is week 1 and the last monday is the
265 if ((wd
= weekday(nd
)) > 3)
266 return (nd
- wd
+ 7);
271 /* return the weekday (Mo = 0 .. Su = 6) */
275 date dmondaygi
= {1997, 8, 16}; /* Internal repr. of 1997-11-17 */
276 static int nmonday
; /* ... which is a monday */
278 /* Cache the daynumber of one monday */
280 nmonday
= ndaysgi(&dmondaygi
);
282 /* return (nd - nmonday) modulo 7 which is the weekday */
283 nd
= (nd
- nmonday
) % 7;
291 * Convert a date to internal date representation: The year starts on
292 * March 1st, month and day numbering start at zero. E. g. March 1st of
293 * year zero is written as y=0, m=0, d=0.
296 date2idt(date
*idt
, date
*dt
)
307 if (idt
->m
< 0 || idt
->m
> 11 || idt
->y
< 0)
313 /* Reverse of date2idt */
315 idt2date(date
*dt
, date
*idt
)