when_exe 0.2.100 → 0.3.1

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 (193) hide show
  1. data/LICENSE.ja.txt +25 -25
  2. data/LICENSE.txt +31 -31
  3. data/bin/irb.rc +5 -0
  4. data/bin/locales.rb +2 -2
  5. data/bin/when.rb +16 -0
  6. data/bin/when.rb.config +7 -0
  7. data/lib/when_exe.rb +616 -14
  8. data/lib/when_exe/basictypes.rb +615 -0
  9. data/lib/when_exe/calendartypes.rb +1700 -0
  10. data/lib/when_exe/coordinates.rb +1936 -0
  11. data/lib/when_exe/core/compatibility.rb +54 -0
  12. data/lib/when_exe/core/duration.rb +72 -72
  13. data/lib/when_exe/core/extension.rb +382 -0
  14. data/lib/when_exe/ephemeris.rb +1845 -0
  15. data/lib/when_exe/googlecalendar.rb +140 -0
  16. data/lib/when_exe/icalendar.rb +1587 -0
  17. data/lib/when_exe/inspect.rb +1237 -0
  18. data/lib/when_exe/locales/af.rb +90 -0
  19. data/lib/when_exe/locales/ar.rb +145 -0
  20. data/lib/when_exe/locales/az.rb +90 -0
  21. data/lib/when_exe/locales/bg.rb +90 -0
  22. data/lib/when_exe/locales/bn.rb +94 -0
  23. data/lib/when_exe/locales/bs.rb +121 -0
  24. data/lib/when_exe/locales/ca.rb +92 -0
  25. data/lib/when_exe/locales/cs.rb +107 -0
  26. data/lib/when_exe/locales/cy.rb +150 -0
  27. data/lib/when_exe/locales/da.rb +84 -0
  28. data/lib/when_exe/locales/de.rb +92 -0
  29. data/lib/when_exe/locales/de_AT.rb +92 -0
  30. data/lib/when_exe/locales/de_CH.rb +92 -0
  31. data/lib/when_exe/locales/el.rb +93 -0
  32. data/lib/when_exe/locales/en.rb +88 -0
  33. data/lib/when_exe/locales/en_AU.rb +88 -0
  34. data/lib/when_exe/locales/en_CA.rb +88 -0
  35. data/lib/when_exe/locales/en_GB.rb +88 -0
  36. data/lib/when_exe/locales/en_IN.rb +88 -0
  37. data/lib/when_exe/locales/en_NZ.rb +88 -0
  38. data/lib/when_exe/locales/eo.rb +89 -0
  39. data/lib/when_exe/locales/es.rb +84 -0
  40. data/lib/when_exe/locales/es_419.rb +84 -0
  41. data/lib/when_exe/locales/es_AR.rb +84 -0
  42. data/lib/when_exe/locales/es_CL.rb +84 -0
  43. data/lib/when_exe/locales/es_CO.rb +84 -0
  44. data/lib/when_exe/locales/es_MX.rb +84 -0
  45. data/lib/when_exe/locales/es_PE.rb +85 -0
  46. data/lib/when_exe/locales/es_VE.rb +84 -0
  47. data/lib/when_exe/locales/et.rb +94 -0
  48. data/lib/when_exe/locales/eu.rb +95 -0
  49. data/lib/when_exe/locales/fa.rb +80 -0
  50. data/lib/when_exe/locales/fi.rb +89 -0
  51. data/lib/when_exe/locales/fr.rb +88 -0
  52. data/lib/when_exe/locales/fr_CA.rb +88 -0
  53. data/lib/when_exe/locales/fr_CH.rb +88 -0
  54. data/lib/when_exe/locales/gl.rb +81 -0
  55. data/lib/when_exe/locales/he.rb +84 -0
  56. data/lib/when_exe/locales/hi.rb +80 -0
  57. data/lib/when_exe/locales/hi_IN.rb +84 -0
  58. data/lib/when_exe/locales/hr.rb +128 -0
  59. data/lib/when_exe/locales/hu.rb +84 -0
  60. data/lib/when_exe/locales/id.rb +89 -0
  61. data/lib/when_exe/locales/is.rb +89 -0
  62. data/lib/when_exe/locales/it.rb +87 -0
  63. data/lib/when_exe/locales/it_CH.rb +87 -0
  64. data/lib/when_exe/locales/ja.rb +78 -0
  65. data/lib/when_exe/locales/kn.rb +86 -0
  66. data/lib/when_exe/locales/ko.rb +78 -0
  67. data/lib/when_exe/locales/links.rb +2342 -0
  68. data/lib/when_exe/locales/lo.rb +123 -0
  69. data/lib/when_exe/locales/locales.rb +91 -0
  70. data/lib/when_exe/locales/lt.rb +111 -0
  71. data/lib/when_exe/locales/lv.rb +118 -0
  72. data/lib/when_exe/locales/mk.rb +93 -0
  73. data/lib/when_exe/locales/mn.rb +80 -0
  74. data/lib/when_exe/locales/nb.rb +81 -0
  75. data/lib/when_exe/locales/ne.rb +81 -0
  76. data/lib/when_exe/locales/nl.rb +92 -0
  77. data/lib/when_exe/locales/nn.rb +73 -0
  78. data/lib/when_exe/locales/or.rb +84 -0
  79. data/lib/when_exe/locales/pl.rb +128 -0
  80. data/lib/when_exe/locales/pt.rb +88 -0
  81. data/lib/when_exe/locales/pt_BR.rb +88 -0
  82. data/lib/when_exe/locales/rm.rb +143 -0
  83. data/lib/when_exe/locales/ro.rb +105 -0
  84. data/lib/when_exe/locales/ru.rb +128 -0
  85. data/lib/when_exe/locales/sk.rb +109 -0
  86. data/lib/when_exe/locales/sl.rb +122 -0
  87. data/lib/when_exe/locales/sr.rb +122 -0
  88. data/lib/when_exe/locales/sv.rb +83 -0
  89. data/lib/when_exe/locales/sw.rb +89 -0
  90. data/lib/when_exe/locales/th.rb +78 -0
  91. data/lib/when_exe/locales/tl.rb +99 -0
  92. data/lib/when_exe/locales/tr.rb +96 -0
  93. data/lib/when_exe/locales/uk.rb +128 -0
  94. data/lib/when_exe/locales/uz.rb +128 -0
  95. data/lib/when_exe/locales/vi.rb +94 -0
  96. data/lib/when_exe/locales/wo.rb +82 -0
  97. data/lib/when_exe/locales/zh_CN.rb +77 -0
  98. data/lib/when_exe/locales/zh_HK.rb +77 -0
  99. data/lib/when_exe/locales/zh_TW.rb +77 -0
  100. data/lib/when_exe/mini_application.rb +252 -0
  101. data/lib/when_exe/parts/enumerator.rb +472 -0
  102. data/lib/when_exe/parts/geometric_complex.rb +379 -0
  103. data/lib/when_exe/parts/locale.rb +513 -0
  104. data/lib/when_exe/parts/method_cash.rb +207 -0
  105. data/lib/when_exe/parts/resource.rb +806 -0
  106. data/lib/when_exe/parts/timezone.rb +182 -0
  107. data/lib/when_exe/region/bahai.rb +145 -0
  108. data/lib/when_exe/region/balinese.rb +627 -0
  109. data/lib/when_exe/region/chinese.rb +896 -0
  110. data/lib/when_exe/region/chinese_calendar.rb +919 -0
  111. data/lib/when_exe/region/chinese_epoch.rb +1245 -0
  112. data/lib/when_exe/region/christian.rb +644 -0
  113. data/lib/when_exe/region/far_east.rb +192 -0
  114. data/lib/when_exe/region/french.rb +66 -0
  115. data/lib/when_exe/region/geologicalage.rb +639 -0
  116. data/lib/when_exe/region/indian.rb +1066 -0
  117. data/lib/when_exe/region/iranian.rb +66 -0
  118. data/lib/when_exe/region/islamic.rb +105 -0
  119. data/lib/when_exe/region/japanese.rb +851 -0
  120. data/lib/when_exe/region/japanese_notes.rb +964 -0
  121. data/lib/when_exe/region/japanese_residues.rb +1149 -0
  122. data/lib/when_exe/region/javanese.rb +228 -0
  123. data/lib/when_exe/region/jewish.rb +127 -0
  124. data/lib/when_exe/region/korean.rb +267 -0
  125. data/lib/when_exe/region/m17n.rb +115 -0
  126. data/lib/when_exe/region/martian.rb +215 -0
  127. data/lib/when_exe/region/mayan.rb +122 -0
  128. data/lib/when_exe/region/moon.rb +333 -0
  129. data/lib/when_exe/region/nihon_shoki.rb +73 -0
  130. data/lib/when_exe/region/planets.rb +585 -0
  131. data/lib/when_exe/region/pope.rb +298 -0
  132. data/lib/when_exe/region/residue.rb +229 -0
  133. data/lib/when_exe/region/roman.rb +325 -0
  134. data/lib/when_exe/region/ryukyu.rb +98 -0
  135. data/lib/when_exe/region/shire.rb +254 -0
  136. data/lib/when_exe/region/sun.rb +210 -0
  137. data/lib/when_exe/region/thai.rb +227 -0
  138. data/lib/when_exe/region/tibetan.rb +233 -0
  139. data/lib/when_exe/region/v50.rb +111 -0
  140. data/lib/when_exe/region/vietnamese.rb +173 -0
  141. data/lib/when_exe/region/world.rb +197 -0
  142. data/lib/when_exe/timestandard.rb +547 -0
  143. data/lib/when_exe/tmduration.rb +330 -330
  144. data/lib/when_exe/tmobjects.rb +1295 -0
  145. data/lib/when_exe/tmposition.rb +1955 -0
  146. data/lib/when_exe/tmreference.rb +1547 -0
  147. data/lib/when_exe/version.rb +10 -3
  148. data/link_to_online_documents +4 -0
  149. data/test/examples/JapanHolidays.ics +456 -0
  150. data/test/examples/Millennium.ics +17 -0
  151. data/test/examples/NewYork.ics +61 -0
  152. data/test/examples/Residue.m17n +135 -0
  153. data/test/examples/Spatial.m17n +179 -0
  154. data/test/examples/Terms.m17n +39 -0
  155. data/test/examples/Test.ics +53 -0
  156. data/test/examples/USA-DST.ics +61 -0
  157. data/test/examples/geometric_complex.rb +41 -0
  158. data/test/examples/sample.xml +14 -0
  159. data/test/examples/today.rb +61 -0
  160. data/test/test.rb +54 -19
  161. data/test/test.rb.config +1 -0
  162. data/test/test/basictypes.rb +368 -0
  163. data/test/test/calendartypes.rb +57 -0
  164. data/test/test/coordinates.rb +380 -0
  165. data/test/test/ephemeris.rb +127 -0
  166. data/test/test/googlecalendar.rb +167 -0
  167. data/test/test/icalendar.rb +848 -0
  168. data/test/test/inspect.rb +115 -0
  169. data/test/test/parts.rb +480 -0
  170. data/test/test/region/chinese.rb +161 -0
  171. data/test/test/region/french.rb +33 -0
  172. data/test/test/region/geologicalage.rb +14 -0
  173. data/test/test/region/indian.rb +55 -0
  174. data/test/test/region/iran.rb +54 -0
  175. data/test/test/region/islamic.rb +18 -0
  176. data/test/test/region/japanese.rb +62 -0
  177. data/test/test/region/jewish.rb +61 -0
  178. data/test/test/region/m17n.rb +181 -0
  179. data/test/test/region/mayan.rb +78 -0
  180. data/test/test/region/moon.rb +14 -0
  181. data/test/test/region/planets.rb +14 -0
  182. data/test/test/region/residue.rb +123 -0
  183. data/test/test/region/sun.rb +14 -0
  184. data/test/test/region/thai.rb +94 -0
  185. data/test/test/region/tibetan.rb +30 -0
  186. data/test/test/tmobjects.rb +356 -57
  187. data/test/test/tmposition.rb +237 -0
  188. data/test/test/tmreference.rb +95 -0
  189. data/when_exe.gemspec +2 -2
  190. metadata +187 -7
  191. data/doc/COPYING +0 -31
  192. data/doc/COPYING.ja +0 -25
  193. data/doc/document_url +0 -1
@@ -0,0 +1,1700 @@
1
+ # -*- coding: utf-8 -*-
2
+ =begin
3
+ Copyright (C) 2011-2013 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
+ autoload :Rational, 'Rational' unless Object.const_defined?(:Rational)
9
+
10
+ #
11
+ # 具体的な When::TM::ReferenceSystem のサブクラスの実装
12
+ #
13
+ module When::CalendarTypes
14
+
15
+ #
16
+ # Universal Time, Coordinated
17
+ #
18
+ class UTC < When::TM::Clock
19
+
20
+ # この時法の時刻をUTC時刻に変換する
21
+ #
22
+ # Description of an operation for
23
+ # converting a time on this clock to a UTC time
24
+ #
25
+ # @param [When::TM::ClockTime] u_time
26
+ # @return [When::TM::ClockTime]
27
+ #
28
+ def utc_trans(u_time)
29
+ return u_time
30
+ end
31
+ alias :utcTrans :utc_trans
32
+
33
+ # UTC時刻をこの時法の時刻に変換する
34
+ #
35
+ # Description of an operation for
36
+ # converting a UTC time to a time on this clock
37
+ #
38
+ # @param [When::TM::ClockTime] clk_time
39
+ # @return [When::TM::ClockTime]
40
+ #
41
+ def clk_trans(clk_time)
42
+ return clk_time
43
+ end
44
+ alias :clkTrans :clk_trans
45
+
46
+ #
47
+ # Zone 名
48
+ #
49
+ # @return [String]
50
+ #
51
+ def zone
52
+ @label.to_s
53
+ end
54
+
55
+ private
56
+
57
+ # オブジェクトの正規化
58
+ def _normalize(args=[], options={})
59
+ @label ||= m17n('Z')
60
+ @indices ||= When::Coordinates::DefaultTimeIndex
61
+ @note ||= 'JulianDayNotes'
62
+ _normalize_temporal
63
+ @second = (@second||128).to_f
64
+ @zone = '+00:00'
65
+ @time_standard ||= When.Resource('_t:UniversalTime')
66
+ @utc_reference = When::TM::ClockTime.new([0,0,0,0], {:frame=>self})
67
+ end
68
+ end
69
+
70
+ #
71
+ # Local Mean Time
72
+ #
73
+ class LMT < UTC
74
+
75
+ private
76
+
77
+ # オブジェクトの正規化
78
+ def _normalize(args=[], options={})
79
+ @label = m17n('LMT')
80
+ @time_standard = When.Resource("_t:LocalMeanTime?location=_l:long=#{@long||0}%26lat=0")
81
+ super
82
+ end
83
+ end
84
+
85
+ #
86
+ # Local Apparent Time
87
+ #
88
+ class LAT < UTC
89
+
90
+ private
91
+
92
+ # オブジェクトの正規化
93
+ def _normalize(args=[], options={})
94
+ @label = m17n('LAT')
95
+ @time_standard = When.Resource("_t:LocalApparentTime?location=_l:long=#{@long||0}%26lat=0")
96
+ super
97
+ end
98
+ end
99
+
100
+ #
101
+ # Temporal Hour System
102
+ #
103
+ class THS < UTC
104
+
105
+ private
106
+
107
+ # オブジェクトの正規化
108
+ def _normalize(args=[], options={})
109
+ @label = m17n('THS')
110
+ @time_standard = When.Resource("_t:TemporalHourSystem?location=_l:long=#{@long||0}%26lat=#{@lat||0}")
111
+ super
112
+ end
113
+ end
114
+
115
+ # 月日の配当パターンの種類が限定されている暦の抽象基底クラス
116
+ #
117
+ # Calendar which has some fixed arrangement rules for under year
118
+ #
119
+ # 新年の日付が専用メソッドで与えられ、月日の配当が1年の日数等
120
+ # で決まる暦。いわゆる Rule-Based な暦はほとんど該当します。
121
+ class TableBased < When::TM::Calendar
122
+
123
+ # 年月日 -> 通日
124
+ #
125
+ # @param [Numeric] y 年
126
+ # @param [Integer] m 月 (0 始まり)
127
+ # @param [Integer] d 日 (0 始まり)
128
+ #
129
+ # @return [Integer] 通日
130
+ #
131
+ def _coordinates_to_number(y, m, d)
132
+ sdn = _sdn([+y])
133
+ rule = _rule(_key([+y]))
134
+ sdn += d + rule['Offset'][m]
135
+ return sdn if d >= 0
136
+ return sdn + rule['Length'][m % rule['Length'].length]
137
+ end
138
+
139
+ # 通日 - > 年月日
140
+ #
141
+ # @param [Integer] sdn 通日
142
+ #
143
+ # @return [Array<Integer>] [ y, m, d ]
144
+ # y 年
145
+ # m 月 (0 始まり)
146
+ # d 日 (0 始まり)
147
+ #
148
+ def _number_to_coordinates(sdn)
149
+ y, d = Residue.mod(sdn) {|n| _sdn([n])}
150
+ rule = _rule(_key([y]))
151
+ (rule['Months']-1).downto(0) do |m|
152
+ if d >=rule['Offset'][m]
153
+ d -= rule['Offset'][m]
154
+ return [y, m, d]
155
+ end
156
+ end
157
+ return nil
158
+ end
159
+
160
+ # 暦要素数
161
+ #
162
+ # @overload _length(date)
163
+ # @param [Array<Integer>] date ( y )
164
+ #
165
+ # y 年
166
+ #
167
+ # @return [Integer] その年の月数
168
+ #
169
+ # @overload _length(date)
170
+ # @param [Array<Integer>] date ( y, m )
171
+ #
172
+ # y 年
173
+ #
174
+ # m 月 (0 始まり)
175
+ #
176
+ # @return [Integer] その年月の日数
177
+ #
178
+ def _length(date)
179
+ y, m = date
180
+ if (m)
181
+ # 指定した月に含まれる日の数を返します。
182
+ return @unit[2] if @unit[2]
183
+ rule = _rule(_key([y]))
184
+ return rule['Length'][m % rule['Length'].length]
185
+ else
186
+ # 指定した年に含まれる月の数を返します。
187
+ return @unit[1] if @unit[1]
188
+ return _rule(_key([y]))['Months']
189
+ end
190
+ end
191
+
192
+ private
193
+
194
+ # オブジェクトの正規化
195
+ def _normalize(args=[], options={})
196
+ super
197
+
198
+ # rule_table
199
+ # @rule_table = @rule_table.dup
200
+ @rule_table = {'T' => {'Rule' => @rule_table }} if (@rule_table.kind_of?(Array))
201
+ @_m_cash_ = {}
202
+ @_m_cash_["_rule"] = @rule_table
203
+
204
+ # unit length
205
+ unit = @unit[1..2]
206
+ @rule_table.each do |key, rule|
207
+ _make_rule(key, rule, unit) if rule.kind_of?(Hash)
208
+ end
209
+
210
+ # mean month length
211
+ if @entry_key
212
+ ::Rational
213
+ @mean_month = Rational(@rule_table[@entry_key]['Days'], @rule_table[@entry_key]['Months'])
214
+ @mean_year = Rational(@rule_table[@entry_key]['Days'], @rule_table[@entry_key]['Years' ])
215
+ end
216
+ end
217
+
218
+ # rule の正規化
219
+ def _make_rule(key, rule, unit=[])
220
+ # @rule_table[key]['Years', 'Months', 'Offset', 'Days']
221
+ rule['IDs'] = Pair._en_pair_array(rule['IDs']) if rule['IDs'].kind_of?(String)
222
+ rule['Years'] ||= 1
223
+ rule['Months'] ||= (rule['IDs']||rule['Length']).length
224
+ rule['Offset'] = []
225
+ sum, len = 0, rule['Length'].length
226
+ rule['Months'].times do |k|
227
+ rule['Offset'] << sum
228
+ sum += rule['Length'][k % len]
229
+ end
230
+ rule['Days'] ||= sum
231
+
232
+ # Months in Year
233
+ unit[0] ||= rule['Months']
234
+ unit[0] = 0 unless (unit[0]==rule['Months'])
235
+
236
+ # Days in Month
237
+ len = rule['Length'][0]
238
+ if rule['Length'].length == 1 && (rule['Days'] % len) == 0
239
+ unit[1] ||= len
240
+ unit[1] = 0 unless (unit[1]==len)
241
+ else
242
+ unit[1] = 0
243
+ end
244
+ end
245
+
246
+ # 年初の通日によるセットアップ
247
+ def _sdn_setup(c_key, c_date)
248
+ n_date = c_date.dup
249
+ n_date[-1] += 1
250
+ n_key = (n_date.length<=1) ? n_date[0] : n_date
251
+ c_sdn = (@_m_cash_["_sdn"][c_key] ||= _sdn_(c_date))
252
+ n_sdn = (@_m_cash_["_sdn"][n_key] ||= _sdn_(n_date))
253
+ key = n_sdn - c_sdn
254
+ rule = (@_m_cash_["_rule"][key] ||= _rule_(key))
255
+ @_m_cash_["_key"] ||= {}
256
+ @_m_cash_["_ids"] ||= {}
257
+ @_m_cash_["_key"][c_key] ||= key
258
+ @_m_cash_["_ids"][c_key] ||= rule['IDs']
259
+ return c_sdn
260
+ end
261
+
262
+ # 年初の通日
263
+ # このメソッドは subclass で定義します
264
+ #
265
+ # @param [Array<Numeric>] date ( 年 )
266
+ #
267
+ # @return [Integer] 年初の通日
268
+ #
269
+ def _sdn_(date)
270
+ raise TypeError, "Abstract TableBased Calendar Type"
271
+ end
272
+
273
+ # 暦日表のキー取得
274
+ #
275
+ # @param [Array<Numeric>] date ( 年 )
276
+ #
277
+ # @return [Integer] 暦日表のキー 本暦法では当該年の日数を暦日表のキーとします
278
+ #
279
+ def _key_(date)
280
+ n_date = date.dup
281
+ n_date[-1] += 1
282
+ _sdn(n_date) - _sdn(date)
283
+ end
284
+
285
+ # 日時要素の翻訳表の取得
286
+ #
287
+ # @param [Array<Numeric>] date ( 年 )
288
+ #
289
+ # @return [Array<When::Coordinates::Pair>] 日時要素の翻訳表
290
+ #
291
+ def _ids_(date)
292
+ _rule(_key(date))['IDs']
293
+ end
294
+
295
+ # 暦要素数
296
+ #
297
+ # @param [Array<Numeric>] date ( 年 )
298
+ #
299
+ # @return [Integer] その年の日数
300
+ #
301
+ def _sum_(date)
302
+ return _rule(_key([date[0]]))['Days']
303
+ end
304
+
305
+ # 月日の配当
306
+ #
307
+ # @param [Numeric] year 年
308
+ #
309
+ # @return [Array<Integer>] [ 月の日数 ]
310
+ #
311
+ def month_arrangement_(year)
312
+ _rule(_key([year * 1 - @origin_of_MSC]))['Length']
313
+ end
314
+
315
+ # rule の遅延生成
316
+ def _rule_(key)
317
+ rule = {
318
+ 'Years' => 1,
319
+ 'Months' => key.length,
320
+ 'Days' => key.length * 29 + key.gsub(/[a-z]/,'').length,
321
+ 'IDs' => [],
322
+ 'Length' => [],
323
+ 'Offset' => []
324
+ }
325
+
326
+ key.length.times do |k|
327
+ rule['Length'] << (key[k,1] =~ /[a-z]/ ? 29 : 30)
328
+ rule['Offset'] << (k == 0 ? 0 : rule['Offset'][k-1]+rule['Length'][k-1])
329
+ trunk = key.upcase[k]
330
+ branch = (trunk == key.upcase[k-1]) ? 1 : 0
331
+ trunk = trunk.ord if (trunk.kind_of?(String))
332
+ trunk -= 64
333
+ rule['IDs'] << ((branch==0) ? trunk : When::Coordinates::Pair.new(trunk, branch))
334
+ end
335
+ return rule
336
+ end
337
+ end
338
+
339
+ # 表引きにより実現する太陰太陽暦
340
+ #
341
+ # Luni-Solar calendar which uses year / month /day table
342
+ #
343
+ class PatternTableBasedLuniSolar < TableBased
344
+
345
+ private
346
+
347
+ # new で指定された月日配当規則をプログラムで利用可能にします。
348
+ #
349
+ # key 年月日配当規則のハッシュキー
350
+ # rule 年月日配当規則
351
+ #
352
+ # インスタンス変数 ハッシュのハッシュ@rule_table の要素
353
+ # Years => the period length / year
354
+ # Months => the period length / month
355
+ # Days => the period length / day
356
+ # Rule => Array of sub rules' key and offset
357
+ def _make_rule(key, rule, unit=nil)
358
+
359
+ mm, dd = 0, 0
360
+ rule['Rule'].each_index do |k|
361
+ subkey = rule['Rule'][k]
362
+ case subkey
363
+ when String ; rule['Rule'][k] = [subkey, dd, mm]
364
+ when Array ; subkey, dd, mm = rule['Rule'][k]
365
+ else ; raise TypeError, "Irregal subkey type"
366
+ end
367
+ mm += subkey.length
368
+ dd += subkey.length * 29 + subkey.gsub(/[a-z]/,'').length
369
+ end
370
+
371
+ rule['Years'] ||= rule['Rule'].length
372
+ rule['Months'] ||= mm
373
+ rule['Days'] ||= dd
374
+
375
+ @entry_key ||= key
376
+ end
377
+
378
+ # 年初の通日によるセットアップ
379
+ def _sdn_setup(c_key, c_date)
380
+ root_rule = @rule_table[@entry_key]
381
+ count, year = c_date[0].divmod(root_rule['Years'])
382
+ key, dd, mm = root_rule['Rule'][year]
383
+ rule = (@_m_cash_["_rule"][key] ||= _rule_(key))
384
+ @_m_cash_["_key"] ||= {}
385
+ @_m_cash_["_ids"] ||= {}
386
+ @_m_cash_["_key"][c_key] ||= key
387
+ @_m_cash_["_ids"][c_key] ||= rule['IDs']
388
+ @_m_cash_["_sdn"][c_key] ||= @origin_of_LSC + dd + count * root_rule['Days']
389
+ end
390
+
391
+ # 年初の通日
392
+ #
393
+ # @param [Array<Numeric>] date ( y )
394
+ #
395
+ # y 年
396
+ #
397
+ # @return [Integer] 年初の通日
398
+ #
399
+ def _sdn_(date)
400
+ rule = @rule_table[@entry_key]
401
+ count, year = date[0].divmod(rule['Years'])
402
+ return @origin_of_LSC + rule['Rule'][year][1] + count * rule['Days']
403
+ end
404
+
405
+ # 暦日表のキー取得
406
+ #
407
+ # @param [Array<Numeric>] date ( y )
408
+ #
409
+ # y 年
410
+ #
411
+ # @return [Integer] 暦日表のキー
412
+ #
413
+ def _key_(date)
414
+ rule = @rule_table[@entry_key]
415
+ count, year = date[0].divmod(rule['Years'])
416
+ return rule['Rule'][year][0]
417
+ end
418
+
419
+ # オブジェクトの正規化
420
+ #
421
+ # @note インスタンス変数 @note は to_a でデフォルトとして用いる暦注
422
+ #
423
+ def _normalize(args=[], options={})
424
+ @note ||= When.CalendarNote('ChineseNotes') # See when.rb
425
+ super
426
+ end
427
+ end
428
+
429
+ # 年の配当パターンが限定されている暦
430
+ #
431
+ # Calendar which has some fixed arrangement rules of year pattern
432
+ #
433
+ class CyclicTableBased < TableBased
434
+
435
+ # 通日 - > 年月日
436
+ #
437
+ # @param [Integer] sdn 通日
438
+ #
439
+ # @return [Array<Integer>] [ y, m, d ]
440
+ # y 年
441
+ # m 月 (0 始まり)
442
+ # d 日 (0 始まり)
443
+ #
444
+ def _number_to_coordinates(sdn)
445
+ root_rule = @rule_table[@entry_key]
446
+ count, value = (sdn-@origin_of_LSC).divmod(root_rule['Days'])
447
+ y, d, key = _read_period(@entry_key,
448
+ 'Days', value,
449
+ 'Years', count * root_rule['Years'])
450
+ rule = _rule(key)
451
+ (rule['Months']-1).downto(0) do |m|
452
+ if d >=rule['Offset'][m]
453
+ d -= rule['Offset'][m]
454
+ return [y, m, d]
455
+ end
456
+ end
457
+ return nil
458
+ end
459
+
460
+ private
461
+
462
+ #
463
+ # new で指定された月日配当規則をプログラムで利用可能にします。
464
+ #
465
+ # key 年月日配当規則のハッシュキー
466
+ # rule 年月日配当規則
467
+ #
468
+ # インスタンス変数 ハッシュのハッシュ@rule_table の要素
469
+ # Years => the period length / year
470
+ # Months => the period length / month
471
+ # Days => the period length / day
472
+ # Rule => Array of sub rules' key
473
+ #
474
+ def _make_rule(key, rule, unit=nil)
475
+ if rule.key?('Rule') # Table of Many Years
476
+ ['Years', 'Months', 'Days'].each do |u|
477
+ rule[u] ||=
478
+ begin
479
+ s = 0
480
+ rule['Rule'].each do |part|
481
+ subkey, count = part
482
+ subrule = @rule_table[subkey]
483
+ _make_rule(subkey, subrule, unit) unless subrule[u]
484
+ s += (count||1) * subrule[u]
485
+ end
486
+ s
487
+ end
488
+ end
489
+ if !@entry_key ||
490
+ @rule_table[@entry_key]['Days'] < rule['Days']
491
+ @entry_key = key
492
+ end
493
+ else # Table of One Year
494
+ super
495
+ end
496
+ end
497
+
498
+ # 年初の通日によるセットアップ
499
+ def _sdn_setup(c_key, c_date)
500
+ root_rule = @rule_table[@entry_key]
501
+ count, value = c_date[0].divmod(root_rule['Years'])
502
+ sdn, y, key = _read_period(@entry_key,
503
+ 'Years', value,
504
+ 'Days', @origin_of_LSC + count * root_rule['Days'])
505
+ @_m_cash_["_key"] ||= {}
506
+ @_m_cash_["_ids"] ||= {}
507
+ @_m_cash_["_key"][c_key] ||= key
508
+ @_m_cash_["_ids"][c_key] ||= @_m_cash_["_rule"][key]['IDs']
509
+ @_m_cash_["_sdn"][c_key] ||= sdn
510
+ end
511
+
512
+ # 年初の通日
513
+ #
514
+ # @param [Array<Numeric>] date ( y )
515
+ #
516
+ # y 年
517
+ #
518
+ # @return [Integer] 年初の通日
519
+ #
520
+ def _sdn_(date)
521
+ root_rule = @rule_table[@entry_key]
522
+ count, value = date[0].divmod(root_rule['Years'])
523
+ sdn, y, key = _read_period(@entry_key,
524
+ 'Years', value,
525
+ 'Days', @origin_of_LSC + count * root_rule['Days'])
526
+ return sdn
527
+ end
528
+
529
+ # 暦日表のキー取得
530
+ #
531
+ # @param [Array<Numeric>] date ( y )
532
+ #
533
+ # y 年
534
+ #
535
+ # @return [Integer] 暦日表のキー
536
+ #
537
+ def _key_(date)
538
+ root_rule = @rule_table[@entry_key]
539
+ count, value = date[0].divmod(root_rule['Years'])
540
+ sdn, y, key = _read_period(@entry_key,
541
+ 'Years', value,
542
+ 'Days', @origin_of_LSC + count * root_rule['Days'])
543
+ return key
544
+ end
545
+
546
+ # 年の配当規則を読み出します。
547
+ #
548
+ # key 年の配当規則のキー
549
+ # akey 入力が'Days'か'Years'かを指定
550
+ # avalue 入力の'Days'または'Years'の値
551
+ # zkey 出力が'Years'か'Days'かを指定
552
+ # zvalue 出力の'Years'または'Days'の値
553
+ def _read_period(key, akey, avalue, zkey, zvalue)
554
+ rule = @rule_table
555
+ rule[key]['Rule'].each do |part|
556
+ subkey, count, = [*part] << 1
557
+ if avalue >= count * rule[subkey][akey]
558
+ avalue -= count * rule[subkey][akey]
559
+ zvalue += count * rule[subkey][zkey]
560
+ else
561
+ count, avalue = avalue.divmod(rule[subkey][akey])
562
+ zvalue += count * rule[subkey][zkey]
563
+ return zvalue, avalue, subkey unless rule[subkey].key?('Rule')
564
+ return _read_period(subkey, akey, avalue, zkey, zvalue)
565
+ end
566
+ end
567
+ end
568
+ end
569
+
570
+ #
571
+ # 年初を太陽黄経で決定する暦
572
+ #
573
+ class YearLengthTableBased < TableBased
574
+
575
+ # 時間帯
576
+ #
577
+ # @return [Array<Numeric>]
578
+ #
579
+ attr_reader :timezone
580
+
581
+ # 天体暦アルゴリズム
582
+ #
583
+ # @return [Array<When::Ephemeris::Formula>]
584
+ #
585
+ attr_reader :formula
586
+
587
+ #protected
588
+
589
+ private
590
+
591
+ # 年初の通日
592
+ #
593
+ # @param [Array<Numeric>] date ( y )
594
+ #
595
+ # y 年
596
+ #
597
+ # @return [Integer] 年初の通日
598
+ #
599
+ def _sdn_(date)
600
+ y = +date[0]
601
+ t = @formula[0].cn_to_time(y.to_f + @cycle_offset)
602
+ return (t + 0.5 + @day_offset + @timezone[0]).floor
603
+ end
604
+
605
+ # オブジェクトの正規化
606
+ #
607
+ # YearLengthTableBased+オブジェクトの性質定義を初期設定します。
608
+ #
609
+ def _normalize(args=[], options={})
610
+
611
+ Rational
612
+ @cycle_offset = (@cycle_offset||0).to_r
613
+ @day_offset = (@day_offset||0).to_r
614
+ @timezone = (@timezone||0).to_r
615
+ @formula = 'Formula?formula=1S'
616
+
617
+ super
618
+ end
619
+ end
620
+
621
+ # 月日の配当が太陽または月の位置によって決定される暦
622
+ #
623
+ # Calendar based on the ephemeris of the Sun or the Moon
624
+ #
625
+ class EphemerisBased < When::TM::Calendar
626
+
627
+ # 天体暦
628
+ #
629
+ # @return [When::Ephmeris::Formula]
630
+ #
631
+ attr_reader :formula
632
+
633
+ #protected
634
+
635
+ # 年月日 -> 通日
636
+ #
637
+ # @param [Numeric] y 年
638
+ # @param [Integer] m 月 (0 始まり)
639
+ # @param [Integer] d 日 (0 始まり)
640
+ #
641
+ # @return [Integer] 通日
642
+ #
643
+ def _coordinates_to_number(y, m, d)
644
+ _new_month(@months_in_year * (+y) + m) + d
645
+ end
646
+
647
+ # 通日 - > 年月日
648
+ #
649
+ # @param [Integer] sdn 通日
650
+ #
651
+ # @return [Array<Integer>] [ y, m, d ]
652
+ # y 年
653
+ # m 月 (0 始まり)
654
+ # d 日 (0 始まり)
655
+ #
656
+ def _number_to_coordinates(sdn)
657
+ m, d = Residue.mod(sdn) {|m| _new_month(m)}
658
+ y, m = m.divmod(@months_in_year)
659
+ return y, m, d
660
+ end
661
+
662
+ # 暦要素数
663
+ #
664
+ # @overload _length(date)
665
+ # @param [Array<Integer>] date ( y )
666
+ #
667
+ # y 年
668
+ #
669
+ # @return [Integer] その年の月数
670
+ #
671
+ # @overload _length(date)
672
+ # @param [Array<Integer>] date ( y, m )
673
+ #
674
+ # y 年
675
+ #
676
+ # m 月 (0 始まり)
677
+ #
678
+ # @return [Integer] その年月の日数
679
+ #
680
+ def _length(date)
681
+ y, m = date
682
+ if (m)
683
+ # 指定した月に含まれる日の数を返します。
684
+ m += @months_in_year * +y
685
+ return _new_month(m+1) - _new_month(m)
686
+ else
687
+ # 指定した年に含まれる月の数を返します。
688
+ return @months_in_year
689
+ end
690
+ end
691
+
692
+ # 暦要素数
693
+ #
694
+ # @param [Array<Numeric>] date ( y )
695
+ #
696
+ # y 年
697
+ #
698
+ # @return [Integer] その年の日数
699
+ #
700
+ def _sum_(date)
701
+ y, = date
702
+ m = @months_in_year * +y
703
+ return _new_month(m+@months_in_year) - _new_month(m)
704
+ end
705
+
706
+ private
707
+
708
+ # オブジェクトの正規化
709
+ #
710
+ # @months_in_year = 1年の月の数
711
+ #
712
+ def _normalize(args=[], options={})
713
+ @months_in_year ||= 12
714
+ super
715
+ end
716
+ end
717
+
718
+ # 月日の配当が太陽の位置によって決定される太陽暦
719
+ #
720
+ # Calendar based on the ephemeris of the Sun
721
+ #
722
+ class EphemerisBasedSolar < EphemerisBased
723
+
724
+ # 時間帯
725
+ #
726
+ # @return [Array<Numeric>]
727
+ #
728
+ attr_reader :timezone
729
+
730
+ #protected
731
+
732
+ # 月初の通日
733
+ #
734
+ # @param [Integer] m 通月
735
+ #
736
+ # @return [Integer] 月初の通日
737
+ #
738
+ def _new_month_(m)
739
+ return (@formula[0].cn_to_time(m + @cycle_offset) + 0.5 + @timezone[0]).floor
740
+ end
741
+
742
+ private
743
+
744
+ # オブジェクトの正規化
745
+ # @cycle_offset = 位相のオフセット / 1か月分の角度
746
+ # @formula = 位相の計算に用いる太陽の Formula
747
+ #
748
+ def _normalize(args=[], options={})
749
+ @cycle_offset ||= -1.5
750
+ @formula ||= "Formula?formula=#{@months_in_year||12}S"
751
+ super
752
+ end
753
+ end
754
+
755
+ # 月日の配当が月の位相によって決定される純太陰暦
756
+ #
757
+ # Calendar based on the ephemeris of the Moon
758
+ #
759
+ class EphemerisBasedLunar < EphemerisBased
760
+
761
+ # 時間帯
762
+ #
763
+ # @return [Array<Numeric, (Numeric)>]
764
+ #
765
+ attr_reader :timezone
766
+
767
+ #protected
768
+
769
+ # 月初の通日
770
+ #
771
+ # @param [Integer] m 通月
772
+ #
773
+ # @return [Integer] 月初の通日
774
+ #
775
+ def _new_month_(m)
776
+ return (@formula[-1].cn_to_time(m + @cycle_offset) + 0.5 + @timezone[-1]).floor
777
+ end
778
+
779
+ private
780
+
781
+ # オブジェクトの正規化
782
+ # @cycle_offset = Goldstein Number に対する暦元の補正
783
+ #
784
+ def _normalize(args=[], options={})
785
+ @cycle_offset ||= 1671 * 12 + 4
786
+ super
787
+ end
788
+ end
789
+
790
+ # 月日の配当が太陽および月の位置によって決定される太陰太陽暦
791
+ #
792
+ # Calendar based on the ephemeris of the Sun and the Moon
793
+ #
794
+ class EphemerisBasedLuniSolar < EphemerisBasedSolar
795
+
796
+ # 計算方法
797
+ # @return [Array<When::Ephemeris::Formula>]
798
+ attr_reader :formula
799
+
800
+ #protected
801
+
802
+ # 年月日 -> 通日
803
+ #
804
+ # @param [Numeric] yy 年
805
+ # @param [Integer] mm 月 (0 始まり)
806
+ # @param [Integer] dd 日 (0 始まり)
807
+ #
808
+ # @return [Integer] 通日
809
+ #
810
+ def _coordinates_to_number(yy, mm=0, dd=0)
811
+ _new_month(_new_year_month(+yy) + mm) + dd
812
+ end
813
+
814
+ # 通日 - > 年月日
815
+ #
816
+ # @param [Integer] sdn 通日
817
+ #
818
+ # @return [Array<Integer>] ( y, m, d )
819
+ # [ y 年 ]
820
+ # [ m 月 (0 始まり) ]
821
+ # [ d 日 (0 始まり) ]
822
+ #
823
+ def _number_to_coordinates(sdn)
824
+ nn, dd = Residue.mod(sdn) {|m| _new_month(m)}
825
+ yy, mm = Residue.mod(nn) {|y| _new_year_month(y)}
826
+ [yy, mm, dd]
827
+ end
828
+
829
+ # 暦要素数
830
+ #
831
+ # @overload _length(date)
832
+ # @param [Array<Integer>] date ( 年 )
833
+ # @return [Integer] その年の月数
834
+ #
835
+ # @overload _length(date)
836
+ # @param [Array<Integer>] date ( 年, 月 )
837
+ # @note 月は 0 始まり
838
+ # @return [Integer] その年月の日数
839
+ #
840
+ def _length(date)
841
+ y, m = date
842
+ if (m)
843
+ # 指定した月に含まれる日の数を返します。
844
+ m += _new_year_month(+y)
845
+ return _new_month(m+1) - _new_month(m)
846
+ else
847
+ # 指定した年に含まれる月の数を返します。
848
+ return _ids([y]).length
849
+ end
850
+ end
851
+
852
+ private
853
+
854
+ # 暦要素数
855
+ #
856
+ # @param [Array<Numeric>] date ( y )
857
+ #
858
+ # y 年
859
+ #
860
+ # @return [Integer] その年の日数
861
+ #
862
+ def _sum_(date)
863
+ y = +date[0]
864
+ return _new_month(_new_year_month(y+1)) - _new_month(_new_year_month(y))
865
+ end
866
+
867
+ # 太陽月初の通日
868
+ #
869
+ #
870
+ alias :_new_epoch_ :_new_month_
871
+
872
+ # 太陰月初の通日
873
+ #
874
+ # @param [Integer] m 通月
875
+ #
876
+ # @return [Integer] 月初の通日
877
+ #
878
+ def _new_month_(m)
879
+ (@formula[-1].cn_to_time(m) + 0.5 + @timezone[-1]).floor
880
+ end
881
+
882
+ # 年初の通月
883
+ #
884
+ # @param [Integer] y 年
885
+ #
886
+ # @return [Integer] 年初の通月
887
+ #
888
+ def _new_year_month_(y)
889
+ raise TypeError, 'EphemerisBasedLuniSolar is abstract class'
890
+ end
891
+
892
+ # オブジェクトの正規化
893
+ #
894
+ # @cycle_offset = 雨水の場合 -1
895
+ # @formula = 位相の計算に用いる太陽と月の Formula
896
+ # @timezone[1] = 進朔量
897
+ # @notes = to_a でデフォルトとして用いる暦注
898
+ #
899
+ def _normalize(args=[], options={})
900
+ @formula ||= ['Formula?formula=12S', 'Formula?formula=1L']
901
+ super
902
+ end
903
+ end
904
+
905
+ #
906
+ # 日時要素の境界 - Border
907
+ #
908
+ class Border < When::TM::ReferenceSystem
909
+ #
910
+ # 境界の振舞
911
+ #
912
+ # @return [Numeric]
913
+ #
914
+ # Pair(-1,+1) - 暦年/暦日が進む(境界が前年/日にあり、境界後が当年/日の扱いになる)
915
+ #
916
+ # Pair( 0, 0) - 暦年/暦日が戻る(境界が当年/日にあり、境界前が前年/日の扱いになる)
917
+ #
918
+ def behavior
919
+ @border[0]
920
+ end
921
+
922
+ # 境界の取得
923
+ #
924
+ # @param [Array<Numeric>] date 境界を計算する年/日
925
+ # @param [When::TM::ReferenceSystem] frame 使用する暦法/時法
926
+ #
927
+ # @return [Array<Numeric>] その年/日の境界
928
+ #
929
+ def border(date=[], frame=nil)
930
+ last = date.length-1
931
+ return @border if (last<0)
932
+ bDate = date[0..last] + @border[(last+1)..-1]
933
+ branch = @border[last] * 0
934
+ return bDate if (branch==0)
935
+ bDate[last] = When::Coordinates::Pair.new(+date[last]-branch, branch)
936
+ return bDate
937
+ end
938
+
939
+ # 境界の正規化
940
+ #
941
+ # @param [Array<Numeric>] date 境界を計算する年/日
942
+ # @param [When::TM::ReferenceSystem] frame 使用する暦法/時法
943
+ #
944
+ # @return [Array<Numeric>] その年/日の境界
945
+ #
946
+ def _adjust_epoch(date, frame=nil)
947
+ s_date = date.dup
948
+ e_date = border(date[0..0], frame)
949
+ branch = behavior * 0
950
+ branch += 1 if ((s_date[1..-1] <=> e_date[1..-1]) < 0)
951
+ s_date[0] = When::Coordinates::Pair.new(+s_date[0]-branch, branch)
952
+ return s_date
953
+ end
954
+
955
+ private
956
+
957
+ # 要素の正規化
958
+ def _normalize(args=[], options={})
959
+ @border = When::Coordinates::Pair._en_pair_date_time(@border) if (@border.kind_of?(String))
960
+ end
961
+ end
962
+
963
+ #
964
+ # 日時要素の境界 - 年/日によって、異なる境界を使用する場合
965
+ #
966
+ class MultiBorder < Border
967
+
968
+ #
969
+ # 境界の配列
970
+ # @return [Array<When::CalendarTypes::Border>]
971
+ attr_reader :borders
972
+
973
+ #
974
+ # 境界の振舞
975
+ #
976
+ # @return [Numeric]
977
+ #
978
+ # Pair(-1,+1) - 暦年/暦日が進む(境界が前年/日にあり、境界後が当年/日の扱いになる)
979
+ #
980
+ # Pair( 0, 0) - 暦年/暦日が戻る(境界が当年/日にあり、境界前が前年/日の扱いになる)
981
+ #
982
+ def behavior
983
+ @borders[0][:border].behavior
984
+ end
985
+
986
+ # 境界の取得
987
+ #
988
+ # @param [Array<Numeric>] date 境界を計算する年/日
989
+ # @param [When::TM::ReferenceSystem] frame 使用する暦法/時法
990
+ #
991
+ # @return [Array<Numeric>] その年/日の境界
992
+ #
993
+ def border(date=[], frame=nil)
994
+ last = date.length-1
995
+ return @borders[0][:boder] if (last<0)
996
+ @borders.each do |border|
997
+ return border[:border].border(date, frame) if date[0] >= border[:key]
998
+ end
999
+ date[0..last]
1000
+ end
1001
+
1002
+ # 境界の正規化
1003
+ #
1004
+ # @param [Array<Numeric>] date 境界を計算する年/日
1005
+ # @param [When::TM::ReferenceSystem] frame 使用する暦法/時法
1006
+ #
1007
+ # @return [Array<Numeric>] その年/日の境界
1008
+ #
1009
+ def _adjust_epoch(date, frame=nil)
1010
+ @borders.each do |border|
1011
+ next unless date[0] >= border[:key]
1012
+ s_date = date.dup
1013
+ e_date = border[:border].border(date[0..0], frame)
1014
+ branch = border[:border].behavior * 0
1015
+ branch += 1 if ((s_date[1..-1] <=> e_date[1..-1]) < 0)
1016
+ s_date[0] = When::Coordinates::Pair.new(+s_date[0]-branch, branch)
1017
+ return s_date
1018
+ end
1019
+ date
1020
+ end
1021
+
1022
+ private
1023
+
1024
+ # 要素の正規化
1025
+ def _normalize(args=[], options={})
1026
+ if @borders.kind_of?(String)
1027
+ list = @borders.split(/(\(.+?\))/)
1028
+ list.shift if list[0]==''
1029
+ list.unshift(-Float::MAX) unless list[0] =~ /\(/
1030
+ list.push('0-1-1') if list[-1] =~ /\(/
1031
+ @borders = []
1032
+ loop do
1033
+ key, border, *list = list
1034
+ break unless key
1035
+ key = $1.to_i if key.kind_of?(String) && /\((.+?)\)/ =~ key
1036
+ border = "_c:Border?border=#{border}" unless border =~ /^[A-Z_]/i
1037
+ border = When.Calendar(border)
1038
+ @borders << {:key=>key, :border=>border}
1039
+ end
1040
+ end
1041
+ @borders = @borders.sort_by {|border| -border[:key]}
1042
+ end
1043
+ end
1044
+
1045
+ #
1046
+ # 日時要素の境界 - 日の出,日の入り
1047
+ #
1048
+ class DayBorder < Border
1049
+
1050
+ # 境界の取得
1051
+ #
1052
+ # @param [Array<Numeric>] date 境界を計算する日
1053
+ # @param [When::TM::ReferenceSystem] clock 使用する時法
1054
+ #
1055
+ # @return [Array<Numeric>] その日の境界
1056
+ #
1057
+ # @note 属性 @event によって境界を計算する (see {When::Ephemeris::Formula#day_event})
1058
+ #
1059
+ def border(date=[], clock=When.utc)
1060
+ return @border unless date[0] && clock.formula
1061
+
1062
+ clock._encode(
1063
+ clock._number_to_coordinates(clock.second *
1064
+ clock.time_standard.from_dynamical_time(
1065
+ When::TM::JulianDate._d_to_t(
1066
+ clock.formula[-1].day_event(
1067
+ clock.time_standard.to_dynamical_date(date[0]), @event, When.Resource('_ep:Sun'), @height
1068
+ )))), false)
1069
+ end
1070
+ end
1071
+
1072
+ #
1073
+ # 日時要素の境界 - 日の出
1074
+ #
1075
+ class SunRise < DayBorder
1076
+
1077
+ private
1078
+
1079
+ # 要素の正規化
1080
+ def _normalize(args=[], options={})
1081
+ @border = [0,0,0,0]
1082
+ @event = -1
1083
+ @height ||= '0'
1084
+ end
1085
+ end
1086
+
1087
+ #
1088
+ # 日時要素の境界 - 日の入り
1089
+ #
1090
+ class SunSet < DayBorder
1091
+
1092
+ private
1093
+
1094
+ # 要素の正規化
1095
+ def _normalize(args=[], options={})
1096
+ @border = [When::Coordinates::Pair.new(+1,-1),0,0,0]
1097
+ @event = +1
1098
+ @height ||= '0'
1099
+ end
1100
+ end
1101
+
1102
+ #
1103
+ # 暦注 - Calendar Note
1104
+ #
1105
+ class CalendarNote < When::TM::ReferenceSystem
1106
+
1107
+ #
1108
+ # 暦注要素への名前アクセス機能提供
1109
+ #
1110
+ module LabelAccess
1111
+ attr_reader :_pool
1112
+
1113
+ #
1114
+ # 暦注要素への名前(label)によるアクセス
1115
+ #
1116
+ # @param [Numeric] key 配列インデックスと見なしてアクセス
1117
+ # @param [String] key 名前(label)と見なしてアクセス
1118
+ #
1119
+ # @return [Object] 暦注要素
1120
+ #
1121
+ def [](key)
1122
+ return super if key.kind_of?(Numeric)
1123
+ @_pool ||= Hash[*(inject([]) {|pair, v| pair << v.label.to_s << v})]
1124
+ @_pool[key]
1125
+ end
1126
+ end
1127
+
1128
+ #
1129
+ # 暦注要素のひな形クラス
1130
+ #
1131
+ class NoteElement < When::BasicTypes::Object
1132
+ #
1133
+ # _m17n_form のための要素生成
1134
+ #
1135
+ # @param [Hash] options 未使用
1136
+ #
1137
+ def _to_hash_value(options={})
1138
+ label
1139
+ end
1140
+ end
1141
+
1142
+ # デフォルトイベント名
1143
+ #
1144
+ # @return [String]
1145
+ #
1146
+ # @note イベント名の後ろに数字が使われている場合、数字部分以降はイベントメソッドの引数になります。
1147
+ # SolarTermsクラスで 'term180' は、太陽黄経180度のイベントすなわち秋分を意味します。
1148
+ #
1149
+ attr_accessor :event
1150
+ protected :event=
1151
+
1152
+ # デフォルトイベントの指定
1153
+ #
1154
+ # @param [String] event 指定値を@eventとした新しいオブジェクトを作る
1155
+ #
1156
+ # @return [When::CalendarTypes::CalendarNote]
1157
+ #
1158
+ def copy(event)
1159
+ c = self.clone
1160
+ c.event = event
1161
+ c
1162
+ end
1163
+
1164
+ # 典型的なイベントの発生間隔
1165
+ #
1166
+ # @param [String] event
1167
+ #
1168
+ # @return [When::TM::PeriodDuration]
1169
+ #
1170
+ def duration(event=@event)
1171
+ void, event, parameter = event.split(/^([^\d]+)/)
1172
+ send((event+'_delta').downcase.to_sym, parameter)
1173
+ end
1174
+
1175
+ # 指定の日時が指定イベントに該当するか?
1176
+ #
1177
+ # @param [When::TM::TemporalPosition] date チェックされる日時
1178
+ # @param [String] event チェックするイベント名
1179
+ #
1180
+ # @return [Boolean]
1181
+ # [ true - 該当する ]
1182
+ # [ false - 該当しない ]
1183
+ #
1184
+ def include?(date, event=@event)
1185
+ enum_for(date, :forward, event.downcase).next.include?(date)
1186
+ end
1187
+
1188
+ # Enumeratorの生成
1189
+ #
1190
+ # @param [When::TM::TemporalPosition] first 始点
1191
+ # @param [Symbol] direction
1192
+ # [:forward] 昇順
1193
+ # [:reverse] 降順
1194
+ # @param [String] event イベント名
1195
+ # @param [Integer] count_limit 繰り返し回数(デフォルトは指定なし)
1196
+ #
1197
+ # @return [Enumerator]
1198
+ #
1199
+ def enum_for(first, direction=:forward, event=@event, count_limit=nil)
1200
+ Enumerator.new(self, first, direction, event, count_limit)
1201
+ end
1202
+ alias :to_enum :enum_for
1203
+
1204
+ # 暦注の計算
1205
+ #
1206
+ # @param [When::TM::TemporalPosition] date 暦注を計算する日時
1207
+ # @param [When::TM::TemporalPosition 以外] date When::TM::TemporalPosition に変換して使用する
1208
+ # @param [String] options { :notes => String } という Hash の指定と等価
1209
+ # @param [Integer] options { :indices => Integer} という Hash の指定と等価
1210
+ # @param [Hash] options 下記のとおり
1211
+ # @option options [Integer] :indices Integerで指定した暦座標の暦注を計算
1212
+ # [ When::DAY ( 0) - 日 ]
1213
+ # [ When::MONTH(-1) - 月 ]
1214
+ # [ When::YEAR (-2) - 年 ]
1215
+ #
1216
+ # @option options [Array<Integer>] :indices Integerで指定したすべて暦座標の暦注を計算
1217
+ # @option options [nil] :indices すべての暦座標の暦注を計算(デフォルト)
1218
+ # @option options [String] :notes 計算する暦注名(日の暦注)
1219
+ # @option options [Integer] :notes 計算する暦注のビット配列(日の暦注)
1220
+ # @option options [Array<Array<String>>] :notes 計算する暦注名の Array の Array
1221
+ # @option options [Array<Integer>] :notes 計算する暦注のビット配列の Array
1222
+ # @option options [:all] :notes すべての暦注を計算
1223
+ # @option options [:prime, nil] :notes @prime に登録した暦注を計算、@prime未登録なら :all と同じ(デフォルト)
1224
+ # @option options [Hash] :conditions 暦注計算の条件
1225
+ # [ :location => 暦注計算の基準となる場所(String or When::Coordinates::Spatial) ]
1226
+ # [ その他のキー => 個々の暦注クラスごとにその他のキーを使用できる ]
1227
+ #
1228
+ # @option options [Hash] その他のキー date を When::TM::TemporalPosition に変換するために使用する
1229
+ # see {When::TM::TemporalPosition._instance}
1230
+ #
1231
+ # @note 暦注のビットアドレスは、暦注サブクラスのNoteObjects定数の中の定義順序による。
1232
+ # When::CalendarTypes::CalendarNote クラスの場合 new の引数とした暦注要素リストの定義順序による。
1233
+ # ビットアドレスの値が 1 の暦注が計算対象となる。
1234
+ #
1235
+ # @return [Hash] :notes が String の場合、指定の暦注の計算結果を返す。
1236
+ # @return [Array<Hash>] 上記に該当せず、:indices が Integer の場合、指定の暦座標の暦注計算結果を返す。
1237
+ # @return [Array<Array<Hash>>] 上記のいずれにも該当しない場合、暦注計算結果を返す。
1238
+ # [ :note => 暦注要素 (When::Coordinates::Residue, String, When::BasicTypes::M17n) ]
1239
+ # [ :value => 暦注の値 (When::Coordinates::Residue, String, When::BasicTypes::M17n, When::TM::TemporalPosition) ]
1240
+ #
1241
+ # @note
1242
+ # 戻り値の :value が When::TM::TemporalPosition の場合、その日時オブジェクトの events[0] に暦注名の入った
1243
+ # 暦注に該当する日付である。(例) Christian クラス で easter を計算した場合、当該年の復活祭の日付オブジェクトが返る。
1244
+ # @note
1245
+ # 暦注サブクラスの場合、暦注要素が増えたり、:note の暦注要素の型が変わったりすることがある。
1246
+ #
1247
+ def notes(date, options={})
1248
+ dates, indices, notes, conditions, options = _parse(date, options)
1249
+ _result(indices.map {|i|
1250
+ next [] unless i <= date.precision
1251
+ _note_values(dates, notes[i-1], _all_keys[i-1], _elements[i-1]) do |dates, focused_notes, notes_hash|
1252
+ focused_notes.each do |note|
1253
+ unless notes_hash[note]
1254
+ void, event, *parameter = note.split(/^([^\d]+)/)
1255
+ method = event.downcase
1256
+ notes_hash[note] =
1257
+ if respond_to?(method)
1258
+ send(method, dates, *parameter)
1259
+ else
1260
+ _elements[i-1][note].send(When::Coordinates::PRECISION_NAME[i].downcase, dates)
1261
+ end
1262
+ end
1263
+ end
1264
+ notes_hash
1265
+ end
1266
+ }, options)
1267
+ end
1268
+
1269
+ #
1270
+ # 暦注の一致 or 不一致
1271
+ #
1272
+ # @param [When::TM::TemporalPosition] date 暦注を確認する日時
1273
+ # @param [When::TM::TemporalPosition 以外] date When::TM::TemporalPosition に変換して使用する
1274
+ # @param [String] options { :notes => String } または { :value => String } という Hash の指定と等価
1275
+ # (指定の notes が存在する場合は前者、しない場合は後者)
1276
+ # @param [Integer] options { :indices => Integer } という Hash の指定と等価
1277
+ # @param [Hash] options 下記のとおり
1278
+ # @option options [暦注の値] :value 確認する暦注の値
1279
+ # @option options [それぞれ] その他 {When::CalendarTypes::CalendarNote#notes} を参照
1280
+ #
1281
+ # @return [Boolean]
1282
+ # [ true - 暦注が一致 ]
1283
+ # [ false - 暦注が不一致 ]
1284
+ #
1285
+ def note?(date, options={})
1286
+ options = _find_note(options) if options.kind_of?(String)
1287
+ value = options.delete(:value) if options.kind_of?(Hash)
1288
+ result = notes(date, options)
1289
+ result = [result] unless result.kind_of?(Array)
1290
+ result = result.flatten.compact
1291
+ return false unless result.size > 0
1292
+ return true unless value
1293
+ result.each do |hash|
1294
+ return true if value == hash[:value]
1295
+ end
1296
+ return false
1297
+ end
1298
+
1299
+ # 年の名前を暦注として返す
1300
+ # @method year
1301
+ # @return [When::BasicTypes::M17n]
1302
+
1303
+ # 月の名前を暦注として返す
1304
+ # @method month
1305
+ # @return [When::BasicTypes::M17n]
1306
+
1307
+ # 日の名前を暦注として返す
1308
+ # @method day
1309
+ # @return [When::BasicTypes::M17n]
1310
+
1311
+ #
1312
+ # 標準的な暦注として、暦座標の値の名前を暦注として返すメソッドを登録
1313
+ #
1314
+ # @private
1315
+ ['year', 'month', 'day'].each do |c|
1316
+ module_eval %Q{
1317
+ def #{c}(date)
1318
+ date.name('#{c}')
1319
+ end
1320
+ }
1321
+ end
1322
+
1323
+ private
1324
+
1325
+ #
1326
+ # オブジェクトの正規化
1327
+ #
1328
+ def _normalize(args=[], options={})
1329
+ @_elements = (args.size == 0 && self.class.const_defined?(:NoteObjects)) ?
1330
+ When::SourceURI + self.class.to_s.split(/::/)[1..-1].join('/') + '/NoteObjects' :
1331
+ _to_iri(args, options[:prefix] || '_co:')
1332
+ if @_elements.kind_of?(Array)
1333
+ @_elements.each do |e|
1334
+ e.extend LabelAccess
1335
+ end
1336
+ end
1337
+ end
1338
+
1339
+ # 暦注要素
1340
+ #
1341
+ # @return [Array<Array<When::Parts::Resource>>]
1342
+ #
1343
+ def _elements
1344
+ @_elements = When.Resource(@_elements) if @_elements.kind_of?(String)
1345
+ @_elements
1346
+ end
1347
+
1348
+ #
1349
+ # [[暦注名]](全暦注)
1350
+ #
1351
+ # @return [Array<Array<String, When::BasicTypes::M17n>>]
1352
+ #
1353
+ def _all_keys
1354
+ @_all_keys ||= _elements.map { |c|
1355
+ c.map {|n|
1356
+ n.label.to_s
1357
+ }
1358
+ }
1359
+ end
1360
+
1361
+ #
1362
+ # [[暦注名]](主要暦注)
1363
+ #
1364
+ # @return [Array<Array<When::Parts::Resource>>]
1365
+ #
1366
+ def _prime_keys
1367
+ @prime ||= _all_keys
1368
+ end
1369
+
1370
+ #
1371
+ # notes メソッドの引数を parse する
1372
+ #
1373
+ # @return [Array] dates, indices, notes
1374
+ #
1375
+ def _parse(date, options)
1376
+ options =
1377
+ case options
1378
+ when Hash ; options
1379
+ when String ; {:notes => options}
1380
+ when Integer ; {:indices => options}
1381
+ else ; {}
1382
+ end
1383
+ conditions = options.delete(:conditions) || {}
1384
+ _opt = options.dup
1385
+ notes = _notes(_opt.delete(:notes) || :prime)
1386
+ indices = _indices(_opt.delete(:indices), notes)
1387
+ date = When.when?(date, _opt) unless date.kind_of?(When::TM::TemporalPosition)
1388
+ [_to_date_for_note(date), indices, notes, conditions, options]
1389
+ end
1390
+
1391
+ #
1392
+ # notes メソッドの 文字列引数の意味を解釈する
1393
+ #
1394
+ # @return [Hash] options for note String
1395
+ #
1396
+ def _find_note(note)
1397
+ _elements.each_index do |index|
1398
+ return {:notes=>note, :indices => [-index]} if _elements[-1-index]._pool[note]
1399
+ end
1400
+ {:value => note}
1401
+ end
1402
+
1403
+ #
1404
+ # 計算する暦注
1405
+ #
1406
+ # @return [Array<Array<String>, Integer>]
1407
+ #
1408
+ def _notes(notes)
1409
+ case notes
1410
+ when :all ; _all_keys
1411
+ when :prime ; _prime_keys
1412
+ when Integer ; [notes]
1413
+ when String ; [[notes]]
1414
+ else ; notes
1415
+ end
1416
+ end
1417
+
1418
+ #
1419
+ # 暦注を計算する暦座標の配列
1420
+ #
1421
+ # @return [Array<Integer>]
1422
+ #
1423
+ def _indices(indices, notes)
1424
+ case indices
1425
+ when nil ; (0...notes.size).to_a.reverse.map {|i| -i}
1426
+ when Range ; indices.to_a
1427
+ when Array ; indices
1428
+ else ; [indices.to_i]
1429
+ end
1430
+ end
1431
+
1432
+ #
1433
+ # notes メソッドの結果を後処理する
1434
+ #
1435
+ # @return [Array<Array>, Array, String]
1436
+ #
1437
+ def _result(result, options)
1438
+ return result[0][0] if options[:notes].kind_of?(String)
1439
+ return result[0] if options[:indices].kind_of?(Numeric)
1440
+ return result
1441
+ end
1442
+
1443
+ #
1444
+ # 年月日暦注計算の共通処理 - コールバック元
1445
+ #
1446
+ def _note_values(dates, focused_notes, all_notes, note_objects)
1447
+ return [] unless dates && all_notes
1448
+
1449
+ # prepare focused notes
1450
+ case focused_notes
1451
+ when Integer
1452
+ bits = focused_notes << 1
1453
+ focused_notes = all_notes.dup.delete_if { (bits>>=1)[0] == 1 }
1454
+ when []
1455
+ focused_notes = all_notes
1456
+ when nil
1457
+ focused_notes = []
1458
+ end
1459
+ not_focused_notes = all_notes - focused_notes
1460
+ notes = {}
1461
+ not_focused_notes.each do |note|
1462
+ notes[note] = true
1463
+ end
1464
+ focused_notes.each do |note|
1465
+ notes[note] = nil
1466
+ end
1467
+
1468
+ # update notes
1469
+ notes = yield(dates, focused_notes, notes)
1470
+ notes.keys.each do |note|
1471
+ notes.delete(note) unless focused_notes.include?(note)
1472
+ end
1473
+
1474
+ # return Array of Hash
1475
+ focused_notes.map {|note|
1476
+ next nil unless notes[note]
1477
+ if note_objects[note].respond_to?(:to_note_hash)
1478
+ note_objects[note].to_note_hash(notes[note], dates)
1479
+ else
1480
+ {:note=>note_objects[note].label, :value=>notes[note]}
1481
+ end
1482
+ }.compact
1483
+ end
1484
+
1485
+ #
1486
+ # 再帰的に配列の中を Resource化する
1487
+ #
1488
+ def _to_iri(args, prefix)
1489
+ args.map {|arg|
1490
+ case arg
1491
+ when String
1492
+ arg, method = $1, $2 if (arg =~ /^(.+)#([_A-Z0-9]+)$/i)
1493
+ obj = When.Resource(arg, prefix)
1494
+ obj = obj.copy(method) if method
1495
+ obj
1496
+ when Array
1497
+ _to_iri(arg, prefix)
1498
+ else
1499
+ arg
1500
+ end
1501
+ }
1502
+ end
1503
+
1504
+ #
1505
+ # 暦日を当該暦注計算用クラスに変換
1506
+ #
1507
+ # 基底クラスである本クラスでは何もしないで、引数をそのまま返す
1508
+ #
1509
+ def _to_date_for_note(date)
1510
+ date
1511
+ end
1512
+
1513
+ #
1514
+ # イベントを取得する Enumerator
1515
+ #
1516
+ class Enumerator < When::Parts::Enumerator
1517
+
1518
+ #
1519
+ # 次のイベントを得る
1520
+ #
1521
+ # @return [When::TM::TemporalPosition]
1522
+ #
1523
+ def _succ
1524
+ @current = (@current==:first) ? @first : event_eval(@current + @delta)
1525
+ end
1526
+
1527
+ # オブジェクトの生成
1528
+ #
1529
+ # @param [When::CalendarTypes::CalendarNote] parent 暦注アルゴリズム
1530
+ # @param [When::TM::TemporalPosition] first 始点
1531
+ # @param [Symbol] direction
1532
+ # [:forward] 昇順
1533
+ # [:reverse] 降順
1534
+ # @param [String] event イベント名
1535
+ # @param [Integer] count_limit 繰り返し回数(デフォルトは指定なし)
1536
+ #
1537
+ def initialize(parent, first, direction, event, count_limit=nil)
1538
+ @parent = parent
1539
+ void, @event, @parameter = event.split(/^([^\d]+)/)
1540
+ @delta = @parent.send((@event+'_delta').to_sym, @parameter)
1541
+ instance_eval %Q{
1542
+ def event_eval(date)
1543
+ @parent.#{@event}(date, @parameter)
1544
+ end
1545
+ }
1546
+ date = event_eval(first)
1547
+ if direction == :reverse
1548
+ @delta = -@delta
1549
+ date = event_eval(first + @delta) if first.to_i < date.to_i
1550
+ else
1551
+ date = event_eval(first + @delta) if first.to_i > date.to_i
1552
+ end
1553
+ super(@parent, date, direction, count_limit)
1554
+ end
1555
+ end
1556
+ end
1557
+
1558
+ class CalendarNote
1559
+ #
1560
+ # 太陽と月の位置によるイベント
1561
+ #
1562
+ class LuniSolarPositions < self
1563
+
1564
+ # 座標の分子
1565
+ #
1566
+ # @return [Numeric]
1567
+ #
1568
+ attr_reader :num
1569
+
1570
+ # 座標の分母
1571
+ #
1572
+ # @return [Numeric]
1573
+ #
1574
+ attr_reader :den
1575
+
1576
+ # 計算アルゴリズム
1577
+ #
1578
+ # @return [When::Ephemeris::Formula]
1579
+ #
1580
+ attr_reader :formula
1581
+
1582
+ # enumerator の周期
1583
+ #
1584
+ # @return [Numeric]
1585
+ #
1586
+ attr_reader :delta
1587
+
1588
+ # 没滅計算用の補正
1589
+ #
1590
+ # @return [Numeric]
1591
+ #
1592
+ attr_reader :margin
1593
+
1594
+ # イベントの日時
1595
+ #
1596
+ # @param [When::TM::TemporalPosition] date イベントを探す基準とする日時
1597
+ # @param [Array<Numeric>] parameter 座標の分子と分母( num, den)
1598
+ #
1599
+ # num 座標の分子 (デフォルト @num)
1600
+ #
1601
+ # den 座標の分母 (デフォルト @den)
1602
+ #
1603
+ # @param [String] parameter 座標の分子と分母("#{ num }/#{ den }" の形式)
1604
+ # @param [Integer] precision 取得したい時間位置の分解能(デフォルト date の分解能)
1605
+ #
1606
+ # @return [When::TM::CalDate] date またはその直後のイベントの日時
1607
+ #
1608
+ def term(date, parameter=nil, precision=date.precision)
1609
+ precision = nil if precision == When::SYSTEM
1610
+ num, den = parameter.kind_of?(String) ? parameter.split(/\//, 2) : parameter
1611
+ num = (num || @num).to_f
1612
+ den = (den || @den).to_f
1613
+ date = date.floor(precision) if precision
1614
+ options = date._attr
1615
+ quot, mod = (@formula.time_to_cn(date)*30.0).divmod(den)
1616
+ cycle = quot * den + num
1617
+ cycle += den if mod > num
1618
+ time = When::TM::JulianDate._d_to_t(@formula.cn_to_time(cycle/30.0))
1619
+ time = date.time_standard.from_dynamical_time(time) if @formula.is_dynamical
1620
+ date = date.frame.jul_trans(When::TM::JulianDate.universal_time(time), options)
1621
+ precision ? date.floor(precision) : date
1622
+ end
1623
+
1624
+ # 日付に対応する座標
1625
+ #
1626
+ # @param [When::TM::TemporalPosition] date 日付
1627
+ # @param [Numeric] delta 周期の補正(下弦,上弦の場合 0.5, その他は0(デフォルト))
1628
+ #
1629
+ # @return [Array<Integer>] Array< Integer, 0 or 1 or 2 >
1630
+ #
1631
+ # [Integer] 対応する座標
1632
+ #
1633
+ # [0 or 1 or 2] 座標の進み(0 なら 没日, 2 なら滅)
1634
+ #
1635
+ def position(date, delta=0)
1636
+ date = date.floor
1637
+ p0, p1 = [date, date.succ].map {|d| (@formula.time_to_cn(d)*30.0-@margin+delta).floor}
1638
+ [p1 % @den, p1-p0]
1639
+ end
1640
+
1641
+ #
1642
+ # イベントの標準的な間隔を返す
1643
+ #
1644
+ # @param [String] parameter 座標の分子と分母("#{ num }/#{ den }" の形式)
1645
+ #
1646
+ # @return [When::TM::IntervalLength]
1647
+ def term_delta(parameter=nil)
1648
+ return @delta unless parameter
1649
+ num, den = parameter.split(/\//, 2)
1650
+ When::TM::IntervalLength.new([(den || @den).to_f-1,1].max, 'day')
1651
+ end
1652
+ end
1653
+
1654
+ #
1655
+ # 二十四節気
1656
+ #
1657
+ class SolarTerms < LuniSolarPositions
1658
+
1659
+ private
1660
+
1661
+ # オブジェクトの正規化
1662
+ # num - 太陽黄経/度の分子 (デフォルト 0 - 春分)
1663
+ # den - 太陽黄経/度の分母 (デフォルト 360 - 1年)
1664
+ # formula - 計算アルゴリズム(デフォルト '_ep:Formula?formula=12S')
1665
+ # delta - enumerator の周期 (デフォルト (den/360)年)
1666
+ # margin - 没滅計算用の補正 (デフォルト 1E-8)
1667
+ def _normalize(args=[], options={})
1668
+ num, den, formula, delta, margin = args
1669
+ @num = (num || @num || 0).to_f
1670
+ @den = (den || @den || 360).to_f
1671
+ @formula = When.Resource(formula || @formula ||'Formula?formula=12S', '_ep:')
1672
+ @delta = When.Duration(delta || @delta || When::TM::IntervalLength.new(@den/360, 'year'))
1673
+ @margin = (margin || @margin || 1E-8).to_f
1674
+ end
1675
+ end
1676
+
1677
+ #
1678
+ # 月の位相
1679
+ #
1680
+ class LunarPhases < LuniSolarPositions
1681
+
1682
+ private
1683
+
1684
+ # オブジェクトの正規化
1685
+ # num - 月の位相/12度の分子 (デフォルト 0 - 朔)
1686
+ # den - 月の位相/12度の分母 (デフォルト 30 - 1月)
1687
+ # formula - 計算アルゴリズム(デフォルト '_ep:Formula?formula=1L')
1688
+ # delta - enumerator の周期 (デフォルト (den/30)月)
1689
+ # margin - 没滅計算用の補正 (デフォルト 1E-8)
1690
+ def _normalize(args=[], options={})
1691
+ num, den, formula, delta, margin = args
1692
+ @num = (num || @num || 0).to_f
1693
+ @den = (den || @den || 30).to_f
1694
+ @formula = When.Resource(formula || @formula ||'Formula?formula=1L', '_ep:')
1695
+ @delta = When.Duration(delta || @delta || When::TM::IntervalLength.new(@den/30, 'month'))
1696
+ @margin = (margin || @margin || 1E-8).to_f
1697
+ end
1698
+ end
1699
+ end
1700
+ end