when_exe 0.2.100 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
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