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