mk_cal_jpl 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
+