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,1547 @@
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
+ #
9
+ # ISO 19108 Geographic information - Temporal schema
10
+ #
11
+ module When::TM
12
+ #
13
+ # (5.3) Temporal Reference System Package
14
+ #
15
+
16
+ # 時間参照系
17
+ #
18
+ # see {http://schemas.opengis.net/gml/3.1.1/base/temporalReferenceSystems.xsd#AbstractTimeReferenceSystemType gml schema}
19
+ #
20
+ class ReferenceSystem < When::TM::Object
21
+
22
+ # この時間参照系が使用する空間と時間の制限(実装は時間のみ)
23
+ #
24
+ # Limits of space and time within which the temporal reference system is use
25
+ #
26
+ # @return [When::EX::Extent]
27
+ #
28
+ # @note
29
+ # マルチスレッド動作時 CalendarEra の生成で Calendar の本属性が更新される
30
+ # 参照・更新処理は synchronize { ... } の ... の部分に書く必要がある
31
+ #
32
+ attr_accessor :domain_of_validity
33
+ alias :domainOfValidity :domain_of_validity
34
+
35
+ # この時間参照系と関連付けられた時間位置 (relation - Reference)
36
+ #
37
+ # The temporal position associated with the time reference system being described
38
+ #
39
+ # @return [Array<When::TM::(Temporal)Position>]
40
+ #
41
+ attr_reader :position
42
+
43
+ # この時間参照系が使用する時間の範囲
44
+ #
45
+ # Range of time within which the temporal reference system is use
46
+ #
47
+ # @return [When::Parts::GeomerticComplex]
48
+ #
49
+ # @note
50
+ # マルチスレッド動作時 CalendarEra の生成で Calendar の本属性が更新される
51
+ # 参照・更新処理は synchronize { ... } の ... の部分に書く必要がある
52
+ #
53
+ def domain
54
+ @domain ||= When::Parts::GeometricComplex.new([])
55
+ end
56
+ attr_writer :domain
57
+
58
+ # 時間参照系を識別する名称
59
+ #
60
+ # Name by which the temporal reference system is known
61
+ #
62
+ # @return [When::RS::Identifier]
63
+ #
64
+ def name
65
+ @name ||= When::RS::Identifier.new(label, @version, @remark)
66
+ end
67
+ end
68
+
69
+ # 順序時間参照系
70
+ #
71
+ # see {http://schemas.opengis.net/gml/3.1.1/base/temporalReferenceSystems.xsd#TimeOrdinalReferenceSystemType gml schema}
72
+ #
73
+ class OrdinalReferenceSystem < ReferenceSystem
74
+
75
+ # この順序時間参照系の最上位レベルを構成する順序年代 (relation - Structure)
76
+ #
77
+ # Ordinal eras that make up the highest level of this ordinal reference system
78
+ #
79
+ # @return [Array<When::TM::OrdinalEra>]
80
+ #
81
+ alias :component :child
82
+
83
+ end
84
+
85
+ # 暦
86
+ #
87
+ # see {http://schemas.opengis.net/gml/3.1.1/base/temporalReferenceSystems.xsd#TimeCalendarType gml schema}
88
+ #
89
+ class Calendar < ReferenceSystem
90
+
91
+ include When::Coordinates
92
+ include Temporal
93
+
94
+ # 初期化
95
+ #
96
+ # @return [void]
97
+ #
98
+ def self._setup_
99
+ @_lock_ = Mutex.new if When.multi_thread
100
+ @_lock_.lock if @_lock_
101
+ @_pool = {}
102
+ @_lock_.unlock if @_lock_
103
+ end
104
+
105
+ # この暦と関連付けられた暦年代 (relation - Basis)
106
+ #
107
+ # The calendar eras associated with the calendar being described
108
+ #
109
+ # @return [Array<When::TM::CalendarEra>]
110
+ #
111
+ # @note
112
+ # マルチスレッド動作時 CalendarEra の生成で 本属性が更新される
113
+ # 参照・更新処理は synchronize { ... } の ... の部分に書く必要がある
114
+ #
115
+ attr_reader :reference_frame
116
+ alias :referenceFrame :reference_frame
117
+
118
+ # 一暦日の中の時間位置を定めるために、この暦とともに使用する時計 (relation - Resolution)
119
+ #
120
+ # The clock that is used with this calendar to define
121
+ # temporal position within a calendar day
122
+ #
123
+ # @return [Array<When::TM::Clock>]
124
+ #
125
+ attr_reader :time_basis
126
+ alias :timeBasis :time_basis
127
+
128
+ # 時刻制 - additional attribute
129
+ #
130
+ # @return [When::TimeStandard, nil]
131
+ #
132
+ def time_standard
133
+ @time_basis ? @time_basis.time_standard : nil
134
+ end
135
+
136
+ # 時間の歩度
137
+ #
138
+ # @return [Numeric]
139
+ #
140
+ def rate_of_clock
141
+ @time_basis ? @time_basis.time_standard.rate_of_clock : 1.0
142
+ end
143
+
144
+ # 日付と時刻をユリウス日(When::TM::JulianDate)に変換する
145
+ #
146
+ # @param [When::TM::CalDate] cal_date
147
+ # @param [When::TM::ClockTime] time
148
+ #
149
+ # @return [When::TM::JulianDate]
150
+ #
151
+ def date_trans(cal_date, time=nil, options={})
152
+ time = cal_date.clk_time if ((time == nil) && cal_date.kind_of?(DateAndTime))
153
+ frac = (time) ? time.universal_time : 0.0
154
+ jdn = to_julian_date(cal_date.cal_date)
155
+ return JulianDate.universal_time((jdn - JulianDate::JD19700101) * Duration::DAY + frac, options)
156
+ end
157
+ alias :dateTrans :date_trans
158
+
159
+ # ユリウス日(When::TM::JulianDate)を日付に変換する
160
+ #
161
+ # @param [When::TM::JulianDate] jdt
162
+ # @param [Hash] options see {When::TM::TemporalPosition._instance}
163
+ #
164
+ # @return [When::TM::CalDate] if (options[:clock or :tz] == nil)
165
+ # @return [When::TM::CalDateAndTime] if (options[:clock or :tz] != nil)
166
+ #
167
+ def jul_trans(jdt, options={})
168
+ unless jdt.kind_of?(When::TimeValue)
169
+ options[:clock] ||= @time_basis unless rate_of_clock == 1.0
170
+ jdt = JulianDate.new(jdt, options)
171
+ end
172
+ cal_options = jdt._attr
173
+ cal_options.delete(:era_name)
174
+ cal_options.delete(:era)
175
+ unless rate_of_clock == jdt.rate_of_clock
176
+ cal_options.delete(:time_standard)
177
+ cal_options[:clock] = @time_basis || When.utc
178
+ jdt = JulianDate.dynamical_time(jdt.dynamical_time, {:time_standard=>time_standard})
179
+ end
180
+ cal_options.update(options)
181
+ cal_options[:frame] = self
182
+ cal_date = to_cal_date(jdt.to_i)
183
+ cal_date[0] -= cal_options[:era_name][1] if cal_options[:era_name]
184
+ clock = @time_basis || Clock.get_clock_option(cal_options) || jdt.clock
185
+ return CalDate.new(cal_date, cal_options) unless clock
186
+ clock = When.Clock(clock) if clock.kind_of?(String)
187
+ clock = clock._daylight(jdt) if clock._need_validate
188
+ frac = clock.universal_time
189
+ sdn, time = (jdt.universal_time - frac).divmod(Duration::DAY)
190
+ cal_options[:clock] = clock
191
+ return DateAndTime.new(to_cal_date(sdn.to_i + JulianDate::JD19700101), time+frac, cal_options)
192
+ end
193
+ alias :julTrans :jul_trans
194
+ alias :^ :jul_trans
195
+
196
+ # 日付をユリウス日(Numeric)に変換する
197
+ #
198
+ # @param [Numeric] cal_date
199
+ #
200
+ # @return [Integer] JulianDate
201
+ #
202
+ def to_julian_date(cal_date)
203
+ date = _decode(cal_date)
204
+ date[0] = +date[0]
205
+ return _coordinates_to_number(*date)
206
+ end
207
+
208
+ # ユリウス日(Numeric)を日付に変換する
209
+ #
210
+ # @param [Integer] jdn
211
+ #
212
+ # @return [Numeric]
213
+ #
214
+ def to_cal_date(jdn)
215
+ return _encode(_number_to_coordinates(jdn))
216
+ end
217
+
218
+ # 月初の通日
219
+ #
220
+ # @param [Integer] m 通月
221
+ #
222
+ # @return [Numeric] 月初の通日
223
+ #
224
+ def _new_month_(m)
225
+ date = @base.map {|d| d||0}
226
+ if @indices[-2].unit
227
+ date[-2] += m
228
+ _coordinates_to_number(*_decode(date))
229
+ else
230
+ d0 = _coordinates_to_number(*_decode(date))
231
+ date[-3] += (m * @mean_month / @mean_year).floor - 1
232
+ d1 = _coordinates_to_number(*_decode(date))
233
+ date[-2] += m - ((d1 - d0) / @mean_month + 0.5).floor
234
+ _coordinates_to_number(*_decode(date))
235
+ end
236
+ end
237
+
238
+ # 通日 - > [通月,月内日数,月の日数]
239
+ #
240
+ # @param [Integer] sdn 通日
241
+ #
242
+ # @return [Array<Numeric>] ( m, d, n )
243
+ # [ m - 通月]
244
+ # [ d - 月内の日数 (0 始まり)]
245
+ # [ n - 月の日数]
246
+ #
247
+ def _to_month_number_(sdn)
248
+ Residue.mod(sdn) {|m| _new_month(m)}
249
+ end
250
+
251
+ private
252
+
253
+ # オブジェクトの正規化
254
+ def _normalize(args=[], options={})
255
+ @time_basis = When.Calendar(@time_basis) if @time_basis.kind_of?(String)
256
+ @indices ||= DefaultDateIndex
257
+ _normalize_temporal
258
+ @reference_frame ||= []
259
+ end
260
+ end
261
+
262
+ # 時計
263
+ #
264
+ # see {http://schemas.opengis.net/gml/3.1.1/base/temporalReferenceSystems.xsd#TimeClockType gml schema}
265
+ #
266
+ class Clock < ReferenceSystem
267
+
268
+ include When::Coordinates
269
+ include Temporal
270
+
271
+ class << self
272
+ include When::Parts::Resource::Pool
273
+
274
+ # 地方時
275
+ #
276
+ # @return [When::TM::Clock, When::Parts::Timezone, When::V::Timezone]
277
+ #
278
+ # @note
279
+ # 本変数の write access はテスト用である。
280
+ # 本変数は、原則、ライブラリ立ち上げ時に _setup_ で初期化する。
281
+ # 以降、本変数に代入を行っても、すでに生成した When::TM::TemporalPosition には反映されない。
282
+ #
283
+ # @note
284
+ # マルチスレッド動作時 CalendarEra の生成で Calendar の本属性が更新される
285
+ # 参照・更新処理は Clock.synchronize { ... } の ... の部分に書く必要がある
286
+ #
287
+ attr_accessor :local_time
288
+
289
+ # When::TM::Clock Class のグローバルな設定を行う
290
+ #
291
+ # @param [When::TM::Clock, When::Parts::Timezone, When::V::Timezone] local 地方時を使用する場合、指定する
292
+ #
293
+ # @return [void]
294
+ #
295
+ def _setup_(local=nil)
296
+ @_lock_ = Mutex.new if When.multi_thread
297
+ @_lock_.lock if @_lock_
298
+ @_pool = {}
299
+ @local_time = local
300
+ @_lock_.unlock if @_lock_
301
+ end
302
+
303
+ # @private
304
+ def get_clock(options)
305
+ get_clock_option(options) || @local_time || When.utc
306
+ end
307
+
308
+ # @private
309
+ def get_clock_option(options)
310
+ clock = options.delete(:clock)
311
+ tz = options.delete(:tz)
312
+ tz ? (When::V::Timezone[tz] || When::Parts::Timezone[tz]) : clock
313
+ end
314
+
315
+ # @private
316
+ def to_hms(hms, extended=true)
317
+ case hms
318
+ when Numeric
319
+ sgn = (hms >= 0) ? '+' : '-'
320
+ hh, mm = hms.abs.divmod(3600)
321
+ mm, ss = mm.divmod(60)
322
+ ss, ff = ss.divmod(1)
323
+ ff = (ff == 0 || When::STRING <= When::SECOND) ? '' :
324
+ ("%.#{When::STRING - When::SECOND}f" % ff)[1..-1]
325
+ ss = (ss == 0 && ff == '') ? '' : ("%02d" % ss)
326
+ mm = "%02d" % mm
327
+ hh = "%02d" % hh
328
+ when /^([-+])(\d{2})([:=*])?(\d{2})?([:=*])?(\d{2})?(\.\d+)?$/
329
+ sgn, hh, d1, mm, d2, ss, ff = $~[1..7]
330
+ ff ||= ''
331
+ ss ||= ''
332
+ mm ||= ''
333
+ else
334
+ return nil
335
+ end
336
+
337
+ if (extended)
338
+ d1 ||= (mm=='') ? '' : ':'
339
+ d2 ||= (ss=='') ? '' : ':'
340
+ else
341
+ d1 = ''
342
+ d2 = ''
343
+ end
344
+ sgn + hh + d1 + mm + d2 + ss + ff
345
+ end
346
+ end
347
+
348
+ # この時法の基点となる事象
349
+ #
350
+ # Event used as the datum for this clock
351
+ #
352
+ # @return [String]
353
+ #
354
+ # @note
355
+ # new の options 引数に :reference_event があれば設定される。
356
+ # ライブラリとしては本変数を参照していない。下記の振る舞いを String で説明するため用いてもよい。
357
+ #
358
+ # @note
359
+ # 日付の境界が午前0時でない場合、When::Coordinates::Temporal.border により、境界が指定される。
360
+ # border, behavior メソッドをオーバーライドすることで、日の出、日の入りなど event 時刻が一定
361
+ # しない場合にも対応する。
362
+ #
363
+ attr_reader :reference_event
364
+ alias :referenceEvent :reference_event
365
+
366
+ # この時法による参照事象の時刻
367
+ #
368
+ # Time of the reference event for this clock
369
+ #
370
+ # @return [When::TM::ClockTime]
371
+ #
372
+ attr_reader :reference_time
373
+ alias :referenceTime :reference_time
374
+
375
+ # UTCによる参照事象の時刻
376
+ #
377
+ # UTC time of the reference event
378
+ #
379
+ # @return [When::TM::ClockTime]
380
+ #
381
+ attr_reader :utc_reference
382
+ alias :utcReference :utc_reference
383
+
384
+ # 一暦日の中の時間位置を定めるために、この時計とともに使用する暦 (relation - Resolution)
385
+ #
386
+ # The calendar that is used with this clock to define
387
+ # temporal position within a calendar day
388
+ #
389
+ # @return [Array<When::TM::Calendar>]
390
+ #
391
+ attr_reader :date_basis
392
+ alias :dateBasis :date_basis
393
+
394
+ # 時刻制 - additional attribute
395
+ #
396
+ # @return [When::TimeStandard]
397
+ #
398
+ attr_reader :time_standard
399
+
400
+ # この時法を生成した時間帯プロパティ - additional attribute
401
+ #
402
+ # @return [When::V::TimezoneProperty]
403
+ #
404
+ # @note
405
+ # When::TM::TemporalPosition に対して加減算を行うと、時間帯が変わる可能性がある。
406
+ # 本変数により、時間帯決定ルール(When::V::TimezoneProperty#rrule)を参照する。
407
+ #
408
+ attr_accessor :tz_prop
409
+ alias :tzProp :tz_prop
410
+
411
+ # universal_timeとこの時法の最小単位との比 - additional attribute
412
+ #
413
+ # @return [Numeric]
414
+ #
415
+ attr_reader :second
416
+
417
+ # この時法のUTCとの差(ISO 8601 extended format) - additional attribute
418
+ #
419
+ # @return [String] (±hh:mm)
420
+ #
421
+ attr_reader :zone
422
+ alias :to_extended :zone
423
+
424
+ # 時間の歩度
425
+ #
426
+ # @return [Numeric]
427
+ #
428
+ def rate_of_clock
429
+ @time_standard.rate_of_clock
430
+ end
431
+
432
+ # 日の小数による参照事象の時刻
433
+ #
434
+ # Fraction time of the reference event
435
+ #
436
+ # @return [Numeric]
437
+ #
438
+ # T00:00:00Z からの参照事象の経過時間 / 128秒
439
+ #
440
+ def universal_time
441
+ return @utc_reference.universal_time
442
+ end
443
+
444
+ # この時法の時刻をUTC時刻に変換する
445
+ #
446
+ # @param [When::TM::ClockTime] u_time
447
+ #
448
+ # @return [When::TM::ClockTime]
449
+ #
450
+ def utc_trans(u_time)
451
+ return When.utc.to_clk_time(self.to_universal_time(u_time.clk_time))
452
+ end
453
+ alias :utcTrans :utc_trans
454
+
455
+ # UTC時刻をこの時法の時刻に変換する
456
+ #
457
+ # @param [When::TM::ClockTime] clk_time
458
+ #
459
+ # @return [When::TM::ClockTime]
460
+ #
461
+ def clk_trans(clk_time)
462
+ return self.to_clk_time(When.utc.to_universal_time(u_time.clk_time))
463
+ end
464
+ alias :clkTrans :clk_trans
465
+
466
+ # この時法の時刻を日の小数に変換する
467
+ #
468
+ # @param [Numeric] clk_time
469
+ #
470
+ # @return [Numeric]
471
+ #
472
+ def to_universal_time(clk_time)
473
+ return _coordinates_to_number(_decode(clk_time)) / @second
474
+ end
475
+
476
+ # 日の小数をこの時法の時刻に変換する
477
+ #
478
+ # @param [Numeric] fod
479
+ #
480
+ # @return [When::TM::ClockTime]
481
+ #
482
+ def to_clk_time(fod, options={})
483
+ options[:frame] = self
484
+ fod, second = fod.trunk, fod.branch / fod.second if fod.kind_of?(When::Coordinates::LeapSeconds)
485
+ clk_time = ClockTime.new(_encode(_number_to_coordinates(fod * @second)), options)
486
+ return clk_time if (second||0) == 0
487
+ clk_time.clk_time[-1] += second
488
+ return clk_time
489
+ end
490
+
491
+ # 時刻をNumeric(serial time)に変換する
492
+ #
493
+ # @param [Numeric] clk_time
494
+ #
495
+ # @return [Numeric] serial time
496
+ #
497
+ def _coordinates_to_number(clk_time)
498
+ u = 1
499
+ s = 0
500
+ (@base.length-1).downto(1) do |i|
501
+ s += u * (+clk_time[i] - @base[i]) if (clk_time[i])
502
+ u *= @unit[i]
503
+ end
504
+ return s + u * (+clk_time[0]) + @origin_of_LSC
505
+ end
506
+
507
+ # Numeric(serial time)を時刻に変換する
508
+ #
509
+ # @param [Numeric] serial_time
510
+ #
511
+ # @return [Numeric]
512
+ #
513
+ def _number_to_coordinates(serial_time)
514
+ time = [serial_time-@origin_of_LSC]
515
+ (@base.length-1).downto(1) do |i|
516
+ carry, time[0] = (+time[0]).divmod(@unit[i])
517
+ time[0] += @base[i]
518
+ time.unshift(carry)
519
+ end
520
+ return time
521
+ end
522
+
523
+ # When::TM::TemporalPosition の時間帯を変更して複製する
524
+ #
525
+ # @param [When::TM::CalDate, When::TM::DateAndTime, When::TM::JulianDate] date
526
+ # @param [Hash] options see {When::TM::TemporalPosition._instance}
527
+ #
528
+ # @return [When::TM::DateAndTime, When::TM::JulianDate]
529
+ #
530
+ def ^(date, options={})
531
+ date = Position.any_other(date, options)
532
+ my_options = (date.options||{}).merge(options)
533
+ frac = self.universal_time
534
+ sdn, time = (date.universal_time - frac).divmod(Duration::DAY)
535
+ my_options[:frame] ||= date.frame if date.kind_of?(CalDate)
536
+ my_options[:clock] = self
537
+ case date
538
+ when DateAndTime
539
+ return DateAndTime.new(my_options[:frame].to_cal_date(sdn + JulianDate::JD19700101), time+frac, my_options)
540
+ when CalDate
541
+ return CalDate.new(my_options[:frame].to_cal_date(date.to_i), my_options)
542
+ when JulianDate
543
+ my_options[:frame] = my_options.delete(:clock)
544
+ return JulianDate.universal_time(sdn * Duration::DAY, my_options)
545
+ else
546
+ raise TypeError, "Irregal (Temporal)Position"
547
+ end
548
+ end
549
+
550
+ # この時法の時間帯名
551
+ #
552
+ # @param [Symbol] format
553
+ # - :extended ISO 8601 extended format (default)
554
+ # - :basic ISO 8601 basic format
555
+ # - :hash 時間帯名の後ろにISO 8601 extended format を付加する
556
+ #
557
+ # @return [Array<String>]
558
+ #
559
+ # @note
560
+ # :extended または :basicが指定され、上記は時間帯名が定義されていない場合は、ISO 8601形式で返す
561
+ #
562
+ def tzname(format=:extended)
563
+ name = @tz_prop.tzname if @tz_prop.kind_of?(When::V::TimezoneProperty) && format != :hash
564
+ name ||= format == :basic ? to_basic : @zone
565
+ name = Array(name)
566
+ return name unless format == :hash
567
+ tzid = case @tz_prop
568
+ when When::V::TimezoneProperty ; @tz_prop['..'].property['tzid'].object
569
+ when When::Parts::Timezone ; @tz_prop.timezone.name
570
+ else ; ''
571
+ end
572
+ name[0] = tzid + name[0]
573
+ name
574
+ end
575
+
576
+ #
577
+ # _m17n_form のための要素生成
578
+ #
579
+ # @private
580
+ def _to_hash_value(options={})
581
+ tzname(:hash)[0]
582
+ end
583
+
584
+ # この時法のUTCとの差(ISO 8601 basic format)
585
+ #
586
+ # @return [String] (±hhmm)
587
+ #
588
+ def to_basic
589
+ return '' unless @zone
590
+ @zone.gsub(/:/, '')
591
+ end
592
+
593
+ # 夏時間の有無
594
+ # @private
595
+ def _need_validate
596
+ case @tz_prop
597
+ when nil ; false
598
+ when When::V::TimezoneProperty ; @tz_prop._pool['..']._need_validate
599
+ else ; @tz_prop._need_validate
600
+ end
601
+ end
602
+
603
+ # 夏時間
604
+ # @private
605
+ def _daylight(zdate=nil, &block)
606
+ case @tz_prop
607
+ when nil ; return self
608
+ when When::V::TimezoneProperty ; timezone = @tz_prop._pool['..']
609
+ else ; timezone = @tz_prop
610
+ end
611
+ return self unless timezone
612
+ return timezone._daylight(zdate, &block)
613
+ end
614
+
615
+ # この時法の夏時間-標準時間変化量
616
+ # @private
617
+ def _tz_difference
618
+ case @tz_prop
619
+ when nil ; 0
620
+ when When::V::TimezoneProperty ; @tz_prop._pool['..'].difference
621
+ else ; @tz_prop.difference
622
+ end
623
+ end
624
+
625
+ # 期間オブジェクトの桁数合わせ
626
+ # @private
627
+ def _arrange_length(period)
628
+ return period unless period.kind_of?(Array)
629
+ diff = @indices.length - period.length + 1
630
+ return period if (diff == 0)
631
+ return (diff > 0) ? period + Array.new(diff, 0) : period[0...diff]
632
+ end
633
+
634
+ # 時刻配列の分解能
635
+ # @private
636
+ def _precision(time, default=nil)
637
+ nil_index = time.index(nil) || time.length
638
+ precision = nil_index - 1 if (nil_index < @base.length || time[-1].kind_of?(Integer))
639
+ When::Coordinates::Index.precision(default || precision)
640
+ end
641
+
642
+ private
643
+
644
+ # オブジェクトの正規化
645
+ def _normalize(args=[], options={})
646
+ @indices ||= DefaultTimeIndex
647
+
648
+ # note
649
+ @note ||= 'JulianDayNotes'
650
+
651
+ _normalize_temporal
652
+
653
+ # second
654
+ @second = (@second||128).to_f
655
+
656
+ # zone
657
+ @zone = Clock.to_hms(@zone || @label || @reference_event)
658
+
659
+ # time_standard
660
+ @time_standard = When.Resource(@time_standard||'UniversalTime', '_t:') unless @time_standard.kind_of?(When::TimeStandard)
661
+
662
+ # utc_reference
663
+ @utc_reference ||= @zone ? ClockTime.new(@zone.to_s, {:frame=>When.utc}) : (Clock.local_time || When.utc)
664
+
665
+ # reference_time & origin_of_LSC
666
+ case @reference_time
667
+ when Array ; clk_time = @reference_time
668
+ when String ; clk_time = Pair._en_pair_date_time(@reference_time)
669
+ when ClockTime ; clk_time = @reference_time.clk_time
670
+ when nil ; clk_time = [0, 0]
671
+ else ; raise TypeError, "reference_time type mismatch"
672
+ end
673
+ @origin_of_LSC -= (to_universal_time(clk_time) - @utc_reference.universal_time) * @second
674
+ @reference_time = ClockTime.new(clk_time, {:frame=>self})
675
+ end
676
+ end
677
+
678
+ # 時間座標系
679
+ #
680
+ # see {http://schemas.opengis.net/gml/3.1.1/base/temporalReferenceSystems.xsd#TimeCoordinateSystemType gml schema}
681
+ #
682
+ class CoordinateSystem < ReferenceSystem
683
+
684
+ # グレゴリオ暦の日付及びその日のUTCの時刻で表現する、座標参照系の尺度の原点位置
685
+ #
686
+ # Position of the origin of the scale on which the temporal coordinate
687
+ # system is based expressed as a date in the Gregorian calendar and
688
+ # time of day in UTC
689
+ #
690
+ # @return [When::BasicTypes::DateTime]
691
+ #
692
+ attr_reader :origin
693
+
694
+ # この参照系の軸で時間の参照単位とする間隔
695
+ #
696
+ # Standard unit of time used to measure duration
697
+ # on the axis of the coordinate system
698
+ #
699
+ # @return [When::TM::Duration] (changed from String)
700
+ #
701
+ attr_reader :interval
702
+
703
+ # この時間参照系の座標値をグレゴリオ暦及びUTC時刻に変換する
704
+ #
705
+ # @param [When::TM::Coordinate] c_value
706
+ #
707
+ # @return [When::TM::DateAndTime] (When::TM::BasicTypes::DateTimeはまちがい)
708
+ #
709
+ def transform_coord(c_value)
710
+ When.Resource('_c:Gregorian').jul_trans(JulianDate.universal_time(c_value.universal_time, {:frame=>When.utc}))
711
+ end
712
+ alias :transformCoord :transform_coord
713
+
714
+ # グレゴリオ暦及びUTC時刻をこの時間参照系の座標値に変換する
715
+ #
716
+ # @param [When::TM::DateAndTime (BasicTypes::DateTimeはまちがい)] date_time
717
+ #
718
+ # @return [When::TM::Coordinate]
719
+ #
720
+ def transform_date_time(date_time)
721
+ Coordinate.universal_time(date_time.universal_time, {:frame=>self})
722
+ end
723
+ alias :transformDateTime :transform_date_time
724
+
725
+ private
726
+
727
+ # オブジェクトの正規化
728
+ def _normalize(args=[], options={})
729
+ @origin = When.when?(@origin, options)
730
+ @interval = When.Duration(@interval)
731
+ raise TypeError, "Interval should be IntervalLength" unless @interval.kind_of?(IntervalLength)
732
+ end
733
+ end
734
+
735
+ # 順序時間参照系
736
+ #
737
+ # see {http://schemas.opengis.net/gml/3.1.1/base/temporalReferenceSystems.xsd#TimeOrdinalEraType gml schema}
738
+ #
739
+ class OrdinalEra < When::TM::Object
740
+
741
+ include Separation
742
+
743
+ # この順序年代を識別する名称
744
+ #
745
+ # Name that identifies a specific ordinal era
746
+ #
747
+ # @return [String]
748
+ #
749
+ alias :name :label
750
+
751
+ # この順序年代をさらに分割する順序年代
752
+ #
753
+ # Ordinal eras that subdivide this ordinal era
754
+ #
755
+ # @return [Array<When::TM::OrdinalEra>]
756
+ #
757
+ alias :member :child
758
+
759
+ # この順序年代が属する順序時間参照系 (relation - Structure)
760
+ #
761
+ # Ordinal reference system that contains this ordinal era
762
+ #
763
+ # @return [When::TM::OrdinalReferenceSystem, nil]
764
+ #
765
+ def system
766
+ _pool['..'].kind_of?(String) ? _pool['..'] : nil
767
+ end
768
+
769
+ # この順序年代が属する上位順序年代 (relation - Composition)
770
+ #
771
+ # Ordinal era that contains this ordinal era
772
+ #
773
+ # @return [When::TM::OrdinalEra, nil]
774
+ #
775
+ def group
776
+ _pool['..'].kind_of?(String)? nil : _pool['..']
777
+ end
778
+
779
+ # この順序年代が始まる時点
780
+ #
781
+ # Date at which the ordinal era began
782
+ #
783
+ # @return [When::BasicTypes::DateTime]
784
+ #
785
+ attr_reader :begin
786
+
787
+ # この順序年代が終わる時点
788
+ #
789
+ # Date at which the ordinal era ended
790
+ #
791
+ # @return [When::BasicTypes::DateTime]
792
+ #
793
+ def end
794
+ @end || (@_pool['.->'] ? @_pool['.->'].begin : nil)
795
+ end
796
+
797
+ # 日時が属するか?
798
+ #
799
+ # @param [When::TM::TemporalPosition] other
800
+ #
801
+ # @return [Boolean]
802
+ # [ true - 属する ]
803
+ # [ false - 属さない ]
804
+ #
805
+ def include?(other)
806
+ self.begin <= other && other < self.end
807
+ end
808
+
809
+ # When::TM::TemporalPosition ^ When::TM::OrdinalEra で呼ばれる
810
+ # @private
811
+ def ^(other)
812
+ include?(other) ? self : nil
813
+ end
814
+
815
+ private
816
+
817
+ # オブジェクトの正規化
818
+ def _normalize(args=[], options={})
819
+ # options
820
+ @options ||= {}
821
+ term_options = @options.merge({'namespace'=>@namespace, 'locale'=>@locale})
822
+
823
+ label, begun, ended = args
824
+
825
+ # label
826
+ @label = label if label
827
+ @label = m17n(@label, nil, nil, term_options) if (@label.instance_of?(String))
828
+ @label._pool['..'] ||= self
829
+ @_pool[@label.to_s] = @label
830
+
831
+ # begin
832
+ @begin = begun if begun
833
+ @begin = When.when?(@begin, @options) if @begin
834
+ @begin = @child[0].begin if !@begin && @child[0]
835
+
836
+ # end
837
+ @end = ended if ended
838
+ @end = When.when?(@end, @options) if @end
839
+ @end = @child[-1].end if !@end && @child[-1]
840
+ end
841
+
842
+ # その他のメソッド
843
+ #
844
+ # @note
845
+ # When::TM::OrdinalEra で定義されていないメソッドは
846
+ # 処理を @begin (type: When::TM::TemporalPosition) に委譲する
847
+ #
848
+ def method_missing(name, *args, &block)
849
+ @begin.send(name.to_sym, *args, &block)
850
+ end
851
+ end
852
+
853
+ # 暦年代
854
+ #
855
+ # see {http://schemas.opengis.net/gml/3.1.1/base/temporalReferenceSystems.xsd#TimeCalendarEraType gml schema}
856
+ #
857
+ class CalendarEra < When::TM::Object
858
+
859
+ include When
860
+
861
+ class << self
862
+
863
+ include When::Parts::Resource::Pool
864
+
865
+ # When::TM::CalendarEra Class のグローバルな設定を行う
866
+ #
867
+ # @param [Array<String>] order When::TM::CalendarEra の検索順序を指定するIRI文字列のArray
868
+ #
869
+ # @return [void]
870
+ #
871
+ def _setup_(order=nil)
872
+ @_lock_ = Mutex.new if When.multi_thread
873
+ @_lock_.lock if @_lock_
874
+ @_pool = {}
875
+ @order = order || DefaultEpochs
876
+ @_lock_.unlock if @_lock_
877
+ end
878
+
879
+ # When::TM::CalendarEra オブジェクトを検索し取得する
880
+ #
881
+ # @overload _instance(key, epoch=nil, reverse=nil, options={})
882
+ # @param [String, Regexp] key 検索する暦年代または、暦年代にマッチする正規表現
883
+ # @param [Integer] epoch 年数を昇順にカウントする方式での暦元(0年)の通年(デフォルトは nil - 指定なし)
884
+ # @param [Integer] reverse 年数を降順にカウントする方式での暦元(0年)の通年(デフォルトは nil - 指定なし)
885
+ # @param [Hash] options
886
+ # @option options [String] :area 暦年代の使用地域の指定(デフォルトは nil - 指定なし)
887
+ # @option options [String] :period 暦年代の使用時代の指定(デフォルトは nil - 指定なし)
888
+ # @option options [Integer] :count 何件ヒットするまで検索するかを指定(デフォルトは 1件)
889
+ # @option options [String] the_others 例えば When::TM::CalendarEra オブジェクトの epoch_of_use に 'name' などの
890
+ # 指定がある場合、:name に指定しておけば、検索での絞り込みに使用できる。
891
+ #
892
+ def _instance(*args)
893
+ # パラメータ
894
+ args = args.dup
895
+ options = (args[-1].kind_of?(Hash)) ? args.pop.dup : {}
896
+ key, epoch, reverse = options.delete(:label) || args
897
+ key = When::Parts::Locale.ideographic_unification(key)
898
+ if key.kind_of?(String)
899
+ key, *parents = key.split(/::/).reverse
900
+ else
901
+ parents = []
902
+ end
903
+ area = options.delete(:area)
904
+ period = options.delete(:period)
905
+ count = options.delete(:count) || 1
906
+
907
+ # 候補
908
+ _setup_ unless @_pool
909
+ pool = _candidates(options, area, period, key, epoch, false) +
910
+ _candidates(options, area, period, key, reverse, true)
911
+ _compact(pool, parents)
912
+ return pool unless pool.size < count
913
+
914
+ @order.each do |iri|
915
+ When.CalendarEra(iri)
916
+ pool = _candidates(options, area, period, key, epoch, false) +
917
+ _candidates(options, area, period, key, reverse, true)
918
+ _compact(pool, parents)
919
+ return pool unless pool.size < count
920
+ end
921
+
922
+ return []
923
+ end
924
+
925
+ private
926
+
927
+ # 候補の抽出
928
+ def _candidates(options, area, period, key, epoch, reverse)
929
+ regexp, key = key if key.kind_of?(Regexp)
930
+ return [] unless @_pool[area] &&
931
+ @_pool[area][period] &&
932
+ @_pool[area][period][key] &&
933
+ @_pool[area][period][key][epoch]
934
+ pool = @_pool[area][period][key][epoch].dup
935
+ pool.delete_if {|e| regexp !~ e.name} if regexp
936
+ return pool if options.empty?
937
+ pool.delete_if {|e| !_match(e, reverse, options) }
938
+ end
939
+
940
+ def _match(epoch, reverse, options)
941
+ return false unless epoch.reverse? == reverse
942
+ target = {:reference_event => epoch.reference_event,
943
+ :reference_date => epoch.reference_date,
944
+ :julian_reference => epoch.julian_reference
945
+ }
946
+ options.each_pair do |k,v|
947
+ return false unless (v === (target.key?(k) ? target[k] : epoch.options[k]))
948
+ end
949
+ return true
950
+ end
951
+
952
+ def _compact(pool, parents)
953
+ pool.uniq!
954
+ return if parents.empty?
955
+ pool.delete_if {|e|
956
+ !parents.each do |parent|
957
+ e = e.parent
958
+ break false if parent != e.name
959
+ end
960
+ }
961
+ end
962
+ end
963
+
964
+ # @private
965
+ HashProperty =
966
+ [:reference_event, :reference_date, :julian_reference, :dating_system, # :epoch_of_use
967
+ :epoch, :epoch_year, :options]
968
+
969
+ # この暦年代を識別する名称
970
+ #
971
+ # Name by which this calendar era is known
972
+ #
973
+ # @return [String]
974
+ # 通常 String のサブクラスである When::BasicTypes::M17n を使用する。
975
+ #
976
+ alias :name :label
977
+
978
+ # この暦年代の基点となる事象
979
+ #
980
+ # Event used as the datum for this calendar era
981
+ #
982
+ # @return [String]
983
+ # 通常 String のサブクラスである When::BasicTypes::M17n を使用する。
984
+ #
985
+ # @note
986
+ # [Accession,代始]:: 天皇・皇帝などの代始めの改元,必ずしも践祚と連動しない。
987
+ # :: JIS X7108 附属書D表3に参照事象の例として「新しい天皇の即位」とある。
988
+ # :: これは践祚を意味するので、岡田芳朗氏によれば適切ではないとのこと。
989
+ # :: 英語には適切な訳語がないと思われる。
990
+ # [FelicitousEvent,祥瑞]:: 祥瑞の発生に伴う改元
991
+ # [NaturalDisaster,災異]:: 災異の発生に伴う改元
992
+ # [InauspiciousYear,革年]:: 甲子革令・辛酉革命説による改元
993
+ # [Foundation,創業]:: 建国による元号の制定
994
+ # [CalendarReform,改暦]:: 改暦に伴う epoch_of_use の境界
995
+ #
996
+ attr_reader :reference_event
997
+ alias :referenceEvent :reference_event
998
+
999
+ # この暦による参照事象の日付
1000
+ #
1001
+ # Date of the reference event in the calendar being described
1002
+ #
1003
+ # @return [When::TM::CalDate]
1004
+ #
1005
+ # @note
1006
+ # 明治以前の改元は当該年の初めにに遡って適用された。しかし、日記などの資料は当然旧年号で
1007
+ # 記載されている。このような場合、reference_date の分解能を「年」とする。
1008
+ # 本ライブラリでは、reference_date の分解能が「年」の場合、When::TM::TemporalPosition._instance
1009
+ # の options[:lower] で年号使用の下限を年初とするか、epoch_of_use の下限とするかを
1010
+ # 指定することができる。
1011
+ #
1012
+ attr_reader :reference_date
1013
+ alias :referenceDate :reference_date
1014
+
1015
+ # 参照事象のユリウス日
1016
+ #
1017
+ # Julian date of the reference event
1018
+ #
1019
+ # @return [When::TM::JulianDate]
1020
+ #
1021
+ attr_reader :julian_reference
1022
+ alias :julianReference :julian_reference
1023
+
1024
+ # この暦年代が日付の基礎として使用する期間
1025
+ #
1026
+ # Period for which the era was used as a basis for dating
1027
+ #
1028
+ # @return [Array<When::TM::TemporalPosition>]
1029
+ #
1030
+ # @note
1031
+ # 途中の改暦を指定するために要素が必要になることがあり、要素数が2を超えることがある。
1032
+ # 最初の要素が When::TimeValue::MIN(-Infinity)の場合、年数を降順にカウントする。
1033
+ #
1034
+ attr_reader :epoch
1035
+
1036
+ # この暦年代と関連付けられた暦 (relation - Basis)
1037
+ #
1038
+ # The calendar associated with the calendar eras being described
1039
+ #
1040
+ # @return [Array<When::TM::Calendar>]
1041
+ #
1042
+ attr_reader :dating_system
1043
+ alias :datingSystem :dating_system
1044
+
1045
+ # この暦年代の元年の年番号(additional attribute)
1046
+ #
1047
+ # The year number of the calendar associated with the first year of this calendar era
1048
+ #
1049
+ # @return [Integer]
1050
+ #
1051
+ attr_reader :epoch_year
1052
+ alias :epochYear :epoch_year
1053
+
1054
+ # その他の属性 - additional attribute
1055
+ #
1056
+ # @return [Hash]
1057
+ # [ 'area' => 暦年代の使用地域 [When::BasicTypes::M17n] ]
1058
+ # [ 'period' => 暦年代の使用時代 [When::BasicTypes::M17n] ]
1059
+ # [ the others => epoch_of_use の 'name' などの指定を反映 [String] ]
1060
+ #
1061
+ attr_reader :options
1062
+
1063
+ # この暦年代が日付の基礎として使用する期間
1064
+ #
1065
+ # Period for which the era was used as a basis for dating
1066
+ #
1067
+ # @return [When::TM::Period]
1068
+ #
1069
+ # @note
1070
+ # epoch_of_use メソッドの戻り値は ISO19108 で When::TM::Period と規定されている。
1071
+ # このため変数 @epoch とは別に、本メソッドを提供する。
1072
+ #
1073
+ def epoch_of_use
1074
+ @epoch_of_use ||=
1075
+ Period.new(*([0, -1].map {|i|
1076
+ date = @epoch[i]
1077
+ if date.kind_of?(CalDate)
1078
+ options = date._attr
1079
+ options[:frame] = options.delete(:clock)
1080
+ date = JulianDate.universal_time(date.universal_time, options)
1081
+ end
1082
+ Instant.new(date) # See JIS X7108 5.3.2.2 e) When::TM::Period は直接 JulianDate を保持できない
1083
+ }))
1084
+ end
1085
+ alias :epochOfUse :epoch_of_use
1086
+
1087
+ # 年数の数え方
1088
+ #
1089
+ # @return [Boolean]
1090
+ # [ true - 降順 (Before Common Era 方式)]
1091
+ # [ false - 昇順 (Common Era 方式) ]
1092
+ #
1093
+ def reverse?
1094
+ @epoch[0].indeterminated_position == TimeValue::Min
1095
+ end
1096
+
1097
+ # 未来永劫使用するか?
1098
+ #
1099
+ # @return [Boolean]
1100
+ # [ true - する ]
1101
+ # [ false - しない ]
1102
+ #
1103
+ def unlimited?
1104
+ @epoch[-1].indeterminated_position == TimeValue::Max
1105
+ end
1106
+
1107
+ # 時間の歩度
1108
+ #
1109
+ # @return [Numeric]
1110
+ #
1111
+ def rate_of_clock
1112
+ _typical_epoch.rate_of_clock
1113
+ end
1114
+
1115
+ # 当該の暦年代の日付に変換する
1116
+ #
1117
+ # @param [When::TM::TemporalPosition] date
1118
+ # @param [Hash] trans_options 以下の通り
1119
+ # @option trans_options [Hash] :lower 暦年代適用の下限
1120
+ # [ true - epoch_of_use の始め(省略時) ]
1121
+ # [ :reference_date - 参照事象の日付 ]
1122
+ # @option trans_options [Hash] :upper 暦年代適用の上限
1123
+ # [ true - epoch_of_use の終わり(省略時) ]
1124
+ # [ :reference_date - 参照事象の日付 ]
1125
+ #
1126
+ # @return [When::TM::TemporalPosition]
1127
+ # [ When::TimeValue::Before - 当該の暦年代より前の日付である ]
1128
+ # [ When::TimeValue::After - 当該の暦年代より後の日付である ]
1129
+ # [ その他 - 当該の暦年代の日付に変換された When::TM::TemporalPosition ]
1130
+ #
1131
+ def trans(date, trans_options={})
1132
+ # 当該日付の決定
1133
+ date = Position.any_other(date, trans_options) unless date.kind_of?(Array)
1134
+ epoch, cal_date =
1135
+ case date
1136
+ when Array ; _trans_array(date)
1137
+ when JulianDate, DateAndTime ; _trans_date(date, date.clock)
1138
+ when TimeValue ; _trans_date(date)
1139
+ when Numeric ; _trans_date(JulianDate.universal_time((date-JulianDate::JD19700101)*Duration::DAY))
1140
+ else ; raise TypeError, "Irregal Seed Date Type"
1141
+ end
1142
+ return epoch unless cal_date
1143
+
1144
+ # 上下限の確認
1145
+ trans_options ||= {}
1146
+ return TimeValue::Before if cal_date.to_i < lower_bound(trans_options[:lower] || :reference_date)
1147
+ return TimeValue::After if cal_date.to_i > upper_bound(trans_options[:upper] || true)
1148
+
1149
+ # 発見した日時の属性設定
1150
+ cal_date.calendar_era = self
1151
+ cal_date.calendar_era_name = [@label, @epoch_year, reverse?, cal_date.to_i < @epoch[0].to_i]
1152
+ cal_date.cal_date[0] -= @epoch_year
1153
+ cal_date.trans = trans_options.dup
1154
+ cal_date.query = epoch.query.dup
1155
+ return cal_date
1156
+ end
1157
+
1158
+ # When::TM::TemporalPosition ^ When::TM::CalendarEra で呼ばれる
1159
+ # @private
1160
+ def ^(date, options={})
1161
+ date = Position.any_other(date, options)
1162
+ cal_date = trans(date, (date.trans||{}).merge(options))
1163
+ return nil unless cal_date.kind_of?(CalDate)
1164
+ return cal_date
1165
+ end
1166
+
1167
+ # other と @julian_reference とを比較する
1168
+ #
1169
+ # @param [Comparable] other 比較対象
1170
+ #
1171
+ # @return [Integer] 比較結果を 負, 0, 正の値で返す
1172
+ #
1173
+ def <=>(other) #TODO @precision は?
1174
+ @julian_reference.universal_time <=> other.julian_reference.universal_time
1175
+ end
1176
+
1177
+ # 暦年代の下限
1178
+ # @private
1179
+ def lower_bound(type=nil)
1180
+ @lower_bound[type] ||= @epoch[0].indeterminated_position == TimeValue::Min ? -Float::MAX :
1181
+ @reference_date.precision == YEAR &&
1182
+ @reference_date.cal_date[YEAR-1] == 0 ? @epoch[0].ceil(YEAR).to_i :
1183
+ case type
1184
+ when true ; @epoch[0].to_i
1185
+ when :reference_date ; @reference_date.to_i
1186
+ else ; [@reference_date.to_i, @epoch[0].to_i].min
1187
+ end
1188
+ end
1189
+
1190
+ # 暦年代の上限
1191
+ # @private
1192
+ def upper_bound(type=nil)
1193
+ @upper_bound[type] ||= @epoch[-1].indeterminated_position == TimeValue::Max ? +Float::MAX :
1194
+ begin
1195
+ next_era = succ
1196
+ next_ref = next_era.reference_date if next_era.respond_to?(:reference_date)
1197
+ next_ref &&
1198
+ next_ref.precision == YEAR &&
1199
+ next_ref.cal_date[YEAR-1] == 0 ? @epoch[-1].ceil(YEAR).to_i :
1200
+ case type
1201
+ when true ; @epoch[-1].to_i - 1
1202
+ when :reference_date ; @reference_date.to_i
1203
+ else ; [@reference_date.to_i, @epoch[-1].to_i - 1].max
1204
+ end
1205
+ end
1206
+ end
1207
+
1208
+ protected
1209
+
1210
+ # @private
1211
+ def _normalize_leaf_era
1212
+ # r_date and others
1213
+ case @reference_date
1214
+ when String ; format, r_date, r_era = When::BasicTypes::DateTime._to_array(@reference_date)
1215
+ when Array ; r_era, *r_date = @reference_date
1216
+ when CalDate ; r_era, r_date = @reference_date.calendar_era_name, @reference_date.cal_date
1217
+ when nil ;
1218
+ else ; raise TypeError, "ReferenceDate is invalid type"
1219
+ end
1220
+ r_era, r_year = r_era
1221
+
1222
+ epochs = @epoch.dup
1223
+ epochs.shift if (epochs[0].indeterminated_position == TimeValue::Min)
1224
+ # j_date and calculated reference_date !((julian_reference == nil) && (reference_date != nil))
1225
+ if @julian_reference
1226
+ jdn = @julian_reference.to_i
1227
+ epoch = epochs[0]
1228
+ epochs.each do |e|
1229
+ if (e.indeterminated_position == TimeValue::Max)
1230
+ epoch = e
1231
+ break
1232
+ elsif (jdn < e.to_i)
1233
+ break
1234
+ else
1235
+ epoch = e
1236
+ end
1237
+ end
1238
+ @reference_date = epoch.frame.jul_trans(When.when?(jdn), {:frame=>epoch.frame})
1239
+ j_date = @reference_date.cal_date
1240
+ elsif (@reference_date == nil)
1241
+ @reference_date = epochs[0].dup
1242
+ j_date = @reference_date.cal_date
1243
+ end
1244
+
1245
+ # epoch_year
1246
+ @epoch_year ||= r_year
1247
+ @epoch_year = @epoch_year.to_i if (@epoch_year)
1248
+ raise ArgumentError, "EpochYear mismatch" unless (@epoch_year == r_year)
1249
+ unless @epoch_year
1250
+ raise ArgumentError, "ReferenceDate is absent" unless r_date
1251
+ @epoch_year = epochs[0].cal_date[0] * 1 - r_date[0] * 1
1252
+ end
1253
+
1254
+ # j_date and calculated reference_date ((julian_reference == nil) && (reference_date != nil))
1255
+ unless j_date
1256
+ j_date = [+r_date[0]+@epoch_year, *r_date[1..-1]]
1257
+ epochs.each_index do |i|
1258
+ e = epochs[i]
1259
+ d = CalDate.new(j_date,{:frame=>e.frame})
1260
+ if (e.indeterminated_position == TimeValue::Max)
1261
+ @reference_date = d
1262
+ break
1263
+ elsif (d.to_i < e.to_i)
1264
+ @reference_date = d if (i==0)
1265
+ break
1266
+ else
1267
+ @reference_date = d
1268
+ end
1269
+ end
1270
+ end
1271
+
1272
+ # julian_reference and reference_date
1273
+ @julian_reference = JulianDate.universal_time(@reference_date.universal_time)
1274
+ @reference_date.cal_date[0] -= @epoch_year
1275
+ @reference_date.calendar_era_name = [(r_era ? r_era : @label), @epoch_year]
1276
+ if (r_date)
1277
+ raise ArgumentError, "JulianReference and ReferenceDate are mismatch" unless (@epoch_year == +j_date[0]-(+r_date[0]))
1278
+ raise ArgumentError, "JulianReference and ReferenceDate are mismatch" unless (j_date[1..-1] == r_date[1..-1])
1279
+ #raise ArgumentError, "JulianReference and ReferenceDate are mismatch" unless (j_date == r_date)
1280
+ if (r_date[1] == nil)
1281
+ @reference_date.precision = YEAR
1282
+ elsif (r_date[2] == nil)
1283
+ @reference_date.precision = MONTH
1284
+ end
1285
+ end
1286
+ end
1287
+
1288
+ # @private
1289
+ def _register_calendar_era
1290
+ return unless @label.kind_of?(When::BasicTypes::M17n)
1291
+
1292
+ # dating_system
1293
+ @dating_system = (@epoch.map {|e| e.frame}).compact.uniq
1294
+
1295
+ if @epoch.length == 1
1296
+ epoch[0].frame.synchronize {
1297
+ epoch[0].frame.domain |= When::Parts::GeometricComplex.new([[epoch[0],true]])
1298
+ } if epoch[0].frame
1299
+ elsif reverse?
1300
+ epoch[1].frame.synchronize {
1301
+ epoch[1].frame.domain |= When::Parts::GeometricComplex.new([[epoch[1],true]], true)
1302
+ } if epoch[1].frame
1303
+ else
1304
+ (epoch.length-1).times do |i|
1305
+ epoch[i].frame.synchronize {
1306
+ epoch[i].frame.domain |= When::Parts::GeometricComplex.new([[epoch[i],true], [epoch[i+1],false]])
1307
+ } if epoch[i].frame
1308
+ end
1309
+ end
1310
+
1311
+ @dating_system.each do |f|
1312
+ f.synchronize do
1313
+ f.reference_frame << self
1314
+ f.reference_frame.uniq!
1315
+ f.reference_frame.sort!
1316
+ first = f.domain.first(When.when?('-Infinity'))
1317
+ last = f.domain.last(When.when?('+Infinity'))
1318
+ f.domain_of_validity = When::EX::Extent.new(
1319
+ When::TM::Period.new(
1320
+ When::TM::Instant.new(first),
1321
+ When::TM::Instant.new(last))) if first
1322
+ end
1323
+ end
1324
+
1325
+ # インデクス登録
1326
+ ((@area||{}).values + [nil]).each do |a|
1327
+ self.class[a] ||= {}
1328
+ ((@period||{}).values + [nil]).each do |p|
1329
+ self.class[a][p] ||= {}
1330
+ (@label.values + [nil]).each do |k|
1331
+ self.class[a][p][k] ||= {}
1332
+ [@epoch_year, nil].each do |e|
1333
+ self.class[a][p][k][e] ||= []
1334
+ self.class[a][p][k][e] << self
1335
+ end
1336
+ end
1337
+ end
1338
+ end
1339
+ end
1340
+
1341
+ private
1342
+
1343
+ # オブジェクトの正規化
1344
+ def _normalize(args=[], options={})
1345
+ # area, period
1346
+ term_options = {:namespace=>@namespace, :locale=>@locale, :options=>options}
1347
+ @area = m17n(@area, nil, nil, term_options) if (@area.instance_of?(String))
1348
+ @period = m17n(@period, nil, nil, term_options) if (@period.instance_of?(String))
1349
+
1350
+ # 暦年代の上下限
1351
+ @lower_bound = {}
1352
+ @upper_bound = {}
1353
+
1354
+ # other attributes
1355
+ if (@child && @child.length>0)
1356
+ _non_leaf_era(args, term_options)
1357
+ #_register_calendar_era unless _pool['..'].kind_of?(CalendarEra)
1358
+ @child.each do |era|
1359
+ era._register_calendar_era
1360
+ end
1361
+ else
1362
+ _set_leaf_era(args, term_options)
1363
+ _normalize_leaf_era unless @epoch[0].indeterminated_position == TimeValue::Min
1364
+ end
1365
+ end
1366
+
1367
+ def _non_leaf_era(args, term_options)
1368
+ @label = m17n(@label, nil, nil, term_options) if (@label.instance_of?(String))
1369
+ if @label
1370
+ @label._pool['..'] = self # TODO ここを ||= にすると leaf? の判定がおかしくなる
1371
+ @_pool[@label.to_s] = @label
1372
+ end
1373
+
1374
+ # reference_date, reference_event & label
1375
+ @reference_date = @child[0].reference_date
1376
+ @reference_event = @child[0].reference_event
1377
+ @epoch_year = @child[0].epoch_year
1378
+ @julian_reference = @child[0].julian_reference
1379
+
1380
+ # options
1381
+ @options ||= {}
1382
+ @options.update({'area'=>@area, 'period'=>@period})
1383
+
1384
+ # epoch
1385
+ @epoch = []
1386
+ @child.each do |c|
1387
+ c.epoch.each do |e|
1388
+ @epoch << e unless e == @epoch[-1]
1389
+ end
1390
+ end
1391
+ end
1392
+
1393
+ def _set_leaf_era(args, term_options)
1394
+ # 変数の読み込み
1395
+ reference_date, reference_event, *epochs = args
1396
+
1397
+ # reference_date & label
1398
+ if reference_date
1399
+ @reference_date = reference_date
1400
+ @label = m17n(@reference_date[/^\[[^\]]+\]|^[^-+0-9]+/], nil, nil, term_options)
1401
+ end
1402
+ @label._pool['..'] ||= self
1403
+ @_pool[@label.to_s] = @label
1404
+
1405
+ # reference_event
1406
+ @reference_event = reference_event if reference_event
1407
+ @reference_event ||= ""
1408
+ @reference_event = m17n(@reference_event, nil, nil, term_options) if @reference_event.instance_of?(String)
1409
+ @reference_event._pool['..'] ||= self
1410
+ @_pool[@reference_event.to_s] = @reference_event
1411
+
1412
+ # options
1413
+ term_options[:options][:query] ||= {}
1414
+ @options ||= {}
1415
+ @options.update(term_options[:options][:query])
1416
+ @options.update({'area'=>@area, 'period'=>@period})
1417
+
1418
+ # epoch
1419
+ @epoch ||= epochs
1420
+ @epoch[0] ||= '-Infinity'
1421
+ @epoch[1] ||= '+Infinity'
1422
+ term_options[:options][:frame] ||= When.Resource('_c:Gregorian')
1423
+ epoch = ''
1424
+ @epoch = @epoch.map {|e|
1425
+ case e
1426
+ when ''
1427
+ When.when?('+Infinity')
1428
+ when String
1429
+ d, f = e.split(/\^{1,2}/)
1430
+ term_options[:options][:frame] = When.Resource(f, '_c:') if (f)
1431
+ d.split(/;/).each do |v|
1432
+ v.strip!
1433
+ if (v =~ /^[-+\d]|^Now$|^Unknown$|^[-+]Infinity$/i)
1434
+ epoch = v
1435
+ break
1436
+ end
1437
+ k, c = v.split(/\s*[:=]\s*/, 2)
1438
+ if (c.kind_of?(String))
1439
+ code = m17n(c.gsub(/%2C/,','), nil, nil, term_options)
1440
+ @_pool[code.to_s] ||= code
1441
+ @options[k] = term_options[:options][:query][k] = @_pool[code.to_s]
1442
+ else
1443
+ @options.delete(k)
1444
+ term_options[:options][:query].delete(k)
1445
+ end
1446
+ end
1447
+ When.when?(epoch, @options.merge({:frame=>term_options[:options][:frame], :validate=>:epoch}))
1448
+ else
1449
+ e
1450
+ end
1451
+ }
1452
+
1453
+ # normalize for last era
1454
+ last_era = _pool['..'].child[-1] if _pool['..'].kind_of?(CalendarEra)
1455
+ if last_era
1456
+ if last_era.epoch[0].indeterminated_position == TimeValue::Min
1457
+ last_era.epoch[0].frame = @epoch[0].frame
1458
+ last_era.epoch[1] = @epoch[0]
1459
+ last_era._normalize_leaf_era
1460
+ elsif last_era.epoch[-1].indeterminated_position == TimeValue::Max
1461
+ last_era.epoch[-1] = @epoch[0]
1462
+ end
1463
+ end
1464
+ end
1465
+
1466
+ # 配下のオブジェクトの前後関係の設定
1467
+ def _sequence
1468
+ return unless @child
1469
+ prev = nil
1470
+ if @_pool['..'].respond_to?(:child) && @_pool['..'].child
1471
+ (@_pool['..'].child.length-1).downto(0) do |i|
1472
+ v = @_pool['..'].child[i]
1473
+ next if (v.epoch[0]>=self.epoch[0])
1474
+ prev = v
1475
+ break
1476
+ end
1477
+ end
1478
+ @child.each do |v|
1479
+ if prev
1480
+ v._pool['.<-'] = prev
1481
+ prev._pool['.->'] ||= v
1482
+ while (prev.child && prev.child[-1]) do
1483
+ prev = prev.child[-1]
1484
+ prev._pool['.->'] ||= v
1485
+ end
1486
+ end
1487
+ @_pool[v.label.to_s] = v
1488
+ prev = v
1489
+ end
1490
+ end
1491
+
1492
+ def _trans_array(date)
1493
+ date = date.dup
1494
+ cal_date = frame = nil
1495
+ epoch = @epoch[0]
1496
+ @epoch.each do |e|
1497
+ cal_date = CalDate.new(date,{:frame=>e.frame}) unless (frame == e.frame)
1498
+ frame = e.frame
1499
+ break if (e.indeterminated_position == TimeValue::Max)
1500
+ break if (cal_date < e)
1501
+ epoch = e
1502
+ end
1503
+ cal_date = CalDate.new(date, {:frame=>epoch.frame}) unless (frame == epoch.frame)
1504
+ return epoch, cal_date
1505
+ end
1506
+
1507
+ def _trans_date(date, clock=nil)
1508
+ unless rate_of_clock == date.rate_of_clock
1509
+ date = JulianDate.dynamical_time(date.dynamical_time, {:time_standard=>_typical_epoch.time_standard})
1510
+ clock = _typical_epoch.clock
1511
+ end
1512
+ frac = (clock) ? clock.universal_time : 0
1513
+ sdn, time = (date.universal_time - frac).divmod(Duration::DAY)
1514
+ sdn += JulianDate::JD19700101
1515
+ epoch = @epoch[0]
1516
+ return TimeValue::Before if sdn < lower_bound
1517
+ return TimeValue::After if sdn > upper_bound
1518
+ @epoch.each do |e|
1519
+ break if (e.indeterminated_position == When::TimeValue::Max)
1520
+ break if (sdn < e.to_i)
1521
+ epoch = e
1522
+ end
1523
+ frame = epoch.frame
1524
+ cal_date = frame.to_cal_date(sdn)
1525
+ return epoch, CalDate.new(cal_date, {:frame=>frame}) unless clock
1526
+ return epoch, DateAndTime.new(cal_date, time+frac, {:frame=>frame, :clock=>clock})
1527
+ end
1528
+
1529
+ # 代表的な元期
1530
+ #
1531
+ # @return [When::TM::TemporalPosition]
1532
+ #
1533
+ def _typical_epoch
1534
+ @_typical_epoch ||= reverse? ? @epoch[-1] : @epoch[0]
1535
+ end
1536
+
1537
+ # その他のメソッド
1538
+ #
1539
+ # @note
1540
+ # When::TM::CalendarEra で定義されていないメソッドは
1541
+ # 処理を @reference_date (type: When::TM::TemporalPosition) に委譲する
1542
+ #
1543
+ def method_missing(name, *args, &block)
1544
+ @reference_date.send(name.to_sym, *args, &block)
1545
+ end
1546
+ end
1547
+ end