xref: /netbsd-src/external/bsd/ntp/dist/libntp/caltontp.c (revision eabc0478de71e4e011a5b4e0392741e01d491794)
1*eabc0478Schristos /*	$NetBSD: caltontp.c,v 1.7 2024/08/18 20:47:13 christos Exp $	*/
2abb0f93cSkardel 
3abb0f93cSkardel /*
4abb0f93cSkardel  * caltontp - convert a date to an NTP time
5abb0f93cSkardel  */
68585484eSchristos #include <config.h>
7abb0f93cSkardel #include <sys/types.h>
8abb0f93cSkardel 
9abb0f93cSkardel #include "ntp_types.h"
10abb0f93cSkardel #include "ntp_calendar.h"
11abb0f93cSkardel #include "ntp_stdlib.h"
12abb0f93cSkardel #include "ntp_assert.h"
138585484eSchristos #include "ntp_unixtime.h"
14abb0f93cSkardel 
15abb0f93cSkardel /*
16abb0f93cSkardel  * Juergen Perlinger, 2008-11-12
17*eabc0478Schristos  * Add support for full calendar calculations. If the day-of-year is provided
18abb0f93cSkardel  * (that is, not zero) it will be used instead of month and day-of-month;
19abb0f93cSkardel  * otherwise a full turn through the calendar calculations will be taken.
20abb0f93cSkardel  *
21abb0f93cSkardel  * I know that Harlan Stenn likes to see assertions in production code, and I
22*eabc0478Schristos  * agree in general. But here we set 'errno' and try to do our best instead.
23*eabc0478Schristos  * Also note that the bounds check is a bit sloppy: It permits off-by-one
24*eabc0478Schristos  * on the input quantities. That permits some simple/naive adjustments to
25*eabc0478Schristos  * be made before calling this function.
26*eabc0478Schristos  *
27*eabc0478Schristos  * Apart from that the calendar is perfectly capable of dealing with
28*eabc0478Schristos  * off-scale input values!
29abb0f93cSkardel  *
30abb0f93cSkardel  * BTW: A total roundtrip using 'caljulian' would be a quite shaky thing:
31abb0f93cSkardel  * Because of the truncation of the NTP time stamp to 32 bits and the epoch
32abb0f93cSkardel  * unfolding around the current time done by 'caljulian' the roundtrip does
33abb0f93cSkardel  * *not* necessarily reproduce the input, especially if the time spec is more
34abb0f93cSkardel  * than 68 years off from the current time...
35abb0f93cSkardel  */
368585484eSchristos 
378585484eSchristos uint32_t
38abb0f93cSkardel caltontp(
39abb0f93cSkardel 	const struct calendar *jt
40abb0f93cSkardel 	)
41abb0f93cSkardel {
428585484eSchristos 	int32_t eraday;	/* CE Rata Die number	*/
438585484eSchristos 	vint64  ntptime;/* resulting NTP time	*/
44abb0f93cSkardel 
45*eabc0478Schristos 	if (NULL == jt) {
46*eabc0478Schristos 		errno = EINVAL;
47*eabc0478Schristos 		return 0;
48*eabc0478Schristos 	}
49abb0f93cSkardel 
50*eabc0478Schristos 	if (   (jt->month > 13)	/* permit month 0..13! */
51*eabc0478Schristos 	    || (jt->monthday > 32)
52*eabc0478Schristos 	    || (jt->yearday > 366)
53*eabc0478Schristos 	    || (jt->hour > 24)
54*eabc0478Schristos 	    || (jt->minute > MINSPERHR)
55*eabc0478Schristos 	    || (jt->second > SECSPERMIN))
56*eabc0478Schristos 		errno = ERANGE;
57abb0f93cSkardel 
58abb0f93cSkardel 	/*
598585484eSchristos 	 * First convert the date to he corresponding RataDie
608585484eSchristos 	 * number. If yearday is not zero, assume that it contains a
618585484eSchristos 	 * useable value and avoid all calculations involving month
628585484eSchristos 	 * and day-of-month. Do a full evaluation otherwise.
63abb0f93cSkardel 	 */
648585484eSchristos 	if (jt->yearday)
658585484eSchristos 		eraday = ntpcal_year_to_ystart(jt->year)
668585484eSchristos 		       + jt->yearday - 1;
678585484eSchristos 	else
688585484eSchristos 		eraday = ntpcal_date_to_rd(jt);
69abb0f93cSkardel 
708585484eSchristos 	ntptime = ntpcal_dayjoin(eraday - DAY_NTP_STARTS,
718585484eSchristos 				 ntpcal_etime_to_seconds(jt->hour, jt->minute,
728585484eSchristos 							 jt->second));
738585484eSchristos 	return ntptime.d_s.lo;
74abb0f93cSkardel }
75