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,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