1 /*-
2  * Copyright © 2004, 2005, 2006, 2007, 2011
3  *	Thorsten “mirabilos” Glaser <tg@mirbsd.org>
4  *
5  * Provided that these terms and disclaimer and all copyright notices
6  * are retained or reproduced in an accompanying document, permission
7  * is granted to deal in this work without restriction, including un‐
8  * limited rights to use, publicly perform, distribute, sell, modify,
9  * merge, give away, or sublicence.
10  *
11  * This work is provided “AS IS” and WITHOUT WARRANTY of any kind, to
12  * the utmost extent permitted by applicable law, neither express nor
13  * implied; without malicious intent or gross negligence. In no event
14  * may a licensor, author or contributor be held liable for indirect,
15  * direct, other damage, loss, or other issues arising in any way out
16  * of dealing in the work, even if advised of the possibility of such
17  * damage or existence of a defect, except proven that it results out
18  * of said person’s immediate fault when using the work as intended.
19  *-
20  * MirBSD new time functions (common part, mirtime_getleaps is system
21  * specific). The code to convert betwen MJD and broken-down calendar
22  * dates is a re-implementation of algorithms from Dan J. Bernstein.
23  *
24  * This code works by the assumption that leap seconds are always po‐
25  * sitive and happen at most once per cluster (no double leapsecs).
26  */
27 
28 #include <sys/types.h>
29 #include <syskern/mirtime.h>
30 
31 __RCSID("$MirOS: src/kern/c/mirtime.c,v 1.3 2011/11/20 23:40:10 tg Exp $");
32 
33 #ifdef L_timet2posix
34 time_t
timet2posix(time_t t)35 timet2posix(time_t t)
36 {
37 	time_t u = t;
38 	const time_t *lp;
39 
40 	if (__predict_true(t > 0)) {
41 		lp = mirtime_getleaps();
42 		while (__predict_true((*lp) && (t >= *lp))) {
43 			--u;
44 			++lp;
45 		}
46 	}
47 	return (u);
48 }
49 #endif
50 
51 #ifdef L_posix2timet
52 time_t
posix2timet(time_t t)53 posix2timet(time_t t)
54 {
55 	const time_t *lp;
56 
57 	if (__predict_true(t > 0)) {
58 		lp = mirtime_getleaps();
59 		while (__predict_true((*lp) && (t >= *lp))) {
60 			++t;
61 			++lp;
62 		}
63 	}
64 	return (t);
65 }
66 #endif
67 
68 #ifdef L_timet2mjd
69 mirtime_mjd *
timet2mjd(mirtime_mjd * mjd,time_t t)70 timet2mjd(mirtime_mjd *mjd, time_t t)
71 {
72 	time_t u;
73 
74 	/* POSIX time inherent property: days have 86400 seconds */
75 	u = timet2posix(t);
76 	mjd->sec = (int32_t)(u % 86400);
77 	u /= 86400;
78 	u += 40587;
79 
80 	/* normalise */
81 	while (__predict_false(mjd->sec < 0)) {
82 		--u;
83 		mjd->sec += 86400;
84 	}
85 
86 	/* account for a possible leap second */
87 	if (__predict_false(mirtime_isleap(t)))
88 		++mjd->sec;
89 
90 	mjd->mjd = u;
91 	return (mjd);
92 }
93 #endif
94 
95 #ifdef L_mjd2timet
96 time_t
mjd2timet(mirtime_mjd * mjd)97 mjd2timet(mirtime_mjd *mjd)
98 {
99 	time_t t;
100 
101 	/* construct a POSIX timestamp again */
102 	t = mjd->mjd;
103 	t -= 40587;
104 	t *= 86400;
105 	t += (mjd->sec > 86399 ? 86399 : mjd->sec);
106 
107 	/* add leap seconds between epoch and t */
108 	t = posix2timet(t);
109 
110 	/* if mjd was a leap second, account for it */
111 	if (mjd->sec > 86399)
112 		++t;
113 
114 	return (t);
115 }
116 #endif
117 
118 #ifdef L_mjd_explode
119 struct tm *
mjd_explode(struct tm * tm,const mirtime_mjd * mjd)120 mjd_explode(struct tm *tm, const mirtime_mjd *mjd)
121 {
122 	int sec, day, yday, mon;
123 	time_t year;
124 
125 	year = mjd->mjd;
126 	sec = mjd->sec;
127 
128 	/* normalise */
129 	while (sec < 0) {
130 		--year;
131 		sec += 86400;
132 	}
133 	while (sec > 86400) {
134 		++year;
135 		sec -= 86400;
136 	}
137 
138 	/* buffer leap second */
139 	tm->tm_sec = (sec == 86400) ? 1 : 0;
140 	sec -= tm->tm_sec;
141 
142 	/* calculate 400-year cycle (year) and offset in it (day) */
143 	day = (int)(year % 146097);
144 	year /= 146097;
145 
146 	/* add bias: 678881 = days between "convenient origin" and MJD 0 */
147 	/* convenient origin is Wed(3) 1 March 0(fictional)/-1(real) */
148 	day += 678881;
149 	/* recalculate offset in cycle (Gregorian Period) */
150 	year += day / 146097;
151 	day %= 146097;
152 
153 	/* days in 400 years are cyclic, they have 20871 weeks */
154 	tm->tm_wday = (day + 3) % 7;
155 
156 	/* calculate year from period, taking leap years into account */
157 	year *= 4;
158 	/* a long (Julian) century is at the end of each Gregorian Period */
159 	if (__predict_false(day == 146096)) {
160 		year += 3;
161 		day = 36524;
162 	} else {
163 		year += day / 36524;
164 		day %= 36524;
165 	}
166 	year *= 25;
167 	year += day / 1461;
168 	day %= 1461;
169 	year *= 4;
170 
171 	/* March to December, or January/February? */
172 	yday = (day < 306) ? 1 : 0;
173 	/* a leap year is at the end of each olympiad */
174 	if (__predict_false(day == 1460)) {
175 		year += 3;
176 		day = 365;
177 	} else {
178 		year += day / 365;
179 		day %= 365;
180 	}
181 	yday += day;
182 
183 	/* count days and months from 1st March using fixed-point */
184 	day *= 10;
185 	mon = (day + 5) / 306;
186 	day = (day + 5) % 306;
187 	day /= 10;
188 	/* adjust for Jan/Feb offset */
189 	if (__predict_false(mon >= 10)) {
190 		mon -= 10;
191 		yday -= 306;
192 		++year;
193 	} else {
194 		mon += 2;
195 		yday += 31 + 28;
196 	}
197 
198 	/* adjust for year 0(fictional) which did not exist */
199 	if (__predict_false(year < 1))
200 		--year;
201 
202 	/* fill in the values still missing */
203 	tm->tm_sec += sec % 60;
204 	sec /= 60;
205 	tm->tm_min = sec % 60;
206 	tm->tm_hour = sec / 60;
207 	tm->tm_mday = day + 1;
208 	tm->tm_mon = mon;
209 	tm->tm_year = year - 1900;
210 	tm->tm_yday = yday;
211 	/* hardcode these */
212 	tm->tm_isdst = 0;
213 	tm->tm_gmtoff = 0;
214 	tm->tm_zone = (void *)0L;
215 	/* return dst */
216 	return (tm);
217 }
218 #endif
219 
220 #ifdef L_mjd_implode
221 mirtime_mjd *
mjd_implode(mirtime_mjd * mjd,const struct tm * tm)222 mjd_implode(mirtime_mjd *mjd, const struct tm *tm)
223 {
224 	time_t day;
225 	int x, y;
226 
227 	/* get the seconds out first */
228 	mjd->sec = tm->tm_sec + 60 * tm->tm_min + 3600 * tm->tm_hour -
229 	    tm->tm_gmtoff;
230 
231 	/* pull the year; adjust for year 0 not existing */
232 	if (__predict_false((day = tm->tm_year + 1900LL) < 0))
233 		++day;
234 
235 	/* split year into y(ear in Gregorian Period) and convenient day */
236 	y = day % 400;
237 	day /= 400;
238 	day *= 146097;
239 	day -= 678882;
240 	/* add day of month */
241 	day += tm->tm_mday;
242 
243 	/* normalise seconds into days */
244 	while (__predict_false(mjd->sec < 0)) {
245 		--day;
246 		mjd->sec += 86400;
247 	}
248 	while (__predict_false(mjd->sec > 86400)) {
249 		++day;
250 		mjd->sec -= 86400;
251 	}
252 
253 	/* assign x the month and normalise into years */
254 	x = tm->tm_mon;
255 	while (__predict_false(x < 0)) {
256 		--y;
257 		x += 12;
258 	}
259 	y += x / 12;
260 	x %= 12;
261 
262 	/* calculate x as month since march, adjust year for it */
263 	if (__predict_false(x < 2)) {
264 		x += 10;
265 		--y;
266 	} else
267 		x -= 2;
268 
269 	/* add length of month since march by fixed-point arithmetic */
270 	day += (306 * x + 5) / 10;
271 
272 	/* normalise 400-year cycles again */
273 	while (__predict_false(y < 0)) {
274 		day -= 146097;
275 		y += 400;
276 	}
277 	day += 146097 * (y / 400);
278 	y %= 400;
279 
280 	/* add by year, 4 years, 100 years, 400 years */
281 	day += 365 * (y % 4);
282 	y /= 4;
283 	day += 1461 * (y % 25);
284 	day += 36524 * (y / 25);
285 
286 	mjd->mjd = day;
287 	/* return dst */
288 	return (mjd);
289 }
290 #endif
291 
292 #ifdef L_mirtime_isleap
293 int
mirtime_isleap(time_t t)294 mirtime_isleap(time_t t)
295 {
296 	time_t lt;
297 	const time_t *lp;
298 
299 	lp = mirtime_getleaps();
300 	while (__predict_true((lt = *lp))) {
301 		if (__predict_false(t < lt))
302 			return (0);
303 		else if (__predict_false(t == lt))
304 			return (1);
305 		else
306 			++lp;
307 	}
308 	return (0);
309 }
310 #endif
311 
312 #ifdef L_mirtime_macrobodies
313 #undef timet2tm
314 #undef tm2timet
315 struct tm *
timet2tm(struct tm * dst,time_t src)316 timet2tm(struct tm *dst, time_t src)
317 {
318 	mirtime_mjd timet2tm_storage;
319 
320 	return (mjd_explode(dst, timet2mjd(&timet2tm_storage, src)));
321 }
322 
323 time_t
tm2timet(struct tm * src)324 tm2timet(struct tm *src)
325 {
326 	mirtime_mjd tm2timet_storage;
327 
328 	return (mjd2timet(mjd_implode(&tm2timet_storage, src)));
329 }
330 #endif
331