clocktime.c revision 259065
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
30int
31clocktime(
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