-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathjd.go
442 lines (346 loc) · 9.99 KB
/
jd.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
// Copyright 2022 HE Boliang
// All rights reserved.
package gofa
// Calendar
/*
Cal2jd Gregorian Calendar to Julian Date.
Given:
iy,im,id int year, month, day in Gregorian calendar (Note 1)
Returned:
djm0 float64 MJD zero-point: always 2400000.5
djm float64 Modified Julian Date for 0 hrs
Returned (function value):
int status:
0 = OK
-1 = bad year (Note 3: JD not computed)
-2 = bad month (JD not computed)
-3 = bad day (JD computed)
Notes:
1. The algorithm used is valid from -4800 March 1, but this
implementation rejects dates before -4799 January 1.
2. The Julian Date is returned in two pieces, in the usual SOFA
manner, which is designed to preserve time resolution. The
Julian Date is available as a single number by adding djm0 and
djm.
3. In early eras the conversion is from the "Proleptic Gregorian
Calendar"; no account is taken of the date(s) of adoption of
the Gregorian Calendar, nor is the AD/BC numbering convention
observed.
Reference:
Explanatory Supplement to the Astronomical Almanac,
P. Kenneth Seidelmann (ed), University Science Books (1992),
Section 12.92 (p604).
*/
func Cal2jd(iy, im, id int, djm0, djm *float64) int {
var j, ly, my int
var iypmy int
/* Earliest year allowed (4800BC) */
const IYMIN = -4799
/* Month lengths in days */
mtab := []int{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
/* Preset status. */
j = 0
/* Validate year and month. */
if iy < IYMIN {
return -1
}
if im < 1 || im > 12 {
return -2
}
/* If February in a leap year, 1, otherwise 0. */
// ly = ((im == 2) && !(iy%4) && (iy%100 || !(iy%400)));
if (im == 2) && (iy%4 == 0) && ((iy%100 != 0) || (iy%400 == 0)) {
ly = 1
} else {
ly = 0
}
/* Validate day, taking into account leap years. */
if (id < 1) || (id > (mtab[im-1] + ly)) {
j = -3
}
/* Return result. */
my = (im - 14) / 12
iypmy = (iy + my)
*djm0 = DJM0
*djm = float64((1461*(iypmy+4800))/4 + (367*(im-2-12*my))/12 - (3*((iypmy+4900)/100))/4 + id - 2432076)
/* Return status. */
return j
}
/*
Jd2cal Julian Date to Gregorian year, month, day, and fraction of a day.
Given:
dj1,dj2 float64 Julian Date (Notes 1, 2)
Returned (arguments):
iy int year
im int month
id int day
fd float64 fraction of day
Returned (function value):
int status:
0 = OK
-1 = unacceptable date (Note 1)
Notes:
1) The earliest valid date is -68569.5 (-4900 March 1). The
largest value accepted is 1e9.
2) The Julian Date is apportioned in any convenient way between
the arguments dj1 and dj2. For example, JD=2450123.7 could
be expressed in any of these ways, among others:
dj1 dj2
2450123.7 0.0 (JD method)
2451545.0 -1421.3 (J2000 method)
2400000.5 50123.2 (MJD method)
2450123.5 0.2 (date & time method)
Separating integer and fraction uses the "compensated summation"
algorithm of Kahan-Neumaier to preserve as much precision as
possible irrespective of the jd1+jd2 apportionment.
3) In early eras the conversion is from the "proleptic Gregorian
calendar"; no account is taken of the date(s) of adoption of
the Gregorian calendar, nor is the AD/BC numbering convention
observed.
References:
Explanatory Supplement to the Astronomical Almanac,
P. Kenneth Seidelmann (ed), University Science Books (1992),
Section 12.92 (p604).
Klein, A., A Generalized Kahan-Babuska-Summation-Algorithm.
Computing, 76, 279-293 (2006), Section 3.
*/
func Jd2cal(dj1, dj2 float64, iy, im, id *int, fd *float64) int {
/* Minimum and maximum allowed JD */
const DJMIN = -68569.5
const DJMAX = 1e9
var jd, i, l, n, k int64
var dj, f1, f2, d, s, cs, x, t, f float64
var v [2]float64
/* Verify date is acceptable. */
dj = dj1 + dj2
if dj < DJMIN || dj > DJMAX {
return -1
}
/* Separate day and fraction (where -0.5 <= fraction < 0.5). */
d = dnint(dj1)
f1 = dj1 - d
jd = int64(d)
d = dnint(dj2)
f2 = dj2 - d
jd += int64(d)
/* Compute f1+f2+0.5 using compensated summation (Klein 2006). */
s = 0.5
cs = 0.0
v[0] = f1
v[1] = f2
for i := 0; i < 2; i++ {
x = v[i]
t = s + x
if fabs(s) >= fabs(x) {
cs += (s - t) + x
} else {
cs += (x - t) + s
}
s = t
if s >= 1.0 {
jd++
s -= 1.0
}
}
f = s + cs
cs = f - s
/* Deal with negative f. */
if f < 0.0 {
/* Compensated summation: assume that |s| <= 1.0. */
f = s + 1.0
cs += (1.0 - f) + s
s = f
f = s + cs
cs = f - s
jd--
}
/* Deal with f that is 1.0 or more (when rounded to double). */
if (f - 1.0) >= -DBL_EPSILON/4.0 {
/* Compensated summation: assume that |s| <= 1.0. */
t = s - 1.0
cs += (s - t) - 1.0
s = t
f = s + cs
if -DBL_EPSILON/2.0 < f {
jd++
f = gmax(f, 0.0)
}
}
/* Express day in Gregorian calendar. */
l = jd + 68569
n = (4 * l) / 146097
l -= (146097*n + 3) / 4
i = (4000 * (l + 1)) / 1461001
l -= (1461*i)/4 - 31
k = (80 * l) / 2447
*id = int(l - (2447*k)/80)
l = k / 11
*im = int(k + 2 - 12*l)
*iy = int(100*(n-49) + i + l)
*fd = f
/* Success. */
return 0
}
/*
Jdcalf Julian Date to Gregorian Calendar, expressed in a form convenient
for formatting messages: rounded to a specified precision.
Given:
ndp int number of decimal places of days in fraction
dj1,dj2 float64 dj1+dj2 = Julian Date (Note 1)
Returned:
iymdf [4]int year, month, day, fraction in Gregorian calendar
Returned (function value):
int status:
-1 = date out of range
0 = OK
+1 = NDP not 0-9 (interpreted as 0)
Notes:
1) The Julian Date is apportioned in any convenient way between
the arguments dj1 and dj2. For example, JD=2450123.7 could
be expressed in any of these ways, among others:
dj1 dj2
2450123.7 0.0 (JD method)
2451545.0 -1421.3 (J2000 method)
2400000.5 50123.2 (MJD method)
2450123.5 0.2 (date & time method)
2) In early eras the conversion is from the "Proleptic Gregorian
Calendar"; no account is taken of the date(s) of adoption of
the Gregorian Calendar, nor is the AD/BC numbering convention
observed.
3) See also the function Jd2cal.
4) The number of decimal places ndp should be 4 or less if internal
overflows are to be avoided on platforms which use 16-bit
integers.
Called:
Jd2cal JD to Gregorian calendar
Reference:
Explanatory Supplement to the Astronomical Almanac,
P. Kenneth Seidelmann (ed), University Science Books (1992),
Section 12.92 (p604).
*/
func Jdcalf(ndp int, dj1, dj2 float64, iymdf *[4]int) int {
var j, js int
var denom, d1, d2, f1, f2, d, djd, f, rf float64
/* Denominator of fraction (e.g. 100 for 2 decimal places). */
if (ndp >= 0) && (ndp <= 9) {
j = 0
denom = pow10(ndp)
} else {
j = 1
denom = 1.0
}
/* Copy the date, big then small. */
if fabs(dj1) >= fabs(dj2) {
d1 = dj1
d2 = dj2
} else {
d1 = dj2
d2 = dj1
}
/* Realign to midnight (without rounding error). */
d1 -= 0.5
/* Separate day and fraction (as precisely as possible). */
d = dnint(d1)
f1 = d1 - d
djd = d
d = dnint(d2)
f2 = d2 - d
djd += d
d = dnint(f1 + f2)
f = (f1 - d) + f2
if f < 0.0 {
f += 1.0
d -= 1.0
}
djd += d
/* Round the total fraction to the specified number of places. */
rf = dnint(f*denom) / denom
/* Re-align to noon. */
djd += 0.5
/* Convert to Gregorian calendar. */
js = Jd2cal(djd, rf, &iymdf[0], &iymdf[1], &iymdf[2], &f)
if js == 0 {
iymdf[3] = int(dnint(f * denom))
} else {
j = js
}
/* Return the status. */
return j
}
/*
Epb Julian Date to Besselian Epoch.
Given:
dj1,dj2 float64 Julian Date (see note)
Returned (function value):
float64 Besselian Epoch.
Note:
The Julian Date is supplied in two pieces, in the usual SOFA
manner, which is designed to preserve time resolution. The
Julian Date is available as a single number by adding dj1 and
dj2. The maximum resolution is achieved if dj1 is 2451545.0
(J2000.0).
Reference:
Lieske, J.H., 1979. Astron.Astrophys., 73, 282.
*/
func Epb(dj1, dj2 float64) float64 {
/* J2000.0-B1900.0 (2415019.81352) in days */
const D1900 = 36524.68648
return 1900.0 + ((dj1-DJ00)+(dj2+D1900))/DTY
}
/*
Epb2jd Besselian Epoch to Julian Date.
Given:
epb float64 Besselian Epoch (e.g. 1957.3)
Returned:
djm0 float64 MJD zero-point: always 2400000.5
djm float64 Modified Julian Date
Note:
The Julian Date is returned in two pieces, in the usual SOFA
manner, which is designed to preserve time resolution. The
Julian Date is available as a single number by adding djm0 and
djm.
Reference:
Lieske, J.H., 1979, Astron.Astrophys. 73, 282.
*/
func Epb2jd(epb float64, djm0, djm *float64) {
*djm0 = DJM0
*djm = 15019.81352 + (epb-1900.0)*DTY
}
/*
Epj Julian Date to Julian Epoch.
Given:
dj1,dj2 float64 Julian Date (see note)
Returned (function value):
float64 Julian Epoch
Note:
The Julian Date is supplied in two pieces, in the usual SOFA
manner, which is designed to preserve time resolution. The
Julian Date is available as a single number by adding dj1 and
dj2. The maximum resolution is achieved if dj1 is 2451545.0
(J2000.0).
Reference:
Lieske, J.H., 1979, Astron.Astrophys. 73, 282.
*/
func Epj(dj1, dj2 float64) float64 {
epj := 2000.0 + ((dj1-DJ00)+dj2)/DJY
return epj
}
/*
Epj2jd Julian Epoch to Julian Date.
Given:
epj float64 Julian Epoch (e.g. 1996.8)
Returned:
djm0 float64 MJD zero-point: always 2400000.5
djm float64 Modified Julian Date
Note:
The Julian Date is returned in two pieces, in the usual SOFA
manner, which is designed to preserve time resolution. The
Julian Date is available as a single number by adding djm0 and
djm.
Reference:
Lieske, J.H., 1979, Astron.Astrophys. 73, 282.
*/
func Epj2jd(epj float64, djm0, djm *float64) {
*djm0 = DJM0
*djm = DJM00 + (epj-2000.0)*365.25
}