when_exe 0.3.6 → 0.3.7

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.
Files changed (117) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +171 -0
  3. data/lib/when_exe.rb +78 -47
  4. data/lib/when_exe/basictypes.rb +752 -747
  5. data/lib/when_exe/calendarnote.rb +805 -801
  6. data/lib/when_exe/calendartypes.rb +1583 -1531
  7. data/lib/when_exe/coordinates.rb +16 -15
  8. data/lib/when_exe/core/duration.rb +114 -110
  9. data/lib/when_exe/core/extension.rb +504 -504
  10. data/lib/when_exe/ephemeris.rb +1917 -1913
  11. data/lib/when_exe/ephemeris/moon.rb +333 -333
  12. data/lib/when_exe/ephemeris/notes.rb +389 -387
  13. data/lib/when_exe/ephemeris/planets.rb +585 -585
  14. data/lib/when_exe/ephemeris/sun.rb +214 -214
  15. data/lib/when_exe/googlecalendar.rb +144 -140
  16. data/lib/when_exe/icalendar.rb +1636 -1636
  17. data/lib/when_exe/inspect.rb +46 -22
  18. data/lib/when_exe/locales/akt.rb +176 -176
  19. data/lib/when_exe/locales/encoding_conversion.rb +134 -126
  20. data/lib/when_exe/locales/iast.rb +90 -90
  21. data/lib/when_exe/locales/locale.rb +750 -746
  22. data/lib/when_exe/locales/transliteration_table.rb +62 -62
  23. data/lib/when_exe/mini_application.rb +307 -305
  24. data/lib/when_exe/parts/enumerator.rb +2 -2
  25. data/lib/when_exe/parts/geometric_complex.rb +397 -397
  26. data/lib/when_exe/parts/method_cash.rb +224 -224
  27. data/lib/when_exe/parts/resource.rb +1069 -1071
  28. data/lib/when_exe/parts/timezone.rb +240 -230
  29. data/lib/when_exe/region/armenian.rb +56 -56
  30. data/lib/when_exe/region/babylonian.rb +405 -0
  31. data/lib/when_exe/region/bahai.rb +146 -146
  32. data/lib/when_exe/region/balinese.rb +622 -622
  33. data/lib/when_exe/region/chinese.rb +95 -25
  34. data/lib/when_exe/region/chinese/calendars.rb +1016 -1016
  35. data/lib/when_exe/region/chinese/epochs.rb +1 -1
  36. data/lib/when_exe/region/chinese/twins.rb +803 -795
  37. data/lib/when_exe/region/christian.rb +824 -824
  38. data/lib/when_exe/region/coptic.rb +106 -87
  39. data/lib/when_exe/region/discordian.rb +225 -225
  40. data/lib/when_exe/region/far_east.rb +188 -188
  41. data/lib/when_exe/region/french.rb +56 -56
  42. data/lib/when_exe/region/geologicalage.rb +639 -639
  43. data/lib/when_exe/region/goddess.rb +58 -58
  44. data/lib/when_exe/region/indian.rb +1254 -1251
  45. data/lib/when_exe/region/iranian.rb +8 -8
  46. data/lib/when_exe/region/islamic.rb +3 -3
  47. data/lib/when_exe/region/japanese.rb +93 -99
  48. data/lib/when_exe/region/japanese/calendars.rb +396 -397
  49. data/lib/when_exe/region/japanese/epochs.rb +26 -26
  50. data/lib/when_exe/region/japanese/nihon_shoki.rb +71 -71
  51. data/lib/when_exe/region/japanese/notes.rb +1383 -1386
  52. data/lib/when_exe/region/japanese/residues.rb +1306 -1306
  53. data/lib/when_exe/region/japanese/twins.rb +225 -225
  54. data/lib/when_exe/region/japanese/weeks.rb +112 -0
  55. data/lib/when_exe/region/javanese.rb +230 -230
  56. data/lib/when_exe/region/jewish.rb +126 -126
  57. data/lib/when_exe/region/korean.rb +378 -378
  58. data/lib/when_exe/region/m17n.rb +114 -113
  59. data/lib/when_exe/region/martian.rb +258 -255
  60. data/lib/when_exe/region/mayan.rb +32 -32
  61. data/lib/when_exe/region/residue.rb +89 -89
  62. data/lib/when_exe/region/roman.rb +36 -24
  63. data/lib/when_exe/region/ryukyu.rb +97 -97
  64. data/lib/when_exe/region/shire.rb +240 -240
  65. data/lib/when_exe/region/soviet.rb +209 -0
  66. data/lib/when_exe/region/symmetry.rb +50 -50
  67. data/lib/when_exe/region/thai.rb +336 -335
  68. data/lib/when_exe/region/tibetan.rb +316 -315
  69. data/lib/when_exe/region/vietnamese.rb +440 -439
  70. data/lib/when_exe/region/weekdate.rb +80 -80
  71. data/lib/when_exe/region/world.rb +175 -175
  72. data/lib/when_exe/region/yerm.rb +14 -14
  73. data/lib/when_exe/region/zoroastrian.rb +203 -203
  74. data/lib/when_exe/timestandard.rb +707 -681
  75. data/lib/when_exe/tmduration.rb +338 -330
  76. data/lib/when_exe/tmobjects.rb +1346 -1325
  77. data/lib/when_exe/tmposition.rb +2115 -2072
  78. data/lib/when_exe/tmreference.rb +1693 -1669
  79. data/lib/when_exe/version.rb +1 -1
  80. data/link_to_online_documents +1 -1
  81. data/test/examples/JapanHolidaysRFC6350.ics +1 -1
  82. data/test/test.rb +67 -61
  83. data/test/test/basictypes.rb +409 -409
  84. data/test/test/calendarnote.rb +86 -69
  85. data/test/test/calendartypes.rb +97 -97
  86. data/test/test/coordinates.rb +396 -396
  87. data/test/test/ephemeris.rb +83 -74
  88. data/test/test/ephemeris/moon.rb +14 -14
  89. data/test/test/ephemeris/planets.rb +14 -14
  90. data/test/test/ephemeris/sun.rb +14 -14
  91. data/test/test/googlecalendar.rb +194 -176
  92. data/test/test/icalendar.rb +867 -858
  93. data/test/test/inspect.rb +117 -117
  94. data/test/test/parts.rb +487 -487
  95. data/test/test/region/balinese.rb +34 -0
  96. data/test/test/region/chinese.rb +218 -206
  97. data/test/test/region/christian.rb +245 -245
  98. data/test/test/region/coptic.rb +27 -27
  99. data/test/test/region/french.rb +33 -33
  100. data/test/test/region/geologicalage.rb +17 -17
  101. data/test/test/region/indian.rb +57 -57
  102. data/test/test/region/iran.rb +54 -54
  103. data/test/test/region/islamic.rb +18 -18
  104. data/test/test/region/japanese.rb +237 -219
  105. data/test/test/region/jewish.rb +61 -61
  106. data/test/test/region/m17n.rb +184 -184
  107. data/test/test/region/mayan.rb +195 -195
  108. data/test/test/region/residue.rb +147 -139
  109. data/test/test/region/thai.rb +116 -116
  110. data/test/test/region/tibetan.rb +30 -30
  111. data/test/test/region/vietnamese.rb +102 -102
  112. data/test/test/region/yerm.rb +146 -146
  113. data/test/test/timestandard.rb +81 -81
  114. data/test/test/tmobjects.rb +328 -328
  115. data/test/test/tmposition.rb +397 -284
  116. data/test/test/tmreference.rb +157 -157
  117. metadata +13 -10
@@ -1,387 +1,389 @@
1
- # -*- coding: utf-8 -*-
2
- =begin
3
- Copyright (C) 2011-2014 Takashi SUGA
4
-
5
- You may use and/or modify this file according to the license described in the LICENSE.txt file included in this archive.
6
- =end
7
-
8
- #
9
- # Ephemeris を用いる暦注
10
- #
11
- class When::CalendarNote
12
- #
13
- # 太陽と月の位置によるイベント
14
- #
15
- class LuniSolarPositions < self
16
-
17
- # 座標の分子
18
- #
19
- # @return [Numeric]
20
- #
21
- attr_reader :num
22
-
23
- # 座標の分母
24
- #
25
- # @return [Numeric]
26
- #
27
- attr_reader :den
28
-
29
- # 計算アルゴリズム
30
- #
31
- # @return [When::Ephemeris::Formula]
32
- #
33
- attr_reader :formula
34
-
35
- # enumerator の周期
36
- #
37
- # @return [Numeric]
38
- #
39
- attr_reader :delta
40
-
41
- # 没滅計算用の補正
42
- #
43
- # @return [Numeric]
44
- #
45
- attr_reader :margin
46
-
47
- # イベントの日時
48
- #
49
- # @param [When::TM::TemporalPosition] date イベントを探す基準とする日時
50
- # @param [Array<Numeric>] parameter 座標の分子と分母( num, den)
51
- #
52
- # num 座標の分子 (デフォルト @num)
53
- #
54
- # den 座標の分母 (デフォルト @den)
55
- #
56
- # @param [String] parameter 座標の分子と分母("#{ num }/#{ den }" の形式)
57
- # @param [Integer] precision 取得したい時間位置の分解能(デフォルト date の分解能)
58
- #
59
- # @return [When::TM::CalDate] date またはその直後のイベントの日時
60
- #
61
- def event(date, parameter=nil, precision=date.precision)
62
- num, den = parameter.kind_of?(String) ? parameter.split(/\//, 2) : parameter
63
- num = (num || @num).to_f
64
- den = (den || @den).to_f
65
- date = date.floor(precision) if precision < date.precision
66
- options = date._attr
67
- is_date_and_time = options.key?(:clock) || precision > When::DAY
68
- options[:precision] = precision
69
- options[:clock] ||= date.frame.time_basis || When::TM::Clock.local_time
70
- quot, mod = (@formula.time_to_cn(date)*30.0).divmod(den)
71
- cycle = quot * den + num
72
- cycle += den if mod > (num % den)
73
- time = When::TM::JulianDate._d_to_t(@formula.cn_to_time(cycle/30.0))
74
- time = date.time_standard.from_dynamical_time(time) if @formula.is_dynamical
75
- event = date.frame.jul_trans(When::TM::JulianDate.universal_time(time), options)
76
- is_date_and_time ? event : event.to_cal_date
77
- end
78
-
79
- # 日付に対応する座標
80
- #
81
- # @param [When::TM::TemporalPosition] date 日付
82
- # @param [Numeric] delta 周期の補正(土用の時刻の補正に使用,デフォルト 0)
83
- #
84
- # @return [Array<Integer>] Array< Integer, 0 or 1 or 2 >
85
- #
86
- # [Integer] 対応する座標
87
- #
88
- # [0 or 1 or 2] 座標の進み(0 なら 没, 2 なら滅)
89
- #
90
- def position(date, delta=0)
91
- date = date.floor
92
- p0, p1 = [date, date.succ].map {|d| (30.0 * @formula.time_to_cn(d) - @margin + delta).floor}
93
- [p1 % @den, p1 - p0]
94
- end
95
-
96
- #
97
- # イベントの標準的な間隔を返す
98
- #
99
- # @param [String] parameter 座標の分子と分母("#{ num }/#{ den }" の形式)
100
- #
101
- # @return [When::TM::IntervalLength]
102
- #
103
- # @private
104
- def event_delta(parameter=nil)
105
- return @delta unless parameter
106
- num, den = parameter.split(/\//, 2)
107
- When::TM::IntervalLength.new([(den || @den).to_f,1].max*0.9, 'day')
108
- end
109
-
110
- #
111
- # イベント日付(時刻付)
112
- #
113
- # @private
114
- def event_time(date, event_name, event)
115
- etime = term(date - When.Duration('P3D'), event, When::SYSTEM)
116
- if formula.respond_to?(:year_length) && formula.denominator && formula.denominator < 100000
117
- fraction = etime.clk_time.universal_time
118
- fraction += When::TM::Duration::DAY * (etime.to_i - date.to_i)
119
- fraction = (fraction / When::TM::Duration::DAY * formula.denominator * 1000 + 0.5).floor / 1000.0
120
- fraction = fraction.to_i if fraction == fraction.to_i
121
- event_name + "(#{fraction}/#{formula.denominator})"
122
- else
123
- etime.events = [event_name]
124
- etime
125
- end
126
- end
127
- end
128
-
129
- #
130
- # 二十四節気
131
- #
132
- class SolarTerms < LuniSolarPositions
133
-
134
- # 二十四節気のための event の別名
135
- #
136
- # @return [When::TM::CalDate] date またはその直後のイベントの日時
137
- alias :term :event
138
-
139
- private
140
-
141
- # 二十四節気のための event_delta の別名
142
- alias :term_delta :event_delta
143
-
144
- # オブジェクトの正規化
145
- # num - 太陽黄経/度の分子 (デフォルト 0 - 春分)
146
- # den - 太陽黄経/度の分母 (デフォルト 360 - 1年)
147
- # formula - 計算アルゴリズム(デフォルト '_ep:Formula?formula=12S')
148
- # delta - enumerator の周期 (デフォルト (den/360)年)
149
- # margin - 没滅計算用の補正 (デフォルト 1E-8)
150
- def _normalize(args=[], options={})
151
- num, den, formula, delta, margin = args
152
- @num = (num || @num || 0).to_f
153
- @den = (den || @den || 360).to_f
154
- @formula = When.Resource(formula || @formula ||'Formula?formula=12S', '_ep:')
155
- @delta = When.Duration(delta || @delta || When::TM::IntervalLength.new(@den/360, 'year'))
156
- @margin = (margin || @margin || 1E-8).to_f
157
- super
158
- end
159
- end
160
-
161
- #
162
- # 月の位相
163
- #
164
- class LunarPhases < LuniSolarPositions
165
-
166
- # 月の位相のための event の別名
167
- #
168
- # @return [When::TM::CalDate] date またはその直後のイベントの日時
169
- alias :phase :event
170
-
171
- private
172
-
173
- # 月の位相のための event_delta の別名
174
- alias :phase_delta :event_delta
175
-
176
- # オブジェクトの正規化
177
- # num - 月の位相/12度の分子 (デフォルト 0 - 朔)
178
- # den - 月の位相/12度の分母 (デフォルト 30 - 1月)
179
- # formula - 計算アルゴリズム(デフォルト '_ep:Formula?formula=1L')
180
- # delta - enumerator の周期 (デフォルト (den/30)月)
181
- # margin - 没滅計算用の補正 (デフォルト 1E-8)
182
- def _normalize(args=[], options={})
183
- num, den, formula, delta, margin = args
184
- @num = (num || @num || 0).to_f
185
- @den = (den || @den || 30).to_f
186
- @formula = When.Resource(formula || @formula ||'Formula?formula=1L', '_ep:')
187
- @delta = When.Duration(delta || @delta || When::TM::IntervalLength.new(@den/30, 'month'))
188
- @margin = (margin || @margin || 1E-8).to_f
189
- super
190
- end
191
- end
192
-
193
- #
194
- # 天体暦の暦注
195
- #
196
- class Ephemeris < self
197
-
198
- Notes = [When::BasicTypes::M17n, [
199
- "locale:[=en:, ja=ja:, alias=ja:]",
200
- "names:[Ephemeris]",
201
-
202
- # 年の暦注 ----------------------------
203
- [When::BasicTypes::M17n,
204
- "names:[year]"
205
- ],
206
-
207
- # 月の暦注 ----------------------------
208
- [When::BasicTypes::M17n,
209
- "names:[month]",
210
- [When::BasicTypes::M17n,
211
- "names:[Month]"
212
- ]
213
- ],
214
-
215
- # 日の暦注 ----------------------------
216
- [When::BasicTypes::M17n,
217
- "names:[day]",
218
- "[Sunrise, 日の出 ]", # 日の出
219
- "[Sunset, 日の入り ]", # 日の入り
220
- [When::Coordinates::Residue,
221
- "label:[Moon_Age=, 正午月齢=ja:%%<月齢>]",
222
- "divisor:60",
223
- "format:[%s(%4.1f)=]"
224
- ],
225
- "[Moonrise, 月の出 ]", # 月の出
226
- "[Moonset=, 月の入り ]", # 月の入り
227
- [When::BasicTypes::M17n,
228
- "names:[Tide, 潮汐]", # 満潮干潮日時
229
- "[High_Tide=en:Tide, 満潮=ja:%%<潮汐>]",
230
- "[Low_Tide=en:Tide, 干潮=ja:%%<潮汐>]"
231
- ]
232
- ]
233
- ]]
234
-
235
- #
236
- # 日の出
237
- #
238
- # @param [When::TM::TemporalPosition] date
239
- # @param [Hash] options dummy
240
- #
241
- # @return [When::TM::TemporalPosition] 日の出の時刻をイベント時刻とする
242
- #
243
- def sunrise(date, options={})
244
- event = formula(date.location.iri).sunrise(date)
245
- event.events = [@root['Sunrise']]
246
- event
247
- rescue
248
- nil
249
- end
250
-
251
- #
252
- # 日の入り
253
- #
254
- # @param [When::TM::TemporalPosition] date
255
- # @param [Hash] options dummy
256
- #
257
- # @return [When::TM::TemporalPosition] 日の入りの時刻をイベント時刻とする
258
- #
259
- def sunset(date, options={})
260
- event = formula(date.location.iri).sunset(date)
261
- event.events = [@root['Sunset']]
262
- event
263
- rescue
264
- nil
265
- end
266
-
267
- #
268
- # 正午月齢
269
- #
270
- # @param [When::TM::TemporalPosition] date
271
- # @param [Hash] options dummy
272
- #
273
- # @return [Numeric] 正午における朔からの経過日数
274
- #
275
- def moon_age(date, options={})
276
- @phase ||= When.CalendarNote('LunarPhases')
277
- noon = date.floor(When::DAY,When::SYSTEM) + 0.5
278
- @root['Moon_Age'][noon.to_f - @phase.phase(noon, [-30.0,30.0]).to_f]
279
- end
280
-
281
- #
282
- # 月の出
283
- #
284
- # @param [When::TM::TemporalPosition] date
285
- # @param [Hash] options dummy
286
- #
287
- # @return [When::TM::TemporalPosition] 月の出の時刻をイベント時刻とする
288
- #
289
- def moonrise(date, options={})
290
- event = formula(date.location.iri).moonrise(date)
291
- event.events = [@root['Moonrise']]
292
- event
293
- rescue
294
- nil
295
- end
296
-
297
- #
298
- # 月の入り
299
- #
300
- # @param [When::TM::TemporalPosition] date
301
- # @param [Hash] options dummy
302
- #
303
- # @return [When::TM::TemporalPosition] 月の入りの時刻をイベント時刻とする
304
- #
305
- def moonset(date, options={})
306
- event = formula(date.location.iri).moonset(date)
307
- event.events = [@root['Moonset']]
308
- event
309
- rescue
310
- nil
311
- end
312
-
313
- # 干潮・満潮の日時
314
- #
315
- # @param [When::TM::TemporalPosition] date
316
- # @param [Hash] options 以下の通り
317
- # @option options [String] tide 潮汐計算方式 'Horizontal' - 地平高度基準, 'Equatorial' - 子午線通過基準(デフォルト)
318
- #
319
- # @return [Array<Array<Integer, When::TM::TemporalPosotion>>] 干潮・満潮の日時の Array
320
- #
321
- # [Integer] +1:満潮, -1:干潮
322
- #
323
- # [When::TM::TemporalPosotion] 干潮・満潮の日時
324
- #
325
- #
326
- def tide(date, options={})
327
- return nil unless @interval
328
- @target ||= When.Resource('_ep:Moon')
329
- events = @root['Tide']
330
- form = formula(date.location.iri)
331
- type = options[:tide] =~ /^horizon/i ? nil : 0
332
-
333
- now = +date
334
- high_tides = []
335
- 5.times do |i|
336
- high_tide = form.day_event(now + i - 2, type, @target) + @interval
337
- high_tides << high_tide if high_tides.size == 0 || high_tide > high_tides[-1] + 0.5
338
- end
339
- tides = []
340
-
341
- (high_tides.size-1).times do |i|
342
- tides << [0, high_tides[i]]
343
- tides << [1, 0.75*high_tides[i] + 0.25*high_tides[i+1]]
344
- tides << [0, 0.50*high_tides[i] + 0.50*high_tides[i+1]]
345
- tides << [1, 0.25*high_tides[i] + 0.75*high_tides[i+1]]
346
- end
347
- tides << [0, high_tides[-1]]
348
-
349
- today = +date.floor(When::DAY)...+date.ceil(When::DAY)
350
- seed = date._attr
351
- seed[:clock] ||= When::TM::Clock.local_time
352
- tides.select {|x| today.include?(x[1])}.map {|x|
353
- d = form._to_seed_type(x[1], seed)
354
- d.events = [events[x[0]]]
355
- d
356
- }
357
- rescue
358
- nil
359
- end
360
-
361
- private
362
-
363
- # オブジェクトの正規化
364
- # long - 計算に用いる経度 / 度
365
- # lat - 計算に用いる緯度 / 度
366
- # alt - 計算に用いる高度 / m
367
- # interval - 高潮間隔(月の子午線通過から満潮までの時間) / 時間
368
- def _normalize(args=[], options={})
369
- if @location
370
- @location = When.Resource(@location)
371
- @formula = When.Resource(@formula || "Formula?location=(#{@location.iri})", '_ep:')
372
- else
373
- @formula = {}
374
- end
375
- @interval = @interval.sub('@','.').to_f / 24 if @interval
376
- @root = When.CalendarNote('Ephemeris/Notes::day')
377
- @prime ||= [%w(Month), %w(Sunrise Sunset Moon_Age)]
378
- super
379
- end
380
-
381
- # 計算に用いる Ephemeris
382
- def formula(location)
383
- return @formula unless @formula.kind_of?(Hash)
384
- @formula[location] ||= When.Resource("Formula?location=(#{location})", '_ep:')
385
- end
386
- end
387
- end
1
+ # -*- coding: utf-8 -*-
2
+ =begin
3
+ Copyright (C) 2011-2014 Takashi SUGA
4
+
5
+ You may use and/or modify this file according to the license described in the LICENSE.txt file included in this archive.
6
+ =end
7
+
8
+ #
9
+ # Ephemeris を用いる暦注
10
+ #
11
+ class When::CalendarNote
12
+ #
13
+ # 太陽と月の位置によるイベント
14
+ #
15
+ class LuniSolarPositions < self
16
+
17
+ # 座標の分子
18
+ #
19
+ # @return [Numeric]
20
+ #
21
+ attr_reader :num
22
+
23
+ # 座標の分母
24
+ #
25
+ # @return [Numeric]
26
+ #
27
+ attr_reader :den
28
+
29
+ # 計算アルゴリズム
30
+ #
31
+ # @return [When::Ephemeris::Formula]
32
+ #
33
+ attr_reader :formula
34
+
35
+ # enumerator の周期
36
+ #
37
+ # @return [Numeric]
38
+ #
39
+ attr_reader :delta
40
+
41
+ # 没滅計算用の補正
42
+ #
43
+ # @return [Numeric]
44
+ #
45
+ attr_reader :margin
46
+
47
+ # イベントの日時
48
+ #
49
+ # @param [When::TM::TemporalPosition] date イベントを探す基準とする日時
50
+ # @param [Array<Numeric>] parameter 座標の分子と分母( num, den)
51
+ #
52
+ # num 座標の分子 (デフォルト @num)
53
+ #
54
+ # den 座標の分母 (デフォルト @den)
55
+ #
56
+ # @param [String] parameter 座標の分子と分母("#{ num }/#{ den }" の形式)
57
+ # @param [Integer] precision 取得したい時間位置の分解能(デフォルト date の分解能)
58
+ #
59
+ # @return [When::TM::CalDate] date またはその直後のイベントの日時
60
+ #
61
+ def event_eval(date, parameter=@event, precision=date.precision)
62
+ num, den = parameter.kind_of?(String) ? parameter[/\d.*\z/].split(/\//, 2) : parameter
63
+ num = (num || @num).to_f
64
+ den = (den || @den).to_f
65
+ date = date.floor(precision) if precision < date.precision
66
+ options = date._attr
67
+ is_date_and_time = options.key?(:clock) || precision > When::DAY
68
+ options[:precision] = precision
69
+ options[:clock] ||= date.frame.time_basis || When::TM::Clock.local_time
70
+ quot, mod = (@formula.time_to_cn(date)*30.0).divmod(den)
71
+ cycle = quot * den + num
72
+ cycle += den if mod > (num % den)
73
+ time = When::TM::JulianDate._d_to_t(@formula.cn_to_time(cycle/30.0))
74
+ time = date.time_standard.from_dynamical_time(time) if @formula.is_dynamical
75
+ event = date.frame.jul_trans(When::TM::JulianDate.universal_time(time), options)
76
+ is_date_and_time ? event : event.to_cal_date
77
+ end
78
+
79
+ # 日付に対応する座標
80
+ #
81
+ # @param [When::TM::TemporalPosition] date 日付
82
+ # @param [Numeric] delta 周期の補正(土用の時刻の補正に使用,デフォルト 0)
83
+ #
84
+ # @return [Array<Integer>] Array< Integer, 0 or 1 or 2 >
85
+ #
86
+ # [Integer] 対応する座標
87
+ #
88
+ # [0 or 1 or 2] 座標の進み(0 なら 没, 2 なら滅)
89
+ #
90
+ def position(date, delta=0)
91
+ date = date.floor
92
+ p0, p1 = [date, date.succ].map {|d| (30.0 * @formula.time_to_cn(d) - @margin + delta).floor}
93
+ [p1 % @den, p1 - p0]
94
+ end
95
+
96
+ #
97
+ # イベントの標準的な間隔を返す
98
+ #
99
+ # @param [String] parameter 座標の分子と分母("#{ num }/#{ den }" の形式)
100
+ #
101
+ # @return [When::TM::IntervalLength]
102
+ #
103
+ # @private
104
+ def event_delta(parameter=nil)
105
+ return @delta unless parameter
106
+ num, den = parameter.kind_of?(String) ? parameter.split(/\//, 2) : parameter
107
+ When::TM::IntervalLength.new([(den || @den).to_f,1].max*0.9, 'day')
108
+ end
109
+
110
+ #
111
+ # イベント日付(時刻付)
112
+ #
113
+ # @private
114
+ def event_time(date, event_name, event)
115
+ etime = term(date - When.Duration('P3D'), event, When::SYSTEM)
116
+ if formula.respond_to?(:year_length) && formula.denominator && formula.denominator < 100000
117
+ fraction = etime.clk_time.universal_time
118
+ fraction += When::TM::Duration::DAY * (etime.to_i - date.to_i)
119
+ fraction = (fraction / When::TM::Duration::DAY * formula.denominator * 1000 + 0.5).floor / 1000.0
120
+ fraction = fraction.to_i if fraction == fraction.to_i
121
+ event_name + "(#{fraction}/#{formula.denominator})"
122
+ else
123
+ etime.events = [event_name]
124
+ etime
125
+ end
126
+ end
127
+ end
128
+
129
+ #
130
+ # 二十四節気
131
+ #
132
+ class SolarTerms < LuniSolarPositions
133
+
134
+ # 二十四節気のための event の別名
135
+ #
136
+ # @return [When::TM::CalDate] date またはその直後のイベントの日時
137
+ alias :term :event_eval
138
+
139
+ private
140
+
141
+ # 二十四節気のための event_delta の別名
142
+ alias :term_delta :event_delta
143
+
144
+ # オブジェクトの正規化
145
+ # num - 太陽黄経/度の分子 (デフォルト 0 - 春分)
146
+ # den - 太陽黄経/度の分母 (デフォルト 360 - 1年)
147
+ # formula - 計算アルゴリズム(デフォルト '_ep:Formula?formula=12S')
148
+ # delta - enumerator の周期 (デフォルト (den/360)年)
149
+ # margin - 没滅計算用の補正 (デフォルト 1E-8)
150
+ def _normalize(args=[], options={})
151
+ num, den, formula, delta, margin = args
152
+ @event ||= 'term'
153
+ @num = (num || @num || 0).to_f
154
+ @den = (den || @den || 360).to_f
155
+ @formula = When.Resource(formula || @formula ||'Formula?formula=12S', '_ep:')
156
+ @delta = When.Duration(delta || @delta || When::TM::IntervalLength.new(@den/360, 'year'))
157
+ @margin = (margin || @margin || 1E-8).to_f
158
+ super
159
+ end
160
+ end
161
+
162
+ #
163
+ # 月の位相
164
+ #
165
+ class LunarPhases < LuniSolarPositions
166
+
167
+ # 月の位相のための event の別名
168
+ #
169
+ # @return [When::TM::CalDate] date またはその直後のイベントの日時
170
+ alias :phase :event_eval
171
+
172
+ private
173
+
174
+ # 月の位相のための event_delta の別名
175
+ alias :phase_delta :event_delta
176
+
177
+ # オブジェクトの正規化
178
+ # num - 月の位相/12度の分子 (デフォルト 0 - )
179
+ # den - 月の位相/12度の分母 (デフォルト 30 - 1月)
180
+ # formula - 計算アルゴリズム(デフォルト '_ep:Formula?formula=1L')
181
+ # delta - enumerator の周期 (デフォルト (den/30)月)
182
+ # margin - 没滅計算用の補正 (デフォルト 1E-8)
183
+ def _normalize(args=[], options={})
184
+ num, den, formula, delta, margin = args
185
+ @event ||= 'phase'
186
+ @num = (num || @num || 0).to_f
187
+ @den = (den || @den || 30).to_f
188
+ @formula = When.Resource(formula || @formula ||'Formula?formula=1L', '_ep:')
189
+ @delta = When.Duration(delta || @delta || When::TM::IntervalLength.new(@den/30, 'month'))
190
+ @margin = (margin || @margin || 1E-8).to_f
191
+ super
192
+ end
193
+ end
194
+
195
+ #
196
+ # 天体暦の暦注
197
+ #
198
+ class Ephemeris < self
199
+
200
+ Notes = [When::BasicTypes::M17n, [
201
+ "locale:[=en:, ja=ja:, alias=ja:]",
202
+ "names:[Ephemeris]",
203
+
204
+ # 年の暦注 ----------------------------
205
+ [When::BasicTypes::M17n,
206
+ "names:[year]"
207
+ ],
208
+
209
+ # 月の暦注 ----------------------------
210
+ [When::BasicTypes::M17n,
211
+ "names:[month]",
212
+ [When::BasicTypes::M17n,
213
+ "names:[Month]"
214
+ ]
215
+ ],
216
+
217
+ # 日の暦注 ----------------------------
218
+ [When::BasicTypes::M17n,
219
+ "names:[day]",
220
+ "[Sunrise, 日の出 ]", # 日の出
221
+ "[Sunset, 日の入り ]", # 日の入り
222
+ [When::Coordinates::Residue,
223
+ "label:[Moon_Age=, 正午月齢=ja:%%<月齢>]",
224
+ "divisor:60",
225
+ "format:[%s(%4.1f)=]"
226
+ ],
227
+ "[Moonrise, 月の出 ]", # 月の出
228
+ "[Moonset=, 月の入り ]", # 月の入り
229
+ [When::BasicTypes::M17n,
230
+ "names:[Tide, 潮汐]", # 満潮干潮日時
231
+ "[High_Tide=en:Tide, 満潮=ja:%%<潮汐>]",
232
+ "[Low_Tide=en:Tide, 干潮=ja:%%<潮汐>]"
233
+ ]
234
+ ]
235
+ ]]
236
+
237
+ #
238
+ # 日の出
239
+ #
240
+ # @param [When::TM::TemporalPosition] date
241
+ # @param [Hash] options dummy
242
+ #
243
+ # @return [When::TM::TemporalPosition] 日の出の時刻をイベント時刻とする
244
+ #
245
+ def sunrise(date, options={})
246
+ event = formula(date.location.iri).sunrise(date)
247
+ event.events = [@root['Sunrise']]
248
+ event
249
+ rescue
250
+ nil
251
+ end
252
+
253
+ #
254
+ # 日の入り
255
+ #
256
+ # @param [When::TM::TemporalPosition] date
257
+ # @param [Hash] options dummy
258
+ #
259
+ # @return [When::TM::TemporalPosition] 日の入りの時刻をイベント時刻とする
260
+ #
261
+ def sunset(date, options={})
262
+ event = formula(date.location.iri).sunset(date)
263
+ event.events = [@root['Sunset']]
264
+ event
265
+ rescue
266
+ nil
267
+ end
268
+
269
+ #
270
+ # 正午月齢
271
+ #
272
+ # @param [When::TM::TemporalPosition] date
273
+ # @param [Hash] options dummy
274
+ #
275
+ # @return [Numeric] 正午における朔からの経過日数
276
+ #
277
+ def moon_age(date, options={})
278
+ @phase ||= When.CalendarNote('LunarPhases')
279
+ noon = date.floor(When::DAY,When::SYSTEM) + 0.5
280
+ @root['Moon_Age'][noon.to_f - @phase.phase(noon, [-30.0,30.0]).to_f]
281
+ end
282
+
283
+ #
284
+ # 月の出
285
+ #
286
+ # @param [When::TM::TemporalPosition] date
287
+ # @param [Hash] options dummy
288
+ #
289
+ # @return [When::TM::TemporalPosition] 月の出の時刻をイベント時刻とする
290
+ #
291
+ def moonrise(date, options={})
292
+ event = formula(date.location.iri).moonrise(date)
293
+ event.events = [@root['Moonrise']]
294
+ event
295
+ rescue
296
+ nil
297
+ end
298
+
299
+ #
300
+ # 月の入り
301
+ #
302
+ # @param [When::TM::TemporalPosition] date
303
+ # @param [Hash] options dummy
304
+ #
305
+ # @return [When::TM::TemporalPosition] 月の入りの時刻をイベント時刻とする
306
+ #
307
+ def moonset(date, options={})
308
+ event = formula(date.location.iri).moonset(date)
309
+ event.events = [@root['Moonset']]
310
+ event
311
+ rescue
312
+ nil
313
+ end
314
+
315
+ # 干潮・満潮の日時
316
+ #
317
+ # @param [When::TM::TemporalPosition] date
318
+ # @param [Hash] options 以下の通り
319
+ # @option options [String] tide 潮汐計算方式 'Horizontal' - 地平高度基準, 'Equatorial' - 子午線通過基準(デフォルト)
320
+ #
321
+ # @return [Array<Array<Integer, When::TM::TemporalPosotion>>] 干潮・満潮の日時の Array
322
+ #
323
+ # [Integer] +1:満潮, -1:干潮
324
+ #
325
+ # [When::TM::TemporalPosotion] 干潮・満潮の日時
326
+ #
327
+ #
328
+ def tide(date, options={})
329
+ return nil unless @interval
330
+ @target ||= When.Resource('_ep:Moon')
331
+ events = @root['Tide']
332
+ form = formula(date.location.iri)
333
+ type = options[:tide] =~ /\Ahorizon/i ? nil : 0
334
+
335
+ now = +date
336
+ high_tides = []
337
+ 5.times do |i|
338
+ high_tide = form.day_event(now + i - 2, type, @target) + @interval
339
+ high_tides << high_tide if high_tides.size == 0 || high_tide > high_tides[-1] + 0.5
340
+ end
341
+ tides = []
342
+
343
+ (high_tides.size-1).times do |i|
344
+ tides << [0, high_tides[i]]
345
+ tides << [1, 0.75*high_tides[i] + 0.25*high_tides[i+1]]
346
+ tides << [0, 0.50*high_tides[i] + 0.50*high_tides[i+1]]
347
+ tides << [1, 0.25*high_tides[i] + 0.75*high_tides[i+1]]
348
+ end
349
+ tides << [0, high_tides[-1]]
350
+
351
+ today = +date.floor(When::DAY)...+date.ceil(When::DAY)
352
+ seed = date._attr
353
+ seed[:clock] ||= When::TM::Clock.local_time
354
+ tides.select {|x| today.include?(x[1])}.map {|x|
355
+ d = form._to_seed_type(x[1], seed)
356
+ d.events = [events[x[0]]]
357
+ d
358
+ }
359
+ rescue
360
+ nil
361
+ end
362
+
363
+ private
364
+
365
+ # オブジェクトの正規化
366
+ # long - 計算に用いる経度 /
367
+ # lat - 計算に用いる緯度 /
368
+ # alt - 計算に用いる高度 / m
369
+ # interval - 高潮間隔(月の子午線通過から満潮までの時間) / 時間
370
+ def _normalize(args=[], options={})
371
+ if @location
372
+ @location = When.Resource(@location)
373
+ @formula = When.Resource(@formula || "Formula?location=(#{@location.iri})", '_ep:')
374
+ else
375
+ @formula = {}
376
+ end
377
+ @interval = @interval.sub('@','.').to_f / 24 if @interval
378
+ @root = When.CalendarNote('Ephemeris/Notes::day')
379
+ @prime ||= [%w(Month), %w(Sunrise Sunset Moon_Age)]
380
+ super
381
+ end
382
+
383
+ # 計算に用いる Ephemeris
384
+ def formula(location)
385
+ return @formula unless @formula.kind_of?(Hash)
386
+ @formula[location] ||= When.Resource("Formula?location=(#{location})", '_ep:')
387
+ end
388
+ end
389
+ end