46b07657841fe4f15865928ae6ab1f6ff42b8c81
[pspp-builds.git] / lib / julcal / julcal.c
1 /*
2    Modified BLP 8/28/95, 12/15/99 for PSPP.
3
4    Original sources for julcal.c and julcal.h can be found at
5    ftp.cdrom.com in /pub/algorithms/c/julcal10/{julcal.c,julcal.h}.
6  */
7
8 /*
9    Translated from Pascal to C by Jim Van Zandt, July 1992.
10
11    Error-free translation based on error-free PL/I source
12
13    Based on Pascal code copyright 1985 by Michael A. Covington,
14    published in P.C. Tech Journal, December 1985, based on formulae
15    appearing in Astronomical Formulae for Calculators by Jean Meeus
16  */
17
18 /*#include <config.h>*/
19 #include <time.h>
20 #include <assert.h>
21 #include "julcal.h"
22
23 #define JUL_OFFSET 2299160L
24
25 /* Takes Y, M, and D, and returns the corresponding Julian date as an
26    offset in days from the midnight separating 8 Oct 1582 and 9 Oct
27    1582.  (Y,M,D) = (1999,10,1) corresponds to 1 Oct 1999. */
28 long
29 calendar_to_julian (int y, int m, int d)
30 {
31   m--;
32   y += m / 12;
33   m -= m / 12 * 12;
34
35   assert (m > -12 && m < 12);
36   if (m < 0)
37     {
38       m += 12;
39       y--;
40     }
41
42   assert (m >= 0 && m < 12);
43   if (m < 2)
44     {
45       m += 13;
46       y--;
47     }
48   else
49     m++;
50     
51   return ((1461 * (y + 4716L) / 4)
52           + (153 * (m + 1) / 5)
53           + (d - 1)
54           - 1524
55           + 3
56           - y / 100
57           + y / 400
58           - y / 4000
59           - JUL_OFFSET);
60 }
61
62 /* Takes a Julian date JD and sets *Y0, *M0, and *D0 to the
63    corresponding year, month, and day, respectively, where
64    (*Y0,*M0,*D0) = (1999,10,1) would be 1 Oct 1999. */
65 void
66 julian_to_calendar (long jd, int *y0, int *m0, int *d0)
67 {
68   int a, ay, em;
69
70   jd += JUL_OFFSET;
71   
72   {
73     long aa, ab;
74     
75     aa = jd - 1721120L;
76     ab = 31 * (aa / 1460969L);
77     aa %= 1460969L;
78     ab += 3 * (aa / 146097L);
79     aa = aa % 146097L;
80     if (aa == 146096L)
81       ab += 3;
82     else
83       ab += aa / 36524L;
84     a = jd + (ab - 2);
85   }
86   
87   {
88     long ee, b, d;
89     
90     b = a + 1524;
91     ay = (20 * b - 2442) / 7305;
92     d = 1461L * ay / 4;
93     ee = b - d;
94     em = 10000 * ee / 306001;
95     if (d0 != NULL)
96       *d0 = ee - 306001L * em / 10000L;
97   }
98
99   if (y0 != NULL || m0 != NULL)
100     {
101       int m = em - 1;
102       if (m > 12)
103         m -= 12;
104       if (m0 != NULL)
105         *m0 = m;
106
107       if (y0 != NULL)
108         {
109           if (m > 2)
110             *y0 = ay - 4716;
111           else
112             *y0 = ay - 4715;
113         }
114       
115     }
116 }
117
118 /* Takes a julian date JD and returns the corresponding year-relative
119    Julian date, with 1=Jan 1. */
120 int
121 julian_to_jday (long jd)
122 {
123   int year;
124
125   julian_to_calendar (jd, &year, NULL, NULL);
126   return jd - calendar_to_julian (year, 1, 1) + 1;
127 }
128
129
130 /* Takes a julian date JD and returns the corresponding weekday 1...7,
131    with 1=Sunday. */
132 int
133 julian_to_wday (long jd)
134 {
135   return (jd - 3) % 7 + 1;
136 }
137
138 #if STANDALONE
139 #include <stdio.h>
140
141 int
142 main (void)
143 {
144   {
145     long julian[] = 
146       {
147         1, 50000, 102, 1157, 14288, 87365, 109623, 153211, 152371, 144623,
148       };
149     size_t j;
150
151     for (j = 0; j < sizeof julian / sizeof *julian; j++)
152       {
153         int y, m, d;
154         long jd;
155         julian_to_calendar (julian[j], &y, &m, &d);
156         jd = calendar_to_julian (y, m, d);
157         printf ("%ld => %d/%d/%d => %ld\n", julian[j], y, m, d, jd);
158       }
159   }
160   
161   {
162     int date[][3] = 
163       {
164         {1582,10,15}, {1719,9,6}, {1583,1,24}, {1585,12,14},
165         {1621,11,26}, {1821,12,25}, {1882,12,3}, {2002,4,6},
166         {1999,12,19}, {1978,10,1},
167       };
168     size_t j;
169
170     for (j = 0; j < sizeof date / sizeof *date; j++)
171       {
172         int y = date[j][0], m = date[j][1], d = date[j][2];
173         long jd = calendar_to_julian (y, m, d);
174         int y2, m2, d2;
175         julian_to_calendar (jd, &y2, &m2, &d2);
176         printf ("%d/%d/%d => %ld => %d/%d/%d\n",
177                 y, m, d, jd, y2, m2, d2);
178       }
179   }
180     
181   return 0;
182 }
183 #endif