xref: /netbsd-src/external/bsd/ntp/dist/libntp/caltontp.c (revision ccd9df534e375a4366c5b55f23782053c7a98d82)
1 /*	$NetBSD: caltontp.c,v 1.6 2020/05/25 20:47:24 christos Exp $	*/
2 
3 /*
4  * caltontp - convert a date to an NTP time
5  */
6 #include <config.h>
7 #include <sys/types.h>
8 
9 #include "ntp_types.h"
10 #include "ntp_calendar.h"
11 #include "ntp_stdlib.h"
12 #include "ntp_assert.h"
13 #include "ntp_unixtime.h"
14 
15 /*
16  * Juergen Perlinger, 2008-11-12
17  * Add support for full calendar calculatios. If the day-of-year is provided
18  * (that is, not zero) it will be used instead of month and day-of-month;
19  * otherwise a full turn through the calendar calculations will be taken.
20  *
21  * I know that Harlan Stenn likes to see assertions in production code, and I
22  * agree there, but it would be a tricky thing here. The algorithm is quite
23  * capable of producing sensible answers even to seemingly weird inputs: the
24  * date <any year here>-03-00, the 0.th March of the year, will be automtically
25  * treated as the last day of February, no matter whether the year is a leap
26  * year or not. So adding constraints is merely for the benefit of the callers,
27  * because the only thing we can check for consistency is our input, produced
28  * by somebody else.
29  *
30  * BTW: A total roundtrip using 'caljulian' would be a quite shaky thing:
31  * Because of the truncation of the NTP time stamp to 32 bits and the epoch
32  * unfolding around the current time done by 'caljulian' the roundtrip does
33  * *not* necessarily reproduce the input, especially if the time spec is more
34  * than 68 years off from the current time...
35  */
36 
37 uint32_t
38 caltontp(
39 	const struct calendar *jt
40 	)
41 {
42 	int32_t eraday;	/* CE Rata Die number	*/
43 	vint64  ntptime;/* resulting NTP time	*/
44 
45 	REQUIRE(jt != NULL);
46 
47 	REQUIRE(jt->month <= 13);	/* permit month 0..13! */
48 	REQUIRE(jt->monthday <= 32);
49 	REQUIRE(jt->yearday <= 366);
50 	REQUIRE(jt->hour <= 24);
51 	REQUIRE(jt->minute <= MINSPERHR);
52 	REQUIRE(jt->second <= SECSPERMIN);
53 
54 	/*
55 	 * First convert the date to he corresponding RataDie
56 	 * number. If yearday is not zero, assume that it contains a
57 	 * useable value and avoid all calculations involving month
58 	 * and day-of-month. Do a full evaluation otherwise.
59 	 */
60 	if (jt->yearday)
61 		eraday = ntpcal_year_to_ystart(jt->year)
62 		       + jt->yearday - 1;
63 	else
64 		eraday = ntpcal_date_to_rd(jt);
65 
66 	ntptime = ntpcal_dayjoin(eraday - DAY_NTP_STARTS,
67 				 ntpcal_etime_to_seconds(jt->hour, jt->minute,
68 							 jt->second));
69 	return ntptime.d_s.lo;
70 }
71