xref: /freebsd/contrib/ntp/libntp/clocktime.c (revision 3a92d97ff0f22d21608e1c19b83104c4937523b6)
1 /*
2  * clocktime - compute the NTP date from a day of year, hour, minute
3  *	       and second.
4  */
5 #include "ntp_fp.h"
6 #include "ntp_unixtime.h"
7 #include "ntp_stdlib.h"
8 
9 /*
10  * Hacks to avoid excercising the multiplier.  I have no pride.
11  */
12 #define	MULBY10(x)	(((x)<<3) + ((x)<<1))
13 #define	MULBY60(x)	(((x)<<6) - ((x)<<2))	/* watch overflow */
14 #define	MULBY24(x)	(((x)<<4) + ((x)<<3))
15 
16 /*
17  * Two days, in seconds.
18  */
19 #define	TWODAYS		(2*24*60*60)
20 
21 /*
22  * We demand that the time be within CLOSETIME seconds of the receive
23  * time stamp.  This is about 4 hours, which hopefully should be
24  * wide enough to collect most data, while close enough to keep things
25  * from getting confused.
26  */
27 #define	CLOSETIME	(4*60*60)
28 
29 
30 int
31 clocktime(
32 	int yday,
33 	int hour,
34 	int minute,
35 	int second,
36 	int tzoff,
37 	u_long rec_ui,
38 	u_long *yearstart,
39 	u_int32 *ts_ui
40 	)
41 {
42 	register long tmp;
43 	register u_long date;
44 	register u_long yst;
45 
46 	/*
47 	 * Compute the offset into the year in seconds.  Note that
48 	 * this could come out to be a negative number.
49 	 */
50 	tmp = (long)(MULBY24((yday-1)) + hour + tzoff);
51 	tmp = MULBY60(tmp) + (long)minute;
52 	tmp = MULBY60(tmp) + (long)second;
53 
54 	/*
55 	 * Initialize yearstart, if necessary.
56 	 */
57 	yst = *yearstart;
58 	if (yst == 0) {
59 		yst = calyearstart(rec_ui);
60 		*yearstart = yst;
61 	}
62 
63 	/*
64 	 * Now the fun begins.  We demand that the received clock time
65 	 * be within CLOSETIME of the receive timestamp, but
66 	 * there is uncertainty about the year the timestamp is in.
67 	 * Use the current year start for the first check, this should
68 	 * work most of the time.
69 	 */
70 	date = (u_long)(tmp + (long)yst);
71 	if (date < (rec_ui + CLOSETIME) &&
72 	    date > (rec_ui - CLOSETIME)) {
73 		*ts_ui = date;
74 		return 1;
75 	}
76 
77 	/*
78 	 * Trouble.  Next check is to see if the year rolled over and, if
79 	 * so, try again with the new year's start.
80 	 */
81 	yst = calyearstart(rec_ui);
82 	if (yst != *yearstart) {
83 		date = (u_long)((long)yst + tmp);
84 		*ts_ui = date;
85 		if (date < (rec_ui + CLOSETIME) &&
86 		    date > (rec_ui - CLOSETIME)) {
87 			*yearstart = yst;
88 			return 1;
89 		}
90 	}
91 
92 	/*
93 	 * Here we know the year start matches the current system
94 	 * time.  One remaining possibility is that the time code
95 	 * is in the year previous to that of the system time.  This
96 	 * is only worth checking if the receive timestamp is less
97 	 * than a couple of days into the new year.
98 	 */
99 	if ((rec_ui - yst) < TWODAYS) {
100 		yst = calyearstart(yst - TWODAYS);
101 		if (yst != *yearstart) {
102 			date = (u_long)(tmp + (long)yst);
103 			if (date < (rec_ui + CLOSETIME) &&
104 			    date > (rec_ui - CLOSETIME)) {
105 				*yearstart = yst;
106 				*ts_ui = date;
107 				return 1;
108 			}
109 		}
110 	}
111 
112 	/*
113 	 * One last possibility is that the time stamp is in the year
114 	 * following the year the system is in.  Try this one before
115 	 * giving up.
116 	 */
117 	yst = calyearstart(rec_ui + TWODAYS);
118 	if (yst != *yearstart) {
119 		date = (u_long)((long)yst + tmp);
120 		if (date < (rec_ui + CLOSETIME) &&
121 		    date > (rec_ui - CLOSETIME)) {
122 			*yearstart = yst;
123 			*ts_ui = date;
124 			return 1;
125 		}
126 	}
127 
128 	/*
129 	 * Give it up.
130 	 */
131 	return 0;
132 }
133