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