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