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,1955 @@
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
+ module When::TM
9
+ #
10
+ # (5.4) Temporal Position Package
11
+ #
12
+ #
13
+
14
+ # 列挙データ型である When::TM::IndeterminateValue は,不確定な位置のために
15
+ # 6つの値を規定する.このうち Min と Max は 本ライブラリでの拡張である.
16
+ #
17
+ # These values are interpreted as follows:
18
+ #- “Unknown” 時間位置を示す値が与えられていないことを示す(本ライブラリでは“Unknown”は使用しない)
19
+ #- “Now” 常に現時点の時間位置を示す(オブジェクト生成時の時間位置でないことに注意)
20
+ #- “Before” 実際の時間位置は未知だが、指定した値よりも前であることを示す(本ライブラリでは“Before”は無視される)
21
+ #- “After” 実際の時間位置は未知だが、指定した値よりも後であることを示す(本ライブラリでは“After”は無視される)
22
+ #- “Min” 無限の過去を示す
23
+ #- “Max” 無限の未来を示す
24
+ #
25
+ # see {gml schema}[link:http://schemas.opengis.net/gml/3.1.1/base/temporal.xsd#TimeIndeterminateValueType]
26
+ #
27
+ module IndeterminateValue
28
+
29
+ After = :After
30
+ Before = :Before
31
+ Now = :Now
32
+ Unknown = :Unknown
33
+ # additional value for this library
34
+ Min = :Min
35
+ # additional value for this library
36
+ Max = :Max
37
+
38
+ S = {'After'=>After, 'Before'=>Before, 'Now'=>Now, 'Unknown'=>Unknown, '-Infinity'=>Min, '+Infinity'=>Max}
39
+ I = S.invert
40
+ end
41
+
42
+ # 時間位置共用体
43
+ # union of
44
+ # When::TM::TemporalPosition
45
+ # When::BasicTypes::Date
46
+ # When::BasicTypes::Time
47
+ # When::BasicTypes::DateTime
48
+ #
49
+ # see {http://schemas.opengis.net/gml/3.1.1/base/temporal.xsd#TimePositionType gml schema}
50
+ #
51
+ class Position
52
+
53
+ include IndeterminateValue
54
+ include When::Parts::Resource
55
+
56
+ # @private
57
+ HashProperty =
58
+ [:indeterminated_position, :frame,
59
+ [:precision, When::SYSTEM], :events, :options, :trans, :query,
60
+ :location, [:time_standard, When::TimeStandard::UniversalTime], [:rate_of_clock, 1.0]]
61
+
62
+ # 代表文字列
63
+ #
64
+ # @return [When::BasicTypes::DateTime]
65
+ #
66
+ attr_reader :date_time8601
67
+ alias :dateTime8601 :date_time8601
68
+
69
+ # 時間位置
70
+ #
71
+ # @return [When::TM::TemporalPosition]
72
+ #
73
+ attr_reader :any_other
74
+ alias :anyOther :any_other
75
+
76
+ # 諸々のオブジェクトから When::TM::TemporalPosition を取り出す
77
+ #
78
+ # @param [Object] position 変換元の時間位置
79
+ # @param [Hash] options
80
+ # see {When::TM::TemporalPosition._instance}
81
+ #
82
+ # @return [When::TM::TemporalPosition] position の型により下記を返す
83
+ # - {When::BasicTypes::Date}, {When::BasicTypes::Time}, {When::BasicTypes::DateTime} - When::TM::Calendar#jul_trans による変換結果
84
+ # - {When::TM::TemporalPosition} - そのまま position ( optionは無視 )
85
+ # - {When::TM::Position} - position.any_other ( optionは無視 )
86
+ # - {When::Parts::GeometricComplex} - position.first ( optionは無視 )
87
+ #
88
+ def self.any_other(position, options={})
89
+ case position
90
+ when TemporalPosition ; position
91
+ when Position ; position.any_other
92
+ when When::Parts::GeometricComplex ; position.first
93
+ else ; When.Calendar(options[:frame] || 'Gregorian').jul_trans(position, options) || position
94
+ end
95
+ end
96
+
97
+ # オブジェクトの生成
98
+ #
99
+ # @param [String] specification When.exe Standard Representation として解釈して生成する
100
+ # @param [Hash] options 暦法や時法などの指定
101
+ # see {When::TM::TemporalPosition._instance}
102
+ #
103
+ # @note
104
+ # specification が String 以外の場合、そのオブジェクトの代表的な日時
105
+ # (When::TM::CalendarEra#reference_dateなど)により解釈する
106
+ #
107
+ def initialize(specification, options={})
108
+
109
+ case specification
110
+ when String
111
+ @date_time8601 = specification
112
+ @any_other = TemporalPosition._instance(specification, options)
113
+ when Position
114
+ @date_time8601 = specification.date_time8601
115
+ @any_other = specification.any_other
116
+ return
117
+ else
118
+ @any_other = specification
119
+ end
120
+
121
+ klass = specification.class
122
+ message = "Irregal specification type: #{klass}"
123
+
124
+ case specification
125
+ when CalDate ; @date_time8601 = When::BasicTypes::Date.new(specification.to_s)
126
+ when ClockTime ; @date_time8601 = When::BasicTypes::Time.new(specification.to_s)
127
+ when TemporalPosition ; @date_time8601 = When::BasicTypes::DateTime.new(specification.to_s)
128
+ when CalendarEra ; @date_time8601 = When::BasicTypes::Date.new(specification.reference_date.to_s)
129
+ when OrdinalEra ; @date_time8601 = When::BasicTypes::Date.new(specification.begin.to_s)
130
+ when When::BasicTypes::Date ; raise TypeError, message unless klass == CalDate
131
+ when When::BasicTypes::Time ; raise TypeError, message unless klass == ClockTime
132
+ when String ;
133
+ else ; raise TypeError, message
134
+ end
135
+ end
136
+
137
+ private
138
+
139
+ # その他のメソッド
140
+ #
141
+ # @note
142
+ # When::TM::Position で定義されていないメソッドは
143
+ # 処理を @date_time8601 (type: When::BasicTypes::DateTime)
144
+ # または @any_other (type: When::TM::TemporalPosition) に委譲する
145
+ # (両方ともに有効なメソッドは@any_otherを優先する)
146
+ #
147
+ def method_missing(name, *args, &block)
148
+ union = @any_other.respond_to?(name.to_sym) ? @any_other : @date_time8601
149
+ union.send(name.to_sym, *args, &block)
150
+ end
151
+ end
152
+
153
+ # 「時間位置」の基底クラス
154
+ #
155
+ # see {http://schemas.opengis.net/gml/3.1.1/base/temporalAppendix.xsd#TemporalPositionType gml schema}
156
+ #
157
+ class TemporalPosition < ::Object
158
+
159
+ #
160
+ # When::TM::JulianDate, When::TM::CalDate or DateAndTime への変換メソッドを提供
161
+ #
162
+ module Conversion
163
+ #
164
+ # 対応する When::TM::JulianDate を生成
165
+ #
166
+ # @param [Hash] options
167
+ # @option options [When::TM::Clock] :clock
168
+ # @option options [When::Parts::Timezone] :tz
169
+ #
170
+ # @return [When::TM::JulianDate]
171
+ #
172
+ def julian_date(options={})
173
+ When::TM::JulianDate.new(self, options)
174
+ end
175
+ alias :to_julian_date :julian_date
176
+
177
+ #
178
+ # 対応する When::TM::CalDate or DateAndTime を生成
179
+ #
180
+ # @param [Hash] options 暦法や時法などの指定
181
+ # see {When::TM::TemporalPosition._instance}
182
+ #
183
+ # @return [When::TM::CalDate, When::TM::DateAndTime]
184
+ #
185
+ def tm_position(options={})
186
+ When.Calendar(options[:frame] || 'Gregorian').jul_trans(self, options)
187
+ end
188
+ alias :to_tm_position :tm_position
189
+ end
190
+
191
+ include When
192
+ include Comparable
193
+ include IndeterminateValue
194
+ include Coordinates
195
+ include Parts::Resource
196
+ include Conversion
197
+
198
+ # @private
199
+ HashProperty = Position::HashProperty
200
+
201
+ # この時間位置の意味づけ
202
+ #
203
+ # @return [When::TM::IndeterminateValue]
204
+ #
205
+ attr_reader :indeterminated_position
206
+ alias :indeterminatedPosition :indeterminated_position
207
+
208
+ # この時間位置と関連付けられた時間参照系 (relation - Reference)
209
+ #
210
+ # The time reference system associated with the temporal position being described
211
+ #
212
+ # @return [When::TM::ReferenceSystem]
213
+ #
214
+ attr_accessor :frame
215
+ alias :clock :frame
216
+
217
+ # この時間位置と関連付けられたイベント - additional attribute
218
+ #
219
+ # @return [Array<When::Parts::Enumerator>]
220
+ #
221
+ attr_accessor :events
222
+ #protected :events=
223
+
224
+ # この時間位置の分解能 - additional attribute
225
+ #
226
+ # @return [Numeric]
227
+ #
228
+ attr_accessor :precision
229
+
230
+ # その他の属性 - additional attribute
231
+ #
232
+ # @return [Hash] { String=>Object }
233
+ #
234
+ attr_reader :options
235
+
236
+ # その他の属性 - additional attribute
237
+ #
238
+ # @return [Hash] { String=>Object }
239
+ #
240
+ attr_accessor :trans
241
+
242
+ # その他の属性 - additional attribute
243
+ #
244
+ # @return [Hash] { String=>When::BasicTypes::M17n }
245
+ #
246
+ attr_accessor :query
247
+
248
+ # その他の属性 - additional attribute
249
+ #
250
+ # @return [When::Coordinates::Spatial]
251
+ #
252
+ attr_accessor :location
253
+
254
+ class << self
255
+
256
+ include When
257
+ include Coordinates
258
+
259
+ # Temporal Objetct の生成
260
+ #
261
+ # @param [String] specification When.exe Standard Representation
262
+ # @param [Hash] options 下記の通り
263
+ # @option options [When::TM::ReferenceSystem] :frame 暦法の指定
264
+ # @option options [When::TM::Clock] :clock 時法の指定
265
+ # @option options [When::Parts::Timezone] :tz 時法の指定(時間帯を指定する場合 :clock の替わりに用いることができる)
266
+ # @option options [Array<Numeric>] :abbr ISO8601上位省略形式のためのデフォルト日付(省略時 指定なし)
267
+ # @option options [String] :wkst ISO8601週日形式のための暦週開始曜日(省略時 'MO')
268
+ # @option options [Integer] :precision 生成するオブジェクトの分解能
269
+ # @option options [When::TimeStandard::TimeStandard] :time_standard 時刻系の指定(省略時 When::TimeStandard::UnversalTime)
270
+ # @option options [When::Ephemeris::Spatial] :location 観測地の指定(省略時 指定なし)
271
+ # @option options [String] :era_name 暦年代
272
+ # @option options [Hash] :trans 暦年代の上下限
273
+ # - :count => 条件に合致する暦年代のうち何番目を採用するか
274
+ # - :lower => 暦年代適用の下限
275
+ # true - epoch_of_use の始め(省略時)
276
+ # :reference_date - 参照事象の日付
277
+ # - :upper => 暦年代適用の上限
278
+ # true - epoch_of_use の終わり(省略時)
279
+ # :reference_date - 参照事象の日付
280
+ # @option options [Hash] :query 暦年代の絞込み条件
281
+ # - :area => area による暦年代絞込み
282
+ # - :period => period による暦年代絞込み
283
+ # - :name => name による暦年代絞込み(epoch の attribute使用可)
284
+ #
285
+ # @return [When::TM::TemporalPosition] ISO8601 time point
286
+ # @return [When::TM::Duration] ISO8601 duration
287
+ # @return [When::Parts::GeometricComplex] ISO8601 repeating interval
288
+ #
289
+ def _instance(specification, options={})
290
+
291
+ # Suffix - Frame specification
292
+ rfc5545form, frame, *rest = specification.split(/\^{1,2}/)
293
+ return rest.inject(_instance(rfc5545form + '^' + frame, options)) {|p,c| When.Resource(c, '_c:').jul_trans(p)} if rest.size > 0
294
+
295
+ options[:frame] = When.Resource(frame, '_c:') if (frame)
296
+
297
+ # Prefix - RFC 5545 Options
298
+ if (rfc5545form =~ /^([^:]+[^-:\d]):([^:].+)$/)
299
+ rfc5545option, iso8601form = $~[1..2]
300
+ rfc5545option.split(/;/).each do |eq|
301
+ key, value = eq.split(/=/, 2)
302
+ case key
303
+ when 'VALUE' ; options[:precision] = value
304
+ when 'TZID' ; options[:clock] =
305
+ case When::V::Timezone[value]
306
+ when Array ; When::V::Timezone[value][-1]
307
+ when nil ; When::Parts::Timezone.new(value)
308
+ else ; When::V::Timezone[value]
309
+ end
310
+ else ; options[key] = value
311
+ end
312
+ end
313
+ else
314
+ iso8601form = rfc5545form
315
+ end
316
+ options = options.dup
317
+
318
+ # IndeterminateValue
319
+ if (iso8601form.sub!(/\/After$|^Before\/|^Now$|^Unknown$|^[-+]Infinity$/i, ''))
320
+ options[:indeterminated_position] = When::TimeValue::S[$&.sub(/\//,'')]
321
+ case options[:indeterminated_position]
322
+ when When::TimeValue::Now,
323
+ When::TimeValue::Unknown,
324
+ When::TimeValue::Max,
325
+ When::TimeValue::Min
326
+ return self.new(self._options(options))
327
+ end
328
+ end
329
+
330
+ # each specification
331
+ splitted = iso8601form.split(/\//)
332
+ if (splitted[0] =~ /^R(\d+)?$/)
333
+ repeat = $1 ? $1.to_i : true
334
+ splitted.shift
335
+ end
336
+ case splitted.length
337
+ when 1
338
+ when 2
339
+ if (splitted[0] !~ /^[-+]?P/ && splitted[1] =~ /^\d/ && splitted[1].length < splitted[0].length)
340
+ splitted[1] = splitted[0][0..(splitted[0].length-splitted[1].length-1)] + splitted[1]
341
+ end
342
+ else
343
+ raise ArgumentError, "Irregal ISO8601 Format: #{iso8601form}"
344
+ end
345
+ options = self._options(options)
346
+ element = splitted.map { |v| _date_time_or_duration(v, options.dup) }
347
+
348
+ # total result
349
+ case repeat
350
+ when nil
351
+ case element[1]
352
+ when nil
353
+ return element[0]
354
+ when Duration
355
+ case element[0]
356
+ when Duration ; raise TypeError, "Duplicate Duration: #{element[0]} and #{element[1]}"
357
+ when self ; return When::Parts::GeometricComplex.new(*element)
358
+ else ; return When::Parts::GeometricComplex.new(element[0].first, element[1])
359
+ end
360
+ when self
361
+ case element[0]
362
+ when Duration ; return When::Parts::GeometricComplex.new([[element[1]-element[0],false], [element[1],true ]])
363
+ when self ; return When::Parts::GeometricComplex.new(element[0]..element[1])
364
+ else ; return When::Parts::GeometricComplex.new(element[0].first..element[1])
365
+ end
366
+ else
367
+ case element[0]
368
+ when Duration ; return When::Parts::GeometricComplex.new([[element[1].first-element[0],false],
369
+ [element[1].last-element[0]-1,true ]])
370
+ when self ; return When::Parts::GeometricComplex.new(element[0]...element[1].last)
371
+ else ; return When::Parts::GeometricComplex.new(element[0].first...element[1].last)
372
+ end
373
+ end
374
+ when 0 ; return []
375
+ when Integer ; return [element[0]] * repeat unless element[1]
376
+ end
377
+
378
+ case element[1]
379
+ when Duration
380
+ case element[0]
381
+ when Duration ; raise TypeError, "Duplicate Duration: #{element[0]} and #{element[1]}"
382
+ else ; duration = element[1]
383
+ end
384
+ when self
385
+ case element[0]
386
+ when Duration ; duration = -element[0]
387
+ when self ; duration = element[1] - element[0]
388
+ else ; duration = element[1] - element[0].first
389
+ end
390
+ else
391
+ case element[0]
392
+ when Duration ; duration = -element[0]
393
+ when self ; duration = element[1].first - element[0]
394
+ else ; duration = element[1].first - element[0].first
395
+ end
396
+ end
397
+ base = element[0].kind_of?(Duration) ? element[1] : element[0]
398
+
399
+ if repeat.kind_of?(Integer)
400
+ result = case base
401
+ when self ; (1..repeat-1).inject([base]) {|a,i| a << (a[-1] + duration) }
402
+ else ; (1..repeat-1).inject([base]) {|a,i| a << When::Parts::GeometricComplex.new(
403
+ a[-1].first+duration...a[-1].last+duration)}
404
+ end
405
+ result.reverse! if duration.sign < 0
406
+ return result
407
+
408
+ else
409
+ duration = -duration if duration.sign < 0
410
+ return case base
411
+ when self ; When::V::Event.new({'rrule'=>{'FREQ'=>duration}, 'dtstart'=>base})
412
+ else ; When::V::Event.new({'rrule'=>{'FREQ'=>duration}, 'dtstart'=>base.first,
413
+ 'dtend' =>base.last})
414
+ end
415
+ end
416
+ end
417
+
418
+ # option の正規化
419
+ # @private
420
+ def _options(options)
421
+ query = options.dup
422
+ main = {}
423
+ clock = Clock.get_clock_option(query)
424
+ main[:clock] = clock if clock
425
+ [:indeterminated_position, :frame, :events, :precision,
426
+ :era_name, :era, :abbr, :wkst, :time_standard, :location].each do |key|
427
+ main[key] = query.delete(key) if (query.key?(key))
428
+ end
429
+ trans = query.delete(:trans) || {}
430
+ [:lower, :upper, :count].each do |key|
431
+ trans[key] = query.delete(key) if (query.key?(key))
432
+ end
433
+ query = query.merge(query.delete(:query)) if (query.key?(:query))
434
+ main[:query] = query if (query.size > 0)
435
+ main[:trans] = trans if (trans.size > 0)
436
+ return main
437
+ end
438
+
439
+ private
440
+
441
+ # date_time_or_duration
442
+ def _date_time_or_duration(specification, options)
443
+ # IntervalLength
444
+ args = IntervalLength._to_array(specification)
445
+ return IntervalLength.new(*args) if args
446
+
447
+ # PeriodDuration
448
+ sign, *args = PeriodDuration._to_array(specification)
449
+ if (sign)
450
+ args << options
451
+ duration = PeriodDuration.new(*args)
452
+ return (sign >= 0) ? duration : -duration
453
+ end
454
+
455
+ # TemporalPosition
456
+ specification =~ /(.+?)(?:\[([-+]?\d+)\])?$/
457
+ options[:sdn] = $2.to_i if $2
458
+ f, d, t, z, e = When::BasicTypes::DateTime._to_array($1, options)
459
+ raise ArgumentError, "Timezone conflict: #{z} - #{options[:clock]}" if (z && options[:clock])
460
+ options.delete(:abbr)
461
+ z ||= options[:clock]
462
+ z = When.Clock(z) if (z =~ /^[A-Z]+$/)
463
+
464
+ unless (d)
465
+ # ClockTime
466
+ raise ArgumentError, "Timezone conflict: #{z} - #{options[:clock]}" if (z && options[:frame])
467
+ options[:frame] ||= z
468
+ options.delete(:clock)
469
+ return ClockTime.new(t, options)
470
+ end
471
+
472
+ options[:era_name] = e if e
473
+ options[:_format ] = f if f
474
+ d, w = d[0..0], d[1..-1] if (f == :week || f == :day)
475
+ position = z ? DateAndTime.new(d, t||[0], options.update({:clock => z})) :
476
+ t ? DateAndTime.new(d, t, options) :
477
+ CalDate.new(d, options)
478
+ case f
479
+ when :day
480
+ position += PeriodDuration.new(w[0]-1, DAY)
481
+ when :week
482
+ position = ((position + PeriodDuration.new(4, DAY)) & (Residue.day_of_week(options[:wkst]) << 1)) +
483
+ PeriodDuration.new((w[0]-1)*7 + (w[1]||1)-1, DAY)
484
+ position = When::Parts::GeometricComplex.new(position...(position+DurationP1W)) unless w[1]
485
+ end
486
+ return position
487
+ end
488
+ end
489
+
490
+ # 時刻系
491
+ #
492
+ # @return [When::TimeStandard]
493
+ #
494
+ def time_standard
495
+ return @time_standard if @time_standard.kind_of?(When::TimeStandard)
496
+ @time_standard = When.Resource(@time_standard ||
497
+ (clock ? clock.time_standard : nil) ||
498
+ (frame ? frame.time_standard : nil) ||
499
+ 'UniversalTime', '_t:')
500
+ end
501
+
502
+ # 時間の歩度
503
+ #
504
+ # @return [Numeric]
505
+ #
506
+ def rate_of_clock
507
+ time_standard.rate_of_clock
508
+ end
509
+
510
+ # 内部時間
511
+ #
512
+ # @return [Numeric]
513
+ #
514
+ # 1970-01-01T00:00:00Z からの Universal Time, Coordinated の経過時間 / 128秒
515
+ #
516
+ # 暦法によっては、異なる意味を持つことがある
517
+ #
518
+ def universal_time
519
+ case @indeterminated_position
520
+ when Now ; time_standard.from_time_object(Time.now)
521
+ when Max ; +Float::MAX/4
522
+ when Min ; -Float::MAX/4
523
+ else ; raise NameError, "Temporal Reference System is not defined"
524
+ end
525
+ end
526
+
527
+ # 外部時間
528
+ #
529
+ # @return [Numeric]
530
+ #
531
+ # 1970-01-01T00:00:00TT からの terrestrial time の経過時間 / 128秒
532
+ #
533
+ def dynamical_time
534
+ return @dynamical_time if @dynamical_time && @indeterminated_position != Now
535
+ @dynamical_time =
536
+ case @indeterminated_position
537
+ when Max ; +Float::MAX/4
538
+ when Min ; -Float::MAX/4
539
+ else ; time_standard.to_dynamical_time(universal_time)
540
+ end
541
+ end
542
+
543
+ # ユリウス日時(実数)
544
+ #
545
+ # @return [Float]
546
+ #
547
+ # universal time での経過日数を, ユリウス日と1970-01-01T00:00:00Zで時計あわせしたもの
548
+ #
549
+ def to_f
550
+ JulianDate._t_to_d(universal_time)
551
+ end
552
+
553
+ # ユリウス日(整数)
554
+ #
555
+ # @return [Integer]
556
+ #
557
+ # -4712-01-01T12:00:00Z からの経過日数に対応する通番(当該時間帯での午前0時に1進める)
558
+ #
559
+ def to_i
560
+ sd = universal_time
561
+ sd -= @frame.universal_time if @frame.kind_of?(Clock)
562
+ div, mod = sd.divmod(Duration::DAY)
563
+ div + JulianDate::JD19700101
564
+ end
565
+
566
+ # 剰余類化
567
+ #
568
+ # @param [Numeric] remainder 剰余
569
+ # @param [Integer] divisor 法(>0)
570
+ #
571
+ # @return [When::Coordinates::Residue]
572
+ #
573
+ # 当日を基準とする剰余類
574
+ #
575
+ def to_residue(remainder, divisor)
576
+ When::Coordinates::Residue.new(remainder, divisor, {'day'=>to_i})
577
+ end
578
+
579
+ # ユリウス日時(実数)
580
+ #
581
+ # @return [Float]
582
+ #
583
+ # dynamical time での経過日数を, ユリウス日と1970-01-01T00:00:00TTで時計あわせしたもの
584
+ #
585
+ def +@
586
+ JulianDate._t_to_d(dynamical_time)
587
+ end
588
+
589
+ # When::TM::ClockTime オブジェクトへの変換
590
+ #
591
+ # @return [When::TM::ClokTime]
592
+ #
593
+ def to_clock_time
594
+ raise TypeError, "Clock not assigned" unless clock
595
+ clk_time = clock.to_clk_time(universal_time - (to_i - JulianDate::JD19700101)*Duration::DAY)
596
+ clk_time.clk_time[0] += to_i
597
+ return clk_time
598
+ end
599
+
600
+ # 標準ライブラリの DateTime オブジェクトへの変換
601
+ #
602
+ # @param [Hash] option 時間の歩度が1.0でない場合のための option
603
+ # see {When::TM::TemporalPosition._instance}
604
+ #
605
+ # @return [::DateTime]
606
+ #
607
+ def to_date_time(option={:frame=>When.utc})
608
+ return JulianDate.dynamical_time(dynamical_time, option).to_date_time unless rate_of_clock == 1.0
609
+ raise TypeError, "Clock not assigned" unless clock
610
+ Rational
611
+ offset = Rational(-(clock.universal_time/Duration::SECOND).to_i, (Duration::DAY/Duration::SECOND).to_i)
612
+ clk_time = clock.to_clk_time(universal_time - (to_i - JulianDate::JD19700101)*Duration::DAY).clk_time
613
+ ::DateTime.jd(to_i, clk_time[1], clk_time[2], clk_time[3].to_i, offset, ::Date::GREGORIAN)
614
+ end
615
+
616
+ # 標準ライブラリの Date オブジェクトへの変換
617
+ #
618
+ # @param [Hash] option 時間の歩度が1.0でない場合のための option
619
+ # see {When::TM::TemporalPosition._instance}
620
+ #
621
+ # @return [::Date]
622
+ #
623
+ def to_date(option={})
624
+ return JulianDate.dynamical_time(dynamical_time, option).to_date unless rate_of_clock == 1.0
625
+ ::Date.jd(to_i, ::Date::GREGORIAN)
626
+ end
627
+
628
+ # 組み込みライブラリの Time オブジェクトへの変換
629
+ #
630
+ # @return [::Time]
631
+ #
632
+ def to_time
633
+ time_standard.to_time_object(universal_time)
634
+ end
635
+
636
+ # 要素の参照
637
+ #
638
+ # @param [Integer, String] index 参照する要素の指定
639
+ #
640
+ # @return [Numeric]
641
+ #
642
+ def [](index)
643
+ return value(index) if index.kind_of?(String) || !index.respond_to?(:inject)
644
+ index.inject([]) {|list, i| list << value(i) }
645
+ end
646
+
647
+ # 加算
648
+ #
649
+ # @param [Numeric, When::TM::Duration] other
650
+ #
651
+ # @return [When::TM::TemporalPosition]
652
+ #
653
+ def +(other)
654
+ case other
655
+ when Integer ; self + PeriodDuration.new(other, When::DAY)
656
+ when Numeric ; self + IntervalLength.new(other, 'day')
657
+ when PeriodDuration ; _plus(other)
658
+ when Duration ; @frame.jul_trans(JulianDate.dynamical_time(dynamical_time + other.duration), self._attr)
659
+ else ; raise TypeError, "The right operand should be Numeric or Duration"
660
+ end
661
+ rescue RangeError
662
+ (@frame ^ self) + other
663
+ end
664
+
665
+ # 減算
666
+ #
667
+ # @param [Numeric, When::TM::Duration, When::TM::TemporalPosition] other
668
+ #
669
+ # @return [When::TM::TemporalPosition] if other is a Numeric or When::TM::Duration
670
+ # @return [When::TM::Duration] if other is a When::TM::TemporalPosition
671
+ #
672
+ def -(other)
673
+ case other
674
+ when TimeValue ; self.rate_of_clock == other.rate_of_clock && [@precision, other.precision].min <= When::DAY ?
675
+ PeriodDuration.new(self.to_i - other.to_i, When::DAY) :
676
+ IntervalLength.new((self.dynamical_time - other.dynamical_time) / Duration::SECOND, 'second')
677
+ when Integer ; self - PeriodDuration.new(other, When::DAY)
678
+ when Numeric ; self - IntervalLength.new(other, 'day')
679
+ when PeriodDuration ; _plus(-other)
680
+ when Duration ; @frame.jul_trans(JulianDate.dynamical_time(dynamical_time - other.duration), self._attr)
681
+ else ; raise TypeError, "The right operand should be Numeric, Duration or TemporalPosition"
682
+ end
683
+ rescue RangeError
684
+ (@frame ^ self) - other
685
+ end
686
+
687
+ # 分解能に対応する Duration
688
+ #
689
+ # @return [When::TM::PeriodDuration]
690
+ #
691
+ def period
692
+ return @period if @period
693
+ period_name = When::Coordinates::PERIOD_NAME[@precision]
694
+ raise ArgumentError, "Presicion not defined" unless period_name
695
+ @period = When.Duration(period_name)
696
+ end
697
+
698
+ # 前の日時
699
+ #
700
+ # @return [When::TM::TemporalPosition]
701
+ #
702
+ # 分解能に対応する Duration だけ,日時を戻す
703
+ #
704
+ def prev
705
+ @precision==When::DAY ? _force_euqal_day(-1) : self-period
706
+ rescue RangeError
707
+ (When.Calendar('Gregorian') ^ self) - period
708
+ end
709
+
710
+ # 次の日時
711
+ #
712
+ # @return [When::TM::TemporalPosition]
713
+ #
714
+ # 分解能に対応する Duration だけ,日時を進める
715
+ #
716
+ def succ
717
+ @precision==When::DAY ? _force_euqal_day(+1) : self+period
718
+ rescue RangeError
719
+ (When.Calendar('Gregorian') ^ self) + period
720
+ end
721
+ alias :next :succ
722
+
723
+ #
724
+ # 前後の日時を取得可能か?
725
+ #
726
+ # @return [Boolean]
727
+ # [ true - 可能 ]
728
+ # [ false - 不可 ]
729
+ #
730
+ def has_next?
731
+ When::Coordinates::PERIOD_NAME[@precision] != nil
732
+ end
733
+
734
+ # 下位桁の切り捨て
735
+ #
736
+ # @param [Integer] digit これより下の桁を切り捨てる(省略すると When::DAY)
737
+ #
738
+ # @param [Integer] precision 切り捨て結果の分解能
739
+ #
740
+ # @return [When::TM::TemporalPosition] (本 Class では、実際には切り捨てない)
741
+ #
742
+ def floor(digit=DAY, precision=digit)
743
+ self
744
+ end
745
+
746
+ # 分解能が時刻を持つか
747
+ #
748
+ # @return [Boolean]
749
+ #
750
+ def has_time?
751
+ (@precision > 0)
752
+ end
753
+
754
+ # 指定の日時を含むか?
755
+ #
756
+ # @param [When::TM::TemporalPosition] date チェックされる日時
757
+ #
758
+ # @return [Boolean]
759
+ # [ true - 含む ]
760
+ # [ false - 含まない ]
761
+ #
762
+ def include?(date)
763
+ return false if self.precision > date.precision
764
+ return self == date
765
+ end
766
+
767
+ # 大小比較
768
+ #
769
+ # @return [Integer] (-1, 0, 1)
770
+ #
771
+ # 分解能の低い方にあわせて比較を行う
772
+ #
773
+ # Ex. when?('2011-03') <=> when?('2011-03-10') -> 0
774
+ #
775
+ def <=>(other)
776
+ other = other.first if other.kind_of?(When::Parts::GeometricComplex)
777
+ [self.indeterminated_position, other.indeterminated_position].each do |position|
778
+ prec = SYSTEM if [TimeValue::Min, TimeValue::Max].include?(position)
779
+ end
780
+ prec = [self.precision, other.precision].min unless prec
781
+ case prec
782
+ when DAY ; return self.to_i <=> other.to_i
783
+ when SYSTEM ; src, dst = self, other
784
+ else
785
+ if prec < DAY && respond_to?(:most_significant_coordinate) &&
786
+ other.respond_to?(:most_significant_coordinate) && @frame.equal?(other.frame)
787
+ result = most_significant_coordinate <=> other.most_significant_coordinate
788
+ return result unless result == 0 && @cal_date.length + prec > 1
789
+ (@cal_date.length + prec - 2).times do |i|
790
+ result = @cal_date[i+1] <=> other.cal_date[i+1]
791
+ return result unless result == 0
792
+ end
793
+ return @cal_date[prec - 1] <=> other.cal_date[prec - 1]
794
+ end
795
+ src, dst =
796
+ [(prec >= self.precision ) ? self : self.floor(prec),
797
+ (prec >= other.precision) ? other : other.floor(prec)]
798
+ end
799
+ return src.to_i <=> dst.to_i if prec <= DAY
800
+ return src.universal_time <=> dst.universal_time if src.time_standard.equal?(dst.time_standard)
801
+ return src.dynamical_time <=> dst.dynamical_time
802
+ end
803
+
804
+ # 条件を満たすオブジェクトの抽出
805
+ #
806
+ # @param [Module, Array<Moduel>, When::Coordinates::Residue, When::TM::Duration, When::TM::Calendar, When::TM::CalendarEra] other
807
+ # @param [Boolean] leaf extract only leaf Objects.
808
+ # @param [Block] block If block is given, the specified block is yield.
809
+ #
810
+ # @return [Array of (element^self) for all When::Parts::Resource registered elements] (If other is Module)
811
+ # @return [Array of (self^element) for elemnt of other which belong to the specified module or class] (If other is [Array])
812
+ # @return [Enumerator which generates temporal position sequence begins from self with the specified duration] (If other is [When::TM::Duration])
813
+ # @return [Array of temporal position using the specified calendar as a frame] (If other is [When::TM::Calendar])
814
+ # @return [Array of temporal position using the specified calendar era as a calendarEraName] (If other is [When::TM::CalendarEra])
815
+ #
816
+ def scan(other, leaf=false, &block)
817
+ list = []
818
+ case other
819
+ when Numeric, TemporalPosition, Position
820
+ raise TypeError, "Operand should not be Numeric or (Temporal)Position"
821
+
822
+ when Module
823
+ objects = []
824
+ ObjectSpace.each_object(other) do |object|
825
+ objects << object if object.registered?
826
+ end
827
+ objects.each do |object|
828
+ element = (object ^ self)
829
+ if element && !(leaf && element.respond_to?(:leaf?) && !element.leaf?)
830
+ list << element
831
+ yield(element) if block_given?
832
+ end
833
+ end
834
+ return list
835
+
836
+ when Array
837
+ return other.map {|v| scan(v, leaf, &block)}
838
+
839
+ else
840
+ if other.respond_to?(:_enumerator)
841
+ enumerator = other._enumerator(self)
842
+ return enumerator unless block_given?
843
+ return enumerator.each(&block)
844
+ end
845
+
846
+ element = (other ^ self)
847
+ if element && !(leaf && element.respond_to?(:leaf?) && !element.leaf?)
848
+ list << element
849
+ yield(element) if block_given?
850
+ end
851
+ if (other.respond_to?(:child) && other.child)
852
+ other.child.each do |object|
853
+ list += scan(object, leaf, &block)
854
+ end
855
+ end
856
+ return list
857
+ end
858
+ end
859
+
860
+ # 条件を満たすオブジェクトの抽出
861
+ #
862
+ # @param (see #scan)
863
+ # @return (see #scan)
864
+ #
865
+ def ^(other, leaf=true, &block)
866
+ scan(other, leaf, &block)
867
+ end
868
+
869
+ # 属性を変更したコピーを作る
870
+ #
871
+ # @param [Hash] options { 属性=>属性値 }
872
+ #
873
+ # @return [When::TM::TemporalPosition]
874
+ #
875
+ def copy(options={})
876
+ position = self.dup
877
+ position._copy(options)
878
+ position
879
+ end
880
+
881
+ # 属性の Hash
882
+ # @private
883
+ def _attr
884
+ attributes = {}
885
+ ['frame', 'events', 'precision', 'options', 'trans', 'query', 'time_standard'].each do |key|
886
+ attributes[key.to_sym] = instance_variable_get("@#{key}")
887
+ end
888
+ return attributes
889
+ end
890
+
891
+ protected
892
+
893
+ # 属性のコピー
894
+ # @private
895
+ def _copy(options={})
896
+ @frame = options[:frame] if (options.key?(:frame))
897
+ @events = options[:events] if (options.key?(:events))
898
+ @precision = options[:precision] if (options.key?(:precision))
899
+ @query = options[:query] if (options.key?(:query))
900
+ @location = options[:location] if (options.key?(:location))
901
+ @time_standard = options[:time_standard] if (options.key?(:time_standard))
902
+ @sdn = @universal_time = @dynamical_time = @period = nil
903
+ _normalize(options)
904
+ return self
905
+ end
906
+
907
+ private
908
+
909
+ # オブジェクトの生成
910
+ #
911
+ # @param [Hash] options see {When::TM::TemporalPosition._instance}
912
+ #
913
+ def initialize(options={})
914
+ options.reject! {|key,value| value == nil}
915
+ options.each_pair do |key,value|
916
+ self.instance_variable_set("@#{key}", value)
917
+ end
918
+ @keys = []
919
+ @location = When.Resource(@location, '_l:') if @location.kind_of?(String)
920
+ # @sdn = @universal_time = @dynamical_time = nil
921
+ _normalize(options)
922
+ end
923
+
924
+ # オブジェクトの正規化
925
+ def _normalize(options={})
926
+ @precision ||= SYSTEM
927
+ @period = nil
928
+ @keys |= @frame.keys if @frame
929
+ end
930
+
931
+ # 指定桁のチェック
932
+ def _digit(index)
933
+ digit = index.kind_of?(String) ? PRECISION[index.upcase] : index
934
+ raise RangeError, " wrong digit: #{index}" unless digit.kind_of?(Integer) && (!block_given? || yield(digit))
935
+ digit
936
+ end
937
+
938
+ # 指定の日を探す
939
+ def _force_euqal_day(diff)
940
+ jdn = self.to_i + diff
941
+ date = self
942
+ done = {}
943
+ loop do
944
+ case
945
+ when date.to_i == jdn
946
+ return date
947
+ when date.to_i > jdn
948
+ next_date = date - When::DurationP1D
949
+ date = (date.to_i == next_date.to_i) ? date - When::DurationP1D * 2 : next_date
950
+ when date.to_i < jdn
951
+ next_date = date + When::DurationP1D
952
+ date = (date.to_i == next_date.to_i) ? date + When::DurationP1D * 2 : next_date
953
+ end
954
+ raise RangeError, "can't find target date: #{self} -> #{jdn}" if done.key?(date.to_i)
955
+ done[date.to_i] = true
956
+ end
957
+ end
958
+
959
+ # その他のメソッド
960
+ #
961
+ # @note
962
+ # When::TM::TemporalPosition で定義されていないメソッドは
963
+ # 処理を @frame (type: When::TM::Calendar or When::TM::Clock) に委譲する
964
+ #
965
+ def method_missing(name, *args, &block)
966
+ @frame.send(name.to_sym, self, *args, &block)
967
+ end
968
+ end
969
+
970
+ #
971
+ # 時間座標 - 単一の時間間隔によって定義する連続な間隔尺度を基礎とする
972
+ #
973
+ # see {http://schemas.opengis.net/gml/3.1.1/base/temporalAppendix.xsd#TimeCoordinateType gml schema}
974
+ #
975
+ class Coordinate < TemporalPosition
976
+
977
+ class << self
978
+ # 内部時間によるオブジェクトの生成
979
+ alias :universal_time :new
980
+
981
+ # 外部時間によるオブジェクトの生成
982
+ #
983
+ # @param [Numeric] dynamical_time 外部時間による時間座標値
984
+ #
985
+ # @param [Hash] options 下記の通り
986
+ # @option options [When::TimeStandard] :time_standard
987
+ #
988
+ # @return [When::TM::Coordinate]
989
+ #
990
+ def dynamical_time(dynamical_time, options={})
991
+ universal_time(When.Resource(options[:time_standard] || 'UniversalTime', '_t:').from_dynamical_time(dynamical_time), options)
992
+ end
993
+
994
+ # 他種の時間位置によるオブジェクトの生成
995
+ #
996
+ # @param [Numeric, When::TM::ClockTime, ::Time, ::Date, ::DateTime] time 他種の時間位置によるオブジェクト
997
+ #
998
+ # @param [Hash] options 下記の通り
999
+ # @option options [When::TM::Clock] :clock
1000
+ # @option options [When::Parts::Timezone] :tz
1001
+ #
1002
+ # @return [When::TM::Coordinate]
1003
+ #
1004
+ def new(time, options={})
1005
+ options = options.dup
1006
+ options[:frame] = Clock.get_clock_option(options)
1007
+ case time
1008
+ when Numeric
1009
+ options[:frame] ||= When.utc unless time.kind_of?(Integer)
1010
+ external_time = (2*time - (2*JulianDate::JD19700101-1)) * Duration::DAY.to_i / 2.0
1011
+ when ClockTime
1012
+ options[:frame] ||= time.clock
1013
+ external_time = time.clk_time[0] + time.universal_time
1014
+ when ::Time
1015
+ options[:frame] ||= When.Clock(time.gmtoff)
1016
+ external_time = When.Resource('_t:UniversalTime').from_time_object(time)
1017
+ when TimeValue
1018
+ options[:frame] ||= time.clock
1019
+ external_time = time.universal_time
1020
+ else
1021
+ if ::Object.const_defined?(:Date) && time.respond_to?(:ajd)
1022
+ case time
1023
+ when ::DateTime
1024
+ options[:frame] ||= When.Clock((time.offset * 86400).to_i)
1025
+ external_time = (2*time.ajd - (2*JulianDate::JD19700101-1)) * Duration::DAY.to_i / 2.0
1026
+ when ::Date
1027
+ external_time = JulianDate._d_to_t(time.jd)
1028
+ end
1029
+ end
1030
+ end
1031
+ raise TypeError, "Can't create #{self} from #{time.class}" unless external_time
1032
+ universal_time(external_time, options)
1033
+ end
1034
+ end
1035
+
1036
+ # 内部時間による時間座標値
1037
+ #
1038
+ # @return [Numeric]
1039
+ #
1040
+ attr_accessor :universal_time
1041
+ alias :coordinateValue :universal_time
1042
+ protected :universal_time=
1043
+
1044
+ # CoordinateSystem による時間座標値
1045
+ #
1046
+ # @return [Numeric]
1047
+ #
1048
+ def coordinateValue
1049
+ (universal_time - frame.origin.universal_time) / frame.interval.to_f
1050
+ end
1051
+
1052
+ # 加算
1053
+ #
1054
+ # @param [Numeric, When::TM::IntervalLength] other
1055
+ #
1056
+ # @return [When::TM::TemporalPosition]
1057
+ #
1058
+ def +(other)
1059
+ raise TypeError,"The right operand should be IntervalLength" if other.kind_of?(PeriodDuration)
1060
+ super
1061
+ end
1062
+
1063
+ # 減算
1064
+ #
1065
+ # @param [When::TM::TemporalPosition, Numeric, When::TM::IntervalLength] other
1066
+ #
1067
+ # @return [When::TM::TemporalPosition] if other is a Numeric or When::TM::IntervalLength
1068
+ # @return [When::TM::IntervalLength] if other is a When::TM::TemporalPosition
1069
+ #
1070
+ def -(other)
1071
+ raise TypeError,"The right operand should be IntervalLength or (Temporal)Position" if other.kind_of?(PeriodDuration)
1072
+ super
1073
+ end
1074
+
1075
+ # オブジェクトの生成
1076
+ #
1077
+ # @param [Numeric] universal_time 内部時間による時間座標値
1078
+ #
1079
+ # @param [Hash] options 下記の通り
1080
+ # @option options [When::TM::CoordinateSystem] :frame
1081
+ #
1082
+ def initialize(universal_time, options={})
1083
+ super(options)
1084
+ @universal_time = universal_time
1085
+ end
1086
+ end
1087
+
1088
+ #
1089
+ # ユリウス日
1090
+ #
1091
+ # see {http://schemas.opengis.net/gml/3.1.1/base/temporalAppendix.xsd#JulianDateType gml schema}
1092
+ #
1093
+ class JulianDate < Coordinate
1094
+
1095
+ # Julian Day Number
1096
+ # 19700101T120000Z
1097
+ JD19700101 = 2440588
1098
+
1099
+ class << self
1100
+
1101
+ JD19700100_5 = JD19700101 - 0.5
1102
+
1103
+ #
1104
+ # 日時の内部表現をユリウス日に変換
1105
+ #
1106
+ # @param [Numeric] t
1107
+ #
1108
+ # @return [Numeric]
1109
+ #
1110
+ def _t_to_d(t)
1111
+ t / Duration::DAY + JD19700100_5
1112
+ end
1113
+
1114
+ #
1115
+ # ユリウス日をに日時の内部表現変換
1116
+ #
1117
+ # @param [Numeric] d
1118
+ #
1119
+ # @return [Numeric]
1120
+ #
1121
+ def _d_to_t(d)
1122
+ (d - JD19700100_5) * Duration::DAY
1123
+ end
1124
+ end
1125
+
1126
+ # 加算
1127
+ #
1128
+ # @param [Numeric, When::TM::IntervalLength] other
1129
+ #
1130
+ # @return [When::TM::TemporalPosition]
1131
+ #
1132
+ def +(other)
1133
+ new_date = super
1134
+ if new_date.frame && new_date.frame._need_validate
1135
+ new_date.frame = new_date.frame._daylight(self.class.dynamical_time(new_date.dynamical_time, {:frame=>When.utc}))
1136
+ end
1137
+ return new_date
1138
+ end
1139
+
1140
+ # ユリウス日が指定の剰余となる日
1141
+ #
1142
+ # @param [When::Coordinates::Residue] other
1143
+ #
1144
+ # @return [When::TM::TemporalPosition]
1145
+ #
1146
+ def &(other)
1147
+ raise TypeError,"The right operand should be When::Coordinates::Residue" unless other.kind_of?(Residue)
1148
+ raise ArgumentError,"The right operand should have a unit 'day'" unless other.event == 'day'
1149
+ jdn = to_i
1150
+ new_date = self.dup
1151
+ new_date.universal_time += ((other & jdn) - jdn) * Duration::DAY
1152
+ return new_date
1153
+ end
1154
+
1155
+ # ユリウス日の剰余
1156
+ #
1157
+ # @param [When::Coordinates::Residue] other
1158
+ #
1159
+ # @return [Numeric]
1160
+ #
1161
+ def %(other)
1162
+ raise TypeError,"The right operand should be When::Coordinates::Residue" unless other.kind_of?(Residue)
1163
+ raise ArgumentError,"The right operand should have a unit 'day'" unless other.event == 'day'
1164
+ other % to_i
1165
+ end
1166
+
1167
+ private
1168
+
1169
+ # オブジェクトの生成
1170
+ #
1171
+ # @param [Numeric] universal_time 内部時間による時間座標値
1172
+ #
1173
+ # @param [Hash] options 以下の通り
1174
+ # @option options [When::TM::Clock] :frame
1175
+ # @option options [Integer] :precision
1176
+ #
1177
+ def initialize(universal_time, options={})
1178
+ @frame = options.delete(:frame)
1179
+ @frame = When.Clock(@frame) if (@frame.kind_of?(String))
1180
+ @frame = @frame._daylight(self.class.universal_time(universal_time, {:frame=>When.utc})) if @frame && @frame._need_validate
1181
+ precision = options.delete(:precision)
1182
+ precision ||= DAY unless @frame.kind_of?(Clock)
1183
+ @precision = Index.precision(precision)
1184
+ super
1185
+ end
1186
+ end
1187
+
1188
+ #
1189
+ # 順序時間参照系で参照する位置
1190
+ #
1191
+ # see {http://schemas.opengis.net/gml/3.1.1/base/temporalAppendix.xsd#TimeOrdinalPositionType gml schema}
1192
+ #
1193
+ class OrdinalPosition < TemporalPosition
1194
+
1195
+ # この順序位置と関連付けられた順序年代 (relation - Reference)
1196
+ #
1197
+ # The ordinal era associated with the ordinal position being described
1198
+ #
1199
+ # @return [When::TM::OrdinalEra]
1200
+ #
1201
+ attr_reader :ordinal_position
1202
+ alias :ordinalPosition :ordinal_position
1203
+
1204
+ # オブジェクトの生成
1205
+ #
1206
+ # @param [When::TM::OrdinalEra] ordinal_position この順序位置と関連付けられた順序年代
1207
+ # @param [Hash] options see {When::TM::TemporalPosition._instance}
1208
+ #
1209
+ def initialize(ordinal_position, options={})
1210
+ super(options)
1211
+ @ordinal_position = ordinal_position
1212
+ end
1213
+ end
1214
+
1215
+ #
1216
+ # 時刻
1217
+ #
1218
+ # see {http://schemas.opengis.net/gml/3.1.1/base/temporalAppendix.xsd#ClockTimeType gml schema}
1219
+ #
1220
+ class ClockTime < TemporalPosition
1221
+
1222
+ # 時刻要素
1223
+ #
1224
+ # @return [Array<Numeric>]
1225
+ #
1226
+ attr_reader :clk_time
1227
+ alias :clkTime :clk_time
1228
+
1229
+ # 内部時間
1230
+ #
1231
+ # @return [Numeric]
1232
+ #
1233
+ # T00:00:00Z からの Universal Coordinated Time の経過時間 / 128秒
1234
+ #
1235
+ # 時法によっては、異なる意味を持つことがある
1236
+ #
1237
+ def universal_time
1238
+ raise NameError, "Temporal Reference System is not defined" unless @frame
1239
+ @universal_time ||= @frame.to_universal_time(@clk_time)
1240
+ end
1241
+
1242
+ # 繰り上がり
1243
+ #
1244
+ # @return [Numeric]
1245
+ #
1246
+ # 日付の境界が午前0時でない場合、clk_time の最上位桁に 0 以外が入ることがある
1247
+ #
1248
+ def carry
1249
+ return @clk_time[0]
1250
+ end
1251
+
1252
+ # 要素の参照
1253
+ #
1254
+ # @param [Integer, String] index 参照する要素の指定
1255
+ #
1256
+ # @return [Numeric]
1257
+ #
1258
+ def value(index)
1259
+ @clk_time[_digit(index) {|digit| digit >= DAY}]
1260
+ end
1261
+
1262
+ #protected
1263
+ # 属性のコピー
1264
+ # @private
1265
+ def _copy(options={})
1266
+ @clk_time = options[:time] if (options.key?(:time))
1267
+ @frame = options[:clock] if (options.key?(:clock))
1268
+ if (options.key?(:tz_prop))
1269
+ @frame = @frame.dup
1270
+ @frame.tz_prop = options[:tz_prop]
1271
+ end
1272
+ return super
1273
+ end
1274
+
1275
+ # オブジェクトの生成
1276
+ #
1277
+ # @param [String] time ISO8601形式の時刻表現
1278
+ # @param [Array<Numeric>] time (日, 時, 分, 秒)
1279
+ #
1280
+ #
1281
+ # @param [Hash] options 以下の通り
1282
+ # @option options [When::TM::Clock] :frame
1283
+ # @option options [Integer] :precision
1284
+ #
1285
+ def initialize(time, options={})
1286
+ # 参照系の取得
1287
+ @frame = (options[:frame] || Clock.local_time || When.utc)
1288
+ @frame = When.Clock(@frame) if (@frame.kind_of?(String))
1289
+ options.delete(:frame)
1290
+
1291
+ # 時刻表現の解読 ( Time Zone の解釈 )
1292
+ if (time.kind_of?(String))
1293
+ case time
1294
+ when /^([-+])?(\d{2,}?):?(\d{2})?:?(\d{2}(\.\d+)?)?$/
1295
+ sign, hh, mm, ss = $~[1..4]
1296
+ time = @frame._validate([0,0,0,0],
1297
+ [0,
1298
+ -(sign.to_s + "0" + hh.to_s).to_i,
1299
+ -(sign.to_s + "0" + mm.to_s).to_i,
1300
+ Pair._en_number(-(sign.to_s + "0" + ss.to_s).to_f)])
1301
+ time[0] = Pair.new(0, time[0].to_i) if (time[0] != 0)
1302
+ when /^Z$/
1303
+ time = [0,0,0,0]
1304
+ else
1305
+ raise ArgumentError, "Invalid Time Format"
1306
+ end
1307
+ end
1308
+ @clk_time = time
1309
+
1310
+ # 分解能
1311
+ @precision = @frame._precision(time, options.delete(:precision))
1312
+
1313
+ super(options)
1314
+ end
1315
+
1316
+ private
1317
+
1318
+ # オブジェクトの正規化
1319
+ def _normalize(options={})
1320
+ # strftime で使用する locale
1321
+ @keys |= @frame.keys
1322
+
1323
+ # 時刻の正規化
1324
+ @clk_time = @frame._validate(@clk_time) unless options[:validate]
1325
+ end
1326
+
1327
+ # 加減算共通処理
1328
+ def _plus(period)
1329
+ self.dup._copy({:time=>@frame._validate(@clk_time, @frame._arrange_length(period.time)),
1330
+ :events=>nil, :query=>nil, :validate=>:done})
1331
+ end
1332
+ end
1333
+
1334
+ #
1335
+ # 暦日
1336
+ #
1337
+ # see {gml schema}[link:http://schemas.opengis.net/gml/3.1.1/base/temporalAppendix.xsd#CalDateType]
1338
+ #
1339
+ class CalDate < TemporalPosition
1340
+
1341
+ # 検索オプション
1342
+ # @private
1343
+ SearchOption = {After=>[0, -2, Before], Before=>[-2, 0, After]}
1344
+
1345
+ # 日付要素
1346
+ #
1347
+ # @return [Array<Numeric>]
1348
+ #
1349
+ attr_reader :cal_date
1350
+ alias :calDate :cal_date
1351
+
1352
+ # 暦年代名
1353
+ #
1354
+ # @return [Array] ( name, epoch, reverse, go back )
1355
+ # - name [String] 暦年代名
1356
+ # - epoch [Integer] 使用する When::TM::Calendar で暦元に対応する年
1357
+ # - reverse [Boolean] 年数が昇順(false,nil)か降順(true)か
1358
+ # - go back [Boolean] 参照イベントより前の暦日か(true)、否か(false,nil)
1359
+ #
1360
+ attr_accessor :calendar_era_name
1361
+ alias :calendarEraName :calendar_era_name
1362
+
1363
+ # 暦年代
1364
+ #
1365
+ # @return [When::TM::CalendarEra]
1366
+ #
1367
+ attr_accessor :calendar_era
1368
+ alias :calendarEra :calendar_era
1369
+
1370
+ # 時法の取得 - ダミー
1371
+ def clock
1372
+ nil
1373
+ end
1374
+
1375
+ # 内部時間
1376
+ #
1377
+ # @return [Numeric]
1378
+ #
1379
+ # 当日正午の 1970-01-01T00:00:00Z からの Universal Coordinated Time の経過時間 / 128秒
1380
+ #
1381
+ def universal_time
1382
+ return super if [Now, Max, Min].include?(@indeterminated_position)
1383
+ @universal_time ||= JulianDate._d_to_t(to_i)
1384
+ end
1385
+
1386
+ # ユリウス日
1387
+ #
1388
+ # @return [Integer]
1389
+ #
1390
+ # -4712-01-01T12:00:00Z からの経過日数に対応する通番(日の境界で1進める)
1391
+ #
1392
+ def to_i
1393
+ return @sdn if @sdn
1394
+ name, base = @calendar_era_name
1395
+ if base
1396
+ date = @cal_date.dup
1397
+ date[0] += base
1398
+ else
1399
+ date = @cal_date
1400
+ end
1401
+ @sdn = @frame.to_julian_date(date)
1402
+ end
1403
+
1404
+ # 剰余類化
1405
+ #
1406
+ # @param [Numeric] remainder 剰余
1407
+ # @param [Integer] divisor 法(>0)
1408
+ #
1409
+ # @return [When::Coordinates::Residue] 当日、当年を基準とする剰余類
1410
+ #
1411
+ def to_residue(remainder, divisor)
1412
+ When::Coordinates::Residue.new(remainder, divisor, {'day' => least_significant_coordinate,
1413
+ 'year' => most_significant_coordinate})
1414
+ end
1415
+
1416
+ # 要素の参照
1417
+ #
1418
+ # @param [Integer, String] index 参照する要素の指定
1419
+ #
1420
+ # @return [Numeric]
1421
+ #
1422
+ def value(index)
1423
+ @cal_date[(_digit(index) {|digit| digit <= DAY})-1]
1424
+ end
1425
+
1426
+ #
1427
+ # 最上位の要素
1428
+ #
1429
+ # @return [Numeric] 暦年代の epoch に関わらず暦法に従った年の通し番号を返す
1430
+ #
1431
+ def most_significant_coordinate
1432
+ coordinate = @cal_date[0]
1433
+ coordinate += @calendar_era_name[1] if @calendar_era_name
1434
+ @frame.index_of_MSC.times do |i|
1435
+ coordinate = +coordinate * @frame.indices[i].unit + @cal_date[i+1] - @frame.indices[i].base
1436
+ end
1437
+ coordinate
1438
+ end
1439
+
1440
+ #
1441
+ # 最下位の要素
1442
+ #
1443
+ # @return [Numeric] 剰余類の演算に用いる日の通し番号を返す
1444
+ #
1445
+ def least_significant_coordinate
1446
+ return to_i + @frame.indices[-1].shift
1447
+ end
1448
+
1449
+ # ユリウス日または通年が指定の剰余となる日
1450
+ #
1451
+ # @param [When::Coordinates::Residue] other
1452
+ #
1453
+ # @return [When::TM::CalDate]
1454
+ #
1455
+ def &(other)
1456
+ raise TypeError,"The right operand should be When::Coordinates::Residue" unless other.kind_of?(Residue)
1457
+ case other.event
1458
+ when 'day'
1459
+ # 指定の剰余となる日
1460
+ other -= @frame.indices[-1].shift unless @frame.indices[-1].shift == 0
1461
+ date = @frame.to_cal_date(other & to_i)
1462
+ date[0] -= @calendar_era_name[1] if @calendar_era_name
1463
+ return self.dup._copy({:events=>nil, :query=>@query, :validate=>:done, :date=>date})
1464
+
1465
+ when 'year'
1466
+ # 指定の剰余となる年
1467
+ date = @cal_date.dup
1468
+ date[0] = (other & (most_significant_coordinate + @frame._diff_to_CE)) - @frame._diff_to_CE
1469
+ date[0] -= @calendar_era_name[1] if @calendar_era_name
1470
+ return self.dup._copy({:date=>date, :events=>nil, :query=>@query})
1471
+
1472
+ else
1473
+ raise ArgumentError,"The right operand should have a unit 'day' or 'year'"
1474
+ end
1475
+ end
1476
+
1477
+ # ユリウス日または通年の剰余
1478
+ #
1479
+ # @param [When::Coordinates::Residue] other
1480
+ #
1481
+ # @return [Numeric]
1482
+ #
1483
+ def %(other)
1484
+ raise TypeError,"The right operand should be When::Coordinates::Residue" unless other.kind_of?(Residue)
1485
+ case other.event
1486
+ when 'day' ; other % least_significant_coordinate
1487
+ when 'year' ; other % (most_significant_coordinate + @frame._diff_to_CE)
1488
+ else ; raise ArgumentError,"The right operand should have a unit 'day' or 'year'"
1489
+ end
1490
+ end
1491
+
1492
+ # 下位桁の切り捨て
1493
+ #
1494
+ # @param [Integer] digit 切り捨てずに残す、最下位の桁
1495
+ #
1496
+ # @param [Integer] precision 切り捨て結果の分解能
1497
+ #
1498
+ # @return [When::TM::CalDate]
1499
+ #
1500
+ def floor(digit=DAY, precision=digit)
1501
+ options = {:date=>@cal_date[0..(digit-1)], :events=>nil, :query=>nil}
1502
+ options[:precision] = precision if precision
1503
+ self.dup._copy(options)
1504
+ end
1505
+
1506
+ # 下位桁の切り上げ
1507
+ #
1508
+ # @param [Integer] digit 切り上げずに残す、最下位の桁
1509
+ #
1510
+ # @param [Integer] precision 切り上げ結果の分解能
1511
+ #
1512
+ # @return [When::TM::CalDate]
1513
+ #
1514
+ def ceil(digit=DAY, precision=digit)
1515
+ (self + PeriodDuration.new(1, digit, (-@frame.indices.length)..0)).floor(digit, precision)
1516
+ end
1517
+
1518
+ # 要素数 ― 上位要素に含まれる下位要素の数
1519
+ #
1520
+ # @param [Integer] upper 上位要素のインデックス
1521
+ # @param [Integer] lower 下位要素のインデックス(DAY または MONTH)
1522
+ #
1523
+ # @return [Integer]
1524
+ #
1525
+ def length(upper, lower=DAY)
1526
+ range = [floor(upper).to_i, ceil(upper).to_i]
1527
+ range = range.map {|d| (Residue.mod(d) {|m| frame._new_month(m)})[0]} if lower == MONTH
1528
+ range[1] - range[0]
1529
+ end
1530
+
1531
+ # 時刻情報のない When::TM::CalDate を返す
1532
+ #
1533
+ # @return [When::TM::CalDate]
1534
+ #
1535
+ alias :to_cal_date :dup
1536
+ alias :to_CalDate :to_cal_date
1537
+
1538
+ # 暦年代が末端の参照であるか?
1539
+ #
1540
+ # @return [Boolean]
1541
+ #
1542
+ def leaf?
1543
+ name, = @calendar_era_name
1544
+ return true unless name.respond_to?(:_pool)
1545
+ era = name._pool['..']
1546
+ return true unless era.respond_to?(:leaf?)
1547
+ return era.leaf?
1548
+ end
1549
+
1550
+ # 属性の Hash
1551
+ # @private
1552
+ def _attr
1553
+ super.merge({:era_name=>@calendar_era_name, :era=>@calendar_era})
1554
+ end
1555
+ protected
1556
+
1557
+ # 属性のコピー
1558
+ # @private
1559
+ def _copy(options={})
1560
+ @cal_date = options[:date] if (options.key?(:date))
1561
+ return super
1562
+ end
1563
+
1564
+ # オブジェクトの生成
1565
+ #
1566
+ # @param [Array<Numeric>] date 日付表現
1567
+ #
1568
+ # @param [Hash] options 下記の通り (see also {When::TM::TemporalPosition._instance})
1569
+ # @option options [When::TM::Calendar] :frame
1570
+ # @option options [When::TM::CalendarEra, When::BasicTypes::M17n, Array<When::BasicTypes::M17n, Integer>] :era_name
1571
+ # (Integer は 当該年号の 0 年に相当する通年)
1572
+ # @option options [Integer] :precision
1573
+ #
1574
+ def initialize(date, options={})
1575
+ # 年号 & 日付
1576
+ @calendar_era_name = options[:era_name]
1577
+ @calendar_era = options[:era]
1578
+ @cal_date = date
1579
+
1580
+ super(options)
1581
+ end
1582
+
1583
+ private
1584
+
1585
+ # オブジェクトの正規化
1586
+ def _normalize(options={})
1587
+
1588
+ # 日付配列の長さ
1589
+ cal_date_index = @cal_date.index(nil) || @cal_date.length
1590
+
1591
+ # 日付の正規化
1592
+ if @calendar_era_name
1593
+ # Calendar Era がある場合
1594
+ trans_options = @trans || {} # TODO? 消す
1595
+ count = trans_options[:count] || 1
1596
+ query_options = (@query || {}).dup
1597
+ query_options[:label] = @calendar_era_name
1598
+ query_options[:count] = count
1599
+ era = date = nil
1600
+ if @calendar_era
1601
+ era, date = _search_era(@calendar_era, trans_options)
1602
+ else
1603
+ eras = CalendarEra._instance(query_options)
1604
+ raise ArgumentError, "CalendarEraName doesn't exist: #{query_options[:label]}" if (eras.size==0)
1605
+ eras.each do |e|
1606
+ era, date = _search_era(e, trans_options)
1607
+ next unless era
1608
+ count -= 1
1609
+ break unless count > 0
1610
+ end
1611
+ end
1612
+ raise RangeError, "Out of CalendarEra Range" unless era
1613
+ @calendar_era_name = date.calendar_era_name
1614
+ @calendar_era = era
1615
+ @cal_date = date.cal_date
1616
+ @frame = date.frame
1617
+ @query = (@query||{}).merge(date.query)
1618
+ @trans = (@trans||{}).merge(date.trans)
1619
+ @keys |= @calendar_era_name[0].keys | @frame.keys
1620
+ else
1621
+ # Calendar Era がない場合
1622
+ @frame = When.Resource(options[:frame] || @frame || 'Gregorian', '_c:')
1623
+ @cal_date = @frame._validate(@cal_date) unless options[:validate] == :done
1624
+ @keys |= @frame.keys
1625
+ end
1626
+
1627
+ # 分解能
1628
+ precision = options.delete(:precision) || @precision
1629
+ cal_date_index =
1630
+ case options.delete(:_format)
1631
+ when :century ; CENTURY
1632
+ when :week, :day ; DAY
1633
+ else ; cal_date_index - (@frame.indices.length + 1)
1634
+ end
1635
+ precision ||= cal_date_index if cal_date_index < DAY
1636
+ precision ||= @clk_time.precision if @clk_time
1637
+ @precision = Index.precision(precision || DAY)
1638
+ end
1639
+
1640
+ # 暦年代を探す
1641
+ def _search_era(era, trans_options)
1642
+ cal_date = @cal_date.dup
1643
+ cal_date[0] = -cal_date[0] if era.reverse?
1644
+ cal_date[0] += era.epoch_year
1645
+ date = era.trans(cal_date, trans_options)
1646
+ loop do
1647
+ case date
1648
+ when Before, After
1649
+ i0, i1, reverse = SearchOption[date]
1650
+ new_era = (date == Before) ? era.prev : era.succ
1651
+ break unless new_era
1652
+ date = new_era.trans(cal_date, trans_options)
1653
+ if date == reverse
1654
+ cal_date = new_era.epoch[i0].frame.to_cal_date(era.epoch[i1].frame.to_julian_date(cal_date))
1655
+ date = new_era.trans(cal_date, trans_options)
1656
+ break if date == reverse
1657
+ end
1658
+ era = new_era
1659
+ when TimeValue
1660
+ return era, date
1661
+ else
1662
+ break
1663
+ end
1664
+ end
1665
+ return nil
1666
+ end
1667
+
1668
+ # 加減算共通処理
1669
+ def _plus(period)
1670
+ self.dup._copy({:date=>_date_with_era(@frame._validate(_date_without_era,
1671
+ @frame._arrange_length(period.date))),
1672
+ :events=>nil, :query=>nil, :validate=>:done})
1673
+ end
1674
+
1675
+ # 年号を除外した @frame の暦法に対応する日付
1676
+ def _date_without_era
1677
+ date = @cal_date.dup
1678
+ date[0] += @calendar_era_name[1] if @calendar_era_name
1679
+ date
1680
+ end
1681
+
1682
+ # 年号に続く日付
1683
+ def _date_with_era(date)
1684
+ date[0] -= @calendar_era_name[1] if @calendar_era_name
1685
+ date
1686
+ end
1687
+ end
1688
+
1689
+ #
1690
+ # 時刻を伴った日付
1691
+ #
1692
+ # see {http://schemas.opengis.net/gml/3.1.1/base/temporalAppendix.xsd#DateAndTimeType gml schema}
1693
+ #
1694
+ class DateAndTime < CalDate
1695
+
1696
+ # 時刻要素
1697
+ #
1698
+ # @return [When::TM::ClockTime]
1699
+ #
1700
+ attr_reader :clk_time
1701
+ alias :clkTime :clk_time
1702
+
1703
+ # 時法の取得
1704
+ #
1705
+ # @return [When::TM::Clock]
1706
+ #
1707
+ def clock
1708
+ @clk_time.frame
1709
+ end
1710
+
1711
+ # 内部時間
1712
+ #
1713
+ # @return [Numeric]
1714
+ #
1715
+ # 1970-01-01T00:00:00Z からの Universal Coordinated Time の経過時間 / 128秒
1716
+ #
1717
+ # 暦法によっては、異なる意味を持つことがある
1718
+ #
1719
+ def universal_time
1720
+ return super if [Now, Max, Min].include?(@indeterminated_position)
1721
+ raise NameError, "Temporal Reference System is not defined" unless (@frame && clock)
1722
+ @universal_time ||= (to_i - +@clk_time.clk_time[0] - JulianDate::JD19700101) * Duration::DAY +
1723
+ @clk_time.universal_time
1724
+ end
1725
+
1726
+ # 要素の参照
1727
+ #
1728
+ # @param [Integer] index 参照する要素の指定
1729
+ #
1730
+ # @return [Numeric]
1731
+ #
1732
+ def value(index)
1733
+ digit = _digit(index)
1734
+ return (digit <= DAY) ? @cal_date[digit-1] : @clk_time.clk_time[digit]
1735
+ end
1736
+
1737
+ # ユリウス日または通年が指定の剰余となる日
1738
+ #
1739
+ # @param [When::Coordinates::Residue] other
1740
+ #
1741
+ # @return [When::TM::DateAndTime]
1742
+ #
1743
+ def &(other)
1744
+ raise TypeError,"The right operand should be When::Coordinates::Residue" unless other.kind_of?(Residue)
1745
+ case other.event
1746
+ when 'day'
1747
+ # 指定の剰余となる日
1748
+ other -= @frame.indices[-1].shift unless @frame.indices[-1].shift == 0
1749
+ return self.dup._copy({:events=>nil, :query=>@query, :validate=>:done,
1750
+ :date=>_date_with_era(@frame.to_cal_date(other & to_i)),
1751
+ :time=>@clk_time.clk_time.dup})
1752
+
1753
+ when 'year'
1754
+ # 指定の剰余となる年
1755
+ date = @cal_date.dup
1756
+ date[0] = (other & (most_significant_coordinate + @frame._diff_to_CE)) - @frame._diff_to_CE
1757
+ return self.dup._copy({:events=>nil, :query=>@query,
1758
+ :date=>_date_with_era(date),
1759
+ :time=>@clk_time.clk_time.dup})
1760
+
1761
+ else
1762
+ raise ArgumentError,"The right operand should have a unit 'day' or 'year'"
1763
+ end
1764
+ end
1765
+
1766
+ # 下位桁の切り捨て
1767
+ #
1768
+ # @param [Integer] digit 切り捨てずに残す、最下位の桁
1769
+ #
1770
+ # @param [Integer] precision 切り捨て結果の分解能
1771
+ #
1772
+ # @return [When::TM::DateAndTime]
1773
+ #
1774
+ def floor(digit=DAY, precision=digit)
1775
+ count = digit - clock.indices.length
1776
+ date = (digit>=DAY) ? @cal_date.dup : @frame._validate(@cal_date[0..(digit-1)])
1777
+ time = clock._validate(@clk_time.clk_time[0..((digit<=DAY) ? 0 : ((count>=0) ? -1 : digit))])
1778
+
1779
+ if (count >= 0)
1780
+ factor = 10**count
1781
+ time[-1] = (time[-1] * factor).floor.to_f / factor
1782
+ end
1783
+
1784
+ # オブジェクトの生成
1785
+ options = {:date=>date, :validate=>:done, :events=>nil, :query=>nil,
1786
+ :time=>(digit<=DAY) ? time : @clk_time.dup._copy({:time=>time})}
1787
+ options[:precision] = precision if precision
1788
+ return self.dup._copy(options)
1789
+ end
1790
+
1791
+ # 下位桁の切り上げ
1792
+ #
1793
+ # digit : Integer
1794
+ # @param [Integer] digit 切り上げずに残す、最下位の桁
1795
+ #
1796
+ # @param [Integer] precision 切り上げ結果の分解能
1797
+ #
1798
+ # @return [When::TM::DateAndTime]
1799
+ #
1800
+ def ceil(digit=DAY, precision=digit)
1801
+ length = clock.indices.length
1802
+ count = digit - length
1803
+ period = PeriodDuration.new((count<=0) ? 1 : 0.1**count, digit, (-@frame.indices.length)..length)
1804
+ result = floor(digit, precision) + period
1805
+ result += clock._tz_difference if (result.universal_time <= self.universal_time)
1806
+ return result
1807
+ end
1808
+
1809
+ # 時刻情報のない When::TM::CalDate を返す
1810
+ #
1811
+ # @return [When::TM::CalDate]
1812
+ #
1813
+ def to_cal_date
1814
+ options = _attr
1815
+ options.delete(:clock)
1816
+ options[:precision] = [When::DAY, options[:precision]].min
1817
+ CalDate.new(@cal_date, options)
1818
+ end
1819
+ alias :to_CalDate :to_cal_date
1820
+
1821
+ #protected
1822
+
1823
+ # 属性の Hash
1824
+ # @private
1825
+ def _attr
1826
+ super.merge({:clock=>clock})
1827
+ end
1828
+
1829
+ # 属性のコピー
1830
+ # @private
1831
+ def _copy(options={})
1832
+ # 夏時間の調整
1833
+ case options[:time]
1834
+ when Array
1835
+ if clock._need_validate
1836
+ new_clock = clock._daylight { |c| self.class.new(options[:date], options[:time], {:frame=>@frame, :clock=>c}) } || clock
1837
+ options[:time] = options[:time].map {|t| t * 1}
1838
+ else
1839
+ new_clock = clock
1840
+ end
1841
+ options[:time] = @clk_time.dup._copy(options.merge({:clock=>new_clock}))
1842
+ when nil
1843
+ options[:time] = @clk_time.dup._copy(options)
1844
+ end
1845
+
1846
+ return super(options)
1847
+ end
1848
+
1849
+ # オブジェクトの生成
1850
+ #
1851
+ # @param [Array<Numeric>] date 日付表現
1852
+ # @param [Array<Numeric>] time 時刻表現
1853
+ # @param [Hash] options 下記の通り (see also {When::TM::TemporalPosition._instance})
1854
+ # @option options [When::TM::Calendar] :frame
1855
+ # @option options [When::TM::Clock] :clock
1856
+ # @option options [When::TM::CalendarEra, When::BasicTypes::M17n, Array<When::BasicTypes::M17n, Integer>] :era_name
1857
+ # (Integer は 当該年号の 0 年に相当する通年)
1858
+ # @option options [Integer] :precision
1859
+ #
1860
+ def initialize(date, time, options={})
1861
+ options[:time] = time
1862
+ super(date, options)
1863
+ end
1864
+
1865
+ private
1866
+
1867
+ # オブジェクトの正規化
1868
+ def _normalize(options={})
1869
+
1870
+ # Clock
1871
+ unless options[:validate]
1872
+ clock = Clock.get_clock_option(options)
1873
+ clock ||= options[:time].frame if options[:time].kind_of?(ClockTime)
1874
+ clock ||= Clock.local_time || When.utc
1875
+ end
1876
+ clock = When.Clock(clock) if (clock.kind_of?(String))
1877
+ clock_is_timezone = clock.respond_to?(:daylight)
1878
+ clock = clock.daylight if clock_is_timezone
1879
+
1880
+ # ClockTime
1881
+ @clk_time =
1882
+ case options[:time]
1883
+ when ClockTime ; options[:time]
1884
+ when Array ; ClockTime.new(options[:time], {:frame=>clock, :precision=>options[:precision], :validate=>:done})
1885
+ else ; clock.to_clk_time(options[:time], {:precision=>options[:precision]})
1886
+ end
1887
+
1888
+ super
1889
+
1890
+ # 日付と時刻の正規化
1891
+ unless options[:validate]
1892
+ time = @clk_time.clk_time
1893
+ precision = @clk_time.precision
1894
+ second = time[clock.base.length-1]
1895
+ second -= clock.base[-1] if second
1896
+ if second && second != 0 && time_standard.has_leap?
1897
+ zero = DateAndTime.new(@cal_date, time[0..-2],
1898
+ {:frame=>@frame, :clock=>clock, :precision=>precision,
1899
+ :era_name=>@calendar_era_name, :era=>options[:era],
1900
+ :time_standard=>time_standard, :location=>@location})
1901
+ end
1902
+
1903
+ # 日付と時刻の関係の調整
1904
+ @cal_date = _date_with_era(@frame._validate(_date_without_era) {|jdn|
1905
+ time[0] += jdn
1906
+ time[0..-1] = clock._validate(time)
1907
+ jdn = time[0] * 1
1908
+ time[0] -= jdn
1909
+ jdn
1910
+ })
1911
+
1912
+ # 夏時間の調整
1913
+ if clock._need_validate
1914
+ clock = clock._daylight {|clock| self.class.new(@cal_date, time, {:frame=>@frame, :clock=>clock}) } || clock
1915
+ end
1916
+ time = time.map {|t| t * 1}
1917
+ @clk_time = ClockTime.new(time, {:frame=>clock, :precision=>precision, :validate=>:done}) if clock_is_timezone
1918
+
1919
+ # 閏秒
1920
+ if zero
1921
+ leap = ((dynamical_time - zero.dynamical_time) * clock.second - second).to_i
1922
+ if leap != 0 && leap.abs < clock.second
1923
+ @cal_date = zero.cal_date
1924
+ @clk_time = zero.clk_time
1925
+ @clk_time.clk_time[-1] += second
1926
+ leap /= clock.second
1927
+ @universal_time = When::Coordinates::LeapSeconds.new(@universal_time-leap, leap, 1/clock.second)
1928
+ @dynamical_time -= leap
1929
+ end
1930
+ end
1931
+ end
1932
+
1933
+ # 後処理
1934
+ @keys |= @clk_time.keys
1935
+ end
1936
+
1937
+ # 加減算共通処理
1938
+ def _plus(period)
1939
+ # 日時の加算
1940
+ time = @clk_time.clk_time.dup
1941
+ pdate = @frame._arrange_length(period.date)
1942
+ ptime = clock._arrange_length(period.time)
1943
+ date = _date_with_era(@frame._validate(_date_without_era, pdate) {|jdn|
1944
+ time[0] += jdn
1945
+ time = clock._validate(time, ptime)
1946
+ jdn = time[0] * 1
1947
+ time[0] -= jdn
1948
+ jdn
1949
+ })
1950
+
1951
+ # オブジェクトの生成
1952
+ self.dup._copy({:date=>date, :time=>time, :validate=>:done, :events=>nil, :query=>nil})
1953
+ end
1954
+ end
1955
+ end