when_exe 0.3.6 → 0.3.7

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 (117) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +171 -0
  3. data/lib/when_exe.rb +78 -47
  4. data/lib/when_exe/basictypes.rb +752 -747
  5. data/lib/when_exe/calendarnote.rb +805 -801
  6. data/lib/when_exe/calendartypes.rb +1583 -1531
  7. data/lib/when_exe/coordinates.rb +16 -15
  8. data/lib/when_exe/core/duration.rb +114 -110
  9. data/lib/when_exe/core/extension.rb +504 -504
  10. data/lib/when_exe/ephemeris.rb +1917 -1913
  11. data/lib/when_exe/ephemeris/moon.rb +333 -333
  12. data/lib/when_exe/ephemeris/notes.rb +389 -387
  13. data/lib/when_exe/ephemeris/planets.rb +585 -585
  14. data/lib/when_exe/ephemeris/sun.rb +214 -214
  15. data/lib/when_exe/googlecalendar.rb +144 -140
  16. data/lib/when_exe/icalendar.rb +1636 -1636
  17. data/lib/when_exe/inspect.rb +46 -22
  18. data/lib/when_exe/locales/akt.rb +176 -176
  19. data/lib/when_exe/locales/encoding_conversion.rb +134 -126
  20. data/lib/when_exe/locales/iast.rb +90 -90
  21. data/lib/when_exe/locales/locale.rb +750 -746
  22. data/lib/when_exe/locales/transliteration_table.rb +62 -62
  23. data/lib/when_exe/mini_application.rb +307 -305
  24. data/lib/when_exe/parts/enumerator.rb +2 -2
  25. data/lib/when_exe/parts/geometric_complex.rb +397 -397
  26. data/lib/when_exe/parts/method_cash.rb +224 -224
  27. data/lib/when_exe/parts/resource.rb +1069 -1071
  28. data/lib/when_exe/parts/timezone.rb +240 -230
  29. data/lib/when_exe/region/armenian.rb +56 -56
  30. data/lib/when_exe/region/babylonian.rb +405 -0
  31. data/lib/when_exe/region/bahai.rb +146 -146
  32. data/lib/when_exe/region/balinese.rb +622 -622
  33. data/lib/when_exe/region/chinese.rb +95 -25
  34. data/lib/when_exe/region/chinese/calendars.rb +1016 -1016
  35. data/lib/when_exe/region/chinese/epochs.rb +1 -1
  36. data/lib/when_exe/region/chinese/twins.rb +803 -795
  37. data/lib/when_exe/region/christian.rb +824 -824
  38. data/lib/when_exe/region/coptic.rb +106 -87
  39. data/lib/when_exe/region/discordian.rb +225 -225
  40. data/lib/when_exe/region/far_east.rb +188 -188
  41. data/lib/when_exe/region/french.rb +56 -56
  42. data/lib/when_exe/region/geologicalage.rb +639 -639
  43. data/lib/when_exe/region/goddess.rb +58 -58
  44. data/lib/when_exe/region/indian.rb +1254 -1251
  45. data/lib/when_exe/region/iranian.rb +8 -8
  46. data/lib/when_exe/region/islamic.rb +3 -3
  47. data/lib/when_exe/region/japanese.rb +93 -99
  48. data/lib/when_exe/region/japanese/calendars.rb +396 -397
  49. data/lib/when_exe/region/japanese/epochs.rb +26 -26
  50. data/lib/when_exe/region/japanese/nihon_shoki.rb +71 -71
  51. data/lib/when_exe/region/japanese/notes.rb +1383 -1386
  52. data/lib/when_exe/region/japanese/residues.rb +1306 -1306
  53. data/lib/when_exe/region/japanese/twins.rb +225 -225
  54. data/lib/when_exe/region/japanese/weeks.rb +112 -0
  55. data/lib/when_exe/region/javanese.rb +230 -230
  56. data/lib/when_exe/region/jewish.rb +126 -126
  57. data/lib/when_exe/region/korean.rb +378 -378
  58. data/lib/when_exe/region/m17n.rb +114 -113
  59. data/lib/when_exe/region/martian.rb +258 -255
  60. data/lib/when_exe/region/mayan.rb +32 -32
  61. data/lib/when_exe/region/residue.rb +89 -89
  62. data/lib/when_exe/region/roman.rb +36 -24
  63. data/lib/when_exe/region/ryukyu.rb +97 -97
  64. data/lib/when_exe/region/shire.rb +240 -240
  65. data/lib/when_exe/region/soviet.rb +209 -0
  66. data/lib/when_exe/region/symmetry.rb +50 -50
  67. data/lib/when_exe/region/thai.rb +336 -335
  68. data/lib/when_exe/region/tibetan.rb +316 -315
  69. data/lib/when_exe/region/vietnamese.rb +440 -439
  70. data/lib/when_exe/region/weekdate.rb +80 -80
  71. data/lib/when_exe/region/world.rb +175 -175
  72. data/lib/when_exe/region/yerm.rb +14 -14
  73. data/lib/when_exe/region/zoroastrian.rb +203 -203
  74. data/lib/when_exe/timestandard.rb +707 -681
  75. data/lib/when_exe/tmduration.rb +338 -330
  76. data/lib/when_exe/tmobjects.rb +1346 -1325
  77. data/lib/when_exe/tmposition.rb +2115 -2072
  78. data/lib/when_exe/tmreference.rb +1693 -1669
  79. data/lib/when_exe/version.rb +1 -1
  80. data/link_to_online_documents +1 -1
  81. data/test/examples/JapanHolidaysRFC6350.ics +1 -1
  82. data/test/test.rb +67 -61
  83. data/test/test/basictypes.rb +409 -409
  84. data/test/test/calendarnote.rb +86 -69
  85. data/test/test/calendartypes.rb +97 -97
  86. data/test/test/coordinates.rb +396 -396
  87. data/test/test/ephemeris.rb +83 -74
  88. data/test/test/ephemeris/moon.rb +14 -14
  89. data/test/test/ephemeris/planets.rb +14 -14
  90. data/test/test/ephemeris/sun.rb +14 -14
  91. data/test/test/googlecalendar.rb +194 -176
  92. data/test/test/icalendar.rb +867 -858
  93. data/test/test/inspect.rb +117 -117
  94. data/test/test/parts.rb +487 -487
  95. data/test/test/region/balinese.rb +34 -0
  96. data/test/test/region/chinese.rb +218 -206
  97. data/test/test/region/christian.rb +245 -245
  98. data/test/test/region/coptic.rb +27 -27
  99. data/test/test/region/french.rb +33 -33
  100. data/test/test/region/geologicalage.rb +17 -17
  101. data/test/test/region/indian.rb +57 -57
  102. data/test/test/region/iran.rb +54 -54
  103. data/test/test/region/islamic.rb +18 -18
  104. data/test/test/region/japanese.rb +237 -219
  105. data/test/test/region/jewish.rb +61 -61
  106. data/test/test/region/m17n.rb +184 -184
  107. data/test/test/region/mayan.rb +195 -195
  108. data/test/test/region/residue.rb +147 -139
  109. data/test/test/region/thai.rb +116 -116
  110. data/test/test/region/tibetan.rb +30 -30
  111. data/test/test/region/vietnamese.rb +102 -102
  112. data/test/test/region/yerm.rb +146 -146
  113. data/test/test/timestandard.rb +81 -81
  114. data/test/test/tmobjects.rb +328 -328
  115. data/test/test/tmposition.rb +397 -284
  116. data/test/test/tmreference.rb +157 -157
  117. metadata +13 -10
@@ -1,1325 +1,1346 @@
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.2) Temporal Objects Package
11
- #
12
- #
13
-
14
- #
15
- # 長さと距離を計算するための操作を規定する
16
- #
17
- module Separation
18
-
19
- # When::TM::GeometricPrimitive 自身の持続時間
20
- #
21
- # @return [When::TM::Duration]
22
- #
23
- # @abstract
24
- #
25
- def length
26
- raise TypeError, "Absolute Class #{self.class}"
27
- end
28
-
29
- # 他のWhen::TM::GeometricPrimitiveとの時間位置の差の絶対値
30
- #
31
- # @param [When::TM::GeometricPrimitive] other
32
- #
33
- # @return [When::TM::Duration]
34
- #
35
- # @abstract
36
- #
37
- def distance(other)
38
- raise TypeError, "Absolute Class #{self.class}"
39
- end
40
-
41
- end
42
-
43
- #
44
- # 互いの相対位置を判定する操作を規定する
45
- #
46
- module Order
47
-
48
- # 他のWhen::TM::Primitiveとの相対的な時間位置
49
- #
50
- # @param [When::TM::Primitive] other
51
- #
52
- # @return [When::TM::RelativePosition]
53
- #
54
- # @abstract
55
- #
56
- def relative_position(other)
57
- raise TypeError, "Absolute Class #{self.class}"
58
- end
59
- alias :relativePosition :relative_position
60
-
61
- end
62
-
63
- # 相対的な時間位置
64
- #
65
- # Allen(1983) が分類した13種類の相対的な時間位置を定義している
66
- #
67
- # ISO19108では値は Code クラスだが、本実装では値は Symbol である
68
- #
69
- # see {http://schemas.opengis.net/gml/3.1.1/base/temporal.xsd#RelatedTimeType gml schema}
70
- #
71
- # see Allen,J.F., Maintaining Knowledge about Temporal Intervals, Communications of the ACM, 1983,vol.26 pp.832-843
72
- #
73
- module RelativePosition
74
-
75
- Before = :Before
76
- After = :After
77
- Begins = :Begins
78
- Ends = :Ends
79
- During = :During
80
- Equals = :Equals
81
- Contains = :Contains
82
- Overlaps = :Overlaps
83
- Meets = :Meets
84
- OverlappedBy = :OverlappedBy
85
- MetBy = :MetBy
86
- BegunBy = :BegunBy
87
- EndedBy = :EndedBy
88
-
89
- end
90
-
91
- # 時間のオブジェクト
92
- #
93
- # see {http://schemas.opengis.net/gml/3.1.1/base/temporal.xsd#AbstractTimeObjectType gml schema}
94
- #
95
- class Object < When::BasicTypes::Object
96
-
97
- end
98
-
99
- # 複数の時間プリミティブの集成
100
- #
101
- # see {http://schemas.opengis.net/gml/3.1.1/base/temporal.xsd#AbstractTimeComplexType gml schema}
102
- #
103
- class Complex < Object
104
-
105
- end
106
-
107
- # 位相複体 - 連結した位相プリミティブの集合
108
- #
109
- # A temporal topology complex.
110
- #
111
- # see {http://schemas.opengis.net/gml/3.1.1/base/temporalTopology.xsd#TimeTopologyComplexType gml schema}
112
- #
113
- class TopologicalComplex < Complex
114
-
115
- # 対応するプリミティブ (relation - Complex)
116
- #
117
- # @return [Array<When::TM::TopologicalPrimitive>]
118
- #
119
- attr_reader :primitive
120
-
121
- # オブジェクトの生成
122
- #
123
- # @param [When::TM::TopologicalPrimitive] primitive 対応するプリミティブの Array
124
- #
125
- def initialize(primitive)
126
- @primitive = primitive
127
- @primitive.each do |p|
128
- p.complex << self
129
- end
130
- end
131
- end
132
-
133
- # 時間プリミティブ
134
- #
135
- # see {http://schemas.opengis.net/gml/3.1.1/base/temporal.xsd#AbstractTimePrimitiveType gml schema}
136
- #
137
- class Primitive < Object
138
-
139
- include Order
140
-
141
- end
142
-
143
- # 時間幾何プリミティブ
144
- #
145
- # see {http://schemas.opengis.net/gml/3.1.1/base/temporal.xsd#AbstractTimeGeometricPrimitiveType gml schema}
146
- #
147
- class GeometricPrimitive < Primitive
148
-
149
- include Separation
150
-
151
- end
152
-
153
- # 瞬間 - 零次元幾何プリミティブ
154
- #
155
- # see {http://schemas.opengis.net/gml/3.1.1/base/temporal.xsd#TimeInstantType gml schema}
156
- #
157
- class Instant < GeometricPrimitive
158
-
159
- # この瞬間の時間位置
160
- #
161
- # @return [When::TM::Position]
162
- #
163
- attr_reader :position
164
-
165
- # この瞬間を始まりとする期間 (relation - Beginning)
166
- #
167
- # @return [Array<When::TM::Period>]
168
- #
169
- attr_reader :begun_by
170
- alias :begunBy :begun_by
171
-
172
- # この瞬間を終わりとする期間 (relation - Ending)
173
- #
174
- # @return [Array<When::TM::Period>]
175
- #
176
- attr_reader :ended_by
177
- alias :endedBy :ended_by
178
-
179
- # 対応するノード (relation - Realization)
180
- #
181
- # @return [When::TM::Node]
182
- #
183
- attr_reader :topology
184
-
185
- # When::TM::GeometricPrimitive 自身の持続時間
186
- #
187
- # @return [When::TM::Duration]
188
- #
189
- def length()
190
- return When.Duration(0)
191
- end
192
-
193
- # 他のWhen::TM::GeometricPrimitiveとの時間位置の差の絶対値
194
- #
195
- # @param [When::TM::GeometricPrimitive] other
196
- #
197
- # @return [When::TM::Duration]
198
- #
199
- def distance(other)
200
- case other
201
- when Instant
202
- return (self.position - other.position).abs
203
- when Period
204
- verify = other.begin.position - self.position
205
- return verify if verify.sign >= 0
206
- return [self.position - other.end.position, When::TM::PeriodDuration.new(0,When::DAY)].max
207
- else
208
- raise TypeError, "The right operand should be When::TM::Instant or When::TM::Period"
209
- end
210
- end
211
-
212
- # 他のWhen::TM::Primitiveとの相対的な時間位置
213
- #
214
- # @param [When::TM::Primitive] other
215
- #
216
- # @return [When::TM::RelativePosition]
217
- #
218
- def relative_position(other)
219
- case other
220
- when Instant
221
- verify = self.position <=> other.position
222
- return RelativePosition::Before if verify < 0
223
- return RelativePosition::Equals if verify == 0
224
- return RelativePosition::After
225
- when Period
226
- verify = self.position <=> other.begin.position
227
- return RelativePosition::Before if verify < 0
228
- return RelativePosition::Begins if verify == 0
229
- verify = self.position <=> other.end.position
230
- return RelativePosition::During if verify < 0
231
- return RelativePosition::Ends if verify == 0
232
- return RelativePosition::After
233
- else
234
- raise TypeError, "The right operand should be When::TM::Instant or When::TM::Period"
235
- end
236
- end
237
- alias :relativePosition :relative_position
238
-
239
- # オブジェクトの生成
240
- #
241
- # @param [When::TM::Position] position 対応する時間位置
242
- #
243
- def initialize(position)
244
- @position = position
245
- @begun_by = []
246
- @ended_by = []
247
- end
248
-
249
- private
250
-
251
- # その他のメソッド
252
- #
253
- # @note
254
- # When::TM::Instant で定義されていないメソッドは
255
- # 処理を @position (type: When::TM::Position) に委譲する
256
- #
257
- def method_missing(name, *args, &block)
258
- self.class.module_eval %Q{
259
- def #{name}(*args, &block)
260
- list = args.map {|arg| arg.kind_of?(self.class) ? arg.position : arg}
261
- @position.send("#{name}", *list, &block)
262
- end
263
- } unless When::Parts::MethodCash.escape(name)
264
- list = args.map {|arg| arg.kind_of?(self.class) ? arg.position : arg}
265
- @position.send(name, *list, &block)
266
- end
267
- end
268
-
269
- # 期間 - 一次元幾何プリミティブ
270
- #
271
- # see {http://schemas.opengis.net/gml/3.1.1/base/temporal.xsd#TimePeriodType gml schema}
272
- #
273
- class Period < GeometricPrimitive
274
-
275
- RELATIVE_POSITION = {
276
- RelativePosition::Contains => {
277
- RelativePosition::Before => RelativePosition::Overlaps,
278
- RelativePosition::EndedBy => RelativePosition::EndedBy,
279
- RelativePosition::Contains => RelativePosition::Contains
280
- },
281
- RelativePosition::BegunBy => {
282
- RelativePosition::Before => RelativePosition::Begins,
283
- RelativePosition::EndedBy => RelativePosition::Equals,
284
- RelativePosition::Contains => RelativePosition::BegunBy
285
- },
286
- RelativePosition::After => {
287
- RelativePosition::Before => RelativePosition::During,
288
- RelativePosition::EndedBy => RelativePosition::Ends,
289
- RelativePosition::Contains => RelativePosition::OverlappedBy
290
- }
291
- }
292
-
293
- # この期間が始まる瞬間 (relation - Beginning)
294
- #
295
- # @return [When::TM::Instant]
296
- #
297
- attr_reader :begin
298
-
299
- # この期間が終わる瞬間 (relation - Ending)
300
- #
301
- # @return [When::TM::Instant]
302
- #
303
- attr_reader :end
304
-
305
- # 対応するエッジ (relation - Realization)
306
- #
307
- # @return [When::TM::Edge]
308
- #
309
- attr_reader :topology
310
-
311
- # When::TM::GeometricPrimitive 自身の持続時間
312
- #
313
- # @return [When::TM::Duration]
314
- #
315
- def length()
316
- @length ||= @end - @begin
317
- end
318
-
319
- # 他のWhen::TM::GeometricPrimitiveとの時間位置の差の絶対値
320
- #
321
- # @param [When::TM::GeometricPrimitive] other
322
- #
323
- # @return [When::TM::Duration]
324
- #
325
- def distance(other)
326
- case other
327
- when Instant
328
- return other.distance(self)
329
- when Period
330
- verify = other.begin.position - self.end.position
331
- return verify if verify.sign >= 0
332
- return [self.begin.position - other.end.position, When::TM::PeriodDuration.new(0,When::DAY)].max
333
- else
334
- raise TypeError, "The right operand should be Instant or Period"
335
- end
336
- end
337
-
338
- # 他のPrimitiveとの相対的な時間位置
339
- #
340
- # @param [When::TM::Primitive] other
341
- #
342
- # @return [When::TM::RelativePosition]
343
- #
344
- def relative_position(other)
345
- case other
346
- when Instant
347
- verify = self.end.position <=> other.position
348
- return RelativePosition::Before if verify < 0
349
- return RelativePosition::EndedBy if verify == 0
350
- verify = self.begin.position <=> other.position
351
- return RelativePosition::Contains if verify < 0
352
- return RelativePosition::BegunBy if verify == 0
353
- return RelativePosition::After
354
- when Period
355
- verify_b = relative_position(other.begin)
356
- case verify_b
357
- when RelativePosition::Before ; return RelativePosition::Before
358
- when RelativePosition::EndedBy ; return RelativePosition::Meets
359
- end
360
- verify_e = relative_position(other.end)
361
- case verify_e
362
- when RelativePosition::BegunBy ; return RelativePosition::MetBy
363
- when RelativePosition::After ; return RelativePosition::After
364
- else ; return RELATIVE_POSITION[verify_b][verify_e]
365
- end
366
- else
367
- raise TypeError, "The right operand should be Instant or Period"
368
- end
369
- end
370
- alias :relativePosition :relative_position
371
-
372
- # オブジェクトの生成
373
- #
374
- # @param [When::TM::Instant] begun 始点
375
- #
376
- # @param [When::TM::Instant] ended 終点
377
- #
378
- def initialize(begun, ended)
379
- raise ArgumentError, 'Order mismatch: begun > ended' if begun > ended
380
- @begin = begun
381
- @end = ended
382
- @begin.begun_by << self
383
- @end.ended_by << self
384
- end
385
-
386
- private
387
-
388
- # その他のメソッド
389
- #
390
- # @note
391
- # When::TM::Period で定義されていないメソッドは
392
- # 処理を @begin (type: When::TM::Instant) に委譲する
393
- #
394
- def method_missing(name, *args, &block)
395
- self.class.module_eval %Q{
396
- def #{name}(*args, &block)
397
- @begin.send("#{name}", *args, &block)
398
- end
399
- } unless When::Parts::MethodCash.escape(name)
400
- @begin.send(name, *args, &block)
401
- end
402
- end
403
-
404
- # 時間位相プリミティブ - 単独で不可分な位相要素
405
- #
406
- # see {http://schemas.opengis.net/gml/3.1.1/base/temporalTopology.xsd#AbstractTimeTopologyPrimitiveType gml schema}
407
- #
408
- class TopologicalPrimitive < Primitive
409
-
410
- # 対応するコンプレックス (relation - Complex)
411
- #
412
- # @return [Array<When::TM::TopologicalComplex>]
413
- #
414
- attr_accessor :complex
415
-
416
- #
417
- # オブジェクトの生成
418
- #
419
- def initialize
420
- @complex = []
421
- end
422
-
423
- private
424
-
425
- alias :_method_missing :method_missing
426
-
427
- # その他のメソッド
428
- #
429
- # @note
430
- # When::TM::TopologicalPrimitive で定義されていないメソッドは
431
- # 処理を @geometry (type: When::TM::Instant) に委譲する
432
- #
433
- def method_missing(name, *args, &block)
434
- return _method_missing(name, *args, &block) if When::Parts::MethodCash::Escape.key?(name) ||
435
- !respond_to?(:geometry)
436
- self.class.module_eval %Q{
437
- def #{name}(*args, &block)
438
- list = args.map {|arg| arg.respond_to?(:geometry) ? arg.geometry : arg}
439
- geometry.send("#{name}", *list, &block)
440
- end
441
- } unless When::Parts::MethodCash.escape(name)
442
- list = args.map {|arg| arg.respond_to?(:geometry) ? arg.geometry : arg}
443
- geometry.send(name, *list, &block)
444
- end
445
- end
446
-
447
- # 零次元位相プリミティブ - 幾何的実現は When::TM::Instant と対応する
448
- #
449
- # see {http://schemas.opengis.net/gml/3.1.1/base/temporalTopology.xsd#TimeNodeType gml schema}
450
- #
451
- class Node < TopologicalPrimitive
452
-
453
- # 対応するエッジ (relation - Termination)
454
- #
455
- # @return [Array<When::TM::Edge>]
456
- #
457
- attr_reader :previous_edge
458
- alias :previousEdge :previous_edge
459
-
460
- # 対応するエッジ (relation - Initiation)
461
- #
462
- # @return [Array<When::TM::Edge>]
463
- #
464
- attr_reader :next_edge
465
- alias :nextEdge :next_edge
466
-
467
- # 対応する瞬間 (relation - Realization)
468
- #
469
- # @return [When::TM::Instant]
470
- #
471
- attr_reader :geometry
472
-
473
- # オブジェクトの生成
474
- #
475
- # @param [When::TM::Instant] geometry 対応する瞬間
476
- #
477
- def initialize(geometry)
478
- super()
479
- @previous_edge = []
480
- @next_edge = []
481
- @geometry = geometry
482
- @geometry.topology = self
483
- end
484
- end
485
-
486
- # 一次元位相プリミティブ - 幾何的実現は When::TM::Period と対応する
487
- #
488
- # see {http://schemas.opengis.net/gml/3.1.1/base/temporalTopology.xsd#TimeEdgeType gml schema}
489
- #
490
- class Edge < TopologicalPrimitive
491
-
492
- # 対応するノード (relation - Termination)
493
- #
494
- # @return [When::TM::Node]
495
- #
496
- attr_reader :end
497
-
498
- # 対応するノード (relation - Initiation)
499
- #
500
- # @return [When::TM::Node]
501
- #
502
- attr_reader :start
503
-
504
- # 対応する期間 (relation - Realization)
505
- #
506
- # @return [When::TM::Period]
507
- #
508
- attr_reader :geometry
509
-
510
- # オブジェクトの生成
511
- #
512
- # @param [When::TM::Node] start 始点
513
- #
514
- # @param [When::TM::Node] ended 終点
515
- #
516
- def initialize(start, ended)
517
- super()
518
- @start = start
519
- @end = ended
520
- @geometry = Period.new(@start.geometry, @end.geometry)
521
- @geometry.topology = self
522
- @start.next_edge << self
523
- @end.previous_edge << self
524
- end
525
- end
526
-
527
- # 時間次元における長さ又は距離を記述するために使うデータ型
528
- #
529
- # see {http://schemas.opengis.net/gml/3.1.1/base/temporal.xsd#duration gml schema}
530
- #
531
- class Duration
532
-
533
- #
534
- # When::TM::IntervalLength への変換
535
- #
536
- # @return [When::TM::IntervalLength]
537
- #
538
- def to_interval_length
539
- [['week', WEEK], ['day', DAY], ['hour', HOUR], ['minute', MINUTE], ['second', SECOND]].each do |unit|
540
- div, mod = duration.divmod(unit[1])
541
- return When::TM::IntervalLength.new(div, unit[0]) if mod == 0
542
- end
543
- When::TM::IntervalLength.new(duration / SECOND, 'second')
544
- end
545
-
546
- #
547
- # When::TM::PeriodDuration への変換
548
- #
549
- # @return [When::TM::PeriodDuration]
550
- #
551
- def to_period_duration
552
- [[When::WEEK, WEEK], [When::DAY, DAY], [When::HOUR, HOUR], [When::MINUTE, MINUTE], [When::SECOND, SECOND]].each do |unit|
553
- div, mod = duration.divmod(unit[1])
554
- return When::TM::PeriodDuration.new(div, unit[0]) if mod == 0
555
- end
556
- When::TM::PeriodDuration.new(duration / SECOND, When::SECOND)
557
- end
558
-
559
- #
560
- # Duration 用の Enumerator
561
- #
562
- class Enumerator < When::Parts::Enumerator
563
-
564
- # 次の時間位置を取得する
565
- #
566
- # @return [When::TM::TemporalPosition] 次の時間位置
567
- #
568
- def succ
569
- value = @current
570
- @current = (@count_limit.kind_of?(Numeric) && @count >= @count_limit) ? nil :
571
- (@current==:first) ? @first :
572
- (@direction==:forward) ? @first + @parent * @count : @first - @parent * @count
573
- @count += 1
574
- return value
575
- end
576
- end
577
-
578
- # Enumerator の生成
579
- #
580
- # @overload initialize(range, count_limit=nil))
581
- # @param [Range, When::Parts::GeometricComplex] range
582
- # [ 始点 - range.first ]
583
- # [ 終点 - range.last ]
584
- # @param [Integer] count_limit 繰り返し回数(デフォルトは指定なし)
585
- #
586
- # @overload initialize(first, direction, count_limit=nil))
587
- # @param [When::TM::TemporalPosition] first 始点
588
- # @param [Symbol] direction
589
- # [ :forward - 昇順 ]
590
- # [ :reverse - 降順 ]
591
- # @param [Integer] count_limit 繰り返し回数(デフォルトは指定なし)
592
- #
593
- def _enumerator(*args)
594
- return Enumerator.new(*args.unshift(self))
595
- end
596
- alias :to_enum :_enumerator
597
- alias :enum_for :_enumerator
598
- end
599
-
600
- #
601
- # ISO 11404 の時間間隔に基づいて定義された When::TM::Duration の subclass
602
- #
603
- # see {http://schemas.opengis.net/gml/3.1.1/base/temporal.xsd#timeIntervalLengthType gml schema}
604
- #
605
- class IntervalLength < Duration
606
-
607
- Alias = {'Y'=>'year', 'M'=>'month' , 'D'=>'day', 'W'=>'week', 'S'=>'system',
608
- 'h'=>'hour', 'm'=>'minute', 's'=>'second'}
609
-
610
- # Interval Length 形式の表現を分解して配列化する
611
- #
612
- # @param [String] interval
613
- #
614
- # @return [Array<Numeric, String>] ( value, unit_name, factor, radix )
615
- # [ value [Numeric] - 時間間隔 / 単位 ]
616
- # [ unit_name [String] - 単位名 ]
617
- # [ factor [Numeric] - 冪乗 ]
618
- # [ radix [Numeric] - 冪乗の基数 ]
619
- #
620
- # @note value, factor, radix は Numeric
621
- #
622
- def self._to_array(interval)
623
- return nil unless interval =~ /^([-+]?[\d.]+)(?:(E|X|\((\d+)\))([-+]?\d+))?([A-Za-z]+|\*([\d.]+)S)$/
624
- value, radix, radix_quantity, factor, unit, unit_quantity = $~[1..6]
625
- value = When::Coordinates::Pair._en_number(value)
626
- radix = case radix
627
- when 'E', nil ; 10
628
- when 'X' ; 60
629
- else ; radix_quantity.to_i
630
- end
631
- factor = factor ? -factor.to_i : 0
632
- return [value, unit_quantity, factor, radix] if unit_quantity
633
- unit_quantity = Unit[unit.downcase] || Unit[Alias[unit[0..0]]]
634
- return [value, UnitName[unit_quantity], factor, radix] if unit_quantity
635
- return nil
636
- end
637
-
638
- # 時間間隔の長さ (128秒単位)
639
- #
640
- # @return [Numeric]
641
- #
642
- protected :duration=
643
-
644
- # 時間間隔を表現するために使用した測定単位の名称
645
- #
646
- # @return [String] (year|month|week|day|hour|minute|second|system)
647
- #
648
- attr_reader :unit
649
-
650
- # 時間単位となる乗数の基底となる正の整数
651
- #
652
- # @return [Integer]
653
- #
654
- attr_reader :radix
655
-
656
- # 基底のべき乗を行う指数
657
- #
658
- # @return [Integer]
659
- #
660
- attr_reader :factor
661
-
662
- # 時間間隔の長さ / 測定単位
663
- #
664
- # @return [Numeric]
665
- #
666
- attr_accessor :value
667
- protected :value=
668
-
669
- #
670
- # 測定単位の大きさ
671
- #
672
- # @return [Numeric]
673
- #
674
- attr_reader :unit_quantity
675
-
676
- # 時刻配列
677
- #
678
- # @return [Numeric]
679
- # When::TM::PeriodDuration との互換性のために提供
680
- #
681
- # @private
682
- #
683
- def time
684
- [0, 0, @duration / SECOND]
685
- end
686
-
687
- # 日付配列
688
- #
689
- # @return [nil]
690
- # When::TM::PeriodDuration との互換性のために提供
691
- #
692
- # @private
693
- #
694
- def date
695
- nil
696
- end
697
-
698
- # 暦週配列
699
- #
700
- # @return [nil]
701
- # When::TM::PeriodDuration との互換性のために提供
702
- #
703
- # @private
704
- #
705
- def weeks
706
- nil
707
- end
708
-
709
- # 符号反転
710
- #
711
- # @return [When::TM::IntervalLength]
712
- #
713
- def -@
714
- interval = self.dup
715
- interval.value = -@value
716
- interval.duration = -@duration
717
- return interval
718
- end
719
-
720
- #
721
- # 加算
722
- #
723
- # @param [When::TM::Duration] other
724
- # @param [Numeric] other 秒数
725
- # @param [その他] other 日時とみなす
726
- #
727
- # @return [When::TM::IntervalLength] (other が Numeric, When::TM::Duration の場合)
728
- # @return [other と同じクラス] (other がその他の場合)
729
- #
730
- def +(other)
731
- case other
732
- when Duration ; diff = other.duration
733
- when Numeric ; diff = other * SECOND
734
- else ; return other + self
735
- end
736
- interval = self.dup
737
- interval.duration = @duration + diff
738
- internal.value = interval.duration / (@radix ** (-@factor) * @unit_quantity)
739
- return interval
740
- end
741
-
742
- #
743
- # 減算
744
- #
745
- # @param [When::TM::IntervalLength] other
746
- # @param [Numeric] other 秒数
747
- #
748
- # @return [When::TM::IntervalLength]
749
- #
750
- def -(other)
751
- interval = self.dup
752
- interval.duration = @duration - (other.kind_of?(Duration) ? other.duration : other * SECOND)
753
- internal.value = interval.duration / (@radix ** (-@factor) * @unit_quantity)
754
- return interval
755
- end
756
-
757
- # 乗算
758
- #
759
- # @param [Numeric] times
760
- #
761
- # @return [When::TM::IntervalLength]
762
- #
763
- def *(times)
764
- interval = self.dup
765
- interval.value = times * @value
766
- interval.duration = times * @duration
767
- return interval
768
- end
769
-
770
- #
771
- # 除算
772
- #
773
- # @param [When::TM::IntervalLength] other
774
- # @param [Numeric] other 秒数
775
- #
776
- # @return [When::TM::IntervalLength] (other が Numeric の場合)
777
- # @return [Numeric] (other が When::TM::Duration の場合)
778
- #
779
- def /(other)
780
- other.kind_of?(Duration) ? @duration / other.duration : self * (1.0 / other)
781
- end
782
-
783
- # 文字列化
784
- #
785
- # @return [String]
786
- #
787
- def to_s
788
- expression = @value.to_s
789
- unless @factor == 0
790
- case @radix
791
- when 10 ; expression += 'E'
792
- when 60 ; expression += 'X'
793
- else ; expression += '(%d)' % @radix
794
- end
795
- expression += '%+d' % (-@factor)
796
- end
797
- expression += Alias.invert[@unit] || "*#{When::Coordinates::Pair._en_number(@unit)}S"
798
- return expression
799
- end
800
-
801
- #
802
- # When::TM::IntervalLength への変換
803
- #
804
- # 単なるオブジェクトのコピー
805
- #
806
- # @return [When::TM::IntervalLength]
807
- #
808
- def to_interval_length
809
- self.dup
810
- end
811
-
812
- # オブジェクトの生成
813
- #
814
- # @param [Numeric] value 時間間隔の長さ / 測定単位(省略不可)
815
- # @param [String] unit 時間間隔を表現するために使用した測定単位の名称(デフォルト : system)
816
- # ('year'|'month'|'week'|'day'|'hour'|'minute'|'second'|'system')
817
- # @param [Integer] factor 基底の冪乗を行う指数(デフォルト : 0)
818
- # @param [Integer] radix 時間単位となる乗数の基底となる正の整数(デフォルト : 10)
819
- #
820
- def initialize(value, unit='system', factor=0, radix=10)
821
- @value, @factor, @radix = value, factor, radix
822
- @unit_quantity = Unit[unit.downcase] || Unit[Alias[unit[0..0]]] if unit.kind_of?(String)
823
- @unit_quantity ||= unit.to_f
824
- raise TypeError, "Wrong Unit Type: #{unit}" unless @unit_quantity.kind_of?(Numeric)
825
- @unit = UnitName[@unit_quantity] ||
826
- When::Coordinates::Pair._en_number(@unit_quantity).to_s
827
- @duration = @value * @radix ** (-@factor) * @unit_quantity
828
- end
829
-
830
- # オブジェクトの生成(終点と始点を指定)
831
- #
832
- # @param [When::TM::TemporalPosition] ended 終点
833
- # @param [When::TM::TemporalPosition] begun 始点
834
- #
835
- # @return [When::TM::IntervalLength]
836
- # [ 日単位の精度 - 終点と始点の分解能のいずれかが“日”またはそれより粗い場合 ]
837
- # [ システム精度 - 終点と始点の分解能がともに“日”より細かい場合 ]
838
- #
839
- def self.difference(ended, begun)
840
- precision = [ended.precision, begun.precision].min
841
- return new(ended-begun) if precision > When::DAY
842
- return new(ended.to_i - begun.to_i, unit='day')
843
- end
844
-
845
- private
846
-
847
- # その他のメソッド
848
- #
849
- # @note
850
- # When::TM::IntervalLength で定義されていないメソッドは
851
- # 処理を @duration (type:Numeric) に委譲する
852
- #
853
- def method_missing(name, *args, &block)
854
- self.class.module_eval %Q{
855
- def #{name}(*args, &block)
856
- @duration.send("#{name}", *args, &block)
857
- end
858
- } unless When::Parts::MethodCash.escape(name)
859
- @duration.send(name, *args, &block)
860
- end
861
- end
862
-
863
- #
864
- # ISO 8601 (JIS X0301) の時間間隔に基づいて定義された When::TM::Duration の subclass
865
- #
866
- class PeriodDuration < Duration
867
-
868
- include When
869
- include Coordinates
870
-
871
- #
872
- # When::TM::PeriodDuration オブジェクトが月や年などの可変長の単位に依存する場合
873
- # に @duration 属性の参照を禁止するために用いる
874
- #
875
- module NoDuration
876
- #
877
- # 属性 @duration が定義できないとをエラーで示す
878
- #
879
- # @return [Numeric]
880
- #
881
- def duration
882
- raise TypeError, "This PeriodDuration object does't have duration value"
883
- end
884
- end
885
-
886
- # ISO 8601 形式の表現を分解して配列化する
887
- #
888
- # @param [String] period
889
- #
890
- # @return [Array<Numeric, Array<Numeric>>] ( sign, date, time, week )
891
- # [ sign [Numeric] - +1 , -1 ]
892
- # [ date [Array<Numeric>] - 年月日 ]
893
- # [ time [Array<Numeric>] - 時分秒 ]
894
- # [ week [Array<Numeric>] - 週日 ]
895
- #
896
- def self._to_array(period)
897
-
898
- return nil unless period.gsub(/_+/, '') =~ /^([-+])?P(.*?)?(?:T(.+))?$/
899
-
900
- sign = ($1 == '-') ? -1 : +1
901
- pdate, ptime = $~[2..3]
902
-
903
- # 時分秒形式
904
- if (ptime =~ /^(?:([.,\d]+)?([:*=])?H)?(?:([.,\d]+)?([:*=])?M)?(?:([.,\d]+)?([:*=])?S)?((?:[.,\d]*[:*=]?X)*)$/)
905
- trunk = [1,3,5].map {|i|
906
- $~[i] ? Pair._en_pair($~[i], $~[i+1]) : 0
907
- }
908
- extra = $7 ? $7.scan(/([.,\d]+)?([:*=])?X/).map {|d|
909
- d[0] ? Pair._en_pair(d[0], d[1]) : 0
910
- } : []
911
- time = [0] + trunk + extra
912
- time = nil if time.uniq == [0]
913
- end
914
-
915
- case pdate
916
- # 年月日形式
917
- when /^((?:[.,\d]*[-*=]?X)*)(?:([.,\d]+)?([-*=])?Y)?(?:([.,\d]+)?([-+*&%!>=<?])?M)?(?:([.,\d]+)?([-*=?%])?D)?$/
918
- trunk = [2,4,6].map {|i|
919
- $~[i] ? Pair._en_pair($~[i], $~[i+1]) : 0
920
- }
921
- extra = $1 ? $1.scan(/([.,\d]+)?([:*=])?X/).map {|d|
922
- d[0] ? Pair._en_pair(d[0], d[1]) : 0
923
- } : []
924
- date = extra + trunk
925
- date = nil if date.uniq == [0]
926
- return sign, date, time
927
-
928
- # 週日形式
929
- when /^(?:([.,\d]+)?([:*=])?W)(?:([.,\d]+)?([-*=?%])?D)?$/
930
- week = [1,3].map {|i|
931
- $~[i] ? Pair._en_pair($~[i], $~[i+1]) : 0
932
- }
933
- return sign, nil, time if week.uniq == [0]
934
- date = [0, 0, week[1] + 7*week[0]]
935
- return sign, date, time, week
936
-
937
- # 代用形式
938
- else
939
- pdate += 'T' + ptime if ptime
940
- f, d, t, z, e = When::BasicTypes::DateTime._to_array(pdate, {:abbr=>[0]*20})
941
- return nil if e
942
- if d
943
- case f
944
- when :day ; date = [d[0], 0, d[1]]
945
- when :century, nil ; date = (0..2).map {|i| d[i]||0}
946
- when :week ; date, week = [0,0,d[0]*7+(d[1]||0)], [d[0], d[1]||0]
947
- end
948
- end
949
- time = t ? (t.map {|v| v||0}) : nil
950
- return sign, date, time, week
951
- end
952
- end
953
-
954
- # 期間の日付要素
955
- #
956
- # @return [Array<Numeric>]
957
- #
958
- attr_accessor :date
959
- protected :date=
960
-
961
- # 期間の週日要素
962
- #
963
- # @return [Array<Numeric>]
964
- #
965
- attr_accessor :week
966
- protected :week=
967
-
968
- # 期間の時刻要素
969
- #
970
- # @return [Array<Numeric>]
971
- #
972
- attr_accessor :time
973
- protected :time=
974
-
975
- # 要素の参照
976
- #
977
- # @param [Numeric] index When::Coordinates で定義している分解能定数に対応する列挙型( YEAR, ... , SECOND)
978
- #
979
- # @return [Numeric]
980
- #
981
- def [](index)
982
- if (index == WEEK)
983
- return nil unless (@week)
984
- return @week[0]
985
- elsif (index <= 0)
986
- return nil unless (@date)
987
- return @date[index-1]
988
- else
989
- return nil unless (@time)
990
- return @time[index]
991
- end
992
- end
993
-
994
- # 持続期間であることを文字'P'で示す
995
- #
996
- # @return [String]
997
- #
998
- def designator
999
- return 'P'
1000
- end
1001
-
1002
- # 期間に含まれる年数を示す
1003
- #
1004
- # @return [Numeric]
1005
- #
1006
- def years
1007
- return nil unless (@date)
1008
- return @date[YEAR-1].to_s
1009
- end
1010
-
1011
- # 期間に含まれる月数を示す
1012
- #
1013
- # @return [Numeric]
1014
- #
1015
- def months
1016
- return nil unless (@date)
1017
- return @date[MONTH-1].to_s
1018
- end
1019
-
1020
- # 期間に含まれる週数を示す
1021
- #
1022
- # @return [Numeric]
1023
- #
1024
- def weeks
1025
- return nil unless (@week)
1026
- return @week[0].to_s
1027
- end
1028
-
1029
- # 期間に含まれる日数を示す
1030
- #
1031
- # @return [Numeric]
1032
- #
1033
- def days
1034
- return nil unless (@date)
1035
- return @date[DAY-1].to_s
1036
- end
1037
-
1038
- # 期間が1日より短い時間単位を含むとき文字'T'で示す
1039
- #
1040
- # @return [String]
1041
- #
1042
- def time_indicator
1043
- return (@time) ? 'T' : nil
1044
- end
1045
- alias :timeIndicator :time_indicator
1046
-
1047
- # 期間に含まれる時間数を示す
1048
- #
1049
- # @return [Numeric]
1050
- #
1051
- def hours
1052
- return nil unless (@time)
1053
- return @time[HOUR].to_s
1054
- end
1055
-
1056
- # 期間に含まれる分数を示す
1057
- #
1058
- # @return [Numeric]
1059
- #
1060
- def minutes
1061
- return nil unless (@time)
1062
- return @time[MINUTE].to_s
1063
- end
1064
-
1065
- # 期間に含まれる秒数を示す
1066
- #
1067
- # @return [Numeric]
1068
- #
1069
- def seconds
1070
- return nil unless (@time)
1071
- return @time[SECOND].to_s
1072
- end
1073
-
1074
- # 符号反転
1075
- #
1076
- # @return [When::TM::PeriodDuration]
1077
- #
1078
- def -@
1079
- period = self.dup
1080
- period.date = @date.map {|v| -v} if @date
1081
- period.week = @week.map {|v| -v} if @week
1082
- period.time = @time.map {|v| -v} if @time
1083
- return period
1084
- end
1085
-
1086
- # 符号
1087
- #
1088
- # @return [Integer] 0 との比較により、負,0,正の値を返す
1089
- #
1090
- def sign
1091
- ((@week || @date || []) + (@time || [])).each do |v|
1092
- return -1 if +v < 0
1093
- end
1094
- return +1
1095
- end
1096
-
1097
- # 比較
1098
- #
1099
- # @param [When::TM::PeriodDuration] other
1100
- #
1101
- # @return [Integer] other との比較により、負,0,正の値を返す
1102
- #
1103
- def <=>(other)
1104
- unless (@date && @date.size) == (other.date && other.date.size) &&
1105
- (@week && @week.size) == (other.week && other.week.size) &&
1106
- (@time && @time.size) == (other.time && other.time.size)
1107
- raise ArgumentError, "PeriodDuration structure mismatch"
1108
- end
1109
-
1110
- (0...@week.size).each do |i|
1111
- sgn = +@week[i] <=> +other.week[i]
1112
- return sgn unless sgn == 0
1113
- end if @week
1114
-
1115
- (0...@date.size).each do |i|
1116
- sgn = +@date[i] <=> +other.date[i]
1117
- return sgn unless sgn == 0
1118
- end if @date
1119
-
1120
- (0...@time.size).each do |i|
1121
- sgn = +@time[i] <=> +other.time[i]
1122
- return sgn unless sgn == 0
1123
- end if @time
1124
-
1125
- return 0
1126
- end
1127
-
1128
- # オブジェクトの同値
1129
- #
1130
- # @param [比較先] other
1131
- #
1132
- # @return [Boolean]
1133
- # [ true - 同値 ]
1134
- # [ false - 非同値 ]
1135
- #
1136
- def ==(other)
1137
- (self <=> other) == 0
1138
- rescue
1139
- false
1140
- end
1141
-
1142
- # 加算
1143
- #
1144
- # @param [When::TM::PeriodDuration] other
1145
- # @param [その他] other 日時とみなす
1146
- #
1147
- # @return [WWhen::TM::PeriodDuration] (other が When::TM::PeriodDuration の場合)
1148
- # @return [other と同じクラス] (other がその他の場合)
1149
- #
1150
- def +(other)
1151
- other.kind_of?(When::TM::PeriodDuration) ? _plus(other, +1) : other + self
1152
- end
1153
-
1154
- # 減算
1155
- #
1156
- # @param [When::TM::PeriodDuration] other
1157
- #
1158
- # @return [When::TM::PeriodDuration]
1159
- #
1160
- def -(other)
1161
- _plus(other, -1)
1162
- end
1163
-
1164
- # 乗算
1165
- #
1166
- # @param [Numeric] times
1167
- #
1168
- # @return [When::TM::PeriodDuration]
1169
- #
1170
- def *(times)
1171
- period = self.dup
1172
- period.date = @date.map {|v| v *= times; v.to_i==v.to_f ? v.to_i : v} if @date
1173
- period.week = @week.map {|v| v *= times; v.to_i==v.to_f ? v.to_i : v} if @week
1174
- period.time = @time.map {|v| v *= times; v.to_i==v.to_f ? v.to_i : v} if @time
1175
- return period
1176
- end
1177
-
1178
- # 除算
1179
- #
1180
- # @param [Numeric] divisor
1181
- #
1182
- # @return [When::TM::PeriodDuration]
1183
- #
1184
- def /(divisor)
1185
- self * (1.0 / divisor)
1186
- end
1187
-
1188
- # 文字列化
1189
- #
1190
- # @return [String]
1191
- #
1192
- def to_s
1193
- period = 'P'
1194
- if @week
1195
- period += @week[0].abs.to_s + 'W'
1196
- period += @week[1].abs.to_s + 'D' unless @week[1] == 0
1197
- elsif @date
1198
- (-@date.length..-1).each do |i|
1199
- period += @date[i].abs.to_s + PRECISION_NAME[i+1][0..0] unless @date[i] == 0
1200
- end
1201
- end
1202
- if @time
1203
- period += 'T'
1204
- (1..@time.length-1).each do |i|
1205
- period += @time[i].abs.to_s + PRECISION_NAME[i][0..0] unless @time[i] == 0
1206
- end
1207
- end
1208
- period = '-' + period if sign < 0
1209
- period == 'P' ? 'P0D' : period
1210
- end
1211
-
1212
- #
1213
- # When::TM::PeriodDuration への変換
1214
- #
1215
- # 単なるオブジェクトのコピー
1216
- #
1217
- # @return [When::TM::PeriodDuration]
1218
- #
1219
- def to_period_duration
1220
- self.dup
1221
- end
1222
-
1223
- # オブジェクトの生成
1224
- #
1225
- # @overload initialize(date=nil, time=nil, week=nil)
1226
- # @param [Array<Numeric>] date 期間の日付要素
1227
- # @param [Array<Numeric>] time 期間の時刻要素
1228
- # @param [Array<Numeric>] week 期間の週日要素
1229
- #
1230
- # @overload initialize(value, index, range=YEAR..SECOND)
1231
- # @param [Numeric] value ndex に対応する桁での)時間間隔
1232
- # @param [Numeric] index When で定義している分解能定数(YEAR, ... ,SECOND)
1233
- # @param [Range] range 生成する桁の範囲
1234
- #
1235
- def initialize(*args)
1236
- @options = (args[-1].kind_of?(Hash)) ? (args.pop.reject {|key,value| value == nil}) : {}
1237
- if args[0].kind_of?(Numeric)
1238
- _initialize_by_unit(*args)
1239
- else
1240
- @date, @time, @week = args
1241
- end
1242
- _duration
1243
- end
1244
-
1245
- private
1246
-
1247
- #
1248
- # 引数パターン2での初期化
1249
- #
1250
- def _initialize_by_unit(value, index, range=YEAR..SECOND)
1251
- max = range.first
1252
- min = range.last
1253
- min += 1 if (range.exclude_end?)
1254
- if (index < max)
1255
- if (index > MONTH)
1256
- max = index.floor
1257
- else
1258
- value *= 10**(max-index)
1259
- index = max
1260
- end
1261
- elsif (index > min)
1262
- if (index <= DAY)
1263
- min = index.ceil
1264
- else
1265
- value *= 0.1**(index-min)
1266
- index = min
1267
- end
1268
- end
1269
- value = value.to_i unless value.kind_of?(Pair) || value.to_i != value.to_f
1270
- @date = Array.new(1-max, 0) if (max <= DAY) && (index <= DAY)
1271
- @time = Array.new(1+min, 0) if (min > DAY) && (index > DAY)
1272
- if (index == WEEK)
1273
- @week = [value, 0]
1274
- @date[DAY-1] = 7 * value
1275
- elsif (index <= DAY)
1276
- @date[index-1] = value
1277
- else
1278
- @time[index] = value
1279
- end
1280
- end
1281
-
1282
- #
1283
- # 属性 @duration の計算
1284
- #
1285
- def _duration
1286
- if @time
1287
- @duration = +@time[HOUR ] * Duration::HOUR
1288
- @duration += +@time[MINUTE] * Duration::MINUTE if @time[MINUTE]
1289
- @duration += +@time[SECOND] * Duration::SECOND if @time[SECOND]
1290
- end
1291
- if @week
1292
- @duration = +@week[0] * Duration::WEEK + +@week[1] * Duration::DAY + (@duration||0)
1293
- elsif @date
1294
- date = @date.dup
1295
- date.shift while date[0] == 0
1296
- case date.size
1297
- when 0 ; @duration ||= 0
1298
- when 1 ; @duration = +@date[DAY-1] * Duration::DAY + (@duration||0)
1299
- else ; @duration = nil
1300
- end
1301
- end
1302
- extend NoDuration unless @duration
1303
- end
1304
-
1305
- # 加減算共通処理
1306
- #
1307
- # @param [When::TM::PeriodDuration] other
1308
- # @param [Numeric] sgn +1, -1
1309
- #
1310
- # @return [When::TM::PeriodDuration]
1311
- #
1312
- def _plus(other, sgn)
1313
- unless (@week && @week.size) == (other.week && other.week.size) &&
1314
- (@date && @date.size) == (other.date && other.date.size) &&
1315
- (@time && @time.size) == (other.time && other.time.size)
1316
- raise ArgumentError, "PeriodDuration structure mismatch"
1317
- end
1318
- period = self.dup
1319
- period.week = (0...@week.size).to_a.map {|i| @week[i] + sgn * other.week[i]} if @week
1320
- period.date = (0...@date.size).to_a.map {|i| @date[i] + sgn * other.date[i]} if @date
1321
- period.time = (0...@time.size).to_a.map {|i| @time[i] + sgn * other.time[i]} if @time
1322
- return period
1323
- end
1324
- end
1325
- end
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.2) Temporal Objects Package
11
+ #
12
+ #
13
+
14
+ #
15
+ # 長さと距離を計算するための操作を規定する
16
+ #
17
+ module Separation
18
+
19
+ # When::TM::GeometricPrimitive 自身の持続時間
20
+ #
21
+ # @return [When::TM::Duration]
22
+ #
23
+ # @abstract
24
+ #
25
+ def length
26
+ raise TypeError, "Absolute Class #{self.class}"
27
+ end
28
+
29
+ # 他のWhen::TM::GeometricPrimitiveとの時間位置の差の絶対値
30
+ #
31
+ # @param [When::TM::GeometricPrimitive] other
32
+ #
33
+ # @return [When::TM::Duration]
34
+ #
35
+ # @abstract
36
+ #
37
+ def distance(other)
38
+ raise TypeError, "Absolute Class #{self.class}"
39
+ end
40
+
41
+ end
42
+
43
+ #
44
+ # 互いの相対位置を判定する操作を規定する
45
+ #
46
+ module Order
47
+
48
+ # 他のWhen::TM::Primitiveとの相対的な時間位置
49
+ #
50
+ # @param [When::TM::Primitive] other
51
+ #
52
+ # @return [When::TM::RelativePosition]
53
+ #
54
+ # @abstract
55
+ #
56
+ def relative_position(other)
57
+ raise TypeError, "Absolute Class #{self.class}"
58
+ end
59
+ alias :relativePosition :relative_position
60
+
61
+ end
62
+
63
+ # 相対的な時間位置
64
+ #
65
+ # Allen(1983) が分類した13種類の相対的な時間位置を定義している
66
+ #
67
+ # ISO19108では値は Code クラスだが、本実装では値は Symbol である
68
+ #
69
+ # see {http://schemas.opengis.net/gml/3.1.1/base/temporal.xsd#RelatedTimeType gml schema}
70
+ #
71
+ # see Allen,J.F., Maintaining Knowledge about Temporal Intervals, Communications of the ACM, 1983,vol.26 pp.832-843
72
+ #
73
+ module RelativePosition
74
+
75
+ Before = :Before
76
+ After = :After
77
+ Begins = :Begins
78
+ Ends = :Ends
79
+ During = :During
80
+ Equals = :Equals
81
+ Contains = :Contains
82
+ Overlaps = :Overlaps
83
+ Meets = :Meets
84
+ OverlappedBy = :OverlappedBy
85
+ MetBy = :MetBy
86
+ BegunBy = :BegunBy
87
+ EndedBy = :EndedBy
88
+
89
+ end
90
+
91
+ # 時間のオブジェクト
92
+ #
93
+ # see {http://schemas.opengis.net/gml/3.1.1/base/temporal.xsd#AbstractTimeObjectType gml schema}
94
+ #
95
+ class Object < When::BasicTypes::Object
96
+
97
+ end
98
+
99
+ # 複数の時間プリミティブの集成
100
+ #
101
+ # see {http://schemas.opengis.net/gml/3.1.1/base/temporal.xsd#AbstractTimeComplexType gml schema}
102
+ #
103
+ class Complex < Object
104
+
105
+ end
106
+
107
+ # 位相複体 - 連結した位相プリミティブの集合
108
+ #
109
+ # A temporal topology complex.
110
+ #
111
+ # see {http://schemas.opengis.net/gml/3.1.1/base/temporalTopology.xsd#TimeTopologyComplexType gml schema}
112
+ #
113
+ class TopologicalComplex < Complex
114
+
115
+ # 対応するプリミティブ (relation - Complex)
116
+ #
117
+ # @return [Array<When::TM::TopologicalPrimitive>]
118
+ #
119
+ attr_reader :primitive
120
+
121
+ # オブジェクトの生成
122
+ #
123
+ # @param [When::TM::TopologicalPrimitive] primitive 対応するプリミティブの Array
124
+ #
125
+ def initialize(primitive)
126
+ @primitive = primitive
127
+ @primitive.each do |p|
128
+ p.complex << self
129
+ end
130
+ end
131
+ end
132
+
133
+ # 時間プリミティブ
134
+ #
135
+ # see {http://schemas.opengis.net/gml/3.1.1/base/temporal.xsd#AbstractTimePrimitiveType gml schema}
136
+ #
137
+ class Primitive < Object
138
+
139
+ include Order
140
+
141
+ end
142
+
143
+ # 時間幾何プリミティブ
144
+ #
145
+ # see {http://schemas.opengis.net/gml/3.1.1/base/temporal.xsd#AbstractTimeGeometricPrimitiveType gml schema}
146
+ #
147
+ class GeometricPrimitive < Primitive
148
+
149
+ include Separation
150
+
151
+ end
152
+
153
+ # 瞬間 - 零次元幾何プリミティブ
154
+ #
155
+ # see {http://schemas.opengis.net/gml/3.1.1/base/temporal.xsd#TimeInstantType gml schema}
156
+ #
157
+ class Instant < GeometricPrimitive
158
+
159
+ # この瞬間の時間位置
160
+ #
161
+ # @return [When::TM::Position]
162
+ #
163
+ attr_reader :position
164
+
165
+ # この瞬間を始まりとする期間 (relation - Beginning)
166
+ #
167
+ # @return [Array<When::TM::Period>]
168
+ #
169
+ attr_reader :begun_by
170
+ alias :begunBy :begun_by
171
+
172
+ # この瞬間を終わりとする期間 (relation - Ending)
173
+ #
174
+ # @return [Array<When::TM::Period>]
175
+ #
176
+ attr_reader :ended_by
177
+ alias :endedBy :ended_by
178
+
179
+ # 対応するノード (relation - Realization)
180
+ #
181
+ # @return [When::TM::Node]
182
+ #
183
+ attr_reader :topology
184
+
185
+ # When::TM::GeometricPrimitive 自身の持続時間
186
+ #
187
+ # @return [When::TM::Duration]
188
+ #
189
+ def length()
190
+ return When.Duration(0)
191
+ end
192
+
193
+ # 他のWhen::TM::GeometricPrimitiveとの時間位置の差の絶対値
194
+ #
195
+ # @param [When::TM::GeometricPrimitive] other
196
+ #
197
+ # @return [When::TM::Duration]
198
+ #
199
+ def distance(other)
200
+ case other
201
+ when Instant
202
+ return (self.position - other.position).abs
203
+ when Period
204
+ verify = other.begin.position - self.position
205
+ return verify if verify.sign >= 0
206
+ return [self.position - other.end.position, When::TM::PeriodDuration.new(0,When::DAY)].max
207
+ else
208
+ raise TypeError, "The right operand should be When::TM::Instant or When::TM::Period"
209
+ end
210
+ end
211
+
212
+ # 他のWhen::TM::Primitiveとの相対的な時間位置
213
+ #
214
+ # @param [When::TM::Primitive] other
215
+ #
216
+ # @return [When::TM::RelativePosition]
217
+ #
218
+ def relative_position(other)
219
+ case other
220
+ when Instant
221
+ verify = self.position <=> other.position
222
+ return RelativePosition::Before if verify < 0
223
+ return RelativePosition::Equals if verify == 0
224
+ return RelativePosition::After
225
+ when Period
226
+ verify = self.position <=> other.begin.position
227
+ return RelativePosition::Before if verify < 0
228
+ return RelativePosition::Begins if verify == 0
229
+ verify = self.position <=> other.end.position
230
+ return RelativePosition::During if verify < 0
231
+ return RelativePosition::Ends if verify == 0
232
+ return RelativePosition::After
233
+ else
234
+ raise TypeError, "The right operand should be When::TM::Instant or When::TM::Period"
235
+ end
236
+ end
237
+ alias :relativePosition :relative_position
238
+
239
+ # オブジェクトの生成
240
+ #
241
+ # @param [When::TM::Position] position 対応する時間位置
242
+ #
243
+ def initialize(position)
244
+ @position = position
245
+ @begun_by = []
246
+ @ended_by = []
247
+ end
248
+
249
+ private
250
+
251
+ # その他のメソッド
252
+ #
253
+ # @note
254
+ # When::TM::Instant で定義されていないメソッドは
255
+ # 処理を @position (type: When::TM::Position) に委譲する
256
+ #
257
+ def method_missing(name, *args, &block)
258
+ self.class.module_eval %Q{
259
+ def #{name}(*args, &block)
260
+ list = args.map {|arg| arg.kind_of?(self.class) ? arg.position : arg}
261
+ @position.send("#{name}", *list, &block)
262
+ end
263
+ } unless When::Parts::MethodCash.escape(name)
264
+ list = args.map {|arg| arg.kind_of?(self.class) ? arg.position : arg}
265
+ @position.send(name, *list, &block)
266
+ end
267
+ end
268
+
269
+ # 期間 - 一次元幾何プリミティブ
270
+ #
271
+ # see {http://schemas.opengis.net/gml/3.1.1/base/temporal.xsd#TimePeriodType gml schema}
272
+ #
273
+ class Period < GeometricPrimitive
274
+
275
+ RELATIVE_POSITION = {
276
+ RelativePosition::Contains => {
277
+ RelativePosition::Before => RelativePosition::Overlaps,
278
+ RelativePosition::EndedBy => RelativePosition::EndedBy,
279
+ RelativePosition::Contains => RelativePosition::Contains
280
+ },
281
+ RelativePosition::BegunBy => {
282
+ RelativePosition::Before => RelativePosition::Begins,
283
+ RelativePosition::EndedBy => RelativePosition::Equals,
284
+ RelativePosition::Contains => RelativePosition::BegunBy
285
+ },
286
+ RelativePosition::After => {
287
+ RelativePosition::Before => RelativePosition::During,
288
+ RelativePosition::EndedBy => RelativePosition::Ends,
289
+ RelativePosition::Contains => RelativePosition::OverlappedBy
290
+ }
291
+ }
292
+
293
+ # この期間が始まる瞬間 (relation - Beginning)
294
+ #
295
+ # @return [When::TM::Instant]
296
+ #
297
+ attr_reader :begin
298
+
299
+ # この期間が終わる瞬間 (relation - Ending)
300
+ #
301
+ # @return [When::TM::Instant]
302
+ #
303
+ attr_reader :end
304
+
305
+ # 対応するエッジ (relation - Realization)
306
+ #
307
+ # @return [When::TM::Edge]
308
+ #
309
+ attr_reader :topology
310
+
311
+ # When::TM::GeometricPrimitive 自身の持続時間
312
+ #
313
+ # @return [When::TM::Duration]
314
+ #
315
+ def length()
316
+ @length ||= @end - @begin
317
+ end
318
+
319
+ # 他のWhen::TM::GeometricPrimitiveとの時間位置の差の絶対値
320
+ #
321
+ # @param [When::TM::GeometricPrimitive] other
322
+ #
323
+ # @return [When::TM::Duration]
324
+ #
325
+ def distance(other)
326
+ case other
327
+ when Instant
328
+ return other.distance(self)
329
+ when Period
330
+ verify = other.begin.position - self.end.position
331
+ return verify if verify.sign >= 0
332
+ return [self.begin.position - other.end.position, When::TM::PeriodDuration.new(0,When::DAY)].max
333
+ else
334
+ raise TypeError, "The right operand should be Instant or Period"
335
+ end
336
+ end
337
+
338
+ # 他のPrimitiveとの相対的な時間位置
339
+ #
340
+ # @param [When::TM::Primitive] other
341
+ #
342
+ # @return [When::TM::RelativePosition]
343
+ #
344
+ def relative_position(other)
345
+ case other
346
+ when Instant
347
+ verify = self.end.position <=> other.position
348
+ return RelativePosition::Before if verify < 0
349
+ return RelativePosition::EndedBy if verify == 0
350
+ verify = self.begin.position <=> other.position
351
+ return RelativePosition::Contains if verify < 0
352
+ return RelativePosition::BegunBy if verify == 0
353
+ return RelativePosition::After
354
+ when Period
355
+ verify_b = relative_position(other.begin)
356
+ case verify_b
357
+ when RelativePosition::Before ; return RelativePosition::Before
358
+ when RelativePosition::EndedBy ; return RelativePosition::Meets
359
+ end
360
+ verify_e = relative_position(other.end)
361
+ case verify_e
362
+ when RelativePosition::BegunBy ; return RelativePosition::MetBy
363
+ when RelativePosition::After ; return RelativePosition::After
364
+ else ; return RELATIVE_POSITION[verify_b][verify_e]
365
+ end
366
+ else
367
+ raise TypeError, "The right operand should be Instant or Period"
368
+ end
369
+ end
370
+ alias :relativePosition :relative_position
371
+
372
+ # オブジェクトの生成
373
+ #
374
+ # @param [When::TM::Instant] begun 始点
375
+ #
376
+ # @param [When::TM::Instant] ended 終点
377
+ #
378
+ def initialize(begun, ended)
379
+ raise ArgumentError, 'Order mismatch: begun > ended' if begun > ended
380
+ @begin = begun
381
+ @end = ended
382
+ @begin.begun_by << self
383
+ @end.ended_by << self
384
+ end
385
+
386
+ private
387
+
388
+ # その他のメソッド
389
+ #
390
+ # @note
391
+ # When::TM::Period で定義されていないメソッドは
392
+ # 処理を @begin (type: When::TM::Instant) に委譲する
393
+ #
394
+ def method_missing(name, *args, &block)
395
+ self.class.module_eval %Q{
396
+ def #{name}(*args, &block)
397
+ @begin.send("#{name}", *args, &block)
398
+ end
399
+ } unless When::Parts::MethodCash.escape(name)
400
+ @begin.send(name, *args, &block)
401
+ end
402
+ end
403
+
404
+ # 時間位相プリミティブ - 単独で不可分な位相要素
405
+ #
406
+ # see {http://schemas.opengis.net/gml/3.1.1/base/temporalTopology.xsd#AbstractTimeTopologyPrimitiveType gml schema}
407
+ #
408
+ class TopologicalPrimitive < Primitive
409
+
410
+ # 対応するコンプレックス (relation - Complex)
411
+ #
412
+ # @return [Array<When::TM::TopologicalComplex>]
413
+ #
414
+ attr_accessor :complex
415
+
416
+ #
417
+ # オブジェクトの生成
418
+ #
419
+ def initialize
420
+ @complex = []
421
+ end
422
+
423
+ private
424
+
425
+ alias :_method_missing :method_missing
426
+
427
+ # その他のメソッド
428
+ #
429
+ # @note
430
+ # When::TM::TopologicalPrimitive で定義されていないメソッドは
431
+ # 処理を @geometry (type: When::TM::Instant) に委譲する
432
+ #
433
+ def method_missing(name, *args, &block)
434
+ return _method_missing(name, *args, &block) if When::Parts::MethodCash::Escape.key?(name) ||
435
+ !respond_to?(:geometry)
436
+ self.class.module_eval %Q{
437
+ def #{name}(*args, &block)
438
+ list = args.map {|arg| arg.respond_to?(:geometry) ? arg.geometry : arg}
439
+ geometry.send("#{name}", *list, &block)
440
+ end
441
+ } unless When::Parts::MethodCash.escape(name)
442
+ list = args.map {|arg| arg.respond_to?(:geometry) ? arg.geometry : arg}
443
+ geometry.send(name, *list, &block)
444
+ end
445
+ end
446
+
447
+ # 零次元位相プリミティブ - 幾何的実現は When::TM::Instant と対応する
448
+ #
449
+ # see {http://schemas.opengis.net/gml/3.1.1/base/temporalTopology.xsd#TimeNodeType gml schema}
450
+ #
451
+ class Node < TopologicalPrimitive
452
+
453
+ # 対応するエッジ (relation - Termination)
454
+ #
455
+ # @return [Array<When::TM::Edge>]
456
+ #
457
+ attr_reader :previous_edge
458
+ alias :previousEdge :previous_edge
459
+
460
+ # 対応するエッジ (relation - Initiation)
461
+ #
462
+ # @return [Array<When::TM::Edge>]
463
+ #
464
+ attr_reader :next_edge
465
+ alias :nextEdge :next_edge
466
+
467
+ # 対応する瞬間 (relation - Realization)
468
+ #
469
+ # @return [When::TM::Instant]
470
+ #
471
+ attr_reader :geometry
472
+
473
+ # オブジェクトの生成
474
+ #
475
+ # @param [When::TM::Instant] geometry 対応する瞬間
476
+ #
477
+ def initialize(geometry)
478
+ super()
479
+ @previous_edge = []
480
+ @next_edge = []
481
+ @geometry = geometry
482
+ @geometry.topology = self
483
+ end
484
+ end
485
+
486
+ # 一次元位相プリミティブ - 幾何的実現は When::TM::Period と対応する
487
+ #
488
+ # see {http://schemas.opengis.net/gml/3.1.1/base/temporalTopology.xsd#TimeEdgeType gml schema}
489
+ #
490
+ class Edge < TopologicalPrimitive
491
+
492
+ # 対応するノード (relation - Termination)
493
+ #
494
+ # @return [When::TM::Node]
495
+ #
496
+ attr_reader :end
497
+
498
+ # 対応するノード (relation - Initiation)
499
+ #
500
+ # @return [When::TM::Node]
501
+ #
502
+ attr_reader :start
503
+
504
+ # 対応する期間 (relation - Realization)
505
+ #
506
+ # @return [When::TM::Period]
507
+ #
508
+ attr_reader :geometry
509
+
510
+ # オブジェクトの生成
511
+ #
512
+ # @param [When::TM::Node] start 始点
513
+ #
514
+ # @param [When::TM::Node] ended 終点
515
+ #
516
+ def initialize(start, ended)
517
+ super()
518
+ @start = start
519
+ @end = ended
520
+ @geometry = Period.new(@start.geometry, @end.geometry)
521
+ @geometry.topology = self
522
+ @start.next_edge << self
523
+ @end.previous_edge << self
524
+ end
525
+ end
526
+
527
+ # 時間次元における長さ又は距離を記述するために使うデータ型
528
+ #
529
+ # see {http://schemas.opengis.net/gml/3.1.1/base/temporal.xsd#duration gml schema}
530
+ #
531
+ class Duration
532
+
533
+ #
534
+ # When::TM::IntervalLength への変換
535
+ #
536
+ # @return [When::TM::IntervalLength]
537
+ #
538
+ def to_interval_length
539
+ [['week', WEEK], ['day', DAY], ['hour', HOUR], ['minute', MINUTE], ['second', SECOND]].each do |unit|
540
+ div, mod = duration.divmod(unit[1])
541
+ return When::TM::IntervalLength.new(div, unit[0]) if mod == 0
542
+ end
543
+ When::TM::IntervalLength.new(duration / SECOND, 'second')
544
+ end
545
+
546
+ #
547
+ # When::TM::PeriodDuration への変換
548
+ #
549
+ # @return [When::TM::PeriodDuration]
550
+ #
551
+ def to_period_duration
552
+ [[When::WEEK, WEEK], [When::DAY, DAY], [When::HOUR, HOUR], [When::MINUTE, MINUTE], [When::SECOND, SECOND]].each do |unit|
553
+ div, mod = duration.divmod(unit[1])
554
+ return When::TM::PeriodDuration.new(div, unit[0]) if mod == 0
555
+ end
556
+ When::TM::PeriodDuration.new(duration / SECOND, When::SECOND)
557
+ end
558
+
559
+ #
560
+ # Duration 用の Enumerator
561
+ #
562
+ class Enumerator < When::Parts::Enumerator
563
+
564
+ # 次の時間位置を取得する
565
+ #
566
+ # @return [When::TM::TemporalPosition] 次の時間位置
567
+ #
568
+ def succ
569
+ value = @current
570
+ @current = (@count_limit.kind_of?(Numeric) && @count >= @count_limit) ? nil :
571
+ (@current==:first) ? @first :
572
+ (@direction==:forward) ? @first + @parent * @count : @first - @parent * @count
573
+ @count += 1
574
+ return value
575
+ end
576
+ end
577
+
578
+ # Enumerator の生成
579
+ #
580
+ # @overload initialize(range, count_limit=nil))
581
+ # @param [Range, When::Parts::GeometricComplex] range
582
+ # [ 始点 - range.first ]
583
+ # [ 終点 - range.last ]
584
+ # @param [Integer] count_limit 繰り返し回数(デフォルトは指定なし)
585
+ #
586
+ # @overload initialize(first, direction, count_limit=nil))
587
+ # @param [When::TM::TemporalPosition] first 始点
588
+ # @param [Symbol] direction
589
+ # [ :forward - 昇順 ]
590
+ # [ :reverse - 降順 ]
591
+ # @param [Integer] count_limit 繰り返し回数(デフォルトは指定なし)
592
+ #
593
+ def _enumerator(*args)
594
+ return Enumerator.new(*args.unshift(self))
595
+ end
596
+ alias :to_enum :_enumerator
597
+ alias :enum_for :_enumerator
598
+ end
599
+
600
+ #
601
+ # ISO 11404 の時間間隔に基づいて定義された When::TM::Duration の subclass
602
+ #
603
+ # see {http://schemas.opengis.net/gml/3.1.1/base/temporal.xsd#timeIntervalLengthType gml schema}
604
+ #
605
+ class IntervalLength < Duration
606
+
607
+ Alias = {'Y'=>'year', 'M'=>'month' , 'D'=>'day', 'W'=>'week', 'S'=>'system',
608
+ 'h'=>'hour', 'm'=>'minute', 's'=>'second'}
609
+
610
+ # Interval Length 形式の表現を分解して配列化する
611
+ #
612
+ # @param [String] interval
613
+ #
614
+ # @return [Array<Numeric, String>] ( value, unit_name, factor, radix )
615
+ # [ value [Numeric] - 時間間隔 / 単位 ]
616
+ # [ unit_name [String] - 単位名 ]
617
+ # [ factor [Numeric] - 冪乗 ]
618
+ # [ radix [Numeric] - 冪乗の基数 ]
619
+ #
620
+ # @note value, factor, radix は Numeric
621
+ #
622
+ def self._to_array(interval)
623
+ return nil unless interval =~ /\A([-+]?[\d.]+)(?:(E|X|\((\d+)\))([-+]?\d+))?([A-Za-z]+|\*([\d.]+)S)\z/
624
+ value, radix, radix_quantity, factor, unit, unit_quantity = $~[1..6]
625
+ value = When::Coordinates::Pair._en_number(value)
626
+ radix = case radix
627
+ when 'E', nil ; 10
628
+ when 'X' ; 60
629
+ else ; radix_quantity.to_i
630
+ end
631
+ factor = factor ? -factor.to_i : 0
632
+ return [value, unit_quantity, factor, radix] if unit_quantity
633
+ unit_quantity = Unit[unit.downcase] || Unit[Alias[unit[0..0]]]
634
+ return [value, UnitName[unit_quantity], factor, radix] if unit_quantity
635
+ return nil
636
+ end
637
+
638
+ # 時間間隔の長さ (128秒単位)
639
+ #
640
+ # @return [Numeric]
641
+ #
642
+ protected :duration=
643
+
644
+ # 時間間隔を表現するために使用した測定単位の名称
645
+ #
646
+ # @return [String] (year|month|week|day|hour|minute|second|system)
647
+ #
648
+ attr_reader :unit
649
+
650
+ # 時間単位となる乗数の基底となる正の整数
651
+ #
652
+ # @return [Integer]
653
+ #
654
+ attr_reader :radix
655
+
656
+ # 基底のべき乗を行う指数
657
+ #
658
+ # @return [Integer]
659
+ #
660
+ attr_reader :factor
661
+
662
+ # 時間間隔の長さ / 測定単位
663
+ #
664
+ # @return [Numeric]
665
+ #
666
+ attr_accessor :value
667
+ protected :value=
668
+
669
+ #
670
+ # 測定単位の大きさ
671
+ #
672
+ # @return [Numeric]
673
+ #
674
+ attr_reader :unit_quantity
675
+
676
+ # 時刻配列
677
+ #
678
+ # @return [Numeric]
679
+ # When::TM::PeriodDuration との互換性のために提供
680
+ #
681
+ # @private
682
+ #
683
+ def time
684
+ [0, 0, @duration / SECOND]
685
+ end
686
+
687
+ # 日付配列
688
+ #
689
+ # @return [nil]
690
+ # When::TM::PeriodDuration との互換性のために提供
691
+ #
692
+ # @private
693
+ #
694
+ def date
695
+ nil
696
+ end
697
+
698
+ # 暦週配列
699
+ #
700
+ # @return [nil]
701
+ # When::TM::PeriodDuration との互換性のために提供
702
+ #
703
+ # @private
704
+ #
705
+ def weeks
706
+ nil
707
+ end
708
+
709
+ # 符号反転
710
+ #
711
+ # @return [When::TM::IntervalLength]
712
+ #
713
+ def -@
714
+ interval = self.dup
715
+ interval.value = -@value
716
+ interval.duration = -@duration
717
+ return interval
718
+ end
719
+
720
+ #
721
+ # 加算
722
+ #
723
+ # @param [When::TM::Duration] other
724
+ # @param [Numeric] other 秒数
725
+ # @param [その他] other 日時とみなす
726
+ #
727
+ # @return [When::TM::IntervalLength] (other が Numeric, When::TM::Duration の場合)
728
+ # @return [other と同じクラス] (other がその他の場合)
729
+ #
730
+ def +(other)
731
+ case other
732
+ when Duration ; diff = other.duration
733
+ when Numeric ; diff = other * SECOND
734
+ else ; return other + self
735
+ end
736
+ interval = self.dup
737
+ interval.duration = @duration + diff
738
+ internal.value = interval.duration / (@radix ** (-@factor) * @unit_quantity)
739
+ return interval
740
+ end
741
+
742
+ #
743
+ # 減算
744
+ #
745
+ # @param [When::TM::IntervalLength] other
746
+ # @param [Numeric] other 秒数
747
+ #
748
+ # @return [When::TM::IntervalLength]
749
+ #
750
+ def -(other)
751
+ interval = self.dup
752
+ interval.duration = @duration - (other.kind_of?(Duration) ? other.duration : other * SECOND)
753
+ internal.value = interval.duration / (@radix ** (-@factor) * @unit_quantity)
754
+ return interval
755
+ end
756
+
757
+ # 乗算
758
+ #
759
+ # @param [Numeric] times
760
+ #
761
+ # @return [When::TM::IntervalLength]
762
+ #
763
+ def *(times)
764
+ interval = self.dup
765
+ interval.value = times * @value
766
+ interval.duration = times * @duration
767
+ return interval
768
+ end
769
+
770
+ #
771
+ # 除算
772
+ #
773
+ # @param [When::TM::IntervalLength] other
774
+ # @param [Numeric] other 秒数
775
+ #
776
+ # @return [When::TM::IntervalLength] (other が Numeric の場合)
777
+ # @return [Numeric] (other が When::TM::Duration の場合)
778
+ #
779
+ def /(other)
780
+ other.kind_of?(Duration) ? @duration / other.duration : self * (1.0 / other)
781
+ end
782
+
783
+ # 文字列化
784
+ #
785
+ # @return [String]
786
+ #
787
+ def to_s
788
+ expression = @value.to_s
789
+ unless @factor == 0
790
+ case @radix
791
+ when 10 ; expression += 'E'
792
+ when 60 ; expression += 'X'
793
+ else ; expression += '(%d)' % @radix
794
+ end
795
+ expression += '%+d' % (-@factor)
796
+ end
797
+ expression += Alias.invert[@unit] || "*#{When::Coordinates::Pair._en_number(@unit)}S"
798
+ return expression
799
+ end
800
+
801
+ #
802
+ # When::TM::IntervalLength への変換
803
+ #
804
+ # 単なるオブジェクトのコピー
805
+ #
806
+ # @return [When::TM::IntervalLength]
807
+ #
808
+ def to_interval_length
809
+ self.dup
810
+ end
811
+
812
+ # オブジェクトの生成
813
+ #
814
+ # @param [Numeric] value 時間間隔の長さ / 測定単位(省略不可)
815
+ # @param [String] unit 時間間隔を表現するために使用した測定単位の名称(デフォルト : system)
816
+ # ('year'|'month'|'week'|'day'|'hour'|'minute'|'second'|'system')
817
+ # @param [Integer] factor 基底の冪乗を行う指数(デフォルト : 0)
818
+ # @param [Integer] radix 時間単位となる乗数の基底となる正の整数(デフォルト : 10)
819
+ #
820
+ def initialize(value, unit='system', factor=0, radix=10)
821
+ @value, @factor, @radix = value, factor, radix
822
+ @unit_quantity = Unit[unit.downcase] || Unit[Alias[unit[0..0]]] if unit.kind_of?(String)
823
+ @unit_quantity ||= unit.to_f
824
+ raise TypeError, "Wrong Unit Type: #{unit}" unless @unit_quantity.kind_of?(Numeric)
825
+ @unit = UnitName[@unit_quantity] ||
826
+ When::Coordinates::Pair._en_number(@unit_quantity).to_s
827
+ @duration = @value * @radix ** (-@factor) * @unit_quantity
828
+ end
829
+
830
+ # オブジェクトの生成(終点と始点を指定)
831
+ #
832
+ # @param [When::TM::TemporalPosition] ended 終点
833
+ # @param [When::TM::TemporalPosition] begun 始点
834
+ #
835
+ # @return [When::TM::IntervalLength]
836
+ # [ 日単位の精度 - 終点と始点の分解能のいずれかが“日”またはそれより粗い場合 ]
837
+ # [ システム精度 - 終点と始点の分解能がともに“日”より細かい場合 ]
838
+ #
839
+ def self.difference(ended, begun)
840
+ precision = [ended.precision, begun.precision].min
841
+ return new(ended-begun) if precision > When::DAY
842
+ return new(ended.to_i - begun.to_i, unit='day')
843
+ end
844
+
845
+ private
846
+
847
+ # その他のメソッド
848
+ #
849
+ # @note
850
+ # When::TM::IntervalLength で定義されていないメソッドは
851
+ # 処理を @duration (type:Numeric) に委譲する
852
+ #
853
+ def method_missing(name, *args, &block)
854
+ self.class.module_eval %Q{
855
+ def #{name}(*args, &block)
856
+ @duration.send("#{name}", *args, &block)
857
+ end
858
+ } unless When::Parts::MethodCash.escape(name)
859
+ @duration.send(name, *args, &block)
860
+ end
861
+ end
862
+
863
+ #
864
+ # ISO 8601 (JIS X0301) の時間間隔に基づいて定義された When::TM::Duration の subclass
865
+ #
866
+ class PeriodDuration < Duration
867
+
868
+ include When
869
+ include Coordinates
870
+
871
+ #
872
+ # When::TM::PeriodDuration オブジェクトが月や年などの可変長の単位に依存する場合
873
+ # に @duration 属性の参照を禁止するために用いる
874
+ #
875
+ module NoDuration
876
+ #
877
+ # 属性 @duration が定義できないとをエラーで示す
878
+ #
879
+ # @return [Numeric]
880
+ #
881
+ def duration
882
+ raise TypeError, "This PeriodDuration object does't have duration value"
883
+ end
884
+ end
885
+
886
+ # ISO 8601 形式の表現を分解して配列化する
887
+ #
888
+ # @param [String] period
889
+ #
890
+ # @return [Array<Numeric, Array<Numeric>>] ( sign, date, time, week )
891
+ # [ sign [Numeric] - +1 , -1 ]
892
+ # [ date [Array<Numeric>] - 年月日 ]
893
+ # [ time [Array<Numeric>] - 時分秒 ]
894
+ # [ week [Array<Numeric>] - 週日 ]
895
+ #
896
+ def self._to_array(period)
897
+
898
+ return nil unless period.gsub(/_+/, '') =~ /\A([-+])?P(.*?)?(?:T(.+))?\z/
899
+
900
+ sign = ($1 == '-') ? -1 : +1
901
+ pdate, ptime = $~[2..3]
902
+
903
+ # 時分秒形式
904
+ if (ptime =~ /\A(?:([.,\d]+)?([:*=])?H)?(?:([.,\d]+)?([:*=])?M)?(?:([.,\d]+)?([:*=])?S)?((?:[.,\d]*[:*=]?X)*)\z/)
905
+ trunk = [1,3,5].map {|i|
906
+ $~[i] ? Pair._en_pair($~[i], $~[i+1]) : 0
907
+ }
908
+ extra = $7 ? $7.scan(/([.,\d]+)?([:*=])?X/).map {|d|
909
+ d[0] ? Pair._en_pair(d[0], d[1]) : 0
910
+ } : []
911
+ time = [0] + trunk + extra
912
+ time = nil if time.uniq == [0]
913
+ end
914
+
915
+ case pdate
916
+ # 年月日形式
917
+ when /\A((?:[.,\d]*[-*=]?X)*)(?:([.,\d]+)?([-*=])?Y)?(?:([.,\d]+)?([-+*&%!>=<?])?M)?(?:([.,\d]+)?([-*=?%])?D)?\z/
918
+ trunk = [2,4,6].map {|i|
919
+ $~[i] ? Pair._en_pair($~[i], $~[i+1]) : 0
920
+ }
921
+ extra = $1 ? $1.scan(/([.,\d]+)?([:*=])?X/).map {|d|
922
+ d[0] ? Pair._en_pair(d[0], d[1]) : 0
923
+ } : []
924
+ date = extra + trunk
925
+ date = nil if date.uniq == [0]
926
+ return sign, date, time
927
+
928
+ # 週日形式
929
+ when /\A(?:([.,\d]+)?([:*=])?W)(?:([.,\d]+)?([-*=?%])?D)?\z/
930
+ week = [1,3].map {|i|
931
+ $~[i] ? Pair._en_pair($~[i], $~[i+1]) : 0
932
+ }
933
+ return sign, nil, time if week.uniq == [0]
934
+ date = [0, 0, week[1] + 7*week[0]]
935
+ return sign, date, time, week
936
+
937
+ # 代用形式
938
+ else
939
+ pdate += 'T' + ptime if ptime
940
+ f, d, t, z, e = When::BasicTypes::DateTime._to_array(pdate, {:abbr=>[0]*20})
941
+ return nil if e
942
+ if d
943
+ case f
944
+ when :day ; date = [d[0], 0, d[1]]
945
+ when :century, nil ; date = (0..2).map {|i| d[i]||0}
946
+ when :week ; date, week = [0,0,d[0]*7+(d[1]||0)], [d[0], d[1]||0]
947
+ end
948
+ end
949
+ time = t ? (t.map {|v| v||0}) : nil
950
+ return sign, date, time, week
951
+ end
952
+ end
953
+
954
+ # 期間の日数
955
+ #
956
+ # @return [Integer]
957
+ #
958
+ # @note 固定の整数で表現できない場合は nil
959
+ #
960
+ attr_reader :to_day
961
+
962
+ # 期間の日付要素
963
+ #
964
+ # @return [Array<Numeric>]
965
+ #
966
+ attr_accessor :date
967
+ private :date=
968
+
969
+ # 期間の週日要素
970
+ #
971
+ # @return [Array<Numeric>]
972
+ #
973
+ attr_accessor :week
974
+ private :week=
975
+
976
+ # 期間の時刻要素
977
+ #
978
+ # @return [Array<Numeric>]
979
+ #
980
+ attr_accessor :time
981
+ private :time=
982
+
983
+ # 要素の参照
984
+ #
985
+ # @param [Numeric] index When::Coordinates で定義している分解能定数に対応する列挙型( YEAR, ... , SECOND)
986
+ #
987
+ # @return [Numeric]
988
+ #
989
+ def [](index)
990
+ if index == WEEK
991
+ return nil unless @week
992
+ return @week[0]
993
+ elsif index <= 0
994
+ return nil unless @date
995
+ return @date[index-1]
996
+ else
997
+ return nil unless @time
998
+ return @time[index]
999
+ end
1000
+ end
1001
+
1002
+ # 持続期間であることを文字'P'で示す
1003
+ #
1004
+ # @return [String]
1005
+ #
1006
+ def designator
1007
+ return 'P'
1008
+ end
1009
+
1010
+ # 期間に含まれる年数を示す
1011
+ #
1012
+ # @return [String]
1013
+ #
1014
+ def years
1015
+ return nil unless @date
1016
+ return @date[YEAR-1].to_s
1017
+ end
1018
+
1019
+ # 期間に含まれる月数を示す
1020
+ #
1021
+ # @return [String
1022
+ #
1023
+ def months
1024
+ return nil unless @date
1025
+ return @date[MONTH-1].to_s
1026
+ end
1027
+
1028
+ # 期間に含まれる週数を示す
1029
+ #
1030
+ # @return [String]
1031
+ #
1032
+ def weeks
1033
+ return nil unless @week
1034
+ return @week[0].to_s
1035
+ end
1036
+
1037
+ # 期間に含まれる日数を示す
1038
+ #
1039
+ # @return [String]
1040
+ #
1041
+ def days
1042
+ return nil unless @date
1043
+ return @date[DAY-1].to_s
1044
+ end
1045
+
1046
+ # 期間が1日より短い時間単位を含むとき文字'T'で示す
1047
+ #
1048
+ # @return [String]
1049
+ #
1050
+ def time_indicator
1051
+ return (@time) ? 'T' : nil
1052
+ end
1053
+ alias :timeIndicator :time_indicator
1054
+
1055
+ # 期間に含まれる時間数を示す
1056
+ #
1057
+ # @return [String]
1058
+ #
1059
+ def hours
1060
+ return nil unless @time
1061
+ return @time[HOUR].to_s
1062
+ end
1063
+
1064
+ # 期間に含まれる分数を示す
1065
+ #
1066
+ # @return [String]
1067
+ #
1068
+ def minutes
1069
+ return nil unless @time
1070
+ return @time[MINUTE].to_s
1071
+ end
1072
+
1073
+ # 期間に含まれる秒数を示す
1074
+ #
1075
+ # @return [String]
1076
+ #
1077
+ def seconds
1078
+ return nil unless @time
1079
+ return @time[SECOND].to_s
1080
+ end
1081
+
1082
+ # 符号反転
1083
+ #
1084
+ # @return [When::TM::PeriodDuration]
1085
+ #
1086
+ def -@
1087
+ period = self.dup
1088
+ period.send(:date=, @date.map {|v| -v}) if @date
1089
+ period.send(:week=, @week.map {|v| -v}) if @week
1090
+ period.send(:time=, @time.map {|v| -v}) if @time
1091
+ period.send(:_duration)
1092
+ return period
1093
+ end
1094
+
1095
+ # 符号
1096
+ #
1097
+ # @return [Integer] 0 との比較により、負,0,正の値を返す
1098
+ #
1099
+ def sign
1100
+ ((@week || @date || []) + (@time || [])).each do |v|
1101
+ return -1 if +v < 0
1102
+ end
1103
+ return +1
1104
+ end
1105
+
1106
+ # 比較
1107
+ #
1108
+ # @param [When::TM::PeriodDuration] other
1109
+ #
1110
+ # @return [Integer] other との比較により、負,0,正の値を返す
1111
+ #
1112
+ def <=>(other)
1113
+ unless (@date && @date.size) == (other.date && other.date.size) &&
1114
+ (@week && @week.size) == (other.week && other.week.size) &&
1115
+ (@time && @time.size) == (other.time && other.time.size)
1116
+ raise ArgumentError, "PeriodDuration structure mismatch"
1117
+ end
1118
+
1119
+ (0...@week.size).each do |i|
1120
+ sgn = +@week[i] <=> +other.week[i]
1121
+ return sgn unless sgn == 0
1122
+ end if @week
1123
+
1124
+ (0...@date.size).each do |i|
1125
+ sgn = +@date[i] <=> +other.date[i]
1126
+ return sgn unless sgn == 0
1127
+ end if @date
1128
+
1129
+ (0...@time.size).each do |i|
1130
+ sgn = +@time[i] <=> +other.time[i]
1131
+ return sgn unless sgn == 0
1132
+ end if @time
1133
+
1134
+ return 0
1135
+ end
1136
+
1137
+ # オブジェクトの同値
1138
+ #
1139
+ # @param [比較先] other
1140
+ #
1141
+ # @return [Boolean]
1142
+ # [ true - 同値 ]
1143
+ # [ false - 非同値 ]
1144
+ #
1145
+ def ==(other)
1146
+ (self <=> other) == 0
1147
+ rescue
1148
+ false
1149
+ end
1150
+
1151
+ # 加算
1152
+ #
1153
+ # @param [When::TM::PeriodDuration] other
1154
+ # @param [その他] other 日時とみなす
1155
+ #
1156
+ # @return [WWhen::TM::PeriodDuration] (other が When::TM::PeriodDuration の場合)
1157
+ # @return [other と同じクラス] (other がその他の場合)
1158
+ #
1159
+ def +(other)
1160
+ other.kind_of?(When::TM::PeriodDuration) ? _plus(other, +1) : other + self
1161
+ end
1162
+
1163
+ # 減算
1164
+ #
1165
+ # @param [When::TM::PeriodDuration] other
1166
+ #
1167
+ # @return [When::TM::PeriodDuration]
1168
+ #
1169
+ def -(other)
1170
+ _plus(other, -1)
1171
+ end
1172
+
1173
+ # 乗算
1174
+ #
1175
+ # @param [Numeric] times
1176
+ #
1177
+ # @return [When::TM::PeriodDuration]
1178
+ #
1179
+ def *(times)
1180
+ period = self.dup
1181
+ period.send(:date=, @date.map {|v| v *= times; v.to_i==v.to_f ? v.to_i : v}) if @date
1182
+ period.send(:week=, @week.map {|v| v *= times; v.to_i==v.to_f ? v.to_i : v}) if @week
1183
+ period.send(:time=, @time.map {|v| v *= times; v.to_i==v.to_f ? v.to_i : v}) if @time
1184
+ period.send(:_duration)
1185
+ return period
1186
+ end
1187
+
1188
+ # 除算
1189
+ #
1190
+ # @param [Numeric] divisor
1191
+ #
1192
+ # @return [When::TM::PeriodDuration]
1193
+ #
1194
+ def /(divisor)
1195
+ self * (1.0 / divisor)
1196
+ end
1197
+
1198
+ # 文字列化
1199
+ #
1200
+ # @return [String]
1201
+ #
1202
+ def to_s
1203
+ period = 'P'
1204
+ if @week
1205
+ period += @week[0].abs.to_s + 'W'
1206
+ period += @week[1].abs.to_s + 'D' unless @week[1] == 0
1207
+ elsif @date
1208
+ (-@date.length..-1).each do |i|
1209
+ period += @date[i].abs.to_s + PRECISION_NAME[i+1][0..0] unless @date[i] == 0
1210
+ end
1211
+ end
1212
+ if @time
1213
+ period += 'T'
1214
+ (1..@time.length-1).each do |i|
1215
+ period += @time[i].abs.to_s + PRECISION_NAME[i][0..0] unless @time[i] == 0
1216
+ end
1217
+ end
1218
+ period = '-' + period if sign < 0
1219
+ period == 'P' ? 'P0D' : period
1220
+ end
1221
+
1222
+ #
1223
+ # When::TM::PeriodDuration への変換
1224
+ #
1225
+ # 単なるオブジェクトのコピー
1226
+ #
1227
+ # @return [When::TM::PeriodDuration]
1228
+ #
1229
+ def to_period_duration
1230
+ self.dup
1231
+ end
1232
+
1233
+ # オブジェクトの生成
1234
+ #
1235
+ # @overload initialize(date=nil, time=nil, week=nil)
1236
+ # @param [Array<Numeric>] date 期間の日付要素
1237
+ # @param [Array<Numeric>] time 期間の時刻要素
1238
+ # @param [Array<Numeric>] week 期間の週日要素
1239
+ #
1240
+ # @overload initialize(value, index, range=YEAR..SECOND)
1241
+ # @param [Numeric] value ndex に対応する桁での)時間間隔
1242
+ # @param [Numeric] index When で定義している分解能定数(YEAR, ... ,SECOND)
1243
+ # @param [Range] range 生成する桁の範囲
1244
+ #
1245
+ def initialize(*args)
1246
+ @options = (args[-1].kind_of?(Hash)) ? (args.pop.reject {|key,value| value == nil}) : {}
1247
+ if args[0].kind_of?(Numeric)
1248
+ _initialize_by_unit(*args)
1249
+ else
1250
+ @date, @time, @week = args
1251
+ end
1252
+ _duration
1253
+ end
1254
+
1255
+ private
1256
+
1257
+ #
1258
+ # 引数パターン2での初期化
1259
+ #
1260
+ def _initialize_by_unit(value, index, range=YEAR..SECOND)
1261
+ max = range.first
1262
+ min = range.last
1263
+ min += 1 if (range.exclude_end?)
1264
+ if (index < max)
1265
+ if (index > MONTH)
1266
+ max = index.floor
1267
+ else
1268
+ value *= 10**(max-index)
1269
+ index = max
1270
+ end
1271
+ elsif (index > min)
1272
+ if (index <= DAY)
1273
+ min = index.ceil
1274
+ else
1275
+ value *= 0.1**(index-min)
1276
+ index = min
1277
+ end
1278
+ end
1279
+ value = value.to_i unless value.kind_of?(Pair) || value.to_i != value.to_f
1280
+ @date = Array.new(1-max, 0) if (max <= DAY) && (index <= DAY)
1281
+ @time = Array.new(1+min, 0) if (min > DAY) && (index > DAY)
1282
+ if (index == WEEK)
1283
+ @week = [value, 0]
1284
+ @date[DAY-1] = 7 * value
1285
+ elsif (index <= DAY)
1286
+ @date[index-1] = value
1287
+ else
1288
+ @time[index] = value
1289
+ end
1290
+ end
1291
+
1292
+ #
1293
+ # 属性 @duration の計算
1294
+ #
1295
+ def _duration
1296
+ @duration = nil
1297
+
1298
+ if @time
1299
+ @duration = +@time[HOUR ] * Duration::HOUR
1300
+ @duration += +@time[MINUTE] * Duration::MINUTE if @time[MINUTE]
1301
+ @duration += +@time[SECOND] * Duration::SECOND if @time[SECOND]
1302
+ end
1303
+
1304
+ if @week
1305
+ @duration = +@week[0] * Duration::WEEK + +@week[1] * Duration::DAY + (@duration||0)
1306
+
1307
+ elsif @date
1308
+ date = @date.dup
1309
+ date.shift while date.first == 0
1310
+ case date.size
1311
+ when 0 ; @duration ||= 0
1312
+ when 1 ; @duration = +@date[DAY-1] * Duration::DAY + (@duration||0)
1313
+ else ; @duration = nil
1314
+ end
1315
+ end
1316
+
1317
+ if @duration
1318
+ length = @duration / Duration::DAY
1319
+ @to_day = length.to_i if length.to_i == length.to_f
1320
+ else
1321
+ extend NoDuration
1322
+ end
1323
+ end
1324
+
1325
+ # 加減算共通処理
1326
+ #
1327
+ # @param [When::TM::PeriodDuration] other
1328
+ # @param [Numeric] sgn +1, -1
1329
+ #
1330
+ # @return [When::TM::PeriodDuration]
1331
+ #
1332
+ def _plus(other, sgn)
1333
+ unless (@week && @week.size) == (other.week && other.week.size) &&
1334
+ (@date && @date.size) == (other.date && other.date.size) &&
1335
+ (@time && @time.size) == (other.time && other.time.size)
1336
+ raise ArgumentError, "PeriodDuration structure mismatch"
1337
+ end
1338
+ period = self.dup
1339
+ period.send(:week=, (0...@week.size).to_a.map {|i| @week[i] + sgn * other.week[i]}) if @week
1340
+ period.send(:date=, (0...@date.size).to_a.map {|i| @date[i] + sgn * other.date[i]}) if @date
1341
+ period.send(:time=, (0...@time.size).to_a.map {|i| @time[i] + sgn * other.time[i]}) if @time
1342
+ period.send(:_duration)
1343
+ return period
1344
+ end
1345
+ end
1346
+ end