1
1
// NAA - NOAA's Astronomical Algorithms
2
2
package astrotime
3
3
4
- // (JavaScript web page
4
+ // (JavaScript web page
5
5
// http://www.srrb.noaa.gov/highlights/sunrise/sunrise.html by
6
6
// Chris Cornwall, Aaron Horiuchi and Chris Lehman)
7
7
// Ported to C++ by Pete Gray ([email protected] ), July 2006
8
- // Released as Open Source and can be used in any way, as long as the
8
+ // Released as Open Source and can be used in any way, as long as the
9
9
// above description remains in place.
10
-
10
+ //
11
+ // Modified by Jon Seymour ([email protected] ) to allow dawn
12
+ // and dusk calculations.
13
+ //
11
14
import (
12
15
"math"
13
16
"time"
@@ -26,6 +29,17 @@ const (
26
29
OneDay = time .Hour * 24
27
30
)
28
31
32
+ const (
33
+ ASTRONOMICAL_DAWN = - 18.0
34
+ ASTRONOMICAL_DUSK = - 18.0
35
+ NAUTICAL_DAWN = - 12.0
36
+ NAUTICAL_DUSK = - 12.0
37
+ CIVIL_DAWN = - 6.0
38
+ CIVIL_DUSK = - 6.0
39
+ SUNRISE = 0
40
+ SUNSET = 0
41
+ )
42
+
29
43
// CalcJD converts a time.Time object to a julian date
30
44
func CalcJD (t time.Time ) float64 {
31
45
y , m , d , hh , mm , ss , ms := t .Year (), int (t .Month ()), t .Day (), t .Hour (), t .Minute (), t .Second (), t .Nanosecond ()/ 1e6
@@ -235,10 +249,11 @@ func calcSunDeclination(t float64) float64 {
235
249
//Return value:
236
250
// hour angle of sunrise in radians
237
251
238
- func calcHourAngleSunrise (lat float64 , solarDec float64 ) float64 {
252
+ func calcHourAngleSunrise (lat float64 , solarDec float64 , solarElevation float64 ) float64 {
239
253
latRad := DegToRad * lat
240
254
sdRad := DegToRad * solarDec
241
- return (math .Acos (math .Cos (DegToRad * 90.833 )/ (math .Cos (latRad )* math .Cos (sdRad )) - math .Tan (latRad )* math .Tan (sdRad )))
255
+ correction := calcRefractiveCorrection (solarElevation )
256
+ return (math .Acos (math .Cos (DegToRad * (90 + correction ))/ (math .Cos (latRad )* math .Cos (sdRad )) - math .Tan (latRad )* math .Tan (sdRad )))
242
257
}
243
258
244
259
// Name: calcSolNoonUTC
@@ -273,7 +288,7 @@ func calcSolNoonUTC(t float64, longitude float64) float64 {
273
288
// time in minutes from zero Z
274
289
275
290
// Calculate the UTC sunrise for the given day at the given location
276
- func calcSunriseUTC (jd float64 , latitude float64 , longitude float64 ) float64 {
291
+ func calcSunriseUTC (jd float64 , latitude float64 , longitude float64 , solarElevation float64 ) float64 {
277
292
278
293
t := calcTimeJulianCent (jd )
279
294
@@ -288,7 +303,7 @@ func calcSunriseUTC(jd float64, latitude float64, longitude float64) float64 {
288
303
289
304
eqTime := calcEquationOfTime (tnoon )
290
305
solarDec := calcSunDeclination (tnoon )
291
- hourAngle := calcHourAngleSunrise (latitude , solarDec )
306
+ hourAngle := calcHourAngleSunrise (latitude , solarDec , solarElevation )
292
307
293
308
delta := longitude - RadToDeg * hourAngle
294
309
timeDiff := 4 * delta
@@ -299,37 +314,59 @@ func calcSunriseUTC(jd float64, latitude float64, longitude float64) float64 {
299
314
newt := calcTimeJulianCent (calcJDFromJulianCent (t ) + timeUTC / 1440.0 )
300
315
eqTime = calcEquationOfTime (newt )
301
316
solarDec = calcSunDeclination (newt )
302
- hourAngle = calcHourAngleSunrise (latitude , solarDec )
317
+ hourAngle = calcHourAngleSunrise (latitude , solarDec , solarElevation )
303
318
delta = longitude - RadToDeg * hourAngle
304
319
timeDiff = 4 * delta
305
320
timeUTC = 720 + timeDiff - eqTime
306
321
return timeUTC
307
322
}
308
323
309
- // CalcSunrise calculates the sunrise, in local time, on the day t at the
310
- // location specified in longitude and latitude.
311
- func CalcSunrise (t time.Time , latitude float64 , longitude float64 ) time.Time {
324
+ // CalcDawn calculates the dawn, in local time, on the day t at the
325
+ // location specified in longitude and latitude. If solarElevation is 0, then dawn is identical
326
+ // to sunrise. A negative solarElevation specifies that the time calculated is for when the sun
327
+ // is -solarElevation degrees below the horizon.
328
+ func CalcDawn (t time.Time , latitude float64 , longitude float64 , solarElevation float64 ) time.Time {
312
329
jd := CalcJD (t )
313
- sunriseUTC := time .Duration (math .Floor (calcSunriseUTC (jd , latitude , longitude )* 60 ) * 1e9 )
330
+ sunriseUTC := time .Duration (math .Floor (calcSunriseUTC (jd , latitude , longitude , solarElevation )* 60 ) * 1e9 )
314
331
loc , _ := time .LoadLocation ("UTC" )
315
332
return time .Date (t .Year (), t .Month (), t .Day (), 0 , 0 , 0 , 0 , loc ).Add (sunriseUTC ).In (t .Location ())
316
333
}
317
334
335
+ // CalcSunrise calculates the sunrise, in local time, on the day t at the
336
+ // location specified in longitude and latitude.
337
+ func CalcSunrise (t time.Time , latitude float64 , longitude float64 ) time.Time {
338
+ return CalcDawn (t , latitude , longitude , SUNRISE )
339
+ }
340
+
341
+ // Calculates the refractive correction for the specified solar elevation.
342
+ // The refractive correction only applies at sunrise and sunset (solarElevation == 0).
343
+ // Otherwise the correction is simply the negative of the solarElevation
344
+ func calcRefractiveCorrection (solarElevation float64 ) float64 {
345
+ if solarElevation == 0 {
346
+ return 0.833
347
+ } else {
348
+ return - solarElevation
349
+ }
350
+ }
351
+
318
352
// Name: calcHourAngleSunset
319
353
// Type: Function
320
354
// Purpose: calculate the hour angle of the sun at sunset for the
321
355
// latitude
322
356
// Arguments:
323
357
// lat : latitude of observer in degrees
324
358
// solarDec : declination angle of sun in degrees
359
+ // solarElevation : solarElevation of the sun w.r.t. horizon - 0 for sunset, -6 for civil dusk, etc...
325
360
// Return value:
326
361
// hour angle of sunset in radians
327
362
328
- func calcHourAngleSunset (lat float64 , solarDec float64 ) float64 {
363
+ func calcHourAngleSunset (lat float64 , solarDec float64 , solarElevation float64 ) float64 {
329
364
latRad := DegToRad * lat
330
365
sdRad := DegToRad * solarDec
331
366
332
- HA := (math .Acos (math .Cos (DegToRad * 90.833 )/ (math .Cos (latRad )* math .Cos (sdRad )) - math .Tan (latRad )* math .Tan (sdRad )))
367
+ correction := calcRefractiveCorrection (solarElevation )
368
+
369
+ HA := (math .Acos (math .Cos (DegToRad * (90 + correction ))/ (math .Cos (latRad )* math .Cos (sdRad )) - math .Tan (latRad )* math .Tan (sdRad )))
333
370
334
371
return - HA // in radians
335
372
}
@@ -345,7 +382,7 @@ func calcHourAngleSunset(lat float64, solarDec float64) float64 {
345
382
// Return value:
346
383
// time in minutes from zero Z
347
384
348
- func calcSunsetUTC (jd float64 , latitude float64 , longitude float64 ) float64 {
385
+ func calcSunsetUTC (jd float64 , latitude float64 , longitude float64 , solarElevation float64 ) float64 {
349
386
t := calcTimeJulianCent (jd )
350
387
351
388
// *** Find the time of solar noon at the location, and use
@@ -359,7 +396,7 @@ func calcSunsetUTC(jd float64, latitude float64, longitude float64) float64 {
359
396
360
397
eqTime := calcEquationOfTime (tnoon )
361
398
solarDec := calcSunDeclination (tnoon )
362
- hourAngle := calcHourAngleSunset (latitude , solarDec )
399
+ hourAngle := calcHourAngleSunset (latitude , solarDec , solarElevation )
363
400
364
401
delta := longitude - RadToDeg * hourAngle
365
402
timeDiff := 4 * delta
@@ -370,22 +407,29 @@ func calcSunsetUTC(jd float64, latitude float64, longitude float64) float64 {
370
407
newt := calcTimeJulianCent (calcJDFromJulianCent (t ) + timeUTC / 1440.0 )
371
408
eqTime = calcEquationOfTime (newt )
372
409
solarDec = calcSunDeclination (newt )
373
- hourAngle = calcHourAngleSunset (latitude , solarDec )
410
+ hourAngle = calcHourAngleSunset (latitude , solarDec , solarElevation )
374
411
375
412
delta = longitude - RadToDeg * hourAngle
376
413
timeDiff = 4 * delta
377
414
return 720 + timeDiff - eqTime
378
415
}
379
416
380
- // CalcSunset calculates the sunset, in local time, on the day t at the
381
- // location specified in longitude and latitude.
382
- func CalcSunset (t time.Time , latitude float64 , longitude float64 ) time.Time {
417
+ // CalcDusk calculates the dusk, in local time, on the day t at the
418
+ // location specified in longitude and latitude. The solarElevation specifies that the time that the sun will
419
+ // be -solarElevation degrees below the horizon.
420
+ func CalcDusk (t time.Time , latitude float64 , longitude float64 , solarElevation float64 ) time.Time {
383
421
jd := CalcJD (t )
384
- sunsetUTC := time .Duration (math .Floor (calcSunsetUTC (jd , latitude , longitude )* 60 ) * 1e9 )
422
+ sunsetUTC := time .Duration (math .Floor (calcSunsetUTC (jd , latitude , longitude , solarElevation )* 60 ) * 1e9 )
385
423
loc , _ := time .LoadLocation ("UTC" )
386
424
return time .Date (t .Year (), t .Month (), t .Day (), 0 , 0 , 0 , 0 , loc ).Add (sunsetUTC ).In (t .Location ())
387
425
}
388
426
427
+ // CalcSunset calculates the sunset, in local time, on the day t at the
428
+ // location specified in longitude and latitude.
429
+ func CalcSunset (t time.Time , latitude float64 , longitude float64 ) time.Time {
430
+ return CalcDusk (t , latitude , longitude , SUNSET )
431
+ }
432
+
389
433
// NextSunrise returns date/time of the next sunrise after tAfter
390
434
func NextSunrise (tAfter time.Time , latitude float64 , longitude float64 ) (tSunrise time.Time ) {
391
435
tSunrise = CalcSunrise (tAfter , latitude , longitude )
@@ -395,6 +439,15 @@ func NextSunrise(tAfter time.Time, latitude float64, longitude float64) (tSunris
395
439
return
396
440
}
397
441
442
+ // NextDawn returns date/time of the next dawn at the specified solar solarElevation, after the specified time.
443
+ func NextDawn (tAfter time.Time , latitude float64 , longitude float64 , solarElevation float64 ) (tSunrise time.Time ) {
444
+ tSunrise = CalcDawn (tAfter , latitude , longitude , solarElevation )
445
+ if tAfter .After (tSunrise ) {
446
+ tSunrise = CalcDawn (tAfter .Add (OneDay ), latitude , longitude , solarElevation )
447
+ }
448
+ return
449
+ }
450
+
398
451
// NextSunset returns date/time of the next sunset after tAfter
399
452
func NextSunset (tAfter time.Time , latitude float64 , longitude float64 ) (tSunset time.Time ) {
400
453
tSunset = CalcSunset (tAfter , latitude , longitude )
@@ -403,3 +456,12 @@ func NextSunset(tAfter time.Time, latitude float64, longitude float64) (tSunset
403
456
}
404
457
return
405
458
}
459
+
460
+ // NextDusk returns date/time of the next dusk at the specified solar solarElevation, after the specified tine.
461
+ func NextDusk (tAfter time.Time , latitude float64 , longitude float64 , solarElevation float64 ) (tSunset time.Time ) {
462
+ tSunset = CalcDusk (tAfter , latitude , longitude , solarElevation )
463
+ if tAfter .After (tSunset ) {
464
+ tSunset = CalcDusk (tAfter .Add (OneDay ), latitude , longitude , solarElevation )
465
+ }
466
+ return
467
+ }
0 commit comments