1: /*
2: * caljulian - determine the Julian date from an NTP time.
3: */
4: #include <sys/types.h>
5:
6: #include "ntp_types.h"
7: #include "ntp_calendar.h"
8: #include "ntp_stdlib.h"
9: #include "ntp_fp.h"
10: #include "ntp_unixtime.h"
11:
12: #if !(defined(ISC_CHECK_ALL) || defined(ISC_CHECK_NONE) || \
13: defined(ISC_CHECK_ENSURE) || defined(ISC_CHECK_INSIST) || \
14: defined(ISC_CHECK_INVARIANT))
15: # define ISC_CHECK_ALL
16: #endif
17:
18: #include "ntp_assert.h"
19:
20: #if 1
21:
22: /* Updated 2008-11-10 Juergen Perlinger <juergen.perlinger@t-online.de>
23: *
24: * Make the conversion 2038-proof with proper NTP epoch unfolding and extended
25: * precision calculations. Though we should really get a 'time_t' with more
26: * than 32 bits at least until 2037, because the unfolding cannot work after
27: * the wrap of the 32-bit 'time_t'.
28: */
29:
30: void
31: caljulian(
32: u_long ntptime,
33: register struct calendar *jt
34: )
35: {
36: u_long saved_time = ntptime;
37: u_long ntp_day; /* days (since christian era or in year) */
38: u_long n400; /* # of Gregorian cycles */
39: u_long n100; /* # of normal centuries */
40: u_long n4; /* # of 4-year cycles */
41: u_long n1; /* # of years into a leap year cycle */
42: u_long sclday; /* scaled days for month conversion */
43: int leaps; /* # of leaps days in year */
44: time_t now; /* current system time */
45: u_int32 tmplo; /* double precision tmp value / lo part */
46: int32 tmphi; /* double precision tmp value / hi part */
47:
48: NTP_INSIST(NULL != jt);
49:
50: /*
51: * First we have to unfold the ntp time stamp around the current time
52: * to make sure we are in the right epoch. Also we we do *NOT* fold
53: * before the begin of the first NTP epoch, so we WILL have a
54: * non-negative time stamp afterwards. Though at the time of this
55: * writing (2008 A.D.) it would be really strange to have systems
56: * running with clock set to he 1960's or before...
57: *
58: * But's important to use a 32 bit max signed value -- LONG_MAX is 64
59: * bit on a 64-bit system, and it will give wrong results.
60: */
61: now = time(NULL);
62: tmplo = (u_int32)now;
63: #if ( SIZEOF_TIME_T > 4 )
64: tmphi = (int32)(now >> 16 >> 16);
65: #else
66: /*
67: * Get the correct sign extension in the high part.
68: * (now >> 32) may not work correctly on every 32 bit
69: * system, e.g. it yields garbage under Win32/VC6.
70: */
71: tmphi = (int32)(now >> 31);
72: #endif
73:
74: M_ADD(tmphi, tmplo, 0, ((1UL << 31)-1)); /* 32-bit max signed */
75: M_ADD(tmphi, tmplo, 0, JAN_1970);
76: if ((ntptime > tmplo) && (tmphi > 0))
77: --tmphi;
78: tmplo = ntptime;
79:
80: /*
81: * Now split into days and seconds-of-day, using the fact that
82: * SECSPERDAY (86400) == 675 * 128; we can get roughly 17000 years of
83: * time scale, using only 32-bit calculations. Some magic numbers here,
84: * sorry for that. (This could be streamlined for 64 bit machines, but
85: * is worth the trouble?)
86: */
87: ntptime = tmplo & 127; /* save remainder bits */
88: tmplo = (tmplo >> 7) | (tmphi << 25);
89: ntp_day = (u_int32)tmplo / 675;
90: ntptime += ((u_int32)tmplo % 675) << 7;
91:
92: /* some checks for the algorithm
93: * There's some 64-bit trouble out there: the original NTP time stamp
94: * had only 32 bits, so our calculation invariant only holds in 32 bits!
95: */
96: NTP_ENSURE(ntptime < SECSPERDAY);
97: NTP_INVARIANT((u_int32)(ntptime + ntp_day * SECSPERDAY) == (u_int32)saved_time);
98:
99: /*
100: * Do the easy stuff first: take care of hh:mm:ss, ignoring leap
101: * seconds
102: */
103: jt->second = (u_char)(ntptime % SECSPERMIN);
104: ntptime /= SECSPERMIN;
105: jt->minute = (u_char)(ntptime % MINSPERHR);
106: ntptime /= MINSPERHR;
107: jt->hour = (u_char)(ntptime);
108:
109: /* check time invariants */
110: NTP_ENSURE(jt->second < SECSPERMIN);
111: NTP_ENSURE(jt->minute < MINSPERHR);
112: NTP_ENSURE(jt->hour < HRSPERDAY);
113:
114: /*
115: * Find the day past 1900/01/01 00:00 UTC
116: */
117: ntp_day += DAY_NTP_STARTS - 1; /* convert to days in CE */
118: n400 = ntp_day / GREGORIAN_CYCLE_DAYS; /* split off cycles */
119: ntp_day %= GREGORIAN_CYCLE_DAYS;
120: n100 = ntp_day / GREGORIAN_NORMAL_CENTURY_DAYS;
121: ntp_day %= GREGORIAN_NORMAL_CENTURY_DAYS;
122: n4 = ntp_day / GREGORIAN_NORMAL_LEAP_CYCLE_DAYS;
123: ntp_day %= GREGORIAN_NORMAL_LEAP_CYCLE_DAYS;
124: n1 = ntp_day / DAYSPERYEAR;
125: ntp_day %= DAYSPERYEAR; /* now zero-based day-of-year */
126:
127: NTP_ENSURE(ntp_day < 366);
128:
129: /*
130: * Calculate the year and day-of-year
131: */
132: jt->year = (u_short)(400*n400 + 100*n100 + 4*n4 + n1);
133:
134: if ((n100 | n1) > 3) {
135: /*
136: * If the cycle year ever comes out to 4, it must be December
137: * 31st of a leap year.
138: */
139: jt->month = 12;
140: jt->monthday = 31;
141: jt->yearday = 366;
142: } else {
143: /*
144: * The following code is according to the excellent book
145: * 'Calendrical Calculations' by Nachum Dershowitz and Edward
146: * Reingold. It converts the day-of-year into month and
147: * day-of-month, using a linear transformation with integer
148: * truncation. Magic numbers again, but they will not be used
149: * anywhere else.
150: */
151: sclday = ntp_day * 7 + 217;
152: leaps = ((n1 == 3) && ((n4 != 24) || (n100 == 3))) ? 1 : 0;
153: if (ntp_day >= (u_long)(JAN + FEB + leaps))
154: sclday += (2 - leaps) * 7;
155: ++jt->year;
156: jt->month = (u_char)(sclday / 214);
157: jt->monthday = (u_char)((sclday % 214) / 7 + 1);
158: jt->yearday = (u_short)(1 + ntp_day);
159: }
160:
161: /* check date invariants */
162: NTP_ENSURE(1 <= jt->month && jt->month <= 12);
163: NTP_ENSURE(1 <= jt->monthday && jt->monthday <= 31);
164: NTP_ENSURE(1 <= jt->yearday && jt->yearday <= 366);
165: }
166:
167: #else
168:
169: /* Updated 2003-12-30 TMa
170:
171: Uses common code with the *prettydate functions to convert an ntp
172: seconds count into a calendar date.
173: Will handle ntp epoch wraparound as long as the underlying os/library
174: does so for the unix epoch, i.e. works after 2038.
175: */
176:
177: void
178: caljulian(
179: u_long ntptime,
180: register struct calendar *jt
181: )
182: {
183: struct tm *tm;
184: NTP_REQUIRE(jt != NULL);
185:
186: tm = ntp2unix_tm(ntptime, 0);
187: NTP_INSIST(tm != NULL);
188:
189: jt->hour = (u_char) tm->tm_hour;
190: jt->minute = (u_char) tm->tm_min;
191: jt->month = (u_char) (tm->tm_mon + 1);
192: jt->monthday = (u_char) tm->tm_mday;
193: jt->second = (u_char) tm->tm_sec;
194: jt->year = (u_short) (tm->tm_year + 1900);
195: jt->yearday = (u_short) (tm->tm_yday + 1); /* Assumes tm_yday starts with day 0! */
196: }
197: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>