when_exe 0.4.2 → 0.5.0

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