when_exe 0.4.0 → 0.4.1

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