when_exe 0.4.2 → 0.5.0

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 (144) hide show
  1. checksums.yaml +5 -5
  2. data/LICENSE.ja.txt +8 -21
  3. data/LICENSE.txt +5 -27
  4. data/README.md +25 -79
  5. data/bin/.pryrc +9 -0
  6. data/bin/make_ttl.rb +3 -2
  7. data/bin/make_ttl.rb.config +3 -3
  8. data/lib/when_exe.rb +101 -5
  9. data/lib/when_exe/basictypes.rb +47 -16
  10. data/lib/when_exe/calendarnote.rb +27 -18
  11. data/lib/when_exe/calendartypes.rb +12 -50
  12. data/lib/when_exe/coordinates.rb +37 -391
  13. data/lib/when_exe/ephemeris.rb +53 -14
  14. data/lib/when_exe/ephemeris/eclipse.rb +8 -8
  15. data/lib/when_exe/ephemeris/moon.rb +333 -333
  16. data/lib/when_exe/ephemeris/notes.rb +29 -17
  17. data/lib/when_exe/ephemeris/phase_table.rb +825 -0
  18. data/lib/when_exe/ephemeris/term_table.rb +603 -0
  19. data/lib/when_exe/events.rb +1888 -0
  20. data/lib/when_exe/google_api.rb +26 -31
  21. data/lib/when_exe/icalendar.rb +129 -12
  22. data/lib/when_exe/inspect.rb +5 -5
  23. data/lib/when_exe/linkeddata.rb +43 -23
  24. data/lib/when_exe/locales/akt.rb +63 -0
  25. data/lib/when_exe/locales/encoding_conversion.rb +134 -134
  26. data/lib/when_exe/locales/iast.rb +90 -90
  27. data/lib/when_exe/locales/locale.rb +88 -18
  28. data/lib/when_exe/locales/transliteration_table.rb +62 -62
  29. data/lib/when_exe/mini_application.rb +14 -8
  30. data/lib/when_exe/namespace.rb +42 -0
  31. data/lib/when_exe/parts/enumerator.rb +16 -5
  32. data/lib/when_exe/parts/geometric_complex.rb +52 -2
  33. data/lib/when_exe/parts/method_cash.rb +229 -224
  34. data/lib/when_exe/parts/resource.rb +65 -35
  35. data/lib/when_exe/parts/timezone.rb +25 -34
  36. data/lib/when_exe/region/balinese.rb +5 -3
  37. data/lib/when_exe/region/chinese.rb +39 -11
  38. data/lib/when_exe/region/chinese/calendars.rb +1016 -1016
  39. data/lib/when_exe/region/chinese/epochs.rb +7 -7
  40. data/lib/when_exe/region/chinese/notes.rb +3 -3
  41. data/lib/when_exe/region/chinese/twins.rb +134 -11
  42. data/lib/when_exe/region/dee.rb +4 -4
  43. data/lib/when_exe/region/discordian.rb +1 -1
  44. data/lib/when_exe/region/geologicalage.rb +139 -128
  45. data/lib/when_exe/region/hanke_henry.rb +4 -4
  46. data/lib/when_exe/region/indian.rb +77 -8
  47. data/lib/when_exe/region/international_fixed.rb +3 -3
  48. data/lib/when_exe/region/islamic.rb +1 -1
  49. data/lib/when_exe/region/japanese.rb +12 -8
  50. data/lib/when_exe/region/japanese/calendars.rb +397 -397
  51. data/lib/when_exe/region/japanese/eclipses.rb +1194 -1194
  52. data/lib/when_exe/region/japanese/epochs.rb +8 -4
  53. data/lib/when_exe/region/japanese/location.rb +93 -0
  54. data/lib/when_exe/region/japanese/nihon_shoki.rb +70 -70
  55. data/lib/when_exe/region/japanese/notes.rb +57 -18
  56. data/lib/when_exe/region/japanese/residues.rb +33 -11
  57. data/lib/when_exe/region/japanese/twins.rb +27 -14
  58. data/lib/when_exe/region/japanese/weeks.rb +7 -7
  59. data/lib/when_exe/region/korean.rb +384 -384
  60. data/lib/when_exe/region/location.rb +40 -0
  61. data/lib/when_exe/region/martian.rb +1 -1
  62. data/lib/when_exe/region/mayan.rb +2 -2
  63. data/lib/when_exe/region/roman.rb +2 -2
  64. data/lib/when_exe/region/ryukyu.rb +101 -101
  65. data/lib/when_exe/region/saudi_arabian.rb +57 -0
  66. data/lib/when_exe/region/shire.rb +1 -1
  67. data/lib/when_exe/region/world.rb +3 -3
  68. data/lib/when_exe/region/zoroastrian.rb +1 -1
  69. data/lib/when_exe/spatial.rb +611 -0
  70. data/lib/when_exe/timestandard.rb +9 -7
  71. data/lib/when_exe/tmobjects.rb +34 -2
  72. data/lib/when_exe/tmposition.rb +225 -1322
  73. data/lib/when_exe/tmptypes.rb +1279 -0
  74. data/lib/when_exe/tmreference.rb +42 -7
  75. data/lib/when_exe/version.rb +3 -3
  76. data/test/events/example-datasets +6 -0
  77. data/test/events/history-dataset.csv +22 -0
  78. data/test/events/japanese-holiday-index.csv +28 -0
  79. data/test/events/japanese-holiday.csv +94 -0
  80. data/test/events/japanese-holiday.ttl +948 -0
  81. data/test/events/make_events_ttl.rb +18 -0
  82. data/test/events/mori_wikichoshi.csv +14 -0
  83. data/test/events/ndl_koyomi.csv +220 -0
  84. data/test/events/ndl_koyomi_index.csv +44 -0
  85. data/test/events/primeminister-dataset.csv +19 -0
  86. data/test/events/shogun-dataset.csv +22 -0
  87. data/test/events/test-history-dataset-edge-sparql.csv +26 -0
  88. data/test/events/test-history-dataset-edge.csv +27 -0
  89. data/test/events/test-history-dataset-sparql.csv +22 -0
  90. data/test/events/test-history-dataset.csv +23 -0
  91. data/test/events/test-history-events-edge.ttl +89 -0
  92. data/test/events/test-history-events.csv +6 -0
  93. data/test/examples/JapanHolidays.ics +2 -2
  94. data/test/examples/JapanHolidaysRFC6350.ics +3 -3
  95. data/test/examples/Residue.m17n +2 -2
  96. data/test/examples/Spatial.m17n +3 -3
  97. data/test/examples/Terms.m17n +3 -3
  98. data/test/scripts/8.ext.rb +6 -6
  99. data/test/scripts/8.rb +6 -6
  100. data/test/scripts/geometric_complex.rb +41 -41
  101. data/test/scripts/korea.rb +59 -59
  102. data/test/scripts/thai.rb +36 -36
  103. data/test/test.rb +6 -0
  104. data/test/test/basictypes.rb +431 -431
  105. data/test/test/calendarnote.rb +86 -86
  106. data/test/test/calendartypes.rb +97 -97
  107. data/test/test/coordinates.rb +399 -397
  108. data/test/test/ephemeris.rb +115 -115
  109. data/test/test/ephemeris/moon.rb +14 -14
  110. data/test/test/ephemeris/planets.rb +14 -14
  111. data/test/test/ephemeris/sun.rb +14 -14
  112. data/test/test/events.rb +32 -0
  113. data/test/test/google_api.rb +45 -32
  114. data/test/test/inspect.rb +153 -153
  115. data/test/test/parts.rb +488 -488
  116. data/test/test/region/armenian.rb +20 -20
  117. data/test/test/region/bahai.rb +58 -58
  118. data/test/test/region/balinese.rb +34 -34
  119. data/test/test/region/chinese.rb +229 -229
  120. data/test/test/region/christian.rb +226 -226
  121. data/test/test/region/coptic.rb +27 -27
  122. data/test/test/region/discordian.rb +20 -20
  123. data/test/test/region/french.rb +33 -33
  124. data/test/test/region/geologicalage.rb +17 -17
  125. data/test/test/region/indian.rb +14 -1
  126. data/test/test/region/iran.rb +54 -54
  127. data/test/test/region/islamic.rb +64 -54
  128. data/test/test/region/japanese.rb +281 -261
  129. data/test/test/region/jewish.rb +63 -63
  130. data/test/test/region/m17n.rb +21 -21
  131. data/test/test/region/mayan.rb +17 -16
  132. data/test/test/region/reforms.rb +2 -2
  133. data/test/test/region/residue.rb +7 -7
  134. data/test/test/region/shire.rb +58 -58
  135. data/test/test/region/swedish.rb +45 -45
  136. data/test/test/region/thai.rb +116 -116
  137. data/test/test/region/tibetan.rb +30 -30
  138. data/test/test/region/vietnamese.rb +102 -102
  139. data/test/test/region/zoroastrian.rb +58 -58
  140. data/test/test/timestandard.rb +81 -81
  141. data/test/test/tmobjects.rb +402 -402
  142. data/test/test/tmposition.rb +66 -4
  143. data/test/test/tmreference.rb +157 -157
  144. metadata +36 -93
@@ -0,0 +1,1279 @@
1
+ # -*- coding: utf-8 -*-
2
+ =begin
3
+ Copyright (C) 2011-2016 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
+ #
11
+ # 時間座標 - 単一の時間間隔によって定義する連続な間隔尺度を基礎とする
12
+ #
13
+ # see {http://schemas.opengis.net/gml/3.1.1/base/temporalAppendix.xsd#TimeCoordinateType gml schema}
14
+ #
15
+ class Coordinate < TemporalPosition
16
+
17
+ class << self
18
+ # 内部時間によるオブジェクトの生成
19
+ alias :universal_time :new
20
+
21
+ # 外部時間によるオブジェクトの生成
22
+ #
23
+ # @param [Numeric] dynamical_time 外部時間による時間座標値
24
+ #
25
+ # @param [Hash] options 下記の通り
26
+ # @option options [When::TimeStandard] :time_standard
27
+ #
28
+ # @return [When::TM::Coordinate]
29
+ #
30
+ def dynamical_time(dynamical_time, options={})
31
+ universal_time(When.Resource(options[:time_standard] || 'UniversalTime', '_t:').from_dynamical_time(dynamical_time), options)
32
+ end
33
+
34
+ # 他種の時間位置によるオブジェクトの生成
35
+ #
36
+ # @param [Numeric, When::TM::ClockTime, ::Time, ::Date, ::DateTime] time 他種の時間位置によるオブジェクト
37
+ #
38
+ # @param [Hash] options 下記の通り
39
+ # @option options [When::TM::Clock] :clock
40
+ # @option options [When::Parts::Timezone] :tz
41
+ #
42
+ # @return [When::TM::Coordinate]
43
+ #
44
+ def new(time, options={})
45
+ options = options.dup
46
+ options[:frame] = Clock.get_clock_option(options)
47
+ case time
48
+ when Numeric
49
+ options[:frame] ||= When::UTC unless time.kind_of?(Integer)
50
+ universal_time = (2*time - (2*JulianDate::JD19700101-1)) * Duration::DAY.to_i / 2.0
51
+ when ClockTime
52
+ options[:frame] ||= time.clock
53
+ universal_time = time.clk_time[0] + time.universal_time
54
+ when ::Time
55
+ options[:frame] ||= When.Clock(time.gmtoff)
56
+ universal_time = options[:frame].time_standard.from_time_object(time)
57
+ when TimeValue
58
+ options[:frame] ||= time.clock
59
+ universal_time = time.universal_time
60
+ else
61
+ if ::Object.const_defined?(:Date) && ::Date.method_defined?(:+) && time.respond_to?(:ajd)
62
+ case time
63
+ when ::DateTime
64
+ options[:frame] ||= When.Clock((time.offset * 86400).to_i)
65
+ universal_time = (2*time.ajd - (2*JulianDate::JD19700101-1)) * Duration::DAY.to_i / 2.0
66
+ when ::Date
67
+ universal_time = JulianDate._d_to_t(time.jd)
68
+ if options[:frame] && options[:frame].rate_of_clock != 1.0
69
+ universal_time = options[:frame].time_standard.from_dynamical_time(
70
+ When::TimeStandard.to_dynamical_time(universal_time))
71
+ end
72
+ end
73
+ end
74
+ end
75
+ raise TypeError, "Can't create #{self} from #{time.class}" unless universal_time
76
+ universal_time(universal_time, options)
77
+ end
78
+ end
79
+
80
+ # この時間位置と関連付けられた時間参照系 (relation - Reference)
81
+ #
82
+ # The time reference system associated with the temporal position being described
83
+ #
84
+ # @return [When::TM::ReferenceSystem]
85
+ #
86
+ alias :clock :frame
87
+
88
+ # 内部時間による時間座標値
89
+ #
90
+ # @return [Numeric]
91
+ #
92
+ attr_accessor :universal_time
93
+ alias :coordinateValue :universal_time
94
+ protected :universal_time=
95
+
96
+ # 内部時間(ローカル)
97
+ #
98
+ # @return [Numeric]
99
+ #
100
+ # 1970-01-01T00:00:00(ローカル) からの Universal Coordinated Time の経過時間 / 128秒
101
+ #
102
+ def local_time
103
+ @universal_time
104
+ end
105
+
106
+ # CoordinateSystem による時間座標値
107
+ #
108
+ # @return [Numeric]
109
+ #
110
+ def coordinateValue
111
+ (universal_time - frame.origin.universal_time) / frame.interval.to_f
112
+ end
113
+
114
+ # 加算
115
+ #
116
+ # @param [Numeric, When::TM::IntervalLength] other
117
+ #
118
+ # @return [When::TM::TemporalPosition]
119
+ #
120
+ def +(other)
121
+ other = other.to_interval_length if other.kind_of?(PeriodDuration)
122
+ super(other)
123
+ end
124
+
125
+ # 減算
126
+ #
127
+ # @param [When::TM::TemporalPosition, Numeric, When::TM::IntervalLength] other
128
+ #
129
+ # @return [When::TM::TemporalPosition] if other is a Numeric or When::TM::IntervalLength
130
+ # @return [When::TM::IntervalLength] if other is a When::TM::TemporalPosition
131
+ #
132
+ def -(other)
133
+ other = other.to_interval_length if other.kind_of?(PeriodDuration)
134
+ super(other)
135
+ end
136
+
137
+ # 前の時刻
138
+ #
139
+ # @return [When::TM::TemporalPosition]
140
+ #
141
+ # 分解能に対応する Duration だけ,日時を戻す
142
+ #
143
+ def prev
144
+ self - period
145
+ end
146
+
147
+ # 次の時刻
148
+ #
149
+ # @return [When::TM::TemporalPosition]
150
+ #
151
+ # 分解能に対応する Duration だけ,日時を進める
152
+ #
153
+ def succ
154
+ self + period
155
+ end
156
+ alias :next :succ
157
+
158
+ # オブジェクトの生成
159
+ #
160
+ # @param [Numeric] universal_time 内部時間による時間座標値
161
+ #
162
+ # @param [Hash] options 下記の通り
163
+ # @option options [When::TM::CoordinateSystem] :frame
164
+ #
165
+ def initialize(universal_time, options={})
166
+ super(options)
167
+ @universal_time = universal_time
168
+ end
169
+ end
170
+
171
+ #
172
+ # ユリウス日
173
+ #
174
+ # see {http://schemas.opengis.net/gml/3.1.1/base/temporalAppendix.xsd#JulianDateType CALENdeRsign}
175
+ #
176
+ class JulianDate < Coordinate
177
+
178
+ # Julian Day Number
179
+ # 19700101T120000Z
180
+ JD19700101 = 2440588
181
+
182
+ # Modified Julian Date
183
+ #
184
+ # see {https://en.wikipedia.org/wiki/Julian_day#Variants MJD}
185
+ JDN_of_MJD = 2400000.5
186
+
187
+ # Countdown to Equinoctial Planetconjunction
188
+ #
189
+ # see {http://www.calendersign.com/en/cs_cep-pec.php CEP}
190
+ JDN_of_CEP = 2698162
191
+
192
+ class << self
193
+
194
+ JD19700100_5 = JD19700101 - 0.5
195
+
196
+ #
197
+ # 日時の内部表現をユリウス日に変換
198
+ #
199
+ # @param [Numeric] t
200
+ #
201
+ # @return [Numeric]
202
+ #
203
+ def _t_to_d(t)
204
+ t / Duration::DAY + JD19700100_5
205
+ end
206
+
207
+ #
208
+ # ユリウス日をに日時の内部表現変換
209
+ #
210
+ # @param [Numeric] d
211
+ #
212
+ # @return [Numeric]
213
+ #
214
+ def _d_to_t(d)
215
+ (d - JD19700100_5) * Duration::DAY
216
+ end
217
+
218
+ # Generation of Temporal Objetct
219
+ #
220
+ # @param [String] specification ユリウス通日を表す文字列
221
+ # @param [Hash] options 暦法や時法などの指定 (see {When::TM::TemporalPosition._instance})
222
+ #
223
+ # @return [When::TM::TemporalPosition, When::TM::Duration, When::Parts::GeometricComplex or Array<them>]
224
+ #
225
+ def parse(specification, options={})
226
+ num, *calendars = specification.split(/\^{1,2}/)
227
+ jdn = num.sub!(/[.@]/, '.') ? num.to_f : num.to_i
228
+ case num
229
+ when /MJD/i ; jdn += JDN_of_MJD
230
+ when /CEP/i ; jdn += JDN_of_CEP
231
+ when /DTB/i ; jdn = time_standard(options).from_dynamical_date(jdn)
232
+ end
233
+ frame = calendars.shift || options[:frame]
234
+ return self.new(jdn, options) unless frame
235
+ calendars.unshift(frame).inject(jdn) {|date, calendar| When.Calendar(calendar).jul_trans(date, options)}
236
+ end
237
+
238
+ private
239
+
240
+ #
241
+ # Time Standard を選択する
242
+ #
243
+ def time_standard(options)
244
+ ts = options[:time_standard]
245
+ ts ||= options[:clock] unless options[:clock].kind_of?(When::Parts::Timezone)
246
+ ts ||= '_t:UniversalTime'
247
+ ts = When.Resource(ts)
248
+ ts = ts.time_standard if ts.kind_of?(When::TM::Clock)
249
+ ts
250
+ end
251
+ end
252
+
253
+ # 加算
254
+ #
255
+ # @param [Numeric, When::TM::IntervalLength] other
256
+ #
257
+ # @return [When::TM::TemporalPosition]
258
+ #
259
+ def +(other)
260
+ new_date = super
261
+ new_date.frame = new_date.frame._daylight(new_date.universal_time) if new_date.frame && new_date.frame._need_validate
262
+ return new_date
263
+ end
264
+
265
+ # 減算
266
+ #
267
+ # @param [When::TM::TemporalPosition, Numeric, When::TM::IntervalLength] other
268
+ #
269
+ # @return [When::TM::TemporalPosition]
270
+ #
271
+ def -(other)
272
+ new_date = super
273
+ new_date.frame = new_date.frame._daylight(new_date.universal_time) if new_date.kind_of?(TimeValue) && new_date.frame && new_date.frame._need_validate
274
+ return new_date
275
+ end
276
+
277
+ # ユリウス日が指定の剰余となる日
278
+ #
279
+ # @param [When::Coordinates::Residue] other
280
+ #
281
+ # @return [When::TM::TemporalPosition]
282
+ #
283
+ def &(other)
284
+ raise TypeError,"The right operand should be When::Coordinates::Residue" unless other.kind_of?(Residue)
285
+ raise ArgumentError,"The right operand should have a unit 'day'" unless other.event == 'day'
286
+ jdn = to_i
287
+ new_date = self.dup
288
+ new_date.universal_time += ((other & jdn) - jdn) * Duration::DAY
289
+ return new_date
290
+ end
291
+
292
+ # ユリウス日の剰余
293
+ #
294
+ # @param [When::Coordinates::Residue] other
295
+ #
296
+ # @return [Numeric]
297
+ #
298
+ def %(other)
299
+ raise TypeError,"The right operand should be When::Coordinates::Residue" unless other.kind_of?(Residue)
300
+ raise ArgumentError,"The right operand should have a unit 'day'" unless other.event == 'day'
301
+ other % to_i
302
+ end
303
+
304
+ private
305
+
306
+ # オブジェクトの生成
307
+ #
308
+ # @param [Numeric] universal_time 内部時間による時間座標値
309
+ #
310
+ # @param [Hash] options 以下の通り
311
+ # @option options [When::TM::Clock] :frame
312
+ # @option options [Integer] :precision
313
+ #
314
+ def initialize(universal_time, options={})
315
+ @frame = options.delete(:frame)
316
+ @frame = When.Clock(@frame) if @frame.kind_of?(String)
317
+ @frame = @frame._daylight(universal_time) if @frame && @frame._need_validate
318
+ precision = options.delete(:precision)
319
+ precision ||= DAY unless @frame.kind_of?(Clock)
320
+ @precision = Index.precision(precision)
321
+ super
322
+ end
323
+ end
324
+
325
+ #
326
+ # 順序時間参照系で参照する位置
327
+ #
328
+ # see {http://schemas.opengis.net/gml/3.1.1/base/temporalAppendix.xsd#TimeOrdinalPositionType gml schema}
329
+ #
330
+ class OrdinalPosition < TemporalPosition
331
+
332
+ # この順序位置と関連付けられた順序年代 (relation - Reference)
333
+ #
334
+ # The ordinal era associated with the ordinal position being described
335
+ #
336
+ # @return [When::TM::OrdinalEra]
337
+ #
338
+ attr_reader :ordinal_position
339
+ alias :ordinalPosition :ordinal_position
340
+
341
+ # オブジェクトの生成
342
+ #
343
+ # @param [When::TM::OrdinalEra] ordinal_position この順序位置と関連付けられた順序年代
344
+ # @param [Hash] options see {When::TM::TemporalPosition._instance}
345
+ #
346
+ def initialize(ordinal_position, options={})
347
+ super(options)
348
+ @ordinal_position = ordinal_position
349
+ end
350
+ end
351
+
352
+ #
353
+ # 時刻
354
+ #
355
+ # see {http://schemas.opengis.net/gml/3.1.1/base/temporalAppendix.xsd#ClockTimeType gml schema}
356
+ #
357
+ class ClockTime < TemporalPosition
358
+
359
+ # 時刻要素
360
+ #
361
+ # @return [Array<Numeric>]
362
+ #
363
+ # @note ISO19108 では sequence<Integer> だが、閏時・閏秒などが表現可能なよう Numeric としている。
364
+ #
365
+ attr_reader :clk_time
366
+ alias :clkTime :clk_time
367
+
368
+ # この時間位置と関連付けられた時間参照系 (relation - Reference)
369
+ #
370
+ # The time reference system associated with the temporal position being described
371
+ #
372
+ # @return [When::TM::ReferenceSystem]
373
+ #
374
+ alias :clock :frame
375
+
376
+ # 内部時間
377
+ #
378
+ # @param [Integer] sdn 参照事象の通し番号
379
+ #
380
+ # @return [Numeric]
381
+ #
382
+ # T00:00:00Z からの Universal Coordinated Time の経過時間 / 128秒
383
+ #
384
+ # 時法によっては、異なる意味を持つことがある
385
+ #
386
+ def universal_time(sdn=nil)
387
+ raise NameError, "Temporal Reference System is not defined" unless @frame
388
+ @universal_time ||= @frame.to_universal_time(@clk_time, sdn)
389
+ end
390
+
391
+ # 内部時間(ローカル)
392
+ #
393
+ # @param [Integer] sdn 参照事象の通し番号
394
+ #
395
+ # @return [Numeric]
396
+ #
397
+ # T00:00:00(ローカル) からの Universal Coordinated Time の経過時間 / 128秒
398
+ #
399
+ # 時法によっては、異なる意味を持つことがある
400
+ #
401
+ def local_time(sdn=nil)
402
+ raise NameError, "Temporal Reference System is not defined" unless @frame
403
+ @local_time ||= @frame.to_local_time(@clk_time, sdn)
404
+ end
405
+
406
+ # 繰り上がり
407
+ #
408
+ # @return [Numeric]
409
+ #
410
+ # 日付の境界が午前0時でない場合、clk_time の最上位桁に 0 以外が入ることがある
411
+ #
412
+ def carry
413
+ return @clk_time[0]
414
+ end
415
+
416
+ # 要素の参照
417
+ #
418
+ # @param [Integer, String] index 参照する要素の指定
419
+ #
420
+ # @return [Numeric]
421
+ #
422
+ def value(index)
423
+ @clk_time[_digit(index) {|digit| digit >= DAY}]
424
+ end
425
+
426
+ #protected
427
+ # 属性のコピー
428
+ # @private
429
+ def _copy(options={})
430
+ @clk_time = options[:time] if options.key?(:time)
431
+ if options.key?(:clock)
432
+ options.delete(:frame)
433
+ @frame = options[:clock]
434
+ end
435
+ if options.key?(:tz_prop)
436
+ @frame = @frame.dup
437
+ @frame.tz_prop = options[:tz_prop]
438
+ end
439
+ return super
440
+ end
441
+
442
+ # オブジェクトの生成
443
+ #
444
+ # @param [String] time ISO8601形式の時刻表現
445
+ # @param [Array<Numeric>] time (日, 時, 分, 秒)
446
+ #
447
+ #
448
+ # @param [Hash] options 以下の通り
449
+ # @option options [When::TM::Clock] :frame
450
+ # @option options [Integer] :precision
451
+ #
452
+ def initialize(time, options={})
453
+ # 参照系の取得
454
+ @frame = options[:frame] || Clock.local_time
455
+ @frame = When.Clock(@frame) if (@frame.kind_of?(String))
456
+ options.delete(:frame)
457
+
458
+ # 時刻表現の解読 ( Time Zone の解釈 )
459
+ if (time.kind_of?(String))
460
+ case time
461
+ when /\A([-+])?(\d{2,}?):?(\d{2})?:?(\d{2}(\.\d+)?)?\z/
462
+ sign, hh, mm, ss = $~[1..4]
463
+ time = @frame._validate([0,0,0,0],
464
+ [0,
465
+ -(sign.to_s + "0" + hh.to_s).to_i,
466
+ -(sign.to_s + "0" + mm.to_s).to_i,
467
+ Pair._en_number(-(sign.to_s + "0" + ss.to_s).to_f)])
468
+ time[0] = Pair.new(0, time[0].to_i) if (time[0] != 0)
469
+ when /\AZ\z/
470
+ time = [0,0,0,0]
471
+ else
472
+ raise ArgumentError, "Invalid Time Format"
473
+ end
474
+ end
475
+ @clk_time = time
476
+
477
+ # 分解能
478
+ @precision = @frame._precision(time, options.delete(:precision))
479
+
480
+ super(options)
481
+ end
482
+
483
+ private
484
+
485
+ # オブジェクトの正規化
486
+ def _normalize(options={})
487
+ # strftime で使用する locale
488
+ @keys |= @frame.keys
489
+
490
+ # 時刻の正規化
491
+ @clk_time = @frame._validate(@clk_time) unless options[:validate]
492
+ end
493
+
494
+ # 加減算共通処理
495
+ def _plus(period)
496
+ self.dup._copy({:time=>@frame._validate(@clk_time, @frame._arrange_length(period.time)),
497
+ :events=>nil, :query=>nil, :validate=>:done})
498
+ end
499
+ end
500
+
501
+ #
502
+ # 暦日
503
+ #
504
+ # see {gml schema}[link:http://schemas.opengis.net/gml/3.1.1/base/temporalAppendix.xsd#CalDateType]
505
+ #
506
+ class CalDate < TemporalPosition
507
+
508
+ # 検索オプション
509
+ # @private
510
+ SearchOption = {After=>[0, -2, Before], Before=>[-2, 0, After]}
511
+
512
+ # 日付要素
513
+ #
514
+ # @return [Array<Numeric>]
515
+ #
516
+ # @note ISO19108 では sequence<Integer> だが、閏月などが表現可能なよう Numeric としている。
517
+ #
518
+ attr_reader :cal_date
519
+ alias :calDate :cal_date
520
+
521
+ # この時間位置と関連付けられた時間参照系 (relation - Reference)
522
+ #
523
+ # The time reference system associated with the temporal position being described
524
+ #
525
+ # @return [When::TM::ReferenceSystem]
526
+ #
527
+ alias :calendar :frame
528
+
529
+ # 暦年代
530
+ #
531
+ # @return [When::TM::CalendarEra]
532
+ #
533
+ attr_accessor :calendar_era
534
+ private :calendar_era=
535
+ alias :calendarEra :calendar_era
536
+
537
+ # 暦年代属性
538
+ #
539
+ # @return [Array] ( name, epoch, reverse, go back )
540
+ # - name [String] 暦年代名
541
+ # - epoch [Integer] 使用する When::TM::Calendar で暦元に対応する年
542
+ # - reverse [Boolean] 年数が昇順(false,nil)か降順(true)か
543
+ # - go back [Boolean] 参照イベントより前の暦日か(true)、否か(false,nil)
544
+ #
545
+ attr_accessor :calendar_era_props
546
+ private :calendar_era_props=
547
+
548
+ # 暦年代名
549
+ #
550
+ # @return [String] 暦年代名
551
+ #
552
+ def calendar_era_name
553
+ @calendar_era_props ? @calendar_era_props[0] : nil
554
+ end
555
+ alias :calendarEraName :calendar_era_name
556
+
557
+ # 暦年代元期
558
+ #
559
+ # @return [Integer] 使用する When::TM::Calendar で暦元に対応する年
560
+ #
561
+ def calendar_era_epoch
562
+ @calendar_era_props ? @calendar_era_props[1] : 0
563
+ end
564
+
565
+ # 暦年代正逆
566
+ #
567
+ # @return [Boolean] 年数が昇順(false,nil)か降順(true)か
568
+ #
569
+ def calendar_era_reverse
570
+ @calendar_era_props ? @calendar_era_props[2] : false
571
+ end
572
+
573
+ # 暦年代遡及
574
+ #
575
+ # @return [Boolean] 参照イベントより前の暦日か(true)、否か(false,nil)
576
+ #
577
+ def calendar_era_go_back
578
+ @calendar_era_props ? @calendar_era_props[3] : false
579
+ end
580
+
581
+ # 時法の取得 - ダミー
582
+ def clock
583
+ nil
584
+ end
585
+
586
+ # 内部時間
587
+ #
588
+ # @return [Numeric]
589
+ #
590
+ # 当日正午の 1970-01-01T00:00:00Z からの Universal Coordinated Time の経過時間 / 128秒
591
+ #
592
+ def universal_time
593
+ return super if [Now, Max, Min].include?(@indeterminated_position)
594
+ @universal_time ||= JulianDate._d_to_t(to_i)
595
+ end
596
+ alias :local_time :universal_time
597
+
598
+ # ユリウス日
599
+ #
600
+ # @return [Integer]
601
+ #
602
+ # -4712-01-01からの経過日数に対応する通番
603
+ #
604
+ def to_i
605
+ @sdn ||= _to_i
606
+ end
607
+
608
+ #
609
+ # 暦法上の通日
610
+ #
611
+ def _to_i
612
+ void, epoch = @calendar_era_props
613
+ if epoch
614
+ date = @cal_date.dup
615
+ date[0] += epoch
616
+ else
617
+ date = @cal_date
618
+ end
619
+ @frame.to_julian_date(date)
620
+ end
621
+ private :_to_i
622
+
623
+ # 前の日時
624
+ #
625
+ # @return [When::TM::TemporalPosition]
626
+ #
627
+ # 分解能に対応する Duration だけ,日時を戻す
628
+ #
629
+ def prev
630
+ @precision==When::DAY ? _force_euqal_day(-1) : self-period
631
+ rescue RangeError
632
+ (When::Gregorian ^ self) - period
633
+ end
634
+
635
+ # 次の日時
636
+ #
637
+ # @return [When::TM::TemporalPosition]
638
+ #
639
+ # 分解能に対応する Duration だけ,日時を進める
640
+ #
641
+ def succ
642
+ @precision==When::DAY ? _force_euqal_day(+1) : self+period
643
+ rescue RangeError
644
+ (When::Gregorian ^ self) + period
645
+ end
646
+ alias :next :succ
647
+
648
+ # 剰余類化
649
+ #
650
+ # @param [Numeric] remainder 剰余
651
+ # @param [Integer] divisor 法(>0)
652
+ #
653
+ # @return [When::Coordinates::Residue] 当日、当年を基準とする剰余類
654
+ #
655
+ def to_residue(remainder, divisor)
656
+ When::Coordinates::Residue.new(remainder, divisor, {'day' => least_significant_coordinate,
657
+ 'year' => most_significant_coordinate})
658
+ end
659
+
660
+ # 暦年代の削除
661
+ #
662
+ # @return [When::TM::CalDate] 暦年代を削除した When::TM::CalDate
663
+ #
664
+ def without_era
665
+ target = dup
666
+ return target unless calendar_era
667
+ options = _attr
668
+ options[:era] = nil
669
+ options[:era_name] = nil
670
+ options[:date] = cal_date.dup
671
+ options[:date][0] += calendar_era_epoch
672
+ target._copy(options)
673
+ end
674
+
675
+ # 要素の参照
676
+ #
677
+ # @param [Integer, String] index 参照する要素の指定
678
+ #
679
+ # @return [Numeric]
680
+ #
681
+ def value(index)
682
+ @cal_date[(_digit(index) {|digit| digit <= DAY})-1]
683
+ end
684
+
685
+ #
686
+ # 最上位の要素
687
+ #
688
+ # @return [Numeric] 暦年代の epoch に関わらず暦法に従った年の通し番号を返す
689
+ #
690
+ def most_significant_coordinate
691
+ coordinate = @cal_date[0]
692
+ coordinate += calendar_era_epoch if @calendar_era_props
693
+ @frame.index_of_MSC.times do |i|
694
+ coordinate = +coordinate * @frame.indices[i].unit + @cal_date[i+1] - @frame.indices[i].base
695
+ end
696
+ coordinate
697
+ end
698
+
699
+ #
700
+ # 最下位の要素
701
+ #
702
+ # @return [Numeric] 剰余類の演算に用いる日の通し番号を返す
703
+ #
704
+ def least_significant_coordinate
705
+ return to_i + @frame.indices[-1].shift
706
+ end
707
+
708
+ # ユリウス日または通年が指定の剰余となる日
709
+ #
710
+ # @param [When::Coordinates::Residue] other
711
+ #
712
+ # @return [When::TM::CalDate]
713
+ #
714
+ def &(other)
715
+ raise TypeError,"The right operand should be When::Coordinates::Residue" unless other.kind_of?(Residue)
716
+ case other.event
717
+ when 'day'
718
+ # 指定の剰余となる日
719
+ sdn = other & to_i
720
+ options = {:date=>_date_with_era(@frame.to_cal_date(sdn)), :events=>nil, :query=>@query, :validate=>:done}
721
+ options[:precision] = When::DAY if precision < When::DAY
722
+ result = self.dup._copy(options)
723
+ result.send(:_force_euqal_day, sdn-result.to_i)
724
+
725
+ when 'year'
726
+ # 指定の剰余となる年
727
+ date = @frame.send(:_decode, _date_without_era)
728
+ date[0] = (other & (date[0] + @frame.diff_to_CE)) - @frame.diff_to_CE
729
+ options = {:date=>_date_with_era(@frame.send(:_encode, date)), :events=>nil, :query=>@query}
730
+ options[:precision] = When::YEAR if precision < When::YEAR
731
+ return self.dup._copy(options)
732
+
733
+ else
734
+ raise ArgumentError,"The right operand should have a unit 'day' or 'year'"
735
+ end
736
+ end
737
+
738
+ # ユリウス日または通年の剰余
739
+ #
740
+ # @param [When::Coordinates::Residue] other
741
+ #
742
+ # @return [Numeric]
743
+ #
744
+ def %(other)
745
+ raise TypeError,"The right operand should be When::Coordinates::Residue" unless other.kind_of?(Residue)
746
+ if precision <= When::YEAR && other.units['year'] && other.event != 'year'
747
+ other.to('year') % (most_significant_coordinate + @frame.epoch_in_CE)
748
+ else
749
+ case other.event
750
+ when 'day' ; other % least_significant_coordinate
751
+ when 'year' ; other % (most_significant_coordinate + @frame.epoch_in_CE)
752
+ else ; raise ArgumentError,"The right operand should have a unit 'day' or 'year'"
753
+ end
754
+ end
755
+ end
756
+
757
+ # 下位桁の切り捨て
758
+ #
759
+ # @param [Integer] digit 切り捨てずに残す、最下位の桁
760
+ #
761
+ # @param [Integer] precision 切り捨て結果の分解能
762
+ #
763
+ # @return [When::TM::CalDate]
764
+ #
765
+ def floor(digit=DAY, precision=digit)
766
+ options = {:date=>@cal_date[0..(digit-1)], :events=>nil, :query=>nil}
767
+ options[:precision] = precision if precision
768
+ self.dup._copy(options)
769
+ end
770
+
771
+ # 下位桁の切り上げ
772
+ #
773
+ # @param [Integer] digit 切り上げずに残す、最下位の桁
774
+ #
775
+ # @param [Integer] precision 切り上げ結果の分解能
776
+ #
777
+ # @return [When::TM::CalDate]
778
+ #
779
+ def ceil(digit=DAY, precision=digit)
780
+ (self + PeriodDuration.new(1, digit, (-@frame.indices.length)..0)).floor(digit, precision)
781
+ end
782
+
783
+ # 要素数 ― 上位要素に含まれる下位要素の数
784
+ #
785
+ # @param [Integer] upper 上位要素のインデックス
786
+ # @param [Integer] lower 下位要素のインデックス(DAY または MONTH)
787
+ #
788
+ # @return [Integer]
789
+ #
790
+ def length(upper, lower=DAY)
791
+ range = [floor(upper).to_i, ceil(upper).to_i]
792
+ range = range.map {|d| (Residue.mod(d) {|m| frame._new_month(m)})[0]} if lower == MONTH
793
+ range[1] - range[0]
794
+ end
795
+
796
+ # 時刻情報のない When::TM::CalDate を返す
797
+ #
798
+ # @return [When::TM::CalDate]
799
+ #
800
+ alias :to_cal_date :dup
801
+ alias :to_CalDate :to_cal_date
802
+
803
+ # 暦年代が末端の参照であるか?
804
+ #
805
+ # @return [Boolean]
806
+ #
807
+ def leaf?
808
+ ! @calendar_era.respond_to?(:_pool) || @calendar_era.leaf?
809
+ end
810
+
811
+ # 属性の Hash
812
+ # @private
813
+ def _attr
814
+ super.merge({:era_name=>@calendar_era_props, :era=>@calendar_era})
815
+ end
816
+ protected
817
+
818
+ # 属性のコピー
819
+ # @private
820
+ def _copy(options={})
821
+ @cal_date = options[:date] if options.key?(:date)
822
+ @calendar_era = options[:era] if options.key?(:era)
823
+ @calendar_era_props = options[:era_name] if options.key?(:era_name)
824
+ return super
825
+ end
826
+
827
+ # オブジェクトの生成
828
+ #
829
+ # @param [Array<Numeric>] date 日付表現
830
+ #
831
+ # @param [Hash] options 下記の通り (see also {When::TM::TemporalPosition._instance})
832
+ # @option options [When::TM::Calendar] :frame
833
+ # @option options [When::TM::CalendarEra, When::BasicTypes::M17n, Array<When::BasicTypes::M17n, Integer>] :era_name
834
+ # (Integer は 当該年号の 0 年に相当する通年)
835
+ # @option options [Integer] :precision
836
+ #
837
+ def initialize(date, options={})
838
+ # 年号 & 日付
839
+ @calendar_era_props = options[:era_name]
840
+ @calendar_era = options[:era]
841
+ @cal_date = date
842
+
843
+ super(options)
844
+ end
845
+
846
+ private
847
+
848
+ # オブジェクトの正規化
849
+ def _normalize(options={})
850
+
851
+ # 日付配列の長さ
852
+ cal_date_index = @cal_date.compact.length
853
+
854
+ # 日付の正規化
855
+ if @calendar_era_props
856
+ # Calendar Era がある場合
857
+ trans_options = @trans || {} # TODO? 消す
858
+ count = trans_options[:count] || 1
859
+ query_options = (@query || {}).dup
860
+ query_options[:label] = @calendar_era_props
861
+ query_options[:count] = count
862
+ era = date = nil
863
+ if @calendar_era
864
+ era, date = _search_era(@calendar_era, trans_options)
865
+ else
866
+ eras = CalendarEra._instance(query_options)
867
+ raise ArgumentError, "CalendarEraName doesn't exist: #{query_options[:label]}" if eras.empty?
868
+ eras.each do |e|
869
+ era, date = _search_era(e, trans_options)
870
+ next unless era
871
+ count -= 1
872
+ break unless count > 0
873
+ end
874
+ end
875
+ raise RangeError, "Out of CalendarEra Range" unless era
876
+ @calendar_era_props = date.calendar_era_props
877
+ @calendar_era = era
878
+ @cal_date = date.cal_date
879
+ @frame = date.frame
880
+ @query = (@query||{}).merge(date.query)
881
+ @trans = (@trans||{}).merge(date.trans)
882
+ @keys |= calendar_era_name.keys | @frame.keys
883
+ else
884
+ # Calendar Era がない場合
885
+ @frame = When.Resource(options[:frame] || @frame || 'Gregorian', '_c:')
886
+ @cal_date = @frame._validate(@cal_date) unless options[:validate] == :done
887
+ @keys |= @frame.keys
888
+ end
889
+
890
+ # 分解能
891
+ precision = options.delete(:precision) || @precision
892
+ cal_date_index =
893
+ case options.delete(:_format)
894
+ when :century ; CENTURY
895
+ when :week, :day ; DAY
896
+ else ; cal_date_index - (@frame.indices.length + 1)
897
+ end
898
+ precision ||= cal_date_index if cal_date_index < DAY
899
+ precision ||= @clk_time.precision if @clk_time
900
+ @precision = Index.precision(precision || DAY)
901
+ end
902
+
903
+ # 暦年代を探す
904
+ def _search_era(era, trans_options)
905
+ cal_date = @cal_date.dup
906
+ cal_date[0] = -cal_date[0] if era.reverse?
907
+ cal_date[0] += era.epoch_year
908
+ date = era.trans(cal_date, trans_options)
909
+ loop do
910
+ case date
911
+ when Before, After
912
+ i0, i1, reverse = SearchOption[date]
913
+ new_era = (date == Before) ? era.prev : era.succ
914
+ break unless new_era
915
+ date = new_era.trans(cal_date, trans_options)
916
+ if date == reverse
917
+ cal_date = new_era.epoch[i0].frame.to_cal_date(era.epoch[i1].frame.to_julian_date(cal_date))
918
+ date = new_era.trans(cal_date, trans_options)
919
+ break if date == reverse
920
+ end
921
+ era = new_era
922
+ when TimeValue
923
+ return era, date
924
+ else
925
+ break
926
+ end
927
+ end
928
+ return nil
929
+ end
930
+
931
+ # 加減算共通処理
932
+ def _plus(period)
933
+ _frame_adjust(period, self.dup._copy({:date=>_date_with_era(@frame._validate(_date_without_era,
934
+ @frame._arrange_length(period.date))),
935
+ :events=>nil, :query=>nil, :validate=>:done}))
936
+ end
937
+
938
+ # 年号を除外した @frame の暦法に対応する日付
939
+ def _date_without_era
940
+ date = @cal_date.dup
941
+ date[0] += calendar_era_epoch if @calendar_era_props
942
+ date
943
+ end
944
+
945
+ # 年号に続く日付
946
+ def _date_with_era(date)
947
+ date[0] -= calendar_era_epoch if @calendar_era_props
948
+ date
949
+ end
950
+
951
+ # 暦法が変わった場合の補正
952
+ def _frame_adjust(period, date)
953
+ return date if @frame.equal?(date.frame) || (period.to_day||0) == 0
954
+ diff = period.to_day - (date.to_i - to_i)
955
+ return date if diff == 0
956
+ date.send(:_force_euqal_day, diff)
957
+ end
958
+ end
959
+
960
+ #
961
+ # 時刻を伴った日付
962
+ #
963
+ # see {http://schemas.opengis.net/gml/3.1.1/base/temporalAppendix.xsd#DateAndTimeType gml schema}
964
+ #
965
+ class DateAndTime < CalDate
966
+
967
+ # 時刻要素
968
+ #
969
+ # @return [When::TM::ClockTime]
970
+ #
971
+ attr_reader :clk_time
972
+ alias :clkTime :clk_time
973
+
974
+ # 時法の取得
975
+ #
976
+ # @return [When::TM::Clock]
977
+ #
978
+ def clock
979
+ @clk_time.frame
980
+ end
981
+
982
+ # 内部時間
983
+ #
984
+ # @return [Numeric]
985
+ #
986
+ # 1970-01-01T00:00:00Z からの Universal Coordinated Time の経過時間 / 128秒
987
+ #
988
+ # 暦法によっては、異なる意味を持つことがある
989
+ #
990
+ def universal_time
991
+ return super if [Now, Max, Min].include?(@indeterminated_position)
992
+ raise NameError, "Temporal Reference System is not defined" unless (@frame && clock)
993
+ @universal_time ||= (to_i - JulianDate::JD19700101) * Duration::DAY + @clk_time.universal_time(to_i)
994
+ end
995
+
996
+ # 内部時間(ローカル)
997
+ #
998
+ # @return [Numeric]
999
+ #
1000
+ # 1970-01-01T00:00:00(ローカル) からの Universal Coordinated Time の経過時間 / 128秒
1001
+ #
1002
+ # 暦法によっては、異なる意味を持つことがある
1003
+ #
1004
+ def local_time
1005
+ return super if [Now, Max, Min].include?(@indeterminated_position)
1006
+ raise NameError, "Temporal Reference System is not defined" unless (@frame && clock)
1007
+ @local_time ||= (to_i - JulianDate::JD19700101) * Duration::DAY + @clk_time.local_time(to_i)
1008
+ end
1009
+
1010
+ # 要素の参照
1011
+ #
1012
+ # @param [Integer] index 参照する要素の指定
1013
+ #
1014
+ # @return [Numeric]
1015
+ #
1016
+ def value(index)
1017
+ digit = _digit(index)
1018
+ return (digit <= DAY) ? @cal_date[digit-1] : @clk_time.clk_time[digit]
1019
+ end
1020
+
1021
+ # ユリウス日または通年が指定の剰余となる日
1022
+ #
1023
+ # @param [When::Coordinates::Residue] other
1024
+ #
1025
+ # @return [When::TM::DateAndTime]
1026
+ #
1027
+ def &(other)
1028
+ raise TypeError,"The right operand should be When::Coordinates::Residue" unless other.kind_of?(Residue)
1029
+ case other.event
1030
+ when 'day'
1031
+ # 指定の剰余となる日
1032
+ sdn = other & to_i
1033
+ options = {:date=>_date_with_era(@frame.to_cal_date(sdn)), :time=>@clk_time.clk_time.dup,
1034
+ :events=>nil, :query=>@query, :validate=>:done}
1035
+ options[:precision] = When::DAY if precision < When::DAY
1036
+ result = self.dup._copy(options)
1037
+ result.send(:_force_euqal_day, sdn-result.to_i)
1038
+
1039
+ when 'year'
1040
+ # 指定の剰余となる年
1041
+ date = @frame.send(:_decode, _date_without_era)
1042
+ date[0] = (other & (date[0] + @frame.diff_to_CE)) - @frame.diff_to_CE
1043
+ options = {:date=>_date_with_era(@frame.send(:_encode, date)), :time=>@clk_time.clk_time.dup,
1044
+ :events=>nil, :query=>@query}
1045
+ options[:precision] = When::YEAR if precision < When::YEAR
1046
+ return self.dup._copy(options)
1047
+
1048
+ else
1049
+ raise ArgumentError,"The right operand should have a unit 'day' or 'year'"
1050
+ end
1051
+ end
1052
+
1053
+ # 下位桁の切り捨て
1054
+ #
1055
+ # @param [Integer] digit 切り捨てずに残す、最下位の桁
1056
+ #
1057
+ # @param [Integer] precision 切り捨て結果の分解能
1058
+ #
1059
+ # @return [When::TM::DateAndTime]
1060
+ #
1061
+ def floor(digit=DAY, precision=digit)
1062
+ count = digit - clock.indices.length
1063
+
1064
+ if digit>=DAY
1065
+ date = @cal_date.dup
1066
+ elsif @calendar_era_props
1067
+ date = @cal_date.dup
1068
+ date[0] += calendar_era_epoch
1069
+ date = @frame._validate(date[0..(digit-1)])
1070
+ date[0] -= calendar_era_epoch
1071
+ else
1072
+ date = @frame._validate(@cal_date[0..(digit-1)])
1073
+ end
1074
+
1075
+ time = @clk_time.clk_time[0..((digit<=DAY) ? 0 : ((count>=0) ? -1 : digit))]
1076
+ time[0] += to_i
1077
+ time = clock._validate(time)
1078
+ time[0] -= to_i
1079
+
1080
+ if (count >= 0)
1081
+ factor = 10**count
1082
+ time[-1] = (time[-1] * factor).floor.to_f / factor
1083
+ end
1084
+
1085
+ # オブジェクトの生成
1086
+ options = {:date=>date, :validate=>:done, :events=>nil, :query=>nil,
1087
+ :time=>(digit<=DAY) ? time : @clk_time.dup._copy({:time=>time})}
1088
+ options[:precision] = precision if precision
1089
+ return self.dup._copy(options)
1090
+ end
1091
+
1092
+ # 下位桁の切り上げ
1093
+ #
1094
+ # @param [Integer] digit 切り上げずに残す、最下位の桁
1095
+ #
1096
+ # @param [Integer] precision 切り上げ結果の分解能
1097
+ #
1098
+ # @return [When::TM::DateAndTime]
1099
+ #
1100
+ def ceil(digit=DAY, precision=digit)
1101
+ length = clock.indices.length
1102
+ count = digit - length
1103
+ period = PeriodDuration.new((count<=0) ? 1 : 0.1**count, digit, (-@frame.indices.length)..length)
1104
+ result = floor(digit, precision) + period
1105
+ result += clock.tz_difference if (result.universal_time <= self.universal_time)
1106
+ return result
1107
+ end
1108
+
1109
+ # 位置情報
1110
+ #
1111
+ # @return [When::Coordinates::Spatial]
1112
+ #
1113
+ def location
1114
+ @location ||= @clk_time.frame.location
1115
+ end
1116
+
1117
+ # 時刻情報のない When::TM::CalDate を返す
1118
+ #
1119
+ # @return [When::TM::CalDate]
1120
+ #
1121
+ def to_cal_date
1122
+ options = _attr
1123
+ options.delete(:clock)
1124
+ options[:precision] = [When::DAY, options[:precision]].min
1125
+ CalDate.new(@cal_date, options)
1126
+ end
1127
+ alias :to_CalDate :to_cal_date
1128
+
1129
+ # 標準ライブラリの DateTime オブジェクトへの変換
1130
+ #
1131
+ alias :to_date_or_datetime :to_datetime
1132
+
1133
+ #protected
1134
+
1135
+ # 属性の Hash
1136
+ # @private
1137
+ def _attr
1138
+ super.merge({:clock=>clock})
1139
+ end
1140
+
1141
+ # 属性のコピー
1142
+ # @private
1143
+ def _copy(options={})
1144
+ # 夏時間の調整
1145
+ case options[:time]
1146
+ when Array
1147
+ if clock._need_validate
1148
+ if @calendar_era_props
1149
+ date = options[:date].dup
1150
+ date[0] += calendar_era_epoch
1151
+ else
1152
+ date = options[:date]
1153
+ end
1154
+ new_clock = clock._daylight([@frame, date, options[:time]])
1155
+ options[:time] = options[:time].map {|t| t * 1}
1156
+ else
1157
+ new_clock = clock
1158
+ end
1159
+ options[:time] = @clk_time.dup._copy(options.merge({:clock=>new_clock}))
1160
+ when nil
1161
+ options[:time] = @clk_time.dup._copy(options)
1162
+ end
1163
+
1164
+ return super(options)
1165
+ end
1166
+
1167
+ # オブジェクトの生成
1168
+ #
1169
+ # @param [Array<Numeric>] date 日付表現
1170
+ # @param [Array<Numeric>] time 時刻表現
1171
+ # @param [Hash] options 下記の通り (see also {When::TM::TemporalPosition._instance})
1172
+ # @option options [When::TM::Calendar] :frame
1173
+ # @option options [When::TM::Clock] :clock
1174
+ # @option options [When::TM::CalendarEra, When::BasicTypes::M17n, Array<When::BasicTypes::M17n, Integer>] :era_name
1175
+ # (Integer は 当該年号の 0 年に相当する通年)
1176
+ # @option options [Integer] :precision
1177
+ #
1178
+ def initialize(date, time, options={})
1179
+ options[:time] = time
1180
+ super(date, options)
1181
+ end
1182
+
1183
+ private
1184
+
1185
+ # オブジェクトの正規化
1186
+ def _normalize(options={})
1187
+
1188
+ # Clock
1189
+ unless options[:validate]
1190
+ clock = Clock.get_clock_option(options)
1191
+ clock ||= options[:time].frame if options[:time].kind_of?(ClockTime)
1192
+ clock ||= Clock.local_time
1193
+ end
1194
+ clock = When.Clock(clock) if clock.kind_of?(String)
1195
+ clock_is_timezone = clock && !clock.kind_of?(When::TM::Clock)
1196
+ clock = clock.daylight if clock_is_timezone
1197
+
1198
+ # ClockTime
1199
+ @clk_time =
1200
+ case options[:time]
1201
+ when ClockTime ; options[:time]
1202
+ when Array ; ClockTime.new(options[:time], {:frame=>clock, :precision=>options[:precision], :validate=>:done})
1203
+ else ; clock.to_clk_time(options[:time], {:precision=>options[:precision]})
1204
+ end
1205
+
1206
+ super
1207
+
1208
+ # 日付と時刻の正規化
1209
+ unless options[:validate]
1210
+ time = @clk_time.clk_time
1211
+ precision = @clk_time.precision
1212
+ second = time[clock.base.length-1]
1213
+ second -= clock.base[-1] if second
1214
+ if second && second != 0 && time_standard.has_leap?
1215
+ zero = DateAndTime.new(@cal_date, time[0..-2],
1216
+ {:frame=>@frame, :clock=>clock, :precision=>precision,
1217
+ :era_name=>@calendar_era_props, :era=>options[:era],
1218
+ :time_standard=>time_standard, :location=>@location})
1219
+ end
1220
+
1221
+ # 日付と時刻の関係の調整
1222
+ @cal_date = _date_with_era(@frame._validate(_date_without_era) {|jdn|
1223
+ time[0] += jdn
1224
+ time[0..-1] = clock._validate(time)
1225
+ jdn = time[0] * 1
1226
+ time[0] -= jdn
1227
+ jdn
1228
+ })
1229
+
1230
+ # 夏時間の調整
1231
+ if clock._need_validate
1232
+ if @calendar_era_props
1233
+ cal_date = @cal_date.dup
1234
+ cal_date[0] += calendar_era_epoch
1235
+ else
1236
+ cal_date = @cal_date
1237
+ end
1238
+ clock = clock._daylight([@frame, cal_date, time])
1239
+ end
1240
+ time = [time[0]] + time[1..-1].map {|t| t * 1}
1241
+ @clk_time = ClockTime.new(time, {:frame=>clock, :precision=>precision, :validate=>:done}) if clock_is_timezone
1242
+
1243
+ # 閏秒
1244
+ if zero
1245
+ leap = ((dynamical_time - zero.dynamical_time) * clock.second - second).to_i
1246
+ if leap != 0 && leap.abs < clock.second
1247
+ @cal_date = zero.cal_date
1248
+ @clk_time = zero.clk_time
1249
+ @clk_time.clk_time[-1] += second
1250
+ leap /= clock.second
1251
+ @universal_time = @local_time = When::Coordinates::LeapSeconds.new(@local_time-leap, leap, 1/clock.second)
1252
+ @dynamical_time -= leap
1253
+ end
1254
+ end
1255
+ end
1256
+
1257
+ # 後処理
1258
+ @keys |= @clk_time.keys
1259
+ end
1260
+
1261
+ # 加減算共通処理
1262
+ def _plus(period)
1263
+ # 日時の加算
1264
+ time = @clk_time.clk_time.dup
1265
+ pdate = @frame._arrange_length(period.date)
1266
+ ptime = clock._arrange_length(period.time)
1267
+ date = _date_with_era(@frame._validate(_date_without_era, pdate) {|jdn|
1268
+ time[0] += jdn
1269
+ time = clock._validate(time, ptime)
1270
+ jdn = time[0] * 1
1271
+ time[0] -= jdn
1272
+ jdn
1273
+ })
1274
+
1275
+ # オブジェクトの生成
1276
+ _frame_adjust(period, self.dup._copy({:date=>date, :time=>time, :validate=>:done, :events=>nil, :query=>nil}))
1277
+ end
1278
+ end
1279
+ end