mk_cal_jpl 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,746 @@
1
+ require 'mk_time'
2
+
3
+ module MkCalJpl
4
+ module Compute
5
+ module_function
6
+
7
+ #=========================================================================
8
+ # 休日の計算
9
+ #
10
+ # @param: year
11
+ # @param: month
12
+ # @param: day
13
+ # @return: holiday (漢字1文字)
14
+ #=========================================================================
15
+ def compute_holiday(year, month, day)
16
+ holiday_0 = Array.new # 変動の祝日用
17
+ holiday_1 = Array.new # 国民の休日用
18
+ holiday_2 = Array.new # 振替休日用
19
+
20
+ # 変動の祝日の日付・曜日を計算 ( 振替休日,国民の休日を除く )
21
+ Const::HOLIDAY.each do |holiday|
22
+ unless holiday[1] == 99
23
+ unless holiday[2] == 99 # 月日が既定のもの
24
+ jd_jst = gc2jd(year, holiday[1], holiday[2]) + Const::JST_D
25
+ yobi = compute_yobi(jd_jst)
26
+ holiday_0 << [holiday[1], holiday[2], holiday[0], jd_jst, yobi]
27
+ else # 月日が不定のもの
28
+ if holiday[3] == 21 # 第2月曜日 ( 8 - 14 の月曜日)
29
+ 8.upto(14) do |d|
30
+ jd_jst = gc2jd(year, holiday[1], d) + Const::JST_D
31
+ yobi = compute_yobi(jd_jst)
32
+ holiday_0 << [holiday[1], d, holiday[0], jd_jst, "月"] if yobi == "月"
33
+ end
34
+ elsif holiday[3] == 31 # 第3月曜日 ( 15 - 21 の月曜日)
35
+ 15.upto(21) do |d|
36
+ jd_jst = gc2jd(year, holiday[1], d) + Const::JST_D
37
+ yobi = compute_yobi(jd_jst)
38
+ holiday_0 << [holiday[1], d, holiday[0], jd_jst, "月"] if yobi == "月"
39
+ end
40
+ elsif holiday[3] == 80 # 春分の日
41
+ jd_jst = gc2jd(year, holiday[1], 31) + Const::JST_D
42
+ nibun_jd = compute_last_nc(jd_jst, 90)[0]
43
+ d = jd2ymd(nibun_jd)[2]
44
+ wk_jd = gc2jd(year, holiday[1], d) + Const::JST_D
45
+ yobi = compute_yobi(wk_jd)
46
+ holiday_0 << [holiday[1], d, holiday[0], wk_jd, yobi]
47
+ elsif holiday[3] == 81 # 秋分の日
48
+ jd_jst = gc2jd(year, holiday[1], 30) + Const::JST_D
49
+ nibun_jd = compute_last_nc(jd_jst, 90)[0]
50
+ d = jd2ymd(nibun_jd)[2]
51
+ wk_jd = gc2jd(year, holiday[1], d) + Const::JST_D
52
+ yobi = compute_yobi(wk_jd)
53
+ holiday_0 << [holiday[1], d, holiday[0], wk_jd, yobi]
54
+ end
55
+ end
56
+ end
57
+ end
58
+
59
+ # 国民の休日計算
60
+ # ( 「国民の祝日」で前後を挟まれた「国民の祝日」でない日 )
61
+ # ( 年またぎは考慮していない(今のところ不要) )
62
+ 0.upto(holiday_0.length - 2) do |i|
63
+ if holiday_0[i][3] + 2 == holiday_0[i + 1][3]
64
+ jd = holiday_0[i][3] + 1
65
+ yobi = Const::YOBI[Const::YOBI.index(holiday_0[i][4]) + 1]
66
+ wk_ary = Array.new
67
+ wk_ary << jd2ymd(jd)[1]
68
+ wk_ary << jd2ymd(jd)[2]
69
+ wk_ary << 90
70
+ wk_ary << jd
71
+ wk_ary << yobi
72
+ holiday_1 << wk_ary
73
+ end
74
+ end
75
+
76
+ # 振替休日計算
77
+ # ( 「国民の祝日」が日曜日に当たるときは、
78
+ # その日後においてその日に最も近い「国民の祝日」でない日 )
79
+ 0.upto(holiday_0.length - 1) do |i|
80
+ if holiday_0[i][4] == "日"
81
+ next_jd = holiday_0[i][3] + 1
82
+ next_yobi = Const::YOBI[Const::YOBI.index(holiday_0[i][4]) + 1]
83
+ if i == holiday_0.length - 1
84
+ wk_ary = Array.new
85
+ wk_ary << jd2ymd(next_jd)[1]
86
+ wk_ary << jd2ymd(next_jd)[2]
87
+ wk_ary << 91
88
+ wk_ary << next_jd
89
+ wk_ary << next_yobi
90
+ else
91
+ flg_furikae = 0
92
+ plus_day = 1
93
+ while flg_furikae == 0
94
+ if i + plus_day < holiday_0.length
95
+ if next_jd == holiday_0[i + plus_day][3]
96
+ next_jd += 1
97
+ next_yobi = next_yobi == "土" ? "日" : Const::YOBI[Const::YOBI.index(next_yobi) + 1]
98
+ plus_day += 1
99
+ else
100
+ flg_furikae = 1
101
+ wk_ary = Array.new
102
+ wk_ary << jd2ymd(next_jd)[1]
103
+ wk_ary << jd2ymd(next_jd)[2]
104
+ wk_ary << 91
105
+ wk_ary << next_jd
106
+ wk_ary << next_yobi
107
+ end
108
+ end
109
+ end
110
+ end
111
+ holiday_2 << wk_ary
112
+ end
113
+ end
114
+
115
+ # 配列整理
116
+ code = 99
117
+ (holiday_0 + holiday_1 + holiday_2).sort.each do |holiday|
118
+ if holiday[0] == month && holiday[1] == day
119
+ code = holiday[2]
120
+ break
121
+ end
122
+ end
123
+ holiday = ""
124
+ res = Const::HOLIDAY.select { |h| h[0] == code }
125
+ holiday = res[0][4] unless res == []
126
+ return holiday
127
+ end
128
+
129
+ #=========================================================================
130
+ # 二十四節気の計算
131
+ #
132
+ # @param: jd (ユリウス日(JST))
133
+ # @return: sekki_24 (二十四節気の文字列)
134
+ #=========================================================================
135
+ def compute_sekki_24(jd)
136
+ lsun_today = compute_lambda(jd)
137
+ lsun_tomorrow = compute_lambda(jd + 1)
138
+ lsun_today0 = 15 * (lsun_today / 15.0).truncate
139
+ lsun_tomorrow0 = 15 * (lsun_tomorrow / 15.0).truncate
140
+ return lsun_today0 == lsun_tomorrow0 ? "" : Const::SEKKI_24[lsun_tomorrow0 / 15]
141
+ end
142
+
143
+ #=========================================================================
144
+ # 雑節の計算
145
+ #
146
+ # @param: jd (ユリウス日(JST))
147
+ # @return: [雑節コード1, 雑節コード2]
148
+ #=========================================================================
149
+ def compute_zassetsu(jd)
150
+ zassetsu = Array.new
151
+
152
+ # 計算対象日の太陽の黄経
153
+ lsun_today = compute_lambda(jd)
154
+ # 計算対象日の翌日の太陽の黄経
155
+ lsun_tomorrow = compute_lambda(jd + 1)
156
+ # 計算対象日の5日前の太陽の黄経(社日計算用)
157
+ lsun_before_5 = compute_lambda(jd - 5)
158
+ # 計算対象日の4日前の太陽の黄経(社日計算用)
159
+ lsun_before_4 = compute_lambda(jd - 4)
160
+ # 計算対象日の5日後の太陽の黄経(社日計算用)
161
+ lsun_after_5 = compute_lambda(jd + 5)
162
+ # 計算対象日の6日後の太陽の黄経(社日計算用)
163
+ lsun_after_6 = compute_lambda(jd + 6)
164
+ # 太陽の黄経の整数部分( 土用, 入梅, 半夏生 計算用 )
165
+ lsun_today0 = lsun_today.truncate
166
+ lsun_tomorrow0 = lsun_tomorrow.truncate
167
+
168
+ #### ここから各種雑節計算
169
+ # 0:節分 ( 立春の前日 )
170
+ zassetsu << 0 if compute_sekki_24(jd + 1) == "立春"
171
+ # 1:彼岸入(春) ( 春分の日の3日前 )
172
+ zassetsu << 1 if compute_sekki_24(jd + 3) == "春分"
173
+ # 2:彼岸(春) ( 春分の日 )
174
+ zassetsu << 2 if compute_sekki_24(jd) == "春分"
175
+ # 3:彼岸明(春) ( 春分の日の3日後 )
176
+ zassetsu << 3 if compute_sekki_24(jd - 3) == "春分"
177
+ # 4:社日(春) ( 春分の日に最も近い戊(つちのえ)の日 )
178
+ # * 計算対象日が戊の日の時、
179
+ # * 4日後までもしくは4日前までに春分の日がある時、
180
+ # この日が社日
181
+ # * 5日後が春分の日の時、
182
+ # * 春分点(黄経0度)が午前なら
183
+ # この日が社日
184
+ # * 春分点(黄経0度)が午後なら
185
+ # この日の10日後が社日
186
+ if (jd % 10).truncate == 4 # 戊の日
187
+ # [ 当日から4日後 ]
188
+ 0.upto(4) do |i|
189
+ if compute_sekki_24(jd + i) == "春分"
190
+ zassetsu << 4
191
+ break
192
+ end
193
+ end
194
+ # [ 1日前から4日前 ]
195
+ 1.upto(4) do |i|
196
+ if compute_sekki_24(jd - i) == "春分"
197
+ zassetsu << 4
198
+ break
199
+ end
200
+ end
201
+ # [ 5日後 ]
202
+ if compute_sekki_24(jd + 5) == "春分"
203
+ # 春分の日の黄経(太陽)と翌日の黄経(太陽)の中間点が
204
+ # 0度(360度)以上なら、春分点が午前と判断
205
+ zassetsu << 4 if (lsun_after_5 + lsun_after_6 + 360) / 2.0 >= 360
206
+ end
207
+ # [ 5日前 ]
208
+ if compute_sekki_24(jd - 5) == "春分"
209
+ # 春分の日の黄経(太陽)と翌日の黄経(太陽)の中間点が
210
+ # 0度(360度)未満なら、春分点が午後と判断
211
+ zassetsu << 4 if (lsun_before_4 + lsun_before_5 + 360) / 2.0 < 360
212
+ end
213
+ end
214
+ # 5:土用入(春) ( 黄経(太陽) = 27度 )
215
+ unless lsun_today0 == lsun_tomorrow0
216
+ zassetsu << 5 if lsun_tomorrow0 == 27
217
+ end
218
+ # 6:八十八夜 ( 立春から88日目(87日後) )
219
+ zassetsu << 6 if compute_sekki_24(jd - 87) == "立春"
220
+ # 7:入梅 ( 黄経(太陽) = 80度 )
221
+ unless lsun_today0 == lsun_tomorrow0
222
+ zassetsu << 7 if lsun_tomorrow0 == 80
223
+ end
224
+ # 8:半夏生 ( 黄経(太陽) = 100度 )
225
+ unless lsun_today0 == lsun_tomorrow0
226
+ zassetsu << 8 if lsun_tomorrow0 == 100
227
+ end
228
+ # 9:土用入(夏) ( 黄経(太陽) = 117度 )
229
+ unless lsun_today0 == lsun_tomorrow0
230
+ zassetsu << 9 if lsun_tomorrow0 == 117
231
+ end
232
+ # 10:二百十日 ( 立春から210日目(209日後) )
233
+ zassetsu << 10 if compute_sekki_24(jd - 209) == "立春"
234
+ # 11:二百二十日 ( 立春から220日目(219日後) )
235
+ zassetsu << 11 if compute_sekki_24(jd - 219) == "立春"
236
+ # 12:彼岸入(秋) ( 秋分の日の3日前 )
237
+ zassetsu << 12 if compute_sekki_24(jd + 3) == "秋分"
238
+ # 13:彼岸(秋) ( 秋分の日 )
239
+ zassetsu << 13 if compute_sekki_24(jd) == "秋分"
240
+ # 14:彼岸明(秋) ( 秋分の日の3日後 )
241
+ zassetsu << 14 if compute_sekki_24(jd - 3) == "秋分"
242
+ # 15:社日(秋) ( 秋分の日に最も近い戊(つちのえ)の日 )
243
+ # * 計算対象日が戊の日の時、
244
+ # * 4日後までもしくは4日前までに秋分の日がある時、
245
+ # この日が社日
246
+ # * 5日後が秋分の日の時、
247
+ # * 秋分点(黄経180度)が午前なら
248
+ # この日が社日
249
+ # * 秋分点(黄経180度)が午後なら
250
+ # この日の10日後が社日
251
+ if (jd % 10).truncate == 4 # 戊の日
252
+ # [ 当日から4日後 ]
253
+ 0.upto(4) do |i|
254
+ if compute_sekki_24(jd + i) == "秋分"
255
+ zassetsu << 15
256
+ break
257
+ end
258
+ end
259
+ # [ 1日前から4日前 ]
260
+ 1.upto(4) do |i|
261
+ if compute_sekki_24(jd - i) == "秋分"
262
+ zassetsu << 15
263
+ break
264
+ end
265
+ end
266
+ # [ 5日後 ]
267
+ if compute_sekki_24(jd + 5) == "秋分"
268
+ # 秋分の日の黄経(太陽)と翌日の黄経(太陽)の中間点が
269
+ # 180度以上なら、秋分点が午前と判断
270
+ zassetsu << 15 if (lsun_after_5 + lsun_after_6) / 2.0 >= 180
271
+ end
272
+ # [ 5日前 ]
273
+ if compute_sekki_24(jd - 5) == "秋分"
274
+ # 秋分の日の黄経(太陽)と翌日の黄経(太陽)の中間点が
275
+ # 180度未満なら、秋分点が午後と判断
276
+ zassetsu << 15 if (lsun_before_4 + lsun_before_5) / 2.0 < 180
277
+ end
278
+ end
279
+ # 16:土用入(秋) ( 黄経(太陽) = 207度 )
280
+ unless lsun_today0 == lsun_tomorrow0
281
+ zassetsu << 16 if lsun_tomorrow0 == 207
282
+ end
283
+ # 17:土用入(冬) ( 黄経(太陽) = 297度 )
284
+ unless lsun_today0 == lsun_tomorrow0
285
+ zassetsu << 17 if lsun_tomorrow0 == 297
286
+ end
287
+ return zassetsu.map { |z| Const::ZASSETSU[z] }.join(",")
288
+ end
289
+
290
+ #=========================================================================
291
+ # 曜日の計算
292
+ #
293
+ # * 曜日 = ( ユリウス通日 + 2 ) % 7
294
+ # 0: 日曜, 1: 月曜, 2: 火曜, 3: 水曜, 4: 木曜, 5: 金曜, 6: 土曜
295
+ #
296
+ # @param: jd (ユリウス日(JST))
297
+ # @return: yobi (漢字1文字)
298
+ #=========================================================================
299
+ def compute_yobi(jd)
300
+ return Const::YOBI[(jd.to_i + 2) % 7]
301
+ end
302
+
303
+ #=========================================================================
304
+ # 干支の計算
305
+ #
306
+ # * [ユリウス日(JST) - 10日] を60で割った剰余
307
+ #
308
+ # @param: jd (ユリウス日(JST))
309
+ # @return kanshi (漢字2文字)
310
+ #=========================================================================
311
+ def compute_kanshi(jd)
312
+ return Const::KANSHI[(jd.to_i - 10) % 60]
313
+ end
314
+
315
+ #=========================================================================
316
+ # 節句の計算
317
+ #
318
+ # @param: month
319
+ # @param: day
320
+ # @return: sekku (日本語文字列)
321
+ #=========================================================================
322
+ def compute_sekku(month, day)
323
+ sekku = ""
324
+ res = Const::SEKKU.select { |s| s[1] == month && s[2] == day }
325
+ sekku = res[0][3] unless res == []
326
+ return sekku
327
+ end
328
+
329
+ #=========================================================================
330
+ # 月齢(正午)の計算
331
+ #
332
+ # @param: jd (ユリウス日(JST))
333
+ # @return: moonage
334
+ #=========================================================================
335
+ def compute_moonage(jd)
336
+ return jd - compute_saku(jd - Const::JST_D)
337
+ end
338
+
339
+ #=========================================================================
340
+ # 旧暦の計算
341
+ #
342
+ # * 旧暦一日の六曜
343
+ # 1・7月 : 先勝
344
+ # 2・8月 : 友引
345
+ # 3・9月 : 先負
346
+ # 4・10月 : 仏滅
347
+ # 5・11月 : 大安
348
+ # 6・12月 : 赤口
349
+ # と決まっていて、あとは月末まで順番通り。
350
+ # よって、月と日をたした数を6で割った余りによって六曜を決定することができます。
351
+ # ( 旧暦の月 + 旧暦の日 ) ÷ 6 = ? … 余り
352
+ # 余り 0 : 大安
353
+ # 1 : 赤口
354
+ # 2 : 先勝
355
+ # 3 : 友引
356
+ # 4 : 先負
357
+ # 5 : 仏滅
358
+ #
359
+ # @param: jd (ユリウス日(JST))
360
+ # @return: [旧暦年, 閏月Flag, 旧暦月, 旧暦日, 六曜]
361
+ #=========================================================================
362
+ def compute_oc(jd)
363
+ jd -= 0.5
364
+ tm0 = jd
365
+ # 二分二至,中気の時刻・黄経用配列宣言
366
+ chu = Array.new(4).map { Array.new(2, 0) }
367
+ # 朔用配列宣言
368
+ saku = Array.new(5, 0)
369
+ # 朔日用配列宣言
370
+ m = Array.new(5).map { Array.new(3, 0) }
371
+ # 旧暦用配列宣言
372
+ kyureki = Array.new(4, 0)
373
+
374
+ # 計算対象の直前にあたる二分二至の時刻を計算
375
+ # chu[0][0] : 二分二至の時刻
376
+ # chu[0][1] : その時の太陽黄経
377
+ chu[0] = compute_last_nc(tm0, 90)
378
+ # 中気の時刻を計算 ( 3回計算する )
379
+ # chu[i][0] : 中気の時刻
380
+ # chu[i][1] : その時の太陽黄経
381
+ 1.upto(3) do |i|
382
+ chu[i] = compute_last_nc(chu[i - 1][0] + 32, 30)
383
+ end
384
+ # 計算対象の直前にあたる二分二至の直前の朔の時刻を求める
385
+ saku[0] = compute_saku(chu[0][0])
386
+ # 朔の時刻を求める
387
+ 1.upto(4) do |i|
388
+ tm = saku[i-1] + 30
389
+ saku[i] = compute_saku(tm)
390
+ # 前と同じ時刻を計算した場合( 両者の差が26日以内 )には、初期値を
391
+ # +33日にして再実行させる。
392
+ if (saku[i-1].truncate - saku[i].truncate).abs <= 26
393
+ saku[i] = compute_saku(saku[i-1] + 35)
394
+ end
395
+ end
396
+ # saku[1]が二分二至の時刻以前になってしまった場合には、朔をさかのぼり過ぎ
397
+ # たと考えて、朔の時刻を繰り下げて修正する。
398
+ # その際、計算もれ(saku[4])になっている部分を補うため、朔の時刻を計算
399
+ # する。(近日点通過の近辺で朔があると起こる事があるようだ...?)
400
+ if saku[1].truncate <= chu[0][0].truncate
401
+ 0.upto(3) { |i| saku[i] = saku[i+1] }
402
+ saku[4] = compute_saku(saku[3] + 35)
403
+ # saku[0]が二分二至の時刻以後になってしまった場合には、朔をさかのぼり足
404
+ # りないと見て、朔の時刻を繰り上げて修正する。
405
+ # その際、計算もれ(saku[0])になっている部分を補うため、朔の時刻を計算
406
+ # する。(春分点の近辺で朔があると起こる事があるようだ...?)
407
+ elsif saku[0].truncate > chu[0][0].truncate
408
+ 4.downto(1) { |i| saku[i] = saku[i-1] }
409
+ saku[0] = compute_saku(saku[0] - 27)
410
+ end
411
+ # 閏月検索Flagセット
412
+ # (節月で4ヶ月の間に朔が5回あると、閏月がある可能性がある。)
413
+ # leap=0:平月 leap=1:閏月
414
+ leap = 0
415
+ leap = 1 if saku[4].truncate <= chu[3][0].truncate
416
+ # 朔日行列の作成
417
+ # m[i][0] ... 月名 ( 1:正月 2:2月 3:3月 .... )
418
+ # m[i][1] ... 閏フラグ ( 0:平月 1:閏月 )
419
+ # m[i][2] ... 朔日のjd
420
+ m[0][0] = (chu[0][1] / 30.0).truncate + 2
421
+ m[0][0] -= 12 if m[0][0] > 12
422
+ m[0][2] = saku[0].truncate
423
+ m[0][1] = 0
424
+ 1.upto(4) do |i|
425
+ if leap == 1 && i != 1
426
+ if chu[i-1][0].truncate <= saku[i-1].truncate ||
427
+ chu[i-1][0].truncate >= saku[i].truncate
428
+ m[i-1][0] = m[i-2][0]
429
+ m[i-1][1] = 1
430
+ m[i-1][2] = saku[i-1].truncate
431
+ leap = 0
432
+ end
433
+ end
434
+ m[i][0] = m[i-1][0] + 1
435
+ m[i][0] -= 12 if m[i][0] > 12
436
+ m[i][2] = saku[i].truncate
437
+ m[i][1] = 0
438
+ end
439
+ # 朔日行列から旧暦を求める。
440
+ state, index = 0, 0
441
+ 0.upto(4) do |i|
442
+ index = i
443
+ if tm0.truncate < m[i][2].truncate
444
+ state = 1
445
+ break
446
+ elsif tm0.truncate == m[i][2].truncate
447
+ state = 2
448
+ break
449
+ end
450
+ end
451
+ index -= 1 if state == 1
452
+ kyureki[1] = m[index][1]
453
+ kyureki[2] = m[index][0]
454
+ kyureki[3] = tm0.truncate - m[index][2].truncate + 1
455
+ # 旧暦年の計算
456
+ # (旧暦月が10以上でかつ新暦月より大きい場合には、
457
+ # まだ年を越していないはず...)
458
+ a = jd2ymd(tm0)
459
+ kyureki[0] = a[0]
460
+ kyureki[0] -= 1 if kyureki[2] > 9 && kyureki[2] > a[1]
461
+ # 六曜
462
+ kyureki[4] = Const::ROKUYO[(kyureki[2] + kyureki[3]) % 6]
463
+ return kyureki
464
+ end
465
+
466
+ #=========================================================================
467
+ # 直前二分二至・中気時刻の計算
468
+ #
469
+ # @param: jd (ユリウス日)
470
+ # @param: kbn (90: 二分二至, 30: 中気)
471
+ # @return: [二分二至・中気の時刻, その時の黄経]
472
+ #=========================================================================
473
+ def compute_last_nc(jd, kbn)
474
+ jd -= 0.5
475
+ # 時刻引数を分解
476
+ tm1 = jd.truncate # 整数部分
477
+ tm2 = jd - tm1 # 小数部分
478
+ tm2 -= Const::JST_D
479
+
480
+ # 直前の二分二至の黄経 λsun0 を求める
481
+ rm_sun = compute_lambda(jd + 0.5)
482
+ rm_sun0 = kbn * (rm_sun / kbn.to_f).truncate
483
+
484
+ # 繰り返し計算によって直前の二分二至の時刻を計算する
485
+ # (誤差が±1.0 sec以内になったら打ち切る。)
486
+ delta_t1 = 0 ; delta_t2 = 1
487
+ while (delta_t1 + delta_t2).abs > (1.0 / 86400.0)
488
+ # λsun を計算
489
+ t = tm1 + tm2 + Const::JST_D + 0.5
490
+ rm_sun = compute_lambda(t)
491
+
492
+ # 黄経差 Δλ=λsun -λsun0
493
+ delta_rm = rm_sun - rm_sun0
494
+
495
+ # Δλの引き込み範囲(±180°)を逸脱した場合には、補正を行う
496
+ case
497
+ when delta_rm > 180; delta_rm -= 360
498
+ when delta_rm < -180; delta_rm += 360
499
+ end
500
+
501
+ # 時刻引数の補正値 Δt
502
+ delta_t1 = (delta_rm * 365.2 / 360.0).truncate
503
+ delta_t2 = delta_rm * 365.2 / 360.0 - delta_t1
504
+
505
+ # 時刻引数の補正
506
+ tm1 = tm1 - delta_t1
507
+ tm2 = tm2 - delta_t2
508
+ if tm2 < 0
509
+ tm2 += 1
510
+ tm1 -= 1
511
+ end
512
+ end
513
+
514
+ # nibun_chu[0] : 時刻引数を合成、DT ==> JST 変換を行い、戻り値とする
515
+ # ( 補正時刻=0.0sec と仮定して計算 )
516
+ # nibun_chu[1] : 黄経
517
+ nibun_chu = Array.new(2, 0)
518
+ nibun_chu[0] = tm2 + 9 / 24.0
519
+ nibun_chu[0] += tm1
520
+ nibun_chu[1] = rm_sun0
521
+ return nibun_chu
522
+ end
523
+
524
+ #=========================================================================
525
+ # 直近の朔の時刻(JST)の計算
526
+ #
527
+ # @param: jd (ユリウス日)
528
+ # @return: saku (直前の朔の時刻)
529
+ #=========================================================================
530
+ def compute_saku(jd)
531
+ lc = 1
532
+
533
+ # 時刻引数を分解する
534
+ tm1 = jd.truncate
535
+ tm2 = jd - tm1
536
+ tm2 -= Const::JST_D
537
+
538
+ # 繰り返し計算によって朔の時刻を計算する
539
+ # (誤差が±1.0 sec以内になったら打ち切る。)
540
+ delta_t1 = 0 ; delta_t2 = 1
541
+ while (delta_t1 + delta_t2).abs > (1.0 / 86400.0)
542
+ # 太陽の黄経λsun ,月の黄経λmoon を計算
543
+ t = tm1 + tm2 + Const::JST_D + 0.5
544
+ rm_sun = compute_lambda(t)
545
+ rm_moon = compute_alpha(t)
546
+ # 月と太陽の黄経差Δλ
547
+ # Δλ=λmoon-λsun
548
+ delta_rm = rm_moon - rm_sun
549
+ # ループの1回目 ( lc = 1 ) で delta_rm < 0.0 の場合には引き込み範囲に
550
+ # 入るように補正する
551
+ if lc == 1 && delta_rm < 0
552
+ delta_rm = norm_angle(delta_rm)
553
+ # 春分の近くで朔がある場合 ( 0 ≦λsun≦ 20 ) で、月の黄経λmoon≧300 の
554
+ # 場合には、Δλ= 360.0 - Δλ と計算して補正する
555
+ elsif rm_sun >= 0 && rm_sun <= 20 && rm_moon >= 300
556
+ delta_rm = norm_angle(delta_rm)
557
+ delta_rm = 360 - delta_rm
558
+ # Δλの引き込み範囲 ( ±40° ) を逸脱した場合には、補正を行う
559
+ elsif delta_rm.abs > 40.0
560
+ delta_rm = norm_angle(delta_rm)
561
+ end
562
+ # 時刻引数の補正値 Δt
563
+ delta_t1 = (delta_rm * 29.530589 / 360.0).truncate
564
+ delta_t2 = delta_rm * 29.530589 / 360.0 - delta_t1
565
+ # 時刻引数の補正
566
+ tm1 = tm1 - delta_t1
567
+ tm2 = tm2 - delta_t2
568
+ if tm2 < 0
569
+ tm2 += 1
570
+ tm1 -= 1
571
+ end
572
+ # ループ回数が15回になったら、初期値 tm を tm-26 とする。
573
+ if lc == 15 && (delta_t1 + delta_t2).abs > (1.0 / 86400.0)
574
+ tm1 = (jd - 26).truncate
575
+ tm2 = 0
576
+ # 初期値を補正したにも関わらず、振動を続ける場合には初期値を答えとして
577
+ # 返して強制的にループを抜け出して異常終了させる。
578
+ elsif lc > 30 && (delta_t1+delta_t2).abs > (1.0 / 86400.0)
579
+ tm1 = jd
580
+ tm2 = 0
581
+ break
582
+ end
583
+ lc += 1
584
+ end
585
+ # 時刻引数を合成、DT ==> JST 変換を行い、戻り値とする
586
+ # (補正時刻=0.0sec と仮定して計算)
587
+ return tm2 + tm1 + 9 / 24.0
588
+ end
589
+
590
+ #=========================================================================
591
+ # Gregorian Calendar -> Julian Day
592
+ #
593
+ # * フリーゲルの公式を使用する
594
+ # [ JD ] = int( 365.25 × year )
595
+ # + int( year / 400 )
596
+ # - int( year / 100 )
597
+ # + int( 30.59 ( month - 2 ) )
598
+ # + day
599
+ # + 1721088
600
+ # ※上記の int( x ) は厳密には、x を超えない最大の整数
601
+ # ( ちなみに、[ 準JD ]を求めるなら + 1721088.5 が - 678912 となる )
602
+ #
603
+ # @param: year
604
+ # @param: month
605
+ # @param: day
606
+ # @param: hour
607
+ # @param: minute
608
+ # @param: second
609
+ # @return: jd ( ユリウス日 )
610
+ #=========================================================================
611
+ def gc2jd(year, month, day, hour = 0, min = 0, sec = 0)
612
+ # 1月,2月は前年の13月,14月とする
613
+ if month < 3
614
+ year -= 1
615
+ month += 12
616
+ end
617
+ # 日付(整数)部分計算
618
+ jd = (365.25 * year).truncate
619
+ jd += (year / 400.0).truncate
620
+ jd -= (year / 100.0).truncate
621
+ jd += (30.59 * (month - 2)).truncate
622
+ jd += day
623
+ jd += 1721088.125
624
+ # 時間(小数)部分計算
625
+ t = sec / 3600.0
626
+ t += min / 60.0
627
+ t += hour
628
+ t = t / 24.0
629
+ return jd + t
630
+ end
631
+
632
+ #=========================================================================
633
+ # Julian Day -> UT
634
+ #
635
+ # @param: jd (ユリウス日)
636
+ # @return: [year, month, day, hour, minute, second]
637
+ #=========================================================================
638
+ def jd2ymd(jd)
639
+ ut = Array.new(6, 0)
640
+ x0 = (jd + 68570).truncate
641
+ x1 = (x0 / 36524.25).truncate
642
+ x2 = x0 - (36524.25 * x1 + 0.75).truncate
643
+ x3 = ((x2 + 1) / 365.2425).truncate
644
+ x4 = x2 - (365.25 * x3).truncate + 31
645
+ x5 = (x4.truncate / 30.59).truncate
646
+ x6 = (x5.truncate / 11.0).truncate
647
+ ut[2] = x4 - (30.59 * x5).truncate
648
+ ut[1] = x5 - 12 * x6 + 2
649
+ ut[0] = 100 * (x1 - 49) + x3 + x6
650
+ # 2月30日の補正
651
+ if ut[1]==2 && ut[2] > 28
652
+ if ut[0] % 100 == 0 && ut[0] % 400 == 0
653
+ ut[2] = 29
654
+ elsif ut[0] % 4 == 0
655
+ ut[2] = 29
656
+ else
657
+ ut[2] = 28
658
+ end
659
+ end
660
+ tm = 86400 * (jd - jd.truncate)
661
+ ut[3] = (tm / 3600.0).truncate
662
+ ut[4] = ((tm - 3600 * ut[3]) / 60.0).truncate
663
+ #ut[5] = (tm - 3600 * ut[3] - 60 * ut[4]).truncate
664
+ ut[5] = tm - 3600 * ut[3] - 60 * ut[4]
665
+ return ut
666
+ end
667
+
668
+ #=========================================================================
669
+ # 角度の正規化
670
+ #
671
+ # @param: angle
672
+ # @return: angle
673
+ #=========================================================================
674
+ def norm_angle(angle)
675
+ if angle < 0
676
+ angle1 = angle * (-1)
677
+ angle2 = (angle1 / 360.0).truncate
678
+ angle1 -= 360 * angle2
679
+ angle1 = 360 - angle1
680
+ else
681
+ angle1 = (angle / 360.0).truncate
682
+ angle1 = angle - 360.0 * angle1
683
+ end
684
+ return angle1
685
+ end
686
+
687
+ #=========================================================================
688
+ # ΔT の計算
689
+ #
690
+ # * 1972-01-01 以降、うるう秒挿入済みの年+αまでは、以下で算出
691
+ # TT - UTC = ΔT + DUT1 = TAI + 32.184 - UTC = ΔAT + 32.184
692
+ # [うるう秒実施日一覧](http://jjy.nict.go.jp/QandA/data/leapsec.html)
693
+ #
694
+ # @param: year
695
+ # @param: month
696
+ # @param: day
697
+ # @return: dt
698
+ #=========================================================================
699
+ def compute_dt(year, month, day)
700
+ ymd = sprintf("%04d%02d%02d", year, month, day)
701
+ tm = MkTime.new(ymd)
702
+ return tm.dt
703
+ end
704
+
705
+ #=========================================================================
706
+ # 六曜の計算
707
+ #
708
+ #
709
+ # @param: oc_month (旧暦の月)
710
+ # @param: oc_day (旧暦の日)
711
+ # @return: rokuyo (漢字2文字)
712
+ #=========================================================================
713
+ def compute_rokuyo(oc_month, oc_day)
714
+ return Const::ROKUYO[(oc_month + oc_day) % 6]
715
+ end
716
+
717
+ #=========================================================================
718
+ # 太陽視黄経の計算
719
+ #
720
+ # @param: jd (ユリウス日(JST))
721
+ # @return: lambda
722
+ #=========================================================================
723
+ def compute_lambda(jd)
724
+ year, month, day, hour, min, sec = jd2ymd(jd - Const::JST_D - 0.5)
725
+ ymd = sprintf("%04d%02d%02d%02d%02d%08d", year, month, day, hour, min, sec * 10 ** 6)
726
+ a = MkApos.new(@bin_path, ymd)
727
+ lmd = a.sun[1][0] * 180.0 / Math::PI
728
+ return lmd
729
+ end
730
+
731
+ #=========================================================================
732
+ # 月視黄経の計算
733
+ #
734
+ # @param: jd (ユリウス日(JST))
735
+ # @return: lambda
736
+ #=========================================================================
737
+ def compute_alpha(jd)
738
+ year, month, day, hour, min, sec = jd2ymd(jd - Const::JST_D - 0.5)
739
+ ymd = sprintf("%04d%02d%02d%02d%02d%08d", year, month, day, hour, min, sec * 10 ** 6)
740
+ a = MkApos.new(@bin_path, ymd)
741
+ lmd = a.moon[1][0] * 180.0 / Math::PI
742
+ return lmd
743
+ end
744
+ end
745
+ end
746
+