xref: /freebsd/contrib/ntp/libntp/caljulian.c (revision c0b746e5e8d9479f05b3749cbf1f73b8928719bd)
1c0b746e5SOllivier Robert /*
2c0b746e5SOllivier Robert  * caljulian - determine the Julian date from an NTP time.
3c0b746e5SOllivier Robert  */
4c0b746e5SOllivier Robert #include <sys/types.h>
5c0b746e5SOllivier Robert 
6c0b746e5SOllivier Robert #include "ntp_types.h"
7c0b746e5SOllivier Robert #include "ntp_calendar.h"
8c0b746e5SOllivier Robert #include "ntp_stdlib.h"
9c0b746e5SOllivier Robert 
10c0b746e5SOllivier Robert /*
11c0b746e5SOllivier Robert  * calmonthtab - days-in-the-month table
12c0b746e5SOllivier Robert  */
13c0b746e5SOllivier Robert static u_short calmonthtab[11] = {
14c0b746e5SOllivier Robert 	JAN,
15c0b746e5SOllivier Robert 	FEB,
16c0b746e5SOllivier Robert 	MAR,
17c0b746e5SOllivier Robert 	APR,
18c0b746e5SOllivier Robert 	MAY,
19c0b746e5SOllivier Robert 	JUN,
20c0b746e5SOllivier Robert 	JUL,
21c0b746e5SOllivier Robert 	AUG,
22c0b746e5SOllivier Robert 	SEP,
23c0b746e5SOllivier Robert 	OCT,
24c0b746e5SOllivier Robert 	NOV
25c0b746e5SOllivier Robert };
26c0b746e5SOllivier Robert 
27c0b746e5SOllivier Robert void
28c0b746e5SOllivier Robert caljulian(
29c0b746e5SOllivier Robert 	u_long		  		ntptime,
30c0b746e5SOllivier Robert 	register struct calendar	*jt
31c0b746e5SOllivier Robert 	)
32c0b746e5SOllivier Robert {
33c0b746e5SOllivier Robert 	u_long ntp_day;
34c0b746e5SOllivier Robert 	u_long minutes;
35c0b746e5SOllivier Robert 	/*
36c0b746e5SOllivier Robert 	 * Absolute, zero-adjusted Christian era day, starting from the
37c0b746e5SOllivier Robert 	 * mythical day 12/1/1 BC
38c0b746e5SOllivier Robert 	 */
39c0b746e5SOllivier Robert 	u_long acez_day;
40c0b746e5SOllivier Robert 
41c0b746e5SOllivier Robert 	u_long d400;				 /* Days into a Gregorian cycle */
42c0b746e5SOllivier Robert 	u_long d100;				 /* Days into a normal century */
43c0b746e5SOllivier Robert 	u_long d4;					 /* Days into a 4-year cycle */
44c0b746e5SOllivier Robert 	u_long n400;				 /* # of Gregorian cycles */
45c0b746e5SOllivier Robert 	u_long n100;				 /* # of normal centuries */
46c0b746e5SOllivier Robert 	u_long n4;					 /* # of 4-year cycles */
47c0b746e5SOllivier Robert 	u_long n1;					 /* # of years into a leap year */
48c0b746e5SOllivier Robert 						 /*   cycle */
49c0b746e5SOllivier Robert 
50c0b746e5SOllivier Robert 	/*
51c0b746e5SOllivier Robert 	 * Do the easy stuff first: take care of hh:mm:ss, ignoring leap
52c0b746e5SOllivier Robert 	 * seconds
53c0b746e5SOllivier Robert 	 */
54c0b746e5SOllivier Robert 	jt->second = (u_char)(ntptime % SECSPERMIN);
55c0b746e5SOllivier Robert 	minutes    = ntptime / SECSPERMIN;
56c0b746e5SOllivier Robert 	jt->minute = (u_char)(minutes % MINSPERHR);
57c0b746e5SOllivier Robert 	jt->hour   = (u_char)((minutes / MINSPERHR) % HRSPERDAY);
58c0b746e5SOllivier Robert 
59c0b746e5SOllivier Robert 	/*
60c0b746e5SOllivier Robert 	 * Find the day past 1900/01/01 00:00 UTC
61c0b746e5SOllivier Robert 	 */
62c0b746e5SOllivier Robert 	ntp_day = ntptime / SECSPERDAY;
63c0b746e5SOllivier Robert 	acez_day = DAY_NTP_STARTS + ntp_day - 1;
64c0b746e5SOllivier Robert 	n400	 = acez_day/GREGORIAN_CYCLE_DAYS;
65c0b746e5SOllivier Robert 	d400	 = acez_day%GREGORIAN_CYCLE_DAYS;
66c0b746e5SOllivier Robert 	n100	 = d400 / GREGORIAN_NORMAL_CENTURY_DAYS;
67c0b746e5SOllivier Robert 	d100	 = d400 % GREGORIAN_NORMAL_CENTURY_DAYS;
68c0b746e5SOllivier Robert 	n4		 = d100 / GREGORIAN_NORMAL_LEAP_CYCLE_DAYS;
69c0b746e5SOllivier Robert 	d4		 = d100 % GREGORIAN_NORMAL_LEAP_CYCLE_DAYS;
70c0b746e5SOllivier Robert 	n1		 = d4 / DAYSPERYEAR;
71c0b746e5SOllivier Robert 
72c0b746e5SOllivier Robert 	/*
73c0b746e5SOllivier Robert 	 * Calculate the year and year-of-day
74c0b746e5SOllivier Robert 	 */
75c0b746e5SOllivier Robert 	jt->yearday = (u_short)(1 + d4%DAYSPERYEAR);
76c0b746e5SOllivier Robert 	jt->year	= (u_short)(400*n400 + 100*n100 + n4*4 + n1);
77c0b746e5SOllivier Robert 
78c0b746e5SOllivier Robert 	if (n100 == 4 || n1 == 4)
79c0b746e5SOllivier Robert 	{
80c0b746e5SOllivier Robert 	/*
81c0b746e5SOllivier Robert 	 * If the cycle year ever comes out to 4, it must be December 31st
82c0b746e5SOllivier Robert 	 * of a leap year.
83c0b746e5SOllivier Robert 	 */
84c0b746e5SOllivier Robert 	jt->month	 = 12;
85c0b746e5SOllivier Robert 	jt->monthday = 31;
86c0b746e5SOllivier Robert 	jt->yearday  = 366;
87c0b746e5SOllivier Robert 	}
88c0b746e5SOllivier Robert 	else
89c0b746e5SOllivier Robert 	{
90c0b746e5SOllivier Robert 	/*
91c0b746e5SOllivier Robert 	 * Else, search forwards through the months to get the right month
92c0b746e5SOllivier Robert 	 * and date.
93c0b746e5SOllivier Robert 	 */
94c0b746e5SOllivier Robert 	int monthday;
95c0b746e5SOllivier Robert 
96c0b746e5SOllivier Robert 	jt->year++;
97c0b746e5SOllivier Robert 	monthday = jt->yearday;
98c0b746e5SOllivier Robert 
99c0b746e5SOllivier Robert 	for (jt->month=0;jt->month<11; jt->month++)
100c0b746e5SOllivier Robert 	{
101c0b746e5SOllivier Robert 		int t;
102c0b746e5SOllivier Robert 
103c0b746e5SOllivier Robert 		t = monthday - calmonthtab[jt->month];
104c0b746e5SOllivier Robert 		if (jt->month == 1 && is_leapyear(jt->year))
105c0b746e5SOllivier Robert 		t--;
106c0b746e5SOllivier Robert 
107c0b746e5SOllivier Robert 		if (t > 0)
108c0b746e5SOllivier Robert 		monthday = t;
109c0b746e5SOllivier Robert 		else
110c0b746e5SOllivier Robert 		break;
111c0b746e5SOllivier Robert 	}
112c0b746e5SOllivier Robert 	jt->month++;
113c0b746e5SOllivier Robert 	jt->monthday = monthday;
114c0b746e5SOllivier Robert 	}
115c0b746e5SOllivier Robert }
116