-
Notifications
You must be signed in to change notification settings - Fork 0
/
sun.py
115 lines (85 loc) · 3.41 KB
/
sun.py
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
# https://stackoverflow.com/a/39867990
import datetime
import math
class Sun:
def getSunriseTime(self, coords):
return self.calcSunTime(coords, True)
def getSunsetTime(self, coords):
return self.calcSunTime(coords, False)
def getCurrentUTC(self):
now = datetime.datetime.now()
return [now.day, now.month, now.year]
def calcSunTime(self, coords, isRiseTime, zenith=90.8):
# isRiseTime == False, returns sunsetTime
day, month, year = self.getCurrentUTC()
longitude = coords['longitude']
latitude = coords['latitude']
TO_RAD = math.pi/180
# 1. first calculate the day of the year
N1 = math.floor(275 * month / 9)
N2 = math.floor((month + 9) / 12)
N3 = (1 + math.floor((year - 4 * math.floor(year / 4) + 2) / 3))
N = N1 - (N2 * N3) + day - 30
# 2. convert the longitude to hour value and calculate an approximate time
lngHour = longitude / 15
if isRiseTime:
t = N + ((6 - lngHour) / 24)
else: # sunset
t = N + ((18 - lngHour) / 24)
# 3. calculate the Sun's mean anomaly
M = (0.9856 * t) - 3.289
# 4. calculate the Sun's true longitude
L = M + (1.916 * math.sin(TO_RAD*M)) + (0.020 * math.sin(TO_RAD * 2 * M)) + 282.634
L = self.forceRange(L, 360) # NOTE: L adjusted into the range [0,360)
# 5a. calculate the Sun's right ascension
RA = (1/TO_RAD) * math.atan(0.91764 * math.tan(TO_RAD*L))
RA = self.forceRange(RA, 360) # NOTE: RA adjusted into the range [0,360)
# 5b. right ascension value needs to be in the same quadrant as L
Lquadrant = (math.floor(L/90)) * 90
RAquadrant = (math.floor(RA/90)) * 90
RA = RA + (Lquadrant - RAquadrant)
# 5c. right ascension value needs to be converted into hours
RA = RA / 15
# 6. calculate the Sun's declination
sinDec = 0.39782 * math.sin(TO_RAD*L)
cosDec = math.cos(math.asin(sinDec))
# 7a. calculate the Sun's local hour angle
cosH = (math.cos(TO_RAD*zenith) - (sinDec * math.sin(TO_RAD*latitude))) \
/ (cosDec * math.cos(TO_RAD*latitude))
if cosH > 1:
return {
'status': False,
'msg': 'the sun never rises on this location (on the specified date)'
}
if cosH < -1:
return {
'status': False,
'msg': 'the sun never sets on this location (on the specified date)'
}
# 7b. finish calculating H and convert into hours
if isRiseTime:
H = 360 - (1/TO_RAD) * math.acos(cosH)
else: # setting
H = (1/TO_RAD) * math.acos(cosH)
H = H / 15
# 8. calculate local mean time of rising/setting
T = H + RA - (0.06571 * t) - 6.622
# 9. adjust back to UTC
UT = T - lngHour
UT = self.forceRange(UT, 24) # UTC time in decimal format (e.g. 23.23)
# 10. Return
hr = self.forceRange(int(UT), 24)
min = round((UT - int(UT))*59, 0)
return {
'status': True,
'decimal': UT,
'hr': int(hr),
'min': int(min)
}
def forceRange(self, v, max):
# force v to be >= 0 and < max
if v < 0:
return v + max
elif v >= max:
return v - max
return v