日の出日没計算、日本の空港一覧でやってみよう

日出日没計算、やってみようを、「日本の空港一覧」で、という実践。

これ:

凝ったことはなにもしておりませぬ(numpy なしの生まれたまま python には変更してあります):

  1 #! /usr/bin/python2.7
  2 # -*- coding: utf-8 -*-
  3 # http://www.hoshi-lab.info/env/solar-j.html の javascript を移植して「空港での…」に
  4 # 仕立て上げたもの、です。凝ったことは何もしてません。
  5 #
  6 import math
  7 
  8 # sin function using degree
  9 def _sind(d):
 10     return math.sin(math.radians(d))
 11 
 12 # cos function using degree
 13 def _cosd(d):
 14     return math.cos(math.radians(d))
 15 
 16 # tan function using degree
 17 def _tand(d):
 18     return math.tan(math.radians(d))
 19 
 20 # calculate Julius year (year from 2000/1/1, for variable "t")
 21 def jy(yy, mm, dd, h, m, s, i): # yy/mm/dd h:m:s, i: time difference
 22     yy -= 2000
 23     if (mm <= 2):
 24         mm += 12
 25         yy -= 1
 26 
 27     k = 365 * yy + 30 * mm + dd - 33.5 - i / 24.0 + math.floor(3 * (mm + 1) / 5.0) \
 28         + math.floor(yy / 4.0) - math.floor(yy / 100.0) + math.floor(yy / 400.0)
 29     k += ((s / 60.0 + m) / 60 + h) / 24.0 # plus time
 30     k += (65 + yy) / 86400.0 # plus delta T
 31     return k / 365.25
 32 
 33 # solar position1 (celestial longitude, degree)
 34 def spls(t): # t: Julius year
 35     L = 280.4603 + 360.00769 * t \
 36         + (1.9146 - 0.00005 * t) * _sind(357.538 + 359.991 * t) \
 37         + 0.0200 * _sind(355.05 +  719.981 * t) \
 38         + 0.0048 * _sind(234.95 +   19.341 * t) \
 39         + 0.0020 * _sind(247.1  +  329.640 * t) \
 40         + 0.0018 * _sind(297.8  + 4452.67  * t) \
 41         + 0.0018 * _sind(251.3  +    0.20  * t) \
 42         + 0.0015 * _sind(343.2  +  450.37  * t) \
 43         + 0.0013 * _sind( 81.4  +  225.18  * t) \
 44         + 0.0008 * _sind(132.5  +  659.29  * t) \
 45         + 0.0007 * _sind(153.3  +   90.38  * t) \
 46         + 0.0007 * _sind(206.8  +   30.35  * t) \
 47         + 0.0006 * _sind( 29.8  +  337.18  * t) \
 48         + 0.0005 * _sind(207.4  +    1.50  * t) \
 49         + 0.0005 * _sind(291.2  +   22.81  * t) \
 50         + 0.0004 * _sind(234.9  +  315.56  * t) \
 51         + 0.0004 * _sind(157.3  +  299.30  * t) \
 52         + 0.0004 * _sind( 21.1  +  720.02  * t) \
 53         + 0.0003 * _sind(352.5  + 1079.97  * t) \
 54         + 0.0003 * _sind(329.7  +   44.43  * t)
 55     while (L >= 360):
 56         L -= 360
 57     while (L < 0):
 58         L += 360
 59     return L
 60 
 61 # solar position2 (distance, AU)
 62 def spds(t): # t: Julius year
 63     r = (0.007256 - 0.0000002 * t) * _sind(267.54 + 359.991 * t) \
 64         + 0.000091 * _sind(265.1 +  719.98 * t) \
 65         + 0.000030 * _sind( 90.0) \
 66         + 0.000013 * _sind( 27.8 + 4452.67 * t) \
 67         + 0.000007 * _sind(254   +  450.4  * t) \
 68         + 0.000007 * _sind(156   +  329.6  * t)
 69     r = math.pow(10, r)
 70     return r
 71 
 72 # solar position3 (declination, degree)
 73 def spal(t): # t: Julius year
 74     ls = spls(t) ;
 75     ep = 23.439291 - 0.000130042 * t
 76     al = math.degrees(math.atan(_tand(ls) * _cosd(ep)))
 77     if ((ls >= 0) and (ls < 180)):
 78         while (al < 0):
 79             al += 180
 80         while (al >= 180):
 81             al -= 180
 82     else:
 83         while (al < 180):
 84             al += 180
 85         while (al >= 360):
 86             al -= 180
 87     return al ;
 88 
 89 # solar position4 (the right ascension, degree)
 90 def spdl(t): # t: Julius year
 91     ls = spls(t)
 92     ep = 23.439291 - 0.000130042 * t
 93     dl = math.degrees(math.asin(_sind(ls) * _sind(ep)))
 94     return dl
 95 
 96 # Calculate sidereal hour (degree)
 97 def sh(t, h, m, s, l, i):
 98     # t: julius year, h: hour, m: minute, s: second,
 99     # l: longitude, i: time difference
100     d = ((s / 60.0 + m) / 60.0 + h) / 24.0 # elapsed hour (from 0:00 a.m.)
101     th = 100.4606 + 360.007700536 * t + 0.00000003879 * t * t - 15 * i
102     th += l + 360 * d
103     while (th >= 360):
104         th -= 360
105     while (th < 0):
106         th += 360
107     return th
108 
109 # Calculating the seeming horizon altitude "sa"(degree)
110 def eandp(alt, ds): # subfunction for altitude and parallax
111     e = 0.035333333 * math.sqrt(alt)
112     p = 0.002442818 / ds
113     return p - e
114 
115 def sa(alt, ds): # alt: altitude (m), ds: solar distance (AU)
116     s = 0.266994444 / ds
117     r = 0.585555555
118     k = eandp(alt,ds) - s - r
119     return k
120 
121 # Calculating solar alititude (degree) {
122 def soal(la, th, al, dl):
123     # la: latitude, th: sidereal hour,
124     # al: solar declination, dl: right ascension
125     h = _sind(dl) * _sind(la) + _cosd(dl) * _cosd(la) * _cosd(th - al)
126     h = math.degrees(math.asin(h))
127     return h
128 
129 # Calculating solar direction (degree) {
130 def sodr(la, th, al, dl):
131     # la: latitude, th: sidereal hour,
132     # al: solar declination, dl: right ascension
133     t = th - al
134     dc = -_cosd(dl) * _sind(t)
135     dm = _sind(dl) * _sind(la) - _cosd(dl) * _cosd(la) * _cosd(t)
136     dr = math.degrees(math.atan2(dc, dm))
137 
138     if (dr < 0):
139         dr += 360
140     return dr
141 
142 def calc(yy, mm, dd, i, lon, lat, alt=0, hh=-1, m=-1):
143     """
144     return list:
145         item 0: astronomical twilight start time
146         item 1: voyage twilight start time
147         item 2: citizen twilight start time
148         item 3: sun rise time, and solar direction (in degrees)
149         item 4: meridian time, and solar altitude (in degrees)
150         item 5: sun set time, and solar direction (in degrees)
151         item 6: citizen twilight end time
152         item 7: voyage twilight end time
153         item 8: astronomical twilight end time
154     """
155     result = []
156 
157     t = jy(yy, mm, dd - 1, 23, 59, 0, i)
158     th = sh(t, 23, 59, 0, lon, i)
159     ds = spds(t)
160     ls = spls(t)
161     alp = spal(t)
162     dlt = spdl(t)
163     pht = soal(lat, th, alp, dlt)
164     pdr = sodr(lat, th, alp, dlt)
165 
166     for hh in range(0, 24):
167         for m in range(0, 60):
168             t = jy(yy, mm, dd, hh, m, 0, i)
169             th = sh(t, hh, m, 0, lon, i)
170             ds = spds(t)
171             ls = spls(t)
172             alp = spal(t)
173             dlt = spdl(t)
174             ht = soal(lat, th, alp, dlt)
175             dr = sodr(lat, th, alp, dlt)
176             tt = eandp(alt, ds)
177             t1 = tt - 18
178             t2 = tt - 12
179             t3 = tt - 6
180             t4 = sa(alt, ds)
181 
182             #key = "%d-%02d-%02d %02d:%02d:00+%02d" % (yy, mm, dd, hh, m, i)
183             key = "%02d:%02d+%02d" % (hh, m, i)
184 
185             if ((pht < t1) and (ht > t1)):
186                 result.append((key, ""))
187             if ((pht < t2) and (ht > t2)):
188                 result.append((key, ""))
189             if ((pht < t3) and (ht > t3)):
190                 result.append((key, ""))
191             if ((pht < t4) and (ht > t4)):
192                 result.append((key, math.floor(dr)))
193             if ((pdr < 180) and (dr > 180)):
194                 result.append((key, math.floor(ht)))
195             if ((pht > t4) and (ht < t4)):
196                 result.append((key, math.floor(dr)))
197             if ((pht > t3) and (ht < t3)):
198                 result.append((key, ""))
199             if ((pht > t2) and (ht < t2)):
200                 result.append((key, ""))
201             if ((pht > t1) and (ht < t1)):
202                 result.append((key, ""))
203             pht = ht
204             pdr = dr
205 
206     #f.result.value = ans
207     return result
208 
209 
210 ALL_AIRPORTS = [
211     ('RJCW', {'City': 'Wakkanai', 'Name': 'Wakkanai', 'Altitude': 30, 'Longitude': 141.800833, 'Latitude': 45.404167, 'Timezone': 9.0}),
212     ('RJER', {'City': 'Rishiri Island', 'Name': 'Rishiri', 'Altitude': 112, 'Longitude': 141.186431, 'Latitude': 45.242006, 'Timezone': 9.0}),
213     ('RJEB', {'City': 'Monbetsu', 'Name': 'Monbetsu', 'Altitude': 80, 'Longitude': 143.404028, 'Latitude': 44.303914, 'Timezone': 9.0}),
214     ('RJCM', {'City': 'Memanbetsu', 'Name': 'Memanbetsu', 'Altitude': 135, 'Longitude': 144.164053, 'Latitude': 43.880606, 'Timezone': 9.0}),
215     ('RJEC', {'City': 'Asahikawa', 'Name': 'Asahikawa', 'Altitude': 721, 'Longitude': 142.4475, 'Latitude': 43.670833, 'Timezone': 9.0}),
216     ('RJCN', {'City': 'Nakashibetsu', 'Name': 'Nakashibetsu', 'Altitude': 234, 'Longitude': 144.96, 'Latitude': 43.5775, 'Timezone': 9.0}),
217     ('RJCO', {'City': 'Sapporo', 'Name': 'Okadama Airport', 'Altitude': 25, 'Longitude': 141.38, 'Latitude': 43.1161, 'Timezone': 9.0}),
218     ('RJCK', {'City': 'Kushiro', 'Name': 'Kushiro Airport', 'Altitude': 327, 'Longitude': 144.193, 'Latitude': 43.041, 'Timezone': 9.0}),
219     ('RJCT', {'City': 'Tokachi', 'Name': 'Tokachi', 'Altitude': 281, 'Longitude': 143.158475, 'Latitude': 42.890544, 'Timezone': 9.0}),
220     ('RJCJ', {'City': 'Chitose', 'Name': 'Chitose', 'Altitude': 87, 'Longitude': 141.666447, 'Latitude': 42.794475, 'Timezone': 9.0}),
221     ('RJCC', {'City': 'Sapporo', 'Name': 'New Chitose', 'Altitude': 82, 'Longitude': 141.692283, 'Latitude': 42.7752, 'Timezone': 9.0}),
222     ('RJCB', {'City': 'Obihiro', 'Name': 'Obihiro', 'Altitude': 505, 'Longitude': 143.217222, 'Latitude': 42.733333, 'Timezone': 9.0}),
223     ('RJEO', {'City': 'Okushiri', 'Name': 'Okushiri', 'Altitude': 161, 'Longitude': 139.432911, 'Latitude': 42.071667, 'Timezone': 9.0}),
224     ('RJCH', {'City': 'Hakodate', 'Name': 'Hakodate', 'Altitude': 151, 'Longitude': 140.821944, 'Latitude': 41.77, 'Timezone': 9.0}),
225     ('RJSA', {'City': 'Aomori', 'Name': 'Aomori', 'Altitude': 664, 'Longitude': 140.690833, 'Latitude': 40.734722, 'Timezone': 9.0}),
226     ('RJSM', {'City': 'Misawa', 'Name': 'Misawa Ab', 'Altitude': 119, 'Longitude': 141.368364, 'Latitude': 40.703222, 'Timezone': 9.0}),
227     ('RJSH', {'City': 'Hachinoe', 'Name': 'Hachinohe', 'Altitude': 152, 'Longitude': 141.466325, 'Latitude': 40.556447, 'Timezone': 9.0}),
228     ('RJSR', {'City': 'Odate Noshiro', 'Name': 'Odate Noshiro Airport', 'Altitude': 292, 'Longitude': 140.371, 'Latitude': 40.1919, 'Timezone': 9.0}),
229     ('RJSK', {'City': 'Akita', 'Name': 'Akita', 'Altitude': 313, 'Longitude': 140.218611, 'Latitude': 39.615556, 'Timezone': 9.0}),
230     ('RJSI', {'City': 'Hanamaki', 'Name': 'Hanamaki', 'Altitude': 297, 'Longitude': 141.135278, 'Latitude': 39.428611, 'Timezone': 9.0}),
231     ('RJSY', {'City': 'Shonai', 'Name': 'Shonai Airport', 'Altitude': 86, 'Longitude': 139.787222, 'Latitude': 38.812222, 'Timezone': 9.0}),
232     ('RJSC', {'City': 'Yamagata', 'Name': 'Yamagata', 'Altitude': 353, 'Longitude': 140.371331, 'Latitude': 38.411894, 'Timezone': 9.0}),
233     ('RJST', {'City': 'Matsushima', 'Name': 'Matsushima', 'Altitude': 7, 'Longitude': 141.219572, 'Latitude': 38.404919, 'Timezone': 9.0}),
234     ('RJSS', {'City': 'Sendai', 'Name': 'Sendai', 'Altitude': 15, 'Longitude': 140.916944, 'Latitude': 38.139722, 'Timezone': 9.0}),
235     ('RJSD', {'City': 'Sado', 'Name': 'Sado', 'Altitude': 88, 'Longitude': 138.413928, 'Latitude': 38.060181, 'Timezone': 9.0}),
236     ('RJSN', {'City': 'Niigata', 'Name': 'Niigata', 'Altitude': 1, 'Longitude': 139.0646, 'Latitude': 37.5711, 'Timezone': 9.0}),
237     ('RJNW', {'City': 'Wajima', 'Name': 'Noto', 'Altitude': 718, 'Longitude': 136.961853, 'Latitude': 37.293097, 'Timezone': 9.0}),
238     ('RJSF', {'City': 'Fukushima', 'Name': 'Fukushima Airport', 'Altitude': 1221, 'Longitude': 140.431, 'Latitude': 37.2274, 'Timezone': 9.0}),
239     ('RJNT', {'City': 'Toyama', 'Name': 'Toyama', 'Altitude': 95, 'Longitude': 137.1875, 'Latitude': 36.648333, 'Timezone': 9.0}),
240     ('RJNK', {'City': 'Kanazawa', 'Name': 'Komatsu', 'Altitude': 36, 'Longitude': 136.406544, 'Latitude': 36.394611, 'Timezone': 9.0}),
241     ('RJNO', {'City': 'Oki Island', 'Name': 'Oki', 'Altitude': 311, 'Longitude': 133.324844, 'Latitude': 36.181125, 'Timezone': 9.0}),
242     ('RJAH', {'City': 'Ibaraki', 'Name': 'Hyakuri', 'Altitude': 105, 'Longitude': 140.415444, 'Latitude': 36.181083, 'Timezone': 9.0}),
243     ('RJAF', {'City': 'Matsumoto', 'Name': 'Matsumoto', 'Altitude': 2182, 'Longitude': 137.922669, 'Latitude': 36.166758, 'Timezone': 9.0}),
244     ('RJNF', {'City': 'Fukui', 'Name': 'Fukui', 'Altitude': 19, 'Longitude': 136.223922, 'Latitude': 36.142847, 'Timezone': 9.0}),
245     ('RJTJ', {'City': 'Iruma', 'Name': 'Iruma', 'Altitude': 295, 'Longitude': 139.410556, 'Latitude': 35.841944, 'Timezone': 9.0}),
246     ('RJTL', {'City': 'Shimofusa', 'Name': 'Shimofusa', 'Altitude': 98, 'Longitude': 140.011111, 'Latitude': 35.798944, 'Timezone': 9.0}),
247     ('RJAA', {'City': 'Tokyo', 'Name': 'Narita Intl', 'Altitude': 141, 'Longitude': 140.386389, 'Latitude': 35.764722, 'Timezone': 9.0}),
248     ('RJTY', {'City': 'Yokota', 'Name': 'Yokota Ab', 'Altitude': 463, 'Longitude': 139.348483, 'Latitude': 35.748492, 'Timezone': 9.0}),
249     ('RJTT', {'City': 'Tokyo', 'Name': 'Tokyo Intl', 'Altitude': 35, 'Longitude': 139.779694, 'Latitude': 35.552258, 'Timezone': 9.0}),
250     ('RJOR', {'City': 'Tottori', 'Name': 'Tottori', 'Altitude': 65, 'Longitude': 134.166553, 'Latitude': 35.530069, 'Timezone': 9.0}),
251     ('RJTR', {'City': 'Zama', 'Name': 'Kastner Aaf', 'Altitude': 360, 'Longitude': 139.393675, 'Latitude': 35.513769, 'Timezone': 9.0}),
252     ('RJBT', {'City': 'Toyooka', 'Name': 'Tajima Airport', 'Altitude': 578, 'Longitude': 134.786944, 'Latitude': 35.512778, 'Timezone': 9.0}),
253     ('RJOH', {'City': 'Miho', 'Name': 'Yonago Kitaro', 'Altitude': 20, 'Longitude': 133.236389, 'Latitude': 35.492222, 'Timezone': 9.0}),
254     ('RJTA', {'City': 'Atsugi', 'Name': 'Atsugi Naf', 'Altitude': 205, 'Longitude': 139.450167, 'Latitude': 35.454611, 'Timezone': 9.0}),
255     ('RJOC', {'City': 'Izumo', 'Name': 'Izumo', 'Altitude': 15, 'Longitude': 132.89, 'Latitude': 35.413611, 'Timezone': 9.0}),
256     ('RJTK', {'City': 'Kisarazu', 'Name': 'Kisarazu', 'Altitude': 10, 'Longitude': 139.909936, 'Latitude': 35.398272, 'Timezone': 9.0}),
257     ('RJNG', {'City': 'Gifu', 'Name': 'Gifu', 'Altitude': 128, 'Longitude': 136.869667, 'Latitude': 35.394078, 'Timezone': 9.0}),
258     ('RJNA', {'City': 'Nagoya', 'Name': 'Nagoya Airport', 'Altitude': 52, 'Longitude': 136.924, 'Latitude': 35.255, 'Timezone': 9.0}),
259     ('RJTE', {'City': 'Tateyama', 'Name': 'Tateyama', 'Altitude': 10, 'Longitude': 139.829208, 'Latitude': 34.987053, 'Timezone': 9.0}),
260     ('RJGG', {'City': 'Nagoya', 'Name': 'Chubu Centrair Intl', 'Altitude': 15, 'Longitude': 136.805408, 'Latitude': 34.858414, 'Timezone': 9.0}),
261     ('RJNY', {'City': 'Yaizu', 'Name': 'Shizuhama', 'Altitude': 23, 'Longitude': 138.298056, 'Latitude': 34.812778, 'Timezone': 9.0}),
262     ('RJNS', {'City': 'Shizuoka', 'Name': 'Mt. Fuji Shizuoka Airport', 'Altitude': 433, 'Longitude': 138.189444, 'Latitude': 34.796111, 'Timezone': 9.0}),
263     ('RJOO', {'City': 'Osaka', 'Name': 'Osaka Intl', 'Altitude': 50, 'Longitude': 135.438222, 'Latitude': 34.785528, 'Timezone': 9.0}),
264     ('RJTO', {'City': 'Oshima', 'Name': 'Oshima', 'Altitude': 130, 'Longitude': 139.360306, 'Latitude': 34.782033, 'Timezone': 9.0}),
265     ('RJOB', {'City': 'Okayama', 'Name': 'Okayama', 'Altitude': 806, 'Longitude': 133.855278, 'Latitude': 34.756944, 'Timezone': 9.0}),
266     ('RJNH', {'City': 'Hamamatsu', 'Name': 'Hamamatsu', 'Altitude': 150, 'Longitude': 137.703083, 'Latitude': 34.750239, 'Timezone': 9.0}),
267     ('RJOW', {'City': 'Iwami', 'Name': 'Iwami Airport', 'Altitude': 184, 'Longitude': 131.79, 'Latitude': 34.6764, 'Timezone': 9.0}),
268     ('RJBE', {'City': 'Kobe', 'Name': 'Kobe', 'Altitude': 22, 'Longitude': 135.223889, 'Latitude': 34.632778, 'Timezone': 9.0}),
269     ('RJOY', {'City': 'Osaka', 'Name': 'Yao', 'Altitude': 39, 'Longitude': 135.602944, 'Latitude': 34.596311, 'Timezone': 9.0}),
270     ('RJBK', {'City': 'Kohnan', 'Name': 'Kohnan', 'Altitude': 3, 'Longitude': 133.933225, 'Latitude': 34.590836, 'Timezone': 9.0}),
271     ('RJOE', {'City': 'Akeno', 'Name': 'Akeno Aero', 'Altitude': 12, 'Longitude': 136.672222, 'Latitude': 34.533333, 'Timezone': 9.0}),
272     ('RJOA', {'City': 'Hiroshima', 'Name': 'Hiroshima', 'Altitude': 1088, 'Longitude': 132.919444, 'Latitude': 34.436111, 'Timezone': 9.0}),
273     ('RJBB', {'City': 'Osaka', 'Name': 'Kansai', 'Altitude': 49, 'Longitude': 135.244167, 'Latitude': 34.4347222, 'Timezone': 9.0}),
274     ('RJBH', {'City': 'Hiroshima', 'Name': 'Hiroshima-Nishi', 'Altitude': 9, 'Longitude': 132.408, 'Latitude': 34.367, 'Timezone': 9.0}),
275     ('RJAN', {'City': 'Niijima', 'Name': 'Niijima Airport', 'Altitude': 133, 'Longitude': 139.268611, 'Latitude': 34.366944, 'Timezone': 9.0}),
276     ('RJDT', {'City': 'Tsushima', 'Name': 'Tsushima', 'Altitude': 213, 'Longitude': 129.33055, 'Latitude': 34.284889, 'Timezone': 9.0}),
277     ('RJOT', {'City': 'Takamatsu', 'Name': 'Takamatsu', 'Altitude': 607, 'Longitude': 134.015556, 'Latitude': 34.214167, 'Timezone': 9.0}),
278     ('RJOI', {'City': 'Iwakuni', 'Name': 'Iwakuni Mcas', 'Altitude': 7, 'Longitude': 132.23575, 'Latitude': 34.14386, 'Timezone': 9.0}),
279     ('RJOS', {'City': 'Tokushima', 'Name': 'Tokushima', 'Altitude': 26, 'Longitude': 134.606639, 'Latitude': 34.132808, 'Timezone': 9.0}),
280     ('RJTQ', {'City': 'Miyakejima', 'Name': 'Miyakejima Airport', 'Altitude': 67, 'Longitude': 139.56, 'Latitude': 34.0736, 'Timezone': 9.0}),
281     ('RJOZ', {'City': 'Ozuki', 'Name': 'Ozuki', 'Altitude': 13, 'Longitude': 131.052144, 'Latitude': 34.045322, 'Timezone': 9.0}),
282     ('RJOF', {'City': 'Hofu', 'Name': 'Hofu', 'Altitude': 7, 'Longitude': 131.549194, 'Latitude': 34.034667, 'Timezone': 9.0}),
283     ('RJDC', {'City': 'Yamaguchi', 'Name': 'Yamaguchi Ube', 'Altitude': 23, 'Longitude': 131.278611, 'Latitude': 33.93, 'Timezone': 9.0}),
284     ('RJFA', {'City': 'Ashiya', 'Name': 'Ashiya', 'Altitude': 98, 'Longitude': 130.653, 'Latitude': 33.883083, 'Timezone': 9.0}),
285     ('RJFR', {'City': 'Kitakyushu', 'Name': 'New Kitakyushu', 'Altitude': 21, 'Longitude': 131.034689, 'Latitude': 33.845942, 'Timezone': 9.0}),
286     ('RJOM', {'City': 'Matsuyama', 'Name': 'Matsuyama', 'Altitude': 25, 'Longitude': 132.699722, 'Latitude': 33.827222, 'Timezone': 9.0}),
287     ('RJDB', {'City': 'Iki', 'Name': 'Iki', 'Altitude': 41, 'Longitude': 129.785417, 'Latitude': 33.749027, 'Timezone': 9.0}),
288     ('RJFZ', {'City': 'Tsuiki', 'Name': 'Tsuiki', 'Altitude': 55, 'Longitude': 131.040278, 'Latitude': 33.685, 'Timezone': 9.0}),
289     ('RJBD', {'City': 'Nanki-shirahama', 'Name': 'Nanki Shirahama', 'Altitude': 298, 'Longitude': 135.364444, 'Latitude': 33.662222, 'Timezone': 9.0}),
290     ('RJFF', {'City': 'Fukuoka', 'Name': 'Fukuoka', 'Altitude': 32, 'Longitude': 130.450686, 'Latitude': 33.585942, 'Timezone': 9.0}),
291     ('RJOK', {'City': 'Kochi', 'Name': 'Kochi', 'Altitude': 42, 'Longitude': 133.669444, 'Latitude': 33.546111, 'Timezone': 9.0}),
292     ('RJFO', {'City': 'Oita', 'Name': 'Oita', 'Altitude': 19, 'Longitude': 131.737222, 'Latitude': 33.479444, 'Timezone': 9.0}),
293     ('RJFS', {'City': 'Saga', 'Name': 'Saga Airport', 'Altitude': 6, 'Longitude': 130.302, 'Latitude': 33.1497, 'Timezone': 9.0}),
294     ('RJTH', {'City': 'Hachijojima', 'Name': 'Hachijojima', 'Altitude': 303, 'Longitude': 139.785833, 'Latitude': 33.115, 'Timezone': 9.0}),
295     ('RJFU', {'City': 'Nagasaki', 'Name': 'Nagasaki', 'Altitude': 15, 'Longitude': 129.913611, 'Latitude': 32.916944, 'Timezone': 9.0}),
296     ('RJFT', {'City': 'Kumamoto', 'Name': 'Kumamoto', 'Altitude': 642, 'Longitude': 130.85505, 'Latitude': 32.837319, 'Timezone': 9.0}),
297     ('RJFE', {'City': 'Fukue', 'Name': 'Fukue', 'Altitude': 273, 'Longitude': 128.832808, 'Latitude': 32.666269, 'Timezone': 9.0}),
298     ('RJDA', {'City': 'Amakusa', 'Name': 'Amakusa Airfield', 'Altitude': 340, 'Longitude': 130.158889, 'Latitude': 32.482222, 'Timezone': 9.0}),
299     ('RJFN', {'City': 'Nyutabaru', 'Name': 'Nyutabaru', 'Altitude': 259, 'Longitude': 131.451389, 'Latitude': 32.083611, 'Timezone': 9.0}),
300     ('RJFM', {'City': 'Miyazaki', 'Name': 'Miyazaki', 'Altitude': 20, 'Longitude': 131.448611, 'Latitude': 31.877222, 'Timezone': 9.0}),
301     ('RJFK', {'City': 'Kagoshima', 'Name': 'Kagoshima', 'Altitude': 906, 'Longitude': 130.719408, 'Latitude': 31.803397, 'Timezone': 9.0}),
302     ('RJFY', {'City': 'Kanoya', 'Name': 'Kanoya', 'Altitude': 214, 'Longitude': 130.845456, 'Latitude': 31.367608, 'Timezone': 9.0}),
303     ('RJFG', {'City': 'Tanegashima', 'Name': 'New Tanegashima', 'Altitude': 768, 'Longitude': 130.991231, 'Latitude': 30.605067, 'Timezone': 9.0}),
304     ('RJFC', {'City': 'Yakushima', 'Name': 'Yakushima', 'Altitude': 124, 'Longitude': 130.659017, 'Latitude': 30.385569, 'Timezone': 9.0}),
305     ('RJKA', {'City': 'Amami', 'Name': 'Amami', 'Altitude': 27, 'Longitude': 129.712542, 'Latitude': 28.430633, 'Timezone': 9.0}),
306     ('RJKI', {'City': 'Kikai', 'Name': 'Kikai Airport', 'Altitude': 15, 'Longitude': 129.928056, 'Latitude': 28.321389, 'Timezone': 9.0}),
307     ('RJKN', {'City': 'Tokunoshima', 'Name': 'Tokunoshima', 'Altitude': 17, 'Longitude': 128.881253, 'Latitude': 27.836381, 'Timezone': 9.0}),
308     ('RJKB', {'City': 'Okierabu', 'Name': 'Okierabu', 'Altitude': 101, 'Longitude': 128.700903, 'Latitude': 27.425522, 'Timezone': 9.0}),
309     ('RORY', {'City': 'Yoron', 'Name': 'Yoron', 'Altitude': 52, 'Longitude': 128.401517, 'Latitude': 27.043964, 'Timezone': 9.0}),
310     ('RODE', {'City': 'Iejima', 'Name': 'Ie Shima Aux Ab', 'Altitude': 184, 'Longitude': 127.761775, 'Latitude': 26.728775, 'Timezone': 9.0}),
311     ('RORA', {'City': 'Aguni', 'Name': 'Aguni Airport', 'Altitude': 38, 'Longitude': 127.240278, 'Latitude': 26.592778, 'Timezone': 9.0}),
312     ('ROKJ', {'City': 'Kumejima', 'Name': 'Kumejima', 'Altitude': 23, 'Longitude': 126.713806, 'Latitude': 26.363506, 'Timezone': 9.0}),
313     ('RODN', {'City': 'Kadena', 'Name': 'Kadena Ab', 'Altitude': 143, 'Longitude': 127.767633, 'Latitude': 26.355612, 'Timezone': 9.0}),
314     ('ROTM', {'City': 'Futema', 'Name': 'Futenma Mcas', 'Altitude': 247, 'Longitude': 127.756494, 'Latitude': 26.274275, 'Timezone': 9.0}),
315     ('ROAH', {'City': 'Okinawa', 'Name': 'Naha', 'Altitude': 12, 'Longitude': 127.645869, 'Latitude': 26.195814, 'Timezone': 9.0}),
316     ('ROKR', {'City': 'Kerama', 'Name': 'Kerama Airport', 'Altitude': 156, 'Longitude': 127.293333, 'Latitude': 26.168333, 'Timezone': 9.0}),
317     ('RORK', {'City': 'Kitadaito', 'Name': 'Kitadaito', 'Altitude': 80, 'Longitude': 131.326944, 'Latitude': 25.944722, 'Timezone': 9.0}),
318     ('ROMD', {'City': 'Minami Daito', 'Name': 'Minami Daito', 'Altitude': 167, 'Longitude': 131.263494, 'Latitude': 25.846533, 'Timezone': 9.0}),
319     ('RORS', {'City': 'Shimojishima', 'Name': 'Shimojishima', 'Altitude': 54, 'Longitude': 125.144722, 'Latitude': 24.826667, 'Timezone': 9.0}),
320     ('RJAW', {'City': 'Iwojima', 'Name': 'Iwo Jima', 'Altitude': 384, 'Longitude': 141.322722, 'Latitude': 24.784, 'Timezone': 10.0}),
321     ('ROMY', {'City': 'Miyako', 'Name': 'Miyako', 'Altitude': 150, 'Longitude': 125.295111, 'Latitude': 24.782833, 'Timezone': 9.0}),
322     ('RORT', {'City': 'Tarama', 'Name': 'Tarama', 'Altitude': 36, 'Longitude': 124.675278, 'Latitude': 24.653889, 'Timezone': 9.0}),
323     ('ROYN', {'City': 'Yonaguni Jima', 'Name': 'Yonaguni', 'Altitude': 70, 'Longitude': 122.977778, 'Latitude': 24.466944, 'Timezone': 9.0}),
324     ('ROIG', {'City': 'Ishigaki', 'Name': 'Ishigaki', 'Altitude': 93, 'Longitude': 124.186983, 'Latitude': 24.344525, 'Timezone': 9.0}),
325     ('RJAM', {'City': 'Minami Tori Shima', 'Name': 'Minami Torishima', 'Altitude': 22, 'Longitude': 153.979119, 'Latitude': 24.289697, 'Timezone': 10.0}),
326 ]
327 #ALL_AIRPORTS_DICT = dict(ALL_AIRPORTS)
328 
329 if __name__ == '__main__':
330     import sys, codecs
331     import time
332 
333     fo = codecs.getwriter('utf-8')(open("jp_airports_sunrise_sunset.html", "w"))
334     
335     tm = time.localtime()
336 
337     fo.write("""\
338 <html dir="ltr" lang="ja">
339 <head>
340 <meta charset="UTF-8">
341 <meta name="robots" content="noindex,nofollow,noodp,noydir">
342     <style type="text/css">
343     <!--
344     body { margin: 2em; }
345     h1 {
346         font-size: 2em;
347         padding-bottom: 0.2em;
348         border-bottom: 5px #770000 solid;
349     }
350     .icao4letter { font-weight: 900; background-color: #eef; }
351     .sunrise { background-color: yellow; }
352     .sunset { background-color: orange; }
353     -->
354     </style>
355 </head>
356 <body>
357 """)
358     fo.write(u"""\
359 <h1>日本の空港の日の出日没時刻(%d-%02d-%02d)</h1>
360 <p>
361 <a href="http://hhsprings.pinoko.jp/site-hhs/2015/02/%%E6%%97%%A5%%E5%%87%%BA%%E6%%97%%A5%%E6%%B2%%A1%%E8%%A8%%88%%E7%%AE%%97%%E3%%80%%81%%E3%%82%%84%%E3%%81%%A3%%E3%%81%%A6%%E3%%81%%BF%%E3%%82%%88%%E3%%81%%86/" target="_blank">日出日没計算、やってみよう</a>の実践、です。CGIでもなんでもないただのバッチで毎日静的ページを作っているだけでございます。半年後を知りたい、のようなことには対応できませんです。
362 
363 <p>
364 <a href="http://www.hoshi-lab.info/env/solar-j.html">
365 近畿大学 星 岳彦 さん作成の日の出と日の入りの計算
366 </a>
367 と同じことをしているはずです、多分。Pythonに移植したままのテストプログラムの結果
368 そのもので、あまり正確なテストはしておりませんし、また、もともと1分の精度は
369 ありませんし、本来地形の影響等々様々な原因で日の出日没時間は現実とはずれます。
370 
371 ですので、本データを使用したいかなる損害についても、当方関知しませんし、「そういうものだ」
372 と思ってくださいますよう。
373 <p>
374 """ % (tm.tm_year, tm.tm_mon, tm.tm_mday))
375     fo.write("""\
376 <table border='1'>
377 """)
378     for icao4letter, airpt_info in ALL_AIRPORTS:
379         airpt_info["ICAO4letter"] = icao4letter
380         r = calc(tm.tm_year, tm.tm_mon, tm.tm_mday,
381                  airpt_info["Timezone"],
382                  airpt_info["Longitude"],
383                  airpt_info["Latitude"],
384                  airpt_info["Altitude"] * 0.3048)
385         fo.write("""\
386 <tr>
387 <tr><td rowspan="5" class="icao4letter">{ICAO4letter}</td><td>Name</td><td>{Name}</td></tr>
388 <tr><td>City</td><td>{City}</td></tr>
389 <tr><td>Lon / Lat</td><td>{Longitude} / {Latitude}</td></tr>
390 <tr><td>Altitude</td><td>{Altitude} [feets]</td></tr>
391 <tr>
392 """.format(**airpt_info))
393         fo.write("""\
394 <td></td>
395 <td>
396 <table border="1">
397 <tr><td>astronomical twilight start</td><td>%s</td><td>  </td></tr>
398 <tr><td>nautical twilight start    </td><td>%s</td><td>  </td></tr>
399 <tr><td>citizen twilight start     </td><td>%s</td><td>  </td></tr>
400 <tr class="sunrise"><td>sun rise                   </td><td>%s</td><td>solar direction (in degrees): %d</td></tr>
401 <tr><td>meridian                   </td><td>%s</td><td>solar altitude (in degrees): %d</td></tr>
402 <tr class="sunset"><td>sun set                    </td><td>%s</td><td>solar direction (in degrees): %d</td></tr>
403 <tr><td>citizen twilight end       </td><td>%s</td><td>  </td></tr>
404 <tr><td>nautical twilight end      </td><td>%s</td><td>  </td></tr>
405 <tr><td>astronomical twilight end  </td><td>%s</td><td>  </td></tr>
406 </table>
407 </td>
408 </tr>
409 </tr>
410 
411 """ % (
412                 r[0][0], #astronomical twilight start
413                 r[1][0], #nautical twilight start
414                 r[2][0], #citizen twilight start
415                 r[3][0], r[3][1], #sun rise
416                 r[4][0], r[4][1], #meridian
417                 r[5][0], r[5][1], #sun set
418                 r[6][0], #citizen twilight end
419                 r[7][0], #nautical twilight end
420                 r[8][0], #astronomical twilight end
421                 ))
422     fo.write("""\
423 </table>
424 </body>
425 </html>""")
426     fo.close()