9 #define EPOCH (-577734)
11 /* Calculates and returns floor(a/b) for integer b > 0. */
13 floor_div (int a, int b)
16 return (a >= 0 ? a : a - b + 1) / b;
19 /* Calculates floor(a/b) and the corresponding remainder and
20 stores them into *Q and *R. */
22 floor_divmod (int a, int b, int *q, int *r)
24 *q = floor_div (a, b);
28 /* Returns true if Y is a leap year, false otherwise. */
32 return y % 4 == 0 && (y % 100 != 0 || y % 400 == 0);
36 raw_gregorian_to_offset (int y, int m, int d)
40 + floor_div (y - 1, 4)
41 - floor_div (y - 1, 100)
42 + floor_div (y - 1, 400)
43 + floor_div (367 * m - 362, 12)
44 + (m <= 2 ? 0 : (m >= 2 && is_leap_year (y) ? -1 : -2))
48 /* Returns the number of days from 14 Oct 1582 to (Y,M,D) in the
49 Gregorian calendar. Returns SYSMIS for dates before 14 Oct
52 calendar_gregorian_to_offset (int y, int m, int d,
53 calendar_error_func *error, void *aux)
56 if (y >= 0 && y < 100)
58 int epoch = get_epoch ();
59 int century = epoch / 100 + (y < epoch % 100);
63 /* Normalize month. */
78 error (aux, _("Month %d is not in acceptable range of 0 to 13."), m);
86 error (aux, _("Day %d is not in acceptable range of 0 to 31."), d);
91 if (y < 1582 || (y == 1582 && (m < 10 || (m == 10 && d < 15))))
93 error (aux, _("Date %04d-%d-%d is before the earliest acceptable "
94 "date of 1582-10-15."), y, m, d);
98 /* Calculate offset. */
99 return raw_gregorian_to_offset (y, m, d);
102 /* Returns the number of days in the given YEAR from January 1 up
103 to (but not including) the first day of MONTH. */
105 cum_month_days (int year, int month)
107 static const int cum_month_days[12] =
112 31 + 28 + 31, /* Mar */
113 31 + 28 + 31 + 30, /* Apr */
114 31 + 28 + 31 + 30 + 31, /* May */
115 31 + 28 + 31 + 30 + 31 + 30, /* Jun */
116 31 + 28 + 31 + 30 + 31 + 30 + 31, /* Jul */
117 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31, /* Aug */
118 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30, /* Sep */
119 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31, /* Oct */
120 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30, /* Nov */
123 assert (month >= 1 && month <= 12);
124 return cum_month_days[month - 1] + (month >= 3 && is_leap_year (year));
127 /* Takes a count of days from 14 Oct 1582 and returns the
128 Gregorian calendar year it is in. Dates both before and after
129 the epoch are supported. */
131 calendar_offset_to_year (int ofs)
141 floor_divmod (d0, 365 * 400 + 100 - 3, &n400, &d1);
142 floor_divmod (d1, 365 * 100 + 25 - 1, &n100, &d2);
143 floor_divmod (d2, 365 * 4 + 1, &n4, &d3);
144 n1 = floor_div (d3, 365);
145 y = 400 * n400 + 100 * n100 + 4 * n4 + n1;
146 if (n100 != 4 && n1 != 4)
152 /* Takes a count of days from 14 Oct 1582 and translates it into
153 a Gregorian calendar date in (*Y,*M,*D). Dates both before
154 and after the epoch are supported. */
156 calendar_offset_to_gregorian (int ofs, int *y, int *m, int *d)
158 int year = *y = calendar_offset_to_year (ofs);
159 int january1 = raw_gregorian_to_offset (year, 1, 1);
160 int yday = ofs - january1 + 1;
161 int march1 = january1 + cum_month_days (year, 3);
162 int correction = ofs < march1 ? 0 : (is_leap_year (year) ? 1 : 2);
163 int month = *m = (12 * (yday - 1 + correction) + 373) / 367;
164 *d = yday - cum_month_days (year, month);
167 /* Takes a count of days from 14 Oct 1582 and returns the 1-based
168 year-relative day number, that is, the number of days from the
169 beginning of the year. */
171 calendar_offset_to_yday (int ofs)
173 int year = calendar_offset_to_year (ofs);
174 int january1 = raw_gregorian_to_offset (year, 1, 1);
175 int yday = ofs - january1 + 1;
179 /* Takes a count of days from 14 Oct 1582 and returns the
180 corresponding weekday 1...7, with 1=Sunday. */
182 calendar_offset_to_wday (int ofs)
184 int wday = (ofs - EPOCH + 1) % 7 + 1;
190 /* Takes a count of days from 14 Oct 1582 and returns the month
193 calendar_offset_to_month (int ofs)
196 calendar_offset_to_gregorian (ofs, &y, &m, &d);
200 /* Takes a count of days from 14 Oct 1582 and returns the
201 corresponding day of the month. */
203 calendar_offset_to_mday (int ofs)
206 calendar_offset_to_gregorian (ofs, &y, &m, &d);