when_exe 0.4.1 → 0.4.2

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 (96) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +36 -33
  3. data/bin/locales.rb +1 -1
  4. data/bin/make_ttl.rb.config +1 -1
  5. data/lib/when_exe.rb +27 -16
  6. data/lib/when_exe/basictypes.rb +772 -771
  7. data/lib/when_exe/calendartypes.rb +1485 -1453
  8. data/lib/when_exe/coordinates.rb +5 -0
  9. data/lib/when_exe/core/compatibility.rb +1 -1
  10. data/lib/when_exe/core/duration.rb +147 -116
  11. data/lib/when_exe/core/extension.rb +499 -497
  12. data/lib/when_exe/ephemeris.rb +1952 -1951
  13. data/lib/when_exe/ephemeris/eclipse.rb +5 -4
  14. data/lib/when_exe/ephemeris/notes.rb +457 -421
  15. data/lib/when_exe/ephemeris/planets.rb +585 -585
  16. data/lib/when_exe/ephemeris/sun.rb +214 -214
  17. data/lib/when_exe/google_api.rb +153 -0
  18. data/lib/when_exe/icalendar.rb +1640 -1632
  19. data/lib/when_exe/inspect.rb +42 -20
  20. data/lib/when_exe/linkeddata.rb +28 -7
  21. data/lib/when_exe/locales/autoload.rb +2 -1
  22. data/lib/when_exe/locales/locale.rb +35 -15
  23. data/lib/when_exe/locales/zh.rb +77 -0
  24. data/lib/when_exe/mini_application.rb +3 -1
  25. data/lib/when_exe/{googlecalendar.rb → obsolete/googlecalendar.rb} +144 -144
  26. data/lib/when_exe/parts/enumerator.rb +498 -486
  27. data/lib/when_exe/parts/geometric_complex.rb +397 -397
  28. data/lib/when_exe/parts/timezone.rb +246 -241
  29. data/lib/when_exe/region/armenian.rb +55 -56
  30. data/lib/when_exe/region/babylonian.rb +406 -405
  31. data/lib/when_exe/region/bahai.rb +107 -106
  32. data/lib/when_exe/region/balinese.rb +624 -622
  33. data/lib/when_exe/region/chinese.rb +1071 -1026
  34. data/lib/when_exe/region/chinese/epochs.rb +28 -28
  35. data/lib/when_exe/region/chinese/notes.rb +219 -0
  36. data/lib/when_exe/region/chinese/twins.rb +803 -803
  37. data/lib/when_exe/region/christian.rb +21 -15
  38. data/lib/when_exe/region/coptic.rb +107 -106
  39. data/lib/when_exe/region/discordian.rb +218 -218
  40. data/lib/when_exe/region/east_asian.rb +1 -1
  41. data/lib/when_exe/region/french.rb +126 -56
  42. data/lib/when_exe/region/geologicalage.rb +639 -639
  43. data/lib/when_exe/region/goddess.rb +60 -58
  44. data/lib/when_exe/region/hanke_henry.rb +2 -2
  45. data/lib/when_exe/region/indian.rb +1225 -1222
  46. data/lib/when_exe/region/international_fixed.rb +96 -97
  47. data/lib/when_exe/region/iranian.rb +206 -203
  48. data/lib/when_exe/region/islamic.rb +102 -102
  49. data/lib/when_exe/region/japanese.rb +126 -71
  50. data/lib/when_exe/region/japanese/epochs.rb +426 -426
  51. data/lib/when_exe/region/japanese/notes.rb +101 -81
  52. data/lib/when_exe/region/japanese/residues.rb +1345 -1311
  53. data/lib/when_exe/region/japanese/twins.rb +225 -225
  54. data/lib/when_exe/region/japanese/weeks.rb +112 -112
  55. data/lib/when_exe/region/javanese.rb +230 -230
  56. data/lib/when_exe/region/jewish.rb +130 -131
  57. data/lib/when_exe/region/m17n.rb +114 -114
  58. data/lib/when_exe/region/martian.rb +258 -258
  59. data/lib/when_exe/region/mayan.rb +11 -8
  60. data/lib/when_exe/region/pax.rb +4 -5
  61. data/lib/when_exe/region/pope.rb +1 -1
  62. data/lib/when_exe/region/positivist.rb +100 -100
  63. data/lib/when_exe/region/residue.rb +162 -162
  64. data/lib/when_exe/region/roman.rb +333 -333
  65. data/lib/when_exe/region/{soviet.rb → russian.rb} +221 -209
  66. data/lib/when_exe/region/shire.rb +222 -223
  67. data/lib/when_exe/region/symmetry.rb +50 -50
  68. data/lib/when_exe/region/thai.rb +336 -336
  69. data/lib/when_exe/region/tibetan.rb +315 -316
  70. data/lib/when_exe/region/tranquility.rb +207 -208
  71. data/lib/when_exe/region/vanishing_leprechaun.rb +3 -1
  72. data/lib/when_exe/region/vietnamese.rb +449 -440
  73. data/lib/when_exe/region/weekdate.rb +80 -80
  74. data/lib/when_exe/region/world.rb +170 -171
  75. data/lib/when_exe/region/world_season.rb +89 -89
  76. data/lib/when_exe/region/yerm.rb +3 -3
  77. data/lib/when_exe/region/zoroastrian.rb +205 -205
  78. data/lib/when_exe/timestandard.rb +708 -707
  79. data/lib/when_exe/tmduration.rb +338 -338
  80. data/lib/when_exe/tmobjects.rb +1356 -1356
  81. data/lib/when_exe/tmposition.rb +66 -31
  82. data/lib/when_exe/version.rb +16 -2
  83. data/test/examples/Residue.m17n +83 -83
  84. data/test/examples/Terms.m17n +2 -2
  85. data/test/test.rb +2 -2
  86. data/test/test/google_api.rb +65 -0
  87. data/test/test/linkeddata.rb +1 -1
  88. data/test/test/{googlecalendar.rb → obsolete/googlecalendar.rb} +194 -194
  89. data/test/test/region/indian.rb +90 -85
  90. data/test/test/region/m17n.rb +7 -7
  91. data/test/test/region/mayan.rb +195 -195
  92. data/test/test/region/residue.rb +153 -153
  93. data/test/test/tmposition.rb +11 -1
  94. data/when_exe.gemspec +2 -2
  95. metadata +95 -8
  96. data/test/test.rb.config +0 -1
@@ -1,1356 +1,1356 @@
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==:reverse) ? @first - @parent * @count : @first + @parent * @count
573
- if @last
574
- sign = @parent.sign
575
- sign = -sign if @direction==:reverse
576
- @current = nil if (sign * (@current <=> @last)) > 0
577
- end
578
- @count += 1
579
- return value
580
- end
581
- end
582
-
583
- # Enumerator の生成
584
- #
585
- # @overload initialize(range, count_limit=nil))
586
- # @param [Range, When::Parts::GeometricComplex] range
587
- # [ 始点 - range.first ]
588
- # [ 終点 - range.last ]
589
- # @param [Integer] count_limit 繰り返し回数(デフォルトは指定なし)
590
- #
591
- # @overload initialize(first, direction, count_limit=nil))
592
- # @param [When::TM::TemporalPosition] first 始点
593
- # @param [Symbol] direction
594
- # [ :forward - 昇順 ]
595
- # [ :reverse - 降順 ]
596
- # @param [Integer] count_limit 繰り返し回数(デフォルトは指定なし)
597
- #
598
- def _enumerator(*args)
599
- return Enumerator.new(*args.unshift(self))
600
- end
601
- alias :to_enum :_enumerator
602
- alias :enum_for :_enumerator
603
- end
604
-
605
- #
606
- # ISO 11404 の時間間隔に基づいて定義された When::TM::Duration の subclass
607
- #
608
- # see {http://schemas.opengis.net/gml/3.1.1/base/temporal.xsd#timeIntervalLengthType gml schema}
609
- #
610
- class IntervalLength < Duration
611
-
612
- Alias = {'Y'=>'year', 'M'=>'month' , 'D'=>'day', 'W'=>'week', 'S'=>'system',
613
- 'h'=>'hour', 'm'=>'minute', 's'=>'second'}
614
-
615
- # Interval Length 形式の表現を分解して配列化する
616
- #
617
- # @param [String] interval
618
- #
619
- # @return [Array<Numeric, String>] ( value, unit_name, factor, radix )
620
- # [ value [Numeric] - 時間間隔 / 単位 ]
621
- # [ unit_name [String] - 単位名 ]
622
- # [ factor [Numeric] - 冪乗 ]
623
- # [ radix [Numeric] - 冪乗の基数 ]
624
- #
625
- # @note value, factor, radix は Numeric
626
- #
627
- def self._to_array(interval)
628
- return nil unless interval =~ /\A([-+]?[\d.]+)(?:(E|X|\((\d+)\))([-+]?\d+))?([A-Za-z]+|\*([\d.]+)S)\z/
629
- value, radix, radix_quantity, factor, unit, unit_quantity = $~[1..6]
630
- value = When::Coordinates::Pair._en_number(value)
631
- radix = case radix
632
- when 'E', nil ; 10
633
- when 'X' ; 60
634
- else ; radix_quantity.to_i
635
- end
636
- factor = factor ? -factor.to_i : 0
637
- return [value, unit_quantity, factor, radix] if unit_quantity
638
- unit_quantity = Unit[unit.downcase] || Unit[Alias[unit[0..0]]]
639
- return [value, UnitName[unit_quantity], factor, radix] if unit_quantity
640
- return nil
641
- end
642
-
643
- # 時間間隔の長さ (128秒単位)
644
- #
645
- # @return [Numeric]
646
- #
647
- protected :duration=
648
-
649
- # 時間間隔を表現するために使用した測定単位の名称
650
- #
651
- # @return [String] (year|month|week|day|hour|minute|second|system)
652
- #
653
- attr_reader :unit
654
-
655
- # 時間単位となる乗数の基底となる正の整数
656
- #
657
- # @return [Integer]
658
- #
659
- attr_reader :radix
660
-
661
- # 基底のべき乗を行う指数
662
- #
663
- # @return [Integer]
664
- #
665
- attr_reader :factor
666
-
667
- # 時間間隔の長さ / 測定単位
668
- #
669
- # @return [Numeric]
670
- #
671
- attr_accessor :value
672
- protected :value=
673
-
674
- #
675
- # 測定単位の大きさ
676
- #
677
- # @return [Numeric]
678
- #
679
- attr_reader :unit_quantity
680
-
681
- # 時刻配列
682
- #
683
- # @return [Numeric]
684
- # When::TM::PeriodDuration との互換性のために提供
685
- #
686
- # @private
687
- #
688
- def time
689
- [0, 0, @duration / SECOND]
690
- end
691
-
692
- # 日付配列
693
- #
694
- # @return [nil]
695
- # When::TM::PeriodDuration との互換性のために提供
696
- #
697
- # @private
698
- #
699
- def date
700
- nil
701
- end
702
-
703
- # 暦週配列
704
- #
705
- # @return [nil]
706
- # When::TM::PeriodDuration との互換性のために提供
707
- #
708
- # @private
709
- #
710
- def weeks
711
- nil
712
- end
713
-
714
- # 符号反転
715
- #
716
- # @return [When::TM::IntervalLength]
717
- #
718
- def -@
719
- interval = self.dup
720
- interval.value = -@value
721
- interval.duration = -@duration
722
- return interval
723
- end
724
-
725
- #
726
- # 加算
727
- #
728
- # @param [When::TM::Duration] other
729
- # @param [Numeric] other 秒数
730
- # @param [その他] other 日時とみなす
731
- #
732
- # @return [When::TM::IntervalLength] (other が Numeric, When::TM::Duration の場合)
733
- # @return [other と同じクラス] (other がその他の場合)
734
- #
735
- def +(other)
736
- case other
737
- when Duration ; diff = other.duration
738
- when Numeric ; diff = other * SECOND
739
- else ; return other + self
740
- end
741
- interval = self.dup
742
- interval.duration = @duration + diff
743
- interval.value = interval.duration / (@radix ** (-@factor) * @unit_quantity)
744
- return interval
745
- end
746
-
747
- #
748
- # 減算
749
- #
750
- # @param [When::TM::IntervalLength] other
751
- # @param [Numeric] other 秒数
752
- #
753
- # @return [When::TM::IntervalLength]
754
- #
755
- def -(other)
756
- interval = self.dup
757
- interval.duration = @duration - (other.kind_of?(Duration) ? other.duration : other * SECOND)
758
- interval.value = interval.duration / (@radix ** (-@factor) * @unit_quantity)
759
- return interval
760
- end
761
-
762
- # 乗算
763
- #
764
- # @param [Numeric] times
765
- #
766
- # @return [When::TM::IntervalLength]
767
- #
768
- def *(times)
769
- interval = self.dup
770
- interval.value = times * @value
771
- interval.duration = times * @duration
772
- return interval
773
- end
774
-
775
- #
776
- # 除算
777
- #
778
- # @param [When::TM::IntervalLength] other
779
- # @param [Numeric] other 秒数
780
- #
781
- # @return [When::TM::IntervalLength] (other が Numeric の場合)
782
- # @return [Numeric] (other が When::TM::Duration の場合)
783
- #
784
- def /(other)
785
- other.kind_of?(Duration) ? @duration / other.duration : self * (1.0 / other)
786
- end
787
-
788
- # 文字列化
789
- #
790
- # @return [String]
791
- #
792
- def to_s
793
- expression = @value.to_s
794
- unless @factor == 0
795
- case @radix
796
- when 10 ; expression += 'E'
797
- when 60 ; expression += 'X'
798
- else ; expression += '(%d)' % @radix
799
- end
800
- expression += '%+d' % (-@factor)
801
- end
802
- expression += Alias.invert[@unit] || "*#{When::Coordinates::Pair._en_number(@unit)}S"
803
- return expression
804
- end
805
-
806
- #
807
- # When::TM::IntervalLength への変換
808
- #
809
- # 単なるオブジェクトのコピー
810
- #
811
- # @return [When::TM::IntervalLength]
812
- #
813
- def to_interval_length
814
- self.dup
815
- end
816
-
817
- # オブジェクトの生成
818
- #
819
- # @param [Numeric] value 時間間隔の長さ / 測定単位(省略不可)
820
- # @param [String] unit 時間間隔を表現するために使用した測定単位の名称(デフォルト : system)
821
- # ('year'|'month'|'week'|'day'|'hour'|'minute'|'second'|'system')
822
- # @param [Integer] factor 基底の冪乗を行う指数(デフォルト : 0)
823
- # @param [Integer] radix 時間単位となる乗数の基底となる正の整数(デフォルト : 10)
824
- #
825
- def initialize(value, unit='system', factor=0, radix=10)
826
- @value, @factor, @radix = value, factor, radix
827
- @unit_quantity = Unit[unit.downcase] || Unit[Alias[unit[0..0]]] if unit.kind_of?(String)
828
- @unit_quantity ||= unit.to_f
829
- raise TypeError, "Wrong Unit Type: #{unit}" unless @unit_quantity.kind_of?(Numeric)
830
- @unit = UnitName[@unit_quantity] ||
831
- When::Coordinates::Pair._en_number(@unit_quantity).to_s
832
- @duration = @value * @radix ** (-@factor) * @unit_quantity
833
- end
834
-
835
- # オブジェクトの生成(終点と始点を指定)
836
- #
837
- # @param [When::TM::TemporalPosition] ended 終点
838
- # @param [When::TM::TemporalPosition] begun 始点
839
- #
840
- # @return [When::TM::IntervalLength]
841
- # [ 日単位の精度 - 終点と始点の分解能のいずれかが“日”またはそれより粗い場合 ]
842
- # [ システム精度 - 終点と始点の分解能がともに“日”より細かい場合 ]
843
- #
844
- def self.difference(ended, begun)
845
- precision = [ended.precision, begun.precision].min
846
- return new(ended-begun) if precision > When::DAY
847
- return new(ended.to_i - begun.to_i, unit='day')
848
- end
849
-
850
- private
851
-
852
- # その他のメソッド
853
- #
854
- # @note
855
- # When::TM::IntervalLength で定義されていないメソッドは
856
- # 処理を @duration (type:Numeric) に委譲する
857
- #
858
- def method_missing(name, *args, &block)
859
- self.class.module_eval %Q{
860
- def #{name}(*args, &block)
861
- @duration.send("#{name}", *args, &block)
862
- end
863
- } unless When::Parts::MethodCash.escape(name)
864
- @duration.send(name, *args, &block)
865
- end
866
- end
867
-
868
- #
869
- # ISO 8601 (JIS X0301) の時間間隔に基づいて定義された When::TM::Duration の subclass
870
- #
871
- class PeriodDuration < Duration
872
-
873
- include When
874
- include Coordinates
875
-
876
- #
877
- # When::TM::PeriodDuration オブジェクトが月や年などの可変長の単位に依存する場合
878
- # に @duration 属性の参照を禁止するために用いる
879
- #
880
- module NoDuration
881
- #
882
- # 属性 @duration が定義できないとをエラーで示す
883
- #
884
- # @return [Numeric]
885
- #
886
- def duration
887
- raise TypeError, "This PeriodDuration object does't have duration value"
888
- end
889
- end
890
-
891
- # ISO 8601 形式の表現を分解して配列化する
892
- #
893
- # @param [String] period
894
- #
895
- # @return [Array<Numeric, Array<Numeric>>] ( sign, date, time, week )
896
- # [ sign [Numeric] - +1 , -1 ]
897
- # [ date [Array<Numeric>] - 年月日 ]
898
- # [ time [Array<Numeric>] - 時分秒 ]
899
- # [ week [Array<Numeric>] - 週日 ]
900
- #
901
- def self._to_array(period)
902
-
903
- return nil unless period.gsub(/_+/, '') =~ /\A([-+])?P(.*?)?(?:T(.+))?\z/
904
-
905
- sign = ($1 == '-') ? -1 : +1
906
- pdate, ptime = $~[2..3]
907
-
908
- # 時分秒形式
909
- if (ptime =~ /\A(?:([.,\d]+)?([:*=])?H)?(?:([.,\d]+)?([:*=])?M)?(?:([.,\d]+)?([:*=])?S)?((?:[.,\d]*[:*=]?X)*)\z/)
910
- trunk = [1,3,5].map {|i|
911
- $~[i] ? Pair._en_pair($~[i], $~[i+1]) : 0
912
- }
913
- extra = $7 ? $7.scan(/([.,\d]+)?([:*=])?X/).map {|d|
914
- d[0] ? Pair._en_pair(d[0], d[1]) : 0
915
- } : []
916
- time = [0] + trunk + extra
917
- time = nil if time.uniq == [0]
918
- end
919
-
920
- case pdate
921
- # 年月日形式
922
- when /\A((?:[.,\d]*[-*=]?X)*)(?:([.,\d]+)?([-*=])?Y)?(?:([.,\d]+)?([-+*&%!>=<?])?M)?(?:([.,\d]+)?([-*=?%])?D)?\z/
923
- trunk = [2,4,6].map {|i|
924
- $~[i] ? Pair._en_pair($~[i], $~[i+1]) : 0
925
- }
926
- extra = $1 ? $1.scan(/([.,\d]+)?([:*=])?X/).map {|d|
927
- d[0] ? Pair._en_pair(d[0], d[1]) : 0
928
- } : []
929
- date = extra + trunk
930
- date = nil if date.uniq == [0]
931
- return sign, date, time
932
-
933
- # 週日形式
934
- when /\A(?:([.,\d]+)?([:*=])?W)(?:([.,\d]+)?([-*=?%])?D)?\z/
935
- week = [1,3].map {|i|
936
- $~[i] ? Pair._en_pair($~[i], $~[i+1]) : 0
937
- }
938
- return sign, nil, time if week.uniq == [0]
939
- date = [0, 0, week[1] + 7*week[0]]
940
- return sign, date, time, week
941
-
942
- # 代用形式
943
- else
944
- pdate += 'T' + ptime if ptime
945
- f, d, t, z, e = When::BasicTypes::DateTime._to_array(pdate, {:abbr=>[0]*20})
946
- return nil if e
947
- if d
948
- case f
949
- when :day ; date = [d[0], 0, d[1]]
950
- when :century, nil ; date = (0..2).map {|i| d[i]||0}
951
- when :week ; date, week = [0,0,d[0]*7+(d[1]||0)], [d[0], d[1]||0]
952
- end
953
- end
954
- time = t ? (t.map {|v| v||0}) : nil
955
- return sign, date, time, week
956
- end
957
- end
958
-
959
- # 期間の日数
960
- #
961
- # @return [Integer]
962
- #
963
- # @note 固定の整数で表現できない場合は nil
964
- #
965
- attr_reader :to_day
966
-
967
- # 期間の日付要素
968
- #
969
- # @return [Array<Numeric>]
970
- #
971
- attr_accessor :date
972
- private :date=
973
-
974
- # 期間の週日要素
975
- #
976
- # @return [Array<Numeric>]
977
- #
978
- attr_accessor :week
979
- private :week=
980
-
981
- # 期間の時刻要素
982
- #
983
- # @return [Array<Numeric>]
984
- #
985
- attr_accessor :time
986
- private :time=
987
-
988
- # 要素の参照
989
- #
990
- # @param [Numeric] index When::Coordinates で定義している分解能定数に対応する列挙型( YEAR, ... , SECOND)
991
- #
992
- # @return [Numeric]
993
- #
994
- def [](index)
995
- if index == WEEK
996
- return nil unless @week
997
- return @week[0]
998
- elsif index <= 0
999
- return nil unless @date
1000
- return @date[index-1]
1001
- else
1002
- return nil unless @time
1003
- return @time[index]
1004
- end
1005
- end
1006
-
1007
- # 持続期間であることを文字'P'で示す
1008
- #
1009
- # @return [String]
1010
- #
1011
- def designator
1012
- return 'P'
1013
- end
1014
-
1015
- # 期間に含まれる年数を示す
1016
- #
1017
- # @return [String]
1018
- #
1019
- def years
1020
- return nil unless @date
1021
- return @date[YEAR-1].to_s
1022
- end
1023
-
1024
- # 期間に含まれる月数を示す
1025
- #
1026
- # @return [String
1027
- #
1028
- def months
1029
- return nil unless @date
1030
- return @date[MONTH-1].to_s
1031
- end
1032
-
1033
- # 期間に含まれる週数を示す
1034
- #
1035
- # @return [String]
1036
- #
1037
- def weeks
1038
- return nil unless @week
1039
- return @week[0].to_s
1040
- end
1041
-
1042
- # 期間に含まれる日数を示す
1043
- #
1044
- # @return [String]
1045
- #
1046
- def days
1047
- return nil unless @date
1048
- return @date[DAY-1].to_s
1049
- end
1050
-
1051
- # 期間が1日より短い時間単位を含むとき文字'T'で示す
1052
- #
1053
- # @return [String]
1054
- #
1055
- def time_indicator
1056
- return (@time) ? 'T' : nil
1057
- end
1058
- alias :timeIndicator :time_indicator
1059
-
1060
- # 期間に含まれる時間数を示す
1061
- #
1062
- # @return [String]
1063
- #
1064
- def hours
1065
- return nil unless @time
1066
- return @time[HOUR].to_s
1067
- end
1068
-
1069
- # 期間に含まれる分数を示す
1070
- #
1071
- # @return [String]
1072
- #
1073
- def minutes
1074
- return nil unless @time
1075
- return @time[MINUTE].to_s
1076
- end
1077
-
1078
- # 期間に含まれる秒数を示す
1079
- #
1080
- # @return [String]
1081
- #
1082
- def seconds
1083
- return nil unless @time
1084
- return @time[SECOND].to_s
1085
- end
1086
-
1087
- # 符号反転
1088
- #
1089
- # @return [When::TM::PeriodDuration]
1090
- #
1091
- def -@
1092
- period = self.dup
1093
- period.send(:date=, @date.map {|v| -v}) if @date
1094
- period.send(:week=, @week.map {|v| -v}) if @week
1095
- period.send(:time=, @time.map {|v| -v}) if @time
1096
- period.send(:_duration)
1097
- return period
1098
- end
1099
-
1100
- # 符号
1101
- #
1102
- # @return [Integer] 0 との比較により、負,0,正の値を返す
1103
- #
1104
- def sign
1105
- @sign ||= _sign
1106
- end
1107
-
1108
- def _sign
1109
- ((@week || @date || []) + (@time || [])).each do |v|
1110
- return -1 if +v < 0
1111
- end
1112
- return +1
1113
- end
1114
- private :_sign
1115
-
1116
- # 比較
1117
- #
1118
- # @param [When::TM::PeriodDuration] other
1119
- #
1120
- # @return [Integer] other との比較により、負,0,正の値を返す
1121
- #
1122
- def <=>(other)
1123
- unless (@date && @date.size) == (other.date && other.date.size) &&
1124
- (@week && @week.size) == (other.week && other.week.size) &&
1125
- (@time && @time.size) == (other.time && other.time.size)
1126
- raise ArgumentError, "PeriodDuration structure mismatch"
1127
- end
1128
-
1129
- (0...@week.size).each do |i|
1130
- sgn = +@week[i] <=> +other.week[i]
1131
- return sgn unless sgn == 0
1132
- end if @week
1133
-
1134
- (0...@date.size).each do |i|
1135
- sgn = +@date[i] <=> +other.date[i]
1136
- return sgn unless sgn == 0
1137
- end if @date
1138
-
1139
- (0...@time.size).each do |i|
1140
- sgn = +@time[i] <=> +other.time[i]
1141
- return sgn unless sgn == 0
1142
- end if @time
1143
-
1144
- return 0
1145
- end
1146
-
1147
- # オブジェクトの同値
1148
- #
1149
- # @param [比較先] other
1150
- #
1151
- # @return [Boolean]
1152
- # [ true - 同値 ]
1153
- # [ false - 非同値 ]
1154
- #
1155
- def ==(other)
1156
- (self <=> other) == 0
1157
- rescue
1158
- false
1159
- end
1160
-
1161
- # 加算
1162
- #
1163
- # @param [When::TM::PeriodDuration] other
1164
- # @param [その他] other 日時とみなす
1165
- #
1166
- # @return [WWhen::TM::PeriodDuration] (other が When::TM::PeriodDuration の場合)
1167
- # @return [other と同じクラス] (other がその他の場合)
1168
- #
1169
- def +(other)
1170
- other.kind_of?(When::TM::PeriodDuration) ? _plus(other, +1) : other + self
1171
- end
1172
-
1173
- # 減算
1174
- #
1175
- # @param [When::TM::PeriodDuration] other
1176
- #
1177
- # @return [When::TM::PeriodDuration]
1178
- #
1179
- def -(other)
1180
- _plus(other, -1)
1181
- end
1182
-
1183
- # 乗算
1184
- #
1185
- # @param [Numeric] times
1186
- #
1187
- # @return [When::TM::PeriodDuration]
1188
- #
1189
- def *(times)
1190
- period = self.dup
1191
- period.send(:date=, @date.map {|v| v *= times; v.to_i==v.to_f ? v.to_i : v}) if @date
1192
- period.send(:week=, @week.map {|v| v *= times; v.to_i==v.to_f ? v.to_i : v}) if @week
1193
- period.send(:time=, @time.map {|v| v *= times; v.to_i==v.to_f ? v.to_i : v}) if @time
1194
- period.send(:_duration)
1195
- return period
1196
- end
1197
-
1198
- # 除算
1199
- #
1200
- # @param [Numeric] divisor
1201
- #
1202
- # @return [When::TM::PeriodDuration]
1203
- #
1204
- def /(divisor)
1205
- self * (1.0 / divisor)
1206
- end
1207
-
1208
- # 文字列化
1209
- #
1210
- # @return [String]
1211
- #
1212
- def to_s
1213
- period = 'P'
1214
- if @week
1215
- period += @week[0].abs.to_s + 'W'
1216
- period += @week[1].abs.to_s + 'D' unless @week[1] == 0
1217
- elsif @date
1218
- (-@date.length..-1).each do |i|
1219
- period += @date[i].abs.to_s + PRECISION_NAME[i+1][0..0] unless @date[i] == 0
1220
- end
1221
- end
1222
- if @time
1223
- period += 'T'
1224
- (1..@time.length-1).each do |i|
1225
- period += @time[i].abs.to_s + PRECISION_NAME[i][0..0] unless @time[i] == 0
1226
- end
1227
- end
1228
- period = '-' + period if sign < 0
1229
- period == 'P' ? 'P0D' : period
1230
- end
1231
-
1232
- #
1233
- # When::TM::PeriodDuration への変換
1234
- #
1235
- # 単なるオブジェクトのコピー
1236
- #
1237
- # @return [When::TM::PeriodDuration]
1238
- #
1239
- def to_period_duration
1240
- self.dup
1241
- end
1242
-
1243
- # オブジェクトの生成
1244
- #
1245
- # @overload initialize(date=nil, time=nil, week=nil)
1246
- # @param [Array<Numeric>] date 期間の日付要素
1247
- # @param [Array<Numeric>] time 期間の時刻要素
1248
- # @param [Array<Numeric>] week 期間の週日要素
1249
- #
1250
- # @overload initialize(value, index, range=YEAR..SECOND)
1251
- # @param [Numeric] value ndex に対応する桁での)時間間隔
1252
- # @param [Numeric] index When で定義している分解能定数(YEAR, ... ,SECOND)
1253
- # @param [Range] range 生成する桁の範囲
1254
- #
1255
- def initialize(*args)
1256
- @options = (args[-1].kind_of?(Hash)) ? (args.pop.reject {|key,value| value == nil}) : {}
1257
- if args[0].kind_of?(Numeric)
1258
- _initialize_by_unit(*args)
1259
- else
1260
- @date, @time, @week = args
1261
- end
1262
- _duration
1263
- end
1264
-
1265
- private
1266
-
1267
- #
1268
- # 引数パターン2での初期化
1269
- #
1270
- def _initialize_by_unit(value, index, range=YEAR..SECOND)
1271
- max = range.first
1272
- min = range.last
1273
- min += 1 if (range.exclude_end?)
1274
- if (index < max)
1275
- if (index > MONTH)
1276
- max = index.floor
1277
- else
1278
- value *= 10**(max-index)
1279
- index = max
1280
- end
1281
- elsif (index > min)
1282
- if (index <= DAY)
1283
- min = index.ceil
1284
- else
1285
- value *= 0.1**(index-min)
1286
- index = min
1287
- end
1288
- end
1289
- value = value.to_i unless value.kind_of?(Pair) || value.to_i != value.to_f
1290
- @date = Array.new(1-max, 0) if (max <= DAY) && (index <= DAY)
1291
- @time = Array.new(1+min, 0) if (min > DAY) && (index > DAY)
1292
- if (index == WEEK)
1293
- @week = [value, 0]
1294
- @date[DAY-1] = 7 * value
1295
- elsif (index <= DAY)
1296
- @date[index-1] = value
1297
- else
1298
- @time[index] = value
1299
- end
1300
- end
1301
-
1302
- #
1303
- # 属性 @duration の計算
1304
- #
1305
- def _duration
1306
- @duration = @sign = nil
1307
-
1308
- if @time
1309
- @duration = +@time[HOUR ] * Duration::HOUR
1310
- @duration += +@time[MINUTE] * Duration::MINUTE if @time[MINUTE]
1311
- @duration += +@time[SECOND] * Duration::SECOND if @time[SECOND]
1312
- end
1313
-
1314
- if @week
1315
- @duration = +@week[0] * Duration::WEEK + +@week[1] * Duration::DAY + (@duration||0)
1316
-
1317
- elsif @date
1318
- date = @date.dup
1319
- date.shift while date.first == 0
1320
- case date.size
1321
- when 0 ; @duration ||= 0
1322
- when 1 ; @duration = +@date[DAY-1] * Duration::DAY + (@duration||0)
1323
- else ; @duration = nil
1324
- end
1325
- end
1326
-
1327
- if @duration
1328
- length = @duration / Duration::DAY
1329
- @to_day = length.to_i if length.to_i == length.to_f
1330
- else
1331
- extend NoDuration
1332
- end
1333
- end
1334
-
1335
- # 加減算共通処理
1336
- #
1337
- # @param [When::TM::PeriodDuration] other
1338
- # @param [Numeric] sgn +1, -1
1339
- #
1340
- # @return [When::TM::PeriodDuration]
1341
- #
1342
- def _plus(other, sgn)
1343
- unless (@week && @week.size) == (other.week && other.week.size) &&
1344
- (@date && @date.size) == (other.date && other.date.size) &&
1345
- (@time && @time.size) == (other.time && other.time.size)
1346
- raise ArgumentError, "PeriodDuration structure mismatch"
1347
- end
1348
- period = self.dup
1349
- period.send(:week=, (0...@week.size).to_a.map {|i| @week[i] + sgn * other.week[i]}) if @week
1350
- period.send(:date=, (0...@date.size).to_a.map {|i| @date[i] + sgn * other.date[i]}) if @date
1351
- period.send(:time=, (0...@time.size).to_a.map {|i| @time[i] + sgn * other.time[i]}) if @time
1352
- period.send(:_duration)
1353
- return period
1354
- end
1355
- end
1356
- end
1
+ # -*- coding: utf-8 -*-
2
+ =begin
3
+ Copyright (C) 2011-2015 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==:reverse) ? @first - @parent * @count : @first + @parent * @count
573
+ if @last
574
+ sign = @parent.sign
575
+ sign = -sign if @direction==:reverse
576
+ @current = nil if (sign * (@current <=> @last)) > 0
577
+ end
578
+ @count += 1
579
+ return value
580
+ end
581
+ end
582
+
583
+ # Enumerator の生成
584
+ #
585
+ # @overload initialize(range, count_limit=nil))
586
+ # @param [Range, When::Parts::GeometricComplex] range
587
+ # [ 始点 - range.first ]
588
+ # [ 終点 - range.last ]
589
+ # @param [Integer] count_limit 繰り返し回数(デフォルトは指定なし)
590
+ #
591
+ # @overload initialize(first, direction, count_limit=nil))
592
+ # @param [When::TM::TemporalPosition] first 始点
593
+ # @param [Symbol] direction
594
+ # [ :forward - 昇順 ]
595
+ # [ :reverse - 降順 ]
596
+ # @param [Integer] count_limit 繰り返し回数(デフォルトは指定なし)
597
+ #
598
+ def _enumerator(*args)
599
+ return Enumerator.new(*args.unshift(self))
600
+ end
601
+ alias :to_enum :_enumerator
602
+ alias :enum_for :_enumerator
603
+ end
604
+
605
+ #
606
+ # ISO 11404 の時間間隔に基づいて定義された When::TM::Duration の subclass
607
+ #
608
+ # see {http://schemas.opengis.net/gml/3.1.1/base/temporal.xsd#timeIntervalLengthType gml schema}
609
+ #
610
+ class IntervalLength < Duration
611
+
612
+ Alias = {'Y'=>'year', 'M'=>'month' , 'D'=>'day', 'W'=>'week', 'S'=>'system',
613
+ 'h'=>'hour', 'm'=>'minute', 's'=>'second'}
614
+
615
+ # Interval Length 形式の表現を分解して配列化する
616
+ #
617
+ # @param [String] interval
618
+ #
619
+ # @return [Array<Numeric, String>] ( value, unit_name, factor, radix )
620
+ # [ value [Numeric] - 時間間隔 / 単位 ]
621
+ # [ unit_name [String] - 単位名 ]
622
+ # [ factor [Numeric] - 冪乗 ]
623
+ # [ radix [Numeric] - 冪乗の基数 ]
624
+ #
625
+ # @note value, factor, radix は Numeric
626
+ #
627
+ def self._to_array(interval)
628
+ return nil unless interval =~ /\A([-+]?[\d.]+)(?:(E|X|\((\d+)\))([-+]?\d+))?([A-Za-z]+|\*([\d.]+)S)\z/
629
+ value, radix, radix_quantity, factor, unit, unit_quantity = $~[1..6]
630
+ value = When::Coordinates::Pair._en_number(value)
631
+ radix = case radix
632
+ when 'E', nil ; 10
633
+ when 'X' ; 60
634
+ else ; radix_quantity.to_i
635
+ end
636
+ factor = factor ? -factor.to_i : 0
637
+ return [value, unit_quantity, factor, radix] if unit_quantity
638
+ unit_quantity = Unit[unit.downcase] || Unit[Alias[unit[0..0]]]
639
+ return [value, UnitName[unit_quantity], factor, radix] if unit_quantity
640
+ return nil
641
+ end
642
+
643
+ # 時間間隔の長さ (128秒単位)
644
+ #
645
+ # @return [Numeric]
646
+ #
647
+ protected :duration=
648
+
649
+ # 時間間隔を表現するために使用した測定単位の名称
650
+ #
651
+ # @return [String] (year|month|week|day|hour|minute|second|system)
652
+ #
653
+ attr_reader :unit
654
+
655
+ # 時間単位となる乗数の基底となる正の整数
656
+ #
657
+ # @return [Integer]
658
+ #
659
+ attr_reader :radix
660
+
661
+ # 基底のべき乗を行う指数
662
+ #
663
+ # @return [Integer]
664
+ #
665
+ attr_reader :factor
666
+
667
+ # 時間間隔の長さ / 測定単位
668
+ #
669
+ # @return [Numeric]
670
+ #
671
+ attr_accessor :value
672
+ protected :value=
673
+
674
+ #
675
+ # 測定単位の大きさ
676
+ #
677
+ # @return [Numeric]
678
+ #
679
+ attr_reader :unit_quantity
680
+
681
+ # 時刻配列
682
+ #
683
+ # @return [Numeric]
684
+ # When::TM::PeriodDuration との互換性のために提供
685
+ #
686
+ # @private
687
+ #
688
+ def time
689
+ [0, 0, @duration / SECOND]
690
+ end
691
+
692
+ # 日付配列
693
+ #
694
+ # @return [nil]
695
+ # When::TM::PeriodDuration との互換性のために提供
696
+ #
697
+ # @private
698
+ #
699
+ def date
700
+ nil
701
+ end
702
+
703
+ # 暦週配列
704
+ #
705
+ # @return [nil]
706
+ # When::TM::PeriodDuration との互換性のために提供
707
+ #
708
+ # @private
709
+ #
710
+ def weeks
711
+ nil
712
+ end
713
+
714
+ # 符号反転
715
+ #
716
+ # @return [When::TM::IntervalLength]
717
+ #
718
+ def -@
719
+ interval = self.dup
720
+ interval.value = -@value
721
+ interval.duration = -@duration
722
+ return interval
723
+ end
724
+
725
+ #
726
+ # 加算
727
+ #
728
+ # @param [When::TM::Duration] other
729
+ # @param [Numeric] other 秒数
730
+ # @param [その他] other 日時とみなす
731
+ #
732
+ # @return [When::TM::IntervalLength] (other が Numeric, When::TM::Duration の場合)
733
+ # @return [other と同じクラス] (other がその他の場合)
734
+ #
735
+ def +(other)
736
+ case other
737
+ when Duration ; diff = other.duration
738
+ when Numeric ; diff = other * SECOND
739
+ else ; return other + self
740
+ end
741
+ interval = self.dup
742
+ interval.duration = @duration + diff
743
+ interval.value = interval.duration / (@radix ** (-@factor) * @unit_quantity)
744
+ return interval
745
+ end
746
+
747
+ #
748
+ # 減算
749
+ #
750
+ # @param [When::TM::IntervalLength] other
751
+ # @param [Numeric] other 秒数
752
+ #
753
+ # @return [When::TM::IntervalLength]
754
+ #
755
+ def -(other)
756
+ interval = self.dup
757
+ interval.duration = @duration - (other.kind_of?(Duration) ? other.duration : other * SECOND)
758
+ interval.value = interval.duration / (@radix ** (-@factor) * @unit_quantity)
759
+ return interval
760
+ end
761
+
762
+ # 乗算
763
+ #
764
+ # @param [Numeric] times
765
+ #
766
+ # @return [When::TM::IntervalLength]
767
+ #
768
+ def *(times)
769
+ interval = self.dup
770
+ interval.value = times * @value
771
+ interval.duration = times * @duration
772
+ return interval
773
+ end
774
+
775
+ #
776
+ # 除算
777
+ #
778
+ # @param [When::TM::IntervalLength] other
779
+ # @param [Numeric] other 秒数
780
+ #
781
+ # @return [When::TM::IntervalLength] (other が Numeric の場合)
782
+ # @return [Numeric] (other が When::TM::Duration の場合)
783
+ #
784
+ def /(other)
785
+ other.kind_of?(Duration) ? @duration / other.duration : self * (1.0 / other)
786
+ end
787
+
788
+ # 文字列化
789
+ #
790
+ # @return [String]
791
+ #
792
+ def to_s
793
+ expression = @value.to_s
794
+ unless @factor == 0
795
+ case @radix
796
+ when 10 ; expression += 'E'
797
+ when 60 ; expression += 'X'
798
+ else ; expression += '(%d)' % @radix
799
+ end
800
+ expression += '%+d' % (-@factor)
801
+ end
802
+ expression += Alias.invert[@unit] || "*#{When::Coordinates::Pair._en_number(@unit)}S"
803
+ return expression
804
+ end
805
+
806
+ #
807
+ # When::TM::IntervalLength への変換
808
+ #
809
+ # 単なるオブジェクトのコピー
810
+ #
811
+ # @return [When::TM::IntervalLength]
812
+ #
813
+ def to_interval_length
814
+ self.dup
815
+ end
816
+
817
+ # オブジェクトの生成
818
+ #
819
+ # @param [Numeric] value 時間間隔の長さ / 測定単位(省略不可)
820
+ # @param [String] unit 時間間隔を表現するために使用した測定単位の名称(デフォルト : system)
821
+ # ('year'|'month'|'week'|'day'|'hour'|'minute'|'second'|'system')
822
+ # @param [Integer] factor 基底の冪乗を行う指数(デフォルト : 0)
823
+ # @param [Integer] radix 時間単位となる乗数の基底となる正の整数(デフォルト : 10)
824
+ #
825
+ def initialize(value, unit='system', factor=0, radix=10)
826
+ @value, @factor, @radix = value, factor, radix
827
+ @unit_quantity = Unit[unit.downcase] || Unit[Alias[unit[0..0]]] if unit.kind_of?(String)
828
+ @unit_quantity ||= unit.to_f
829
+ raise TypeError, "Wrong Unit Type: #{unit}" unless @unit_quantity.kind_of?(Numeric)
830
+ @unit = UnitName[@unit_quantity] ||
831
+ When::Coordinates::Pair._en_number(@unit_quantity).to_s
832
+ @duration = @value * @radix ** (-@factor) * @unit_quantity
833
+ end
834
+
835
+ # オブジェクトの生成(終点と始点を指定)
836
+ #
837
+ # @param [When::TM::TemporalPosition] ended 終点
838
+ # @param [When::TM::TemporalPosition] begun 始点
839
+ #
840
+ # @return [When::TM::IntervalLength]
841
+ # [ 日単位の精度 - 終点と始点の分解能のいずれかが“日”またはそれより粗い場合 ]
842
+ # [ システム精度 - 終点と始点の分解能がともに“日”より細かい場合 ]
843
+ #
844
+ def self.difference(ended, begun)
845
+ precision = [ended.precision, begun.precision].min
846
+ return new(ended-begun) if precision > When::DAY
847
+ return new(ended.to_i - begun.to_i, unit='day')
848
+ end
849
+
850
+ private
851
+
852
+ # その他のメソッド
853
+ #
854
+ # @note
855
+ # When::TM::IntervalLength で定義されていないメソッドは
856
+ # 処理を @duration (type:Numeric) に委譲する
857
+ #
858
+ def method_missing(name, *args, &block)
859
+ self.class.module_eval %Q{
860
+ def #{name}(*args, &block)
861
+ @duration.send("#{name}", *args, &block)
862
+ end
863
+ } unless When::Parts::MethodCash.escape(name)
864
+ @duration.send(name, *args, &block)
865
+ end
866
+ end
867
+
868
+ #
869
+ # ISO 8601 (JIS X0301) の時間間隔に基づいて定義された When::TM::Duration の subclass
870
+ #
871
+ class PeriodDuration < Duration
872
+
873
+ include When
874
+ include Coordinates
875
+
876
+ #
877
+ # When::TM::PeriodDuration オブジェクトが月や年などの可変長の単位に依存する場合
878
+ # に @duration 属性の参照を禁止するために用いる
879
+ #
880
+ module NoDuration
881
+ #
882
+ # 属性 @duration が定義できないとをエラーで示す
883
+ #
884
+ # @return [Numeric]
885
+ #
886
+ def duration
887
+ raise TypeError, "This PeriodDuration object does't have duration value"
888
+ end
889
+ end
890
+
891
+ # ISO 8601 形式の表現を分解して配列化する
892
+ #
893
+ # @param [String] period
894
+ #
895
+ # @return [Array<Numeric, Array<Numeric>>] ( sign, date, time, week )
896
+ # [ sign [Numeric] - +1 , -1 ]
897
+ # [ date [Array<Numeric>] - 年月日 ]
898
+ # [ time [Array<Numeric>] - 時分秒 ]
899
+ # [ week [Array<Numeric>] - 週日 ]
900
+ #
901
+ def self._to_array(period)
902
+
903
+ return nil unless period.gsub(/_+/, '') =~ /\A([-+])?P(.*?)?(?:T(.+))?\z/
904
+
905
+ sign = ($1 == '-') ? -1 : +1
906
+ pdate, ptime = $~[2..3]
907
+
908
+ # 時分秒形式
909
+ if (ptime =~ /\A(?:([.,\d]+)?([:*=])?H)?(?:([.,\d]+)?([:*=])?M)?(?:([.,\d]+)?([:*=])?S)?((?:[.,\d]*[:*=]?X)*)\z/)
910
+ trunk = [1,3,5].map {|i|
911
+ $~[i] ? Pair._en_pair($~[i], $~[i+1]) : 0
912
+ }
913
+ extra = $7 ? $7.scan(/([.,\d]+)?([:*=])?X/).map {|d|
914
+ d[0] ? Pair._en_pair(d[0], d[1]) : 0
915
+ } : []
916
+ time = [0] + trunk + extra
917
+ time = nil if time.uniq == [0]
918
+ end
919
+
920
+ case pdate
921
+ # 年月日形式
922
+ when /\A((?:[.,\d]*[-*=]?X)*)(?:([.,\d]+)?([-*=])?Y)?(?:([.,\d]+)?([-+*&%!>=<?])?M)?(?:([.,\d]+)?([-*=?%])?D)?\z/
923
+ trunk = [2,4,6].map {|i|
924
+ $~[i] ? Pair._en_pair($~[i], $~[i+1]) : 0
925
+ }
926
+ extra = $1 ? $1.scan(/([.,\d]+)?([:*=])?X/).map {|d|
927
+ d[0] ? Pair._en_pair(d[0], d[1]) : 0
928
+ } : []
929
+ date = extra + trunk
930
+ date = nil if date.uniq == [0]
931
+ return sign, date, time
932
+
933
+ # 週日形式
934
+ when /\A(?:([.,\d]+)?([:*=])?W)(?:([.,\d]+)?([-*=?%])?D)?\z/
935
+ week = [1,3].map {|i|
936
+ $~[i] ? Pair._en_pair($~[i], $~[i+1]) : 0
937
+ }
938
+ return sign, nil, time if week.uniq == [0]
939
+ date = [0, 0, week[1] + 7*week[0]]
940
+ return sign, date, time, week
941
+
942
+ # 代用形式
943
+ else
944
+ pdate += 'T' + ptime if ptime
945
+ f, d, t, z, e = When::BasicTypes::DateTime._to_array(pdate, {:abbr=>[0]*20})
946
+ return nil if e
947
+ if d
948
+ case f
949
+ when :day ; date = [d[0], 0, d[1]]
950
+ when :century, nil ; date = (0..2).map {|i| d[i]||0}
951
+ when :week ; date, week = [0,0,d[0]*7+(d[1]||0)], [d[0], d[1]||0]
952
+ end
953
+ end
954
+ time = t ? (t.map {|v| v||0}) : nil
955
+ return sign, date, time, week
956
+ end
957
+ end
958
+
959
+ # 期間の日数
960
+ #
961
+ # @return [Integer]
962
+ #
963
+ # @note 固定の整数で表現できない場合は nil
964
+ #
965
+ attr_reader :to_day
966
+
967
+ # 期間の日付要素
968
+ #
969
+ # @return [Array<Numeric>]
970
+ #
971
+ attr_accessor :date
972
+ private :date=
973
+
974
+ # 期間の週日要素
975
+ #
976
+ # @return [Array<Numeric>]
977
+ #
978
+ attr_accessor :week
979
+ private :week=
980
+
981
+ # 期間の時刻要素
982
+ #
983
+ # @return [Array<Numeric>]
984
+ #
985
+ attr_accessor :time
986
+ private :time=
987
+
988
+ # 要素の参照
989
+ #
990
+ # @param [Numeric] index When::Coordinates で定義している分解能定数に対応する列挙型( YEAR, ... , SECOND)
991
+ #
992
+ # @return [Numeric]
993
+ #
994
+ def [](index)
995
+ if index == WEEK
996
+ return nil unless @week
997
+ return @week[0]
998
+ elsif index <= 0
999
+ return nil unless @date
1000
+ return @date[index-1]
1001
+ else
1002
+ return nil unless @time
1003
+ return @time[index]
1004
+ end
1005
+ end
1006
+
1007
+ # 持続期間であることを文字'P'で示す
1008
+ #
1009
+ # @return [String]
1010
+ #
1011
+ def designator
1012
+ return 'P'
1013
+ end
1014
+
1015
+ # 期間に含まれる年数を示す
1016
+ #
1017
+ # @return [String]
1018
+ #
1019
+ def years
1020
+ return nil unless @date
1021
+ return @date[YEAR-1].to_s
1022
+ end
1023
+
1024
+ # 期間に含まれる月数を示す
1025
+ #
1026
+ # @return [String
1027
+ #
1028
+ def months
1029
+ return nil unless @date
1030
+ return @date[MONTH-1].to_s
1031
+ end
1032
+
1033
+ # 期間に含まれる週数を示す
1034
+ #
1035
+ # @return [String]
1036
+ #
1037
+ def weeks
1038
+ return nil unless @week
1039
+ return @week[0].to_s
1040
+ end
1041
+
1042
+ # 期間に含まれる日数を示す
1043
+ #
1044
+ # @return [String]
1045
+ #
1046
+ def days
1047
+ return nil unless @date
1048
+ return @date[DAY-1].to_s
1049
+ end
1050
+
1051
+ # 期間が1日より短い時間単位を含むとき文字'T'で示す
1052
+ #
1053
+ # @return [String]
1054
+ #
1055
+ def time_indicator
1056
+ return (@time) ? 'T' : nil
1057
+ end
1058
+ alias :timeIndicator :time_indicator
1059
+
1060
+ # 期間に含まれる時間数を示す
1061
+ #
1062
+ # @return [String]
1063
+ #
1064
+ def hours
1065
+ return nil unless @time
1066
+ return @time[HOUR].to_s
1067
+ end
1068
+
1069
+ # 期間に含まれる分数を示す
1070
+ #
1071
+ # @return [String]
1072
+ #
1073
+ def minutes
1074
+ return nil unless @time
1075
+ return @time[MINUTE].to_s
1076
+ end
1077
+
1078
+ # 期間に含まれる秒数を示す
1079
+ #
1080
+ # @return [String]
1081
+ #
1082
+ def seconds
1083
+ return nil unless @time
1084
+ return @time[SECOND].to_s
1085
+ end
1086
+
1087
+ # 符号反転
1088
+ #
1089
+ # @return [When::TM::PeriodDuration]
1090
+ #
1091
+ def -@
1092
+ period = self.dup
1093
+ period.send(:date=, @date.map {|v| -v}) if @date
1094
+ period.send(:week=, @week.map {|v| -v}) if @week
1095
+ period.send(:time=, @time.map {|v| -v}) if @time
1096
+ period.send(:_duration)
1097
+ return period
1098
+ end
1099
+
1100
+ # 符号
1101
+ #
1102
+ # @return [Integer] 0 との比較により、負,0,正の値を返す
1103
+ #
1104
+ def sign
1105
+ @sign ||= _sign
1106
+ end
1107
+
1108
+ def _sign
1109
+ ((@week || @date || []) + (@time || [])).each do |v|
1110
+ return -1 if +v < 0
1111
+ end
1112
+ return +1
1113
+ end
1114
+ private :_sign
1115
+
1116
+ # 比較
1117
+ #
1118
+ # @param [When::TM::PeriodDuration] other
1119
+ #
1120
+ # @return [Integer] other との比較により、負,0,正の値を返す
1121
+ #
1122
+ def <=>(other)
1123
+ unless (@date && @date.size) == (other.date && other.date.size) &&
1124
+ (@week && @week.size) == (other.week && other.week.size) &&
1125
+ (@time && @time.size) == (other.time && other.time.size)
1126
+ raise ArgumentError, "PeriodDuration structure mismatch"
1127
+ end
1128
+
1129
+ (0...@week.size).each do |i|
1130
+ sgn = +@week[i] <=> +other.week[i]
1131
+ return sgn unless sgn == 0
1132
+ end if @week
1133
+
1134
+ (0...@date.size).each do |i|
1135
+ sgn = +@date[i] <=> +other.date[i]
1136
+ return sgn unless sgn == 0
1137
+ end if @date
1138
+
1139
+ (0...@time.size).each do |i|
1140
+ sgn = +@time[i] <=> +other.time[i]
1141
+ return sgn unless sgn == 0
1142
+ end if @time
1143
+
1144
+ return 0
1145
+ end
1146
+
1147
+ # オブジェクトの同値
1148
+ #
1149
+ # @param [比較先] other
1150
+ #
1151
+ # @return [Boolean]
1152
+ # [ true - 同値 ]
1153
+ # [ false - 非同値 ]
1154
+ #
1155
+ def ==(other)
1156
+ (self <=> other) == 0
1157
+ rescue
1158
+ false
1159
+ end
1160
+
1161
+ # 加算
1162
+ #
1163
+ # @param [When::TM::PeriodDuration] other
1164
+ # @param [その他] other 日時とみなす
1165
+ #
1166
+ # @return [WWhen::TM::PeriodDuration] (other が When::TM::PeriodDuration の場合)
1167
+ # @return [other と同じクラス] (other がその他の場合)
1168
+ #
1169
+ def +(other)
1170
+ other.kind_of?(When::TM::PeriodDuration) ? _plus(other, +1) : other + self
1171
+ end
1172
+
1173
+ # 減算
1174
+ #
1175
+ # @param [When::TM::PeriodDuration] other
1176
+ #
1177
+ # @return [When::TM::PeriodDuration]
1178
+ #
1179
+ def -(other)
1180
+ _plus(other, -1)
1181
+ end
1182
+
1183
+ # 乗算
1184
+ #
1185
+ # @param [Numeric] times
1186
+ #
1187
+ # @return [When::TM::PeriodDuration]
1188
+ #
1189
+ def *(times)
1190
+ period = self.dup
1191
+ period.send(:date=, @date.map {|v| v *= times; v.to_i==v.to_f ? v.to_i : v}) if @date
1192
+ period.send(:week=, @week.map {|v| v *= times; v.to_i==v.to_f ? v.to_i : v}) if @week
1193
+ period.send(:time=, @time.map {|v| v *= times; v.to_i==v.to_f ? v.to_i : v}) if @time
1194
+ period.send(:_duration)
1195
+ return period
1196
+ end
1197
+
1198
+ # 除算
1199
+ #
1200
+ # @param [Numeric] divisor
1201
+ #
1202
+ # @return [When::TM::PeriodDuration]
1203
+ #
1204
+ def /(divisor)
1205
+ self * (1.0 / divisor)
1206
+ end
1207
+
1208
+ # 文字列化
1209
+ #
1210
+ # @return [String]
1211
+ #
1212
+ def to_s
1213
+ period = 'P'
1214
+ if @week
1215
+ period += @week[0].abs.to_s + 'W'
1216
+ period += @week[1].abs.to_s + 'D' unless @week[1] == 0
1217
+ elsif @date
1218
+ (-@date.length..-1).each do |i|
1219
+ period += @date[i].abs.to_s + PRECISION_NAME[i+1][0..0] unless @date[i] == 0
1220
+ end
1221
+ end
1222
+ if @time
1223
+ period += 'T'
1224
+ (1..@time.length-1).each do |i|
1225
+ period += @time[i].abs.to_s + PRECISION_NAME[i][0..0] unless @time[i] == 0
1226
+ end
1227
+ end
1228
+ period = '-' + period if sign < 0
1229
+ period == 'P' ? 'P0D' : period
1230
+ end
1231
+
1232
+ #
1233
+ # When::TM::PeriodDuration への変換
1234
+ #
1235
+ # 単なるオブジェクトのコピー
1236
+ #
1237
+ # @return [When::TM::PeriodDuration]
1238
+ #
1239
+ def to_period_duration
1240
+ self.dup
1241
+ end
1242
+
1243
+ # オブジェクトの生成
1244
+ #
1245
+ # @overload initialize(date=nil, time=nil, week=nil)
1246
+ # @param [Array<Numeric>] date 期間の日付要素
1247
+ # @param [Array<Numeric>] time 期間の時刻要素
1248
+ # @param [Array<Numeric>] week 期間の週日要素
1249
+ #
1250
+ # @overload initialize(value, index, range=YEAR..SECOND)
1251
+ # @param [Numeric] value ndex に対応する桁での)時間間隔
1252
+ # @param [Numeric] index When で定義している分解能定数(YEAR, ... ,SECOND)
1253
+ # @param [Range] range 生成する桁の範囲
1254
+ #
1255
+ def initialize(*args)
1256
+ @options = (args[-1].kind_of?(Hash)) ? (args.pop.reject {|key,value| value == nil}) : {}
1257
+ if args[0].kind_of?(Numeric)
1258
+ _initialize_by_unit(*args)
1259
+ else
1260
+ @date, @time, @week = args
1261
+ end
1262
+ _duration
1263
+ end
1264
+
1265
+ private
1266
+
1267
+ #
1268
+ # 引数パターン2での初期化
1269
+ #
1270
+ def _initialize_by_unit(value, index, range=YEAR..SECOND)
1271
+ max = range.first
1272
+ min = range.last
1273
+ min += 1 if (range.exclude_end?)
1274
+ if (index < max)
1275
+ if (index > MONTH)
1276
+ max = index.floor
1277
+ else
1278
+ value *= 10**(max-index)
1279
+ index = max
1280
+ end
1281
+ elsif (index > min)
1282
+ if (index <= DAY)
1283
+ min = index.ceil
1284
+ else
1285
+ value *= 0.1**(index-min)
1286
+ index = min
1287
+ end
1288
+ end
1289
+ value = value.to_i unless value.kind_of?(Pair) || value.to_i != value.to_f
1290
+ @date = Array.new(1-max, 0) if (max <= DAY) && (index <= DAY)
1291
+ @time = Array.new(1+min, 0) if (min > DAY) && (index > DAY)
1292
+ if (index == WEEK)
1293
+ @week = [value, 0]
1294
+ @date[DAY-1] = 7 * value
1295
+ elsif (index <= DAY)
1296
+ @date[index-1] = value
1297
+ else
1298
+ @time[index] = value
1299
+ end
1300
+ end
1301
+
1302
+ #
1303
+ # 属性 @duration の計算
1304
+ #
1305
+ def _duration
1306
+ @duration = @sign = nil
1307
+
1308
+ if @time
1309
+ @duration = +@time[HOUR ] * Duration::HOUR
1310
+ @duration += +@time[MINUTE] * Duration::MINUTE if @time[MINUTE]
1311
+ @duration += +@time[SECOND] * Duration::SECOND if @time[SECOND]
1312
+ end
1313
+
1314
+ if @week
1315
+ @duration = +@week[0] * Duration::WEEK + +@week[1] * Duration::DAY + (@duration||0)
1316
+
1317
+ elsif @date
1318
+ date = @date.dup
1319
+ date.shift while date.first == 0
1320
+ case date.size
1321
+ when 0 ; @duration ||= 0
1322
+ when 1 ; @duration = +@date[DAY-1] * Duration::DAY + (@duration||0)
1323
+ else ; @duration = nil
1324
+ end
1325
+ end
1326
+
1327
+ if @duration
1328
+ length = @duration / Duration::DAY
1329
+ @to_day = length.to_i if length.to_i == length.to_f
1330
+ else
1331
+ extend NoDuration
1332
+ end
1333
+ end
1334
+
1335
+ # 加減算共通処理
1336
+ #
1337
+ # @param [When::TM::PeriodDuration] other
1338
+ # @param [Numeric] sgn +1, -1
1339
+ #
1340
+ # @return [When::TM::PeriodDuration]
1341
+ #
1342
+ def _plus(other, sgn)
1343
+ unless (@week && @week.size) == (other.week && other.week.size) &&
1344
+ (@date && @date.size) == (other.date && other.date.size) &&
1345
+ (@time && @time.size) == (other.time && other.time.size)
1346
+ raise ArgumentError, "PeriodDuration structure mismatch"
1347
+ end
1348
+ period = self.dup
1349
+ period.send(:week=, (0...@week.size).to_a.map {|i| @week[i] + sgn * other.week[i]}) if @week
1350
+ period.send(:date=, (0...@date.size).to_a.map {|i| @date[i] + sgn * other.date[i]}) if @date
1351
+ period.send(:time=, (0...@time.size).to_a.map {|i| @time[i] + sgn * other.time[i]}) if @time
1352
+ period.send(:_duration)
1353
+ return period
1354
+ end
1355
+ end
1356
+ end