xref: /freebsd/contrib/ntp/libntp/caltontp.c (revision a90b9d0159070121c221b966469c3e36d912bf82)
1 /*
2  * caltontp - convert a date to an NTP time
3  */
4 #include <config.h>
5 #include <sys/types.h>
6 
7 #include "ntp_types.h"
8 #include "ntp_calendar.h"
9 #include "ntp_stdlib.h"
10 #include "ntp_assert.h"
11 #include "ntp_unixtime.h"
12 
13 /*
14  * Juergen Perlinger, 2008-11-12
15  * Add support for full calendar calculations. If the day-of-year is provided
16  * (that is, not zero) it will be used instead of month and day-of-month;
17  * otherwise a full turn through the calendar calculations will be taken.
18  *
19  * I know that Harlan Stenn likes to see assertions in production code, and I
20  * agree in general. But here we set 'errno' and try to do our best instead.
21  * Also note that the bounds check is a bit sloppy: It permits off-by-one
22  * on the input quantities. That permits some simple/naive adjustments to
23  * be made before calling this function.
24  *
25  * Apart from that the calendar is perfectly capable of dealing with
26  * off-scale input values!
27  *
28  * BTW: A total roundtrip using 'caljulian' would be a quite shaky thing:
29  * Because of the truncation of the NTP time stamp to 32 bits and the epoch
30  * unfolding around the current time done by 'caljulian' the roundtrip does
31  * *not* necessarily reproduce the input, especially if the time spec is more
32  * than 68 years off from the current time...
33  */
34 
35 uint32_t
36 caltontp(
37 	const struct calendar *jt
38 	)
39 {
40 	int32_t eraday;	/* CE Rata Die number	*/
41 	vint64  ntptime;/* resulting NTP time	*/
42 
43 	if (NULL == jt) {
44 		errno = EINVAL;
45 		return 0;
46 	}
47 
48 	if (   (jt->month > 13)	/* permit month 0..13! */
49 	    || (jt->monthday > 32)
50 	    || (jt->yearday > 366)
51 	    || (jt->hour > 24)
52 	    || (jt->minute > MINSPERHR)
53 	    || (jt->second > SECSPERMIN))
54 		errno = ERANGE;
55 
56 	/*
57 	 * First convert the date to he corresponding RataDie
58 	 * number. If yearday is not zero, assume that it contains a
59 	 * useable value and avoid all calculations involving month
60 	 * and day-of-month. Do a full evaluation otherwise.
61 	 */
62 	if (jt->yearday)
63 		eraday = ntpcal_year_to_ystart(jt->year)
64 		       + jt->yearday - 1;
65 	else
66 		eraday = ntpcal_date_to_rd(jt);
67 
68 	ntptime = ntpcal_dayjoin(eraday - DAY_NTP_STARTS,
69 				 ntpcal_etime_to_seconds(jt->hour, jt->minute,
70 							 jt->second));
71 	return ntptime.d_s.lo;
72 }
73