xref: /freebsd/contrib/ntp/libntp/caltontp.c (revision a466cc55373fc3cf86837f09da729535b57e69a1)
1c0b746e5SOllivier Robert /*
2c0b746e5SOllivier Robert  * caltontp - convert a date to an NTP time
3c0b746e5SOllivier Robert  */
42b15cb3dSCy Schubert #include <config.h>
5c0b746e5SOllivier Robert #include <sys/types.h>
6c0b746e5SOllivier Robert 
7c0b746e5SOllivier Robert #include "ntp_types.h"
8c0b746e5SOllivier Robert #include "ntp_calendar.h"
9c0b746e5SOllivier Robert #include "ntp_stdlib.h"
102b15cb3dSCy Schubert #include "ntp_assert.h"
112b15cb3dSCy Schubert #include "ntp_unixtime.h"
12c0b746e5SOllivier Robert 
132b15cb3dSCy Schubert /*
142b15cb3dSCy Schubert  * Juergen Perlinger, 2008-11-12
15*a466cc55SCy Schubert  * Add support for full calendar calculations. If the day-of-year is provided
162b15cb3dSCy Schubert  * (that is, not zero) it will be used instead of month and day-of-month;
172b15cb3dSCy Schubert  * otherwise a full turn through the calendar calculations will be taken.
182b15cb3dSCy Schubert  *
192b15cb3dSCy Schubert  * I know that Harlan Stenn likes to see assertions in production code, and I
20*a466cc55SCy Schubert  * agree in general. But here we set 'errno' and try to do our best instead.
21*a466cc55SCy Schubert  * Also note that the bounds check is a bit sloppy: It permits off-by-one
22*a466cc55SCy Schubert  * on the input quantities. That permits some simple/naive adjustments to
23*a466cc55SCy Schubert  * be made before calling this function.
24*a466cc55SCy Schubert  *
25*a466cc55SCy Schubert  * Apart from that the calendar is perfectly capable of dealing with
26*a466cc55SCy Schubert  * off-scale input values!
272b15cb3dSCy Schubert  *
282b15cb3dSCy Schubert  * BTW: A total roundtrip using 'caljulian' would be a quite shaky thing:
292b15cb3dSCy Schubert  * Because of the truncation of the NTP time stamp to 32 bits and the epoch
302b15cb3dSCy Schubert  * unfolding around the current time done by 'caljulian' the roundtrip does
312b15cb3dSCy Schubert  * *not* necessarily reproduce the input, especially if the time spec is more
322b15cb3dSCy Schubert  * than 68 years off from the current time...
332b15cb3dSCy Schubert  */
342b15cb3dSCy Schubert 
352b15cb3dSCy Schubert uint32_t
caltontp(const struct calendar * jt)36c0b746e5SOllivier Robert caltontp(
372b15cb3dSCy Schubert 	const struct calendar *jt
38c0b746e5SOllivier Robert 	)
39c0b746e5SOllivier Robert {
402b15cb3dSCy Schubert 	int32_t eraday;	/* CE Rata Die number	*/
412b15cb3dSCy Schubert 	vint64  ntptime;/* resulting NTP time	*/
422b15cb3dSCy Schubert 
43*a466cc55SCy Schubert 	if (NULL == jt) {
44*a466cc55SCy Schubert 		errno = EINVAL;
45*a466cc55SCy Schubert 		return 0;
46*a466cc55SCy Schubert 	}
472b15cb3dSCy Schubert 
48*a466cc55SCy Schubert 	if (   (jt->month > 13)	/* permit month 0..13! */
49*a466cc55SCy Schubert 	    || (jt->monthday > 32)
50*a466cc55SCy Schubert 	    || (jt->yearday > 366)
51*a466cc55SCy Schubert 	    || (jt->hour > 24)
52*a466cc55SCy Schubert 	    || (jt->minute > MINSPERHR)
53*a466cc55SCy Schubert 	    || (jt->second > SECSPERMIN))
54*a466cc55SCy Schubert 		errno = ERANGE;
55c0b746e5SOllivier Robert 
56c0b746e5SOllivier Robert 	/*
572b15cb3dSCy Schubert 	 * First convert the date to he corresponding RataDie
582b15cb3dSCy Schubert 	 * number. If yearday is not zero, assume that it contains a
592b15cb3dSCy Schubert 	 * useable value and avoid all calculations involving month
602b15cb3dSCy Schubert 	 * and day-of-month. Do a full evaluation otherwise.
61c0b746e5SOllivier Robert 	 */
622b15cb3dSCy Schubert 	if (jt->yearday)
632b15cb3dSCy Schubert 		eraday = ntpcal_year_to_ystart(jt->year)
642b15cb3dSCy Schubert 		       + jt->yearday - 1;
652b15cb3dSCy Schubert 	else
662b15cb3dSCy Schubert 		eraday = ntpcal_date_to_rd(jt);
67c0b746e5SOllivier Robert 
682b15cb3dSCy Schubert 	ntptime = ntpcal_dayjoin(eraday - DAY_NTP_STARTS,
692b15cb3dSCy Schubert 				 ntpcal_etime_to_seconds(jt->hour, jt->minute,
702b15cb3dSCy Schubert 							 jt->second));
712b15cb3dSCy Schubert 	return ntptime.d_s.lo;
72c0b746e5SOllivier Robert }
73