when_exe 0.3.7 → 0.3.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (108) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +210 -171
  3. data/bin/irb.rc +1 -0
  4. data/lib/when_exe.rb +78 -53
  5. data/lib/when_exe/basictypes.rb +27 -8
  6. data/lib/when_exe/calendarnote.rb +848 -805
  7. data/lib/when_exe/calendartypes.rb +110 -240
  8. data/lib/when_exe/coordinates.rb +2440 -2175
  9. data/lib/when_exe/core/compatibility.rb +1 -1
  10. data/lib/when_exe/core/duration.rb +13 -11
  11. data/lib/when_exe/core/extension.rb +38 -45
  12. data/lib/when_exe/ephemeris.rb +43 -14
  13. data/lib/when_exe/ephemeris/eclipse.rb +149 -0
  14. data/lib/when_exe/ephemeris/notes.rb +39 -7
  15. data/lib/when_exe/icalendar.rb +2 -6
  16. data/lib/when_exe/inspect.rb +1408 -1399
  17. data/lib/when_exe/parts/enumerator.rb +486 -477
  18. data/lib/when_exe/parts/resource.rb +1101 -1069
  19. data/lib/when_exe/parts/timezone.rb +6 -5
  20. data/lib/when_exe/region/babylonian.rb +405 -405
  21. data/lib/when_exe/region/bahai.rb +21 -61
  22. data/lib/when_exe/region/chinese/epochs.rb +81 -81
  23. data/lib/when_exe/region/chinese/twins.rb +51 -51
  24. data/lib/when_exe/region/christian.rb +7 -2
  25. data/lib/when_exe/region/coptic.rb +1 -1
  26. data/lib/when_exe/region/discordian.rb +9 -16
  27. data/lib/when_exe/region/french.rb +1 -1
  28. data/lib/when_exe/region/hanke_henry.rb +57 -0
  29. data/lib/when_exe/region/indian.rb +41 -73
  30. data/lib/when_exe/region/international_fixed.rb +97 -0
  31. data/lib/when_exe/region/iranian.rb +203 -203
  32. data/lib/when_exe/region/japanese.rb +13 -13
  33. data/lib/when_exe/region/japanese/eclipses.rb +1194 -0
  34. data/lib/when_exe/region/japanese/notes.rb +1482 -1383
  35. data/lib/when_exe/region/japanese/residues.rb +726 -721
  36. data/lib/when_exe/region/japanese/twins.rb +37 -37
  37. data/lib/when_exe/region/jewish.rb +2 -2
  38. data/lib/when_exe/region/pax.rb +60 -0
  39. data/lib/when_exe/region/positivist.rb +100 -0
  40. data/lib/when_exe/region/roman.rb +333 -334
  41. data/lib/when_exe/region/shire.rb +3 -20
  42. data/lib/when_exe/region/thai.rb +2 -2
  43. data/lib/when_exe/region/tibetan.rb +3 -3
  44. data/lib/when_exe/region/tranquility.rb +208 -0
  45. data/lib/when_exe/region/vanishing_leprechaun.rb +53 -0
  46. data/lib/when_exe/region/vietnamese.rb +4 -4
  47. data/lib/when_exe/region/world.rb +9 -13
  48. data/lib/when_exe/region/world_season.rb +89 -0
  49. data/lib/when_exe/region/zoroastrian.rb +4 -2
  50. data/lib/when_exe/tmobjects.rb +14 -4
  51. data/lib/when_exe/tmposition.rb +239 -81
  52. data/lib/when_exe/tmreference.rb +57 -28
  53. data/lib/when_exe/version.rb +1 -1
  54. data/link_to_online_documents +6 -3
  55. data/test/examples/today.rb +1 -1
  56. data/test/scripts.rb +23 -0
  57. data/test/scripts/2.ext.rb +169 -0
  58. data/test/scripts/2.rb +169 -0
  59. data/test/scripts/3.ext.rb +133 -0
  60. data/test/scripts/3.rb +134 -0
  61. data/test/scripts/4.ext.rb +112 -0
  62. data/test/scripts/4.min.rb +65 -0
  63. data/test/scripts/4.rb +136 -0
  64. data/test/scripts/5.ext.rb +78 -0
  65. data/test/scripts/5.rb +81 -0
  66. data/test/scripts/6.gcal.rb +131 -0
  67. data/test/scripts/6.rb +205 -0
  68. data/test/scripts/6.tz.rb +105 -0
  69. data/test/scripts/7.phase.rb +109 -0
  70. data/test/scripts/7.rb +95 -0
  71. data/test/scripts/7.term.rb +128 -0
  72. data/test/scripts/7.week.rb +84 -0
  73. data/test/scripts/8.ext.rb +61 -0
  74. data/test/scripts/8.rb +62 -0
  75. data/test/scripts/9.ext.rb +131 -0
  76. data/test/scripts/9.rb +130 -0
  77. data/test/scripts/chinese-luni-solar.rb +52 -0
  78. data/test/{examples → scripts}/geometric_complex.rb +41 -41
  79. data/test/scripts/geometric_complex.txt +18 -0
  80. data/test/scripts/korea.rb +59 -0
  81. data/test/scripts/thai-reviewed.txt +211 -0
  82. data/test/scripts/thai.rb +36 -0
  83. data/test/scripts/thai.txt +210 -0
  84. data/test/test.rb +7 -0
  85. data/test/test/basictypes.rb +22 -0
  86. data/test/test/coordinates.rb +2 -1
  87. data/test/test/ephemeris.rb +34 -2
  88. data/test/test/icalendar.rb +12 -0
  89. data/test/test/inspect.rb +37 -1
  90. data/test/test/parts.rb +4 -3
  91. data/test/test/region/armenian.rb +20 -0
  92. data/test/test/region/bahai.rb +58 -0
  93. data/test/test/region/chinese.rb +14 -3
  94. data/test/test/region/christian.rb +16 -35
  95. data/test/test/region/discordian.rb +20 -0
  96. data/test/test/region/indian.rb +30 -2
  97. data/test/test/region/japanese.rb +24 -0
  98. data/test/test/region/jewish.rb +2 -0
  99. data/test/test/region/m17n.rb +9 -0
  100. data/test/test/region/reforms.rb +121 -0
  101. data/test/test/region/residue.rb +17 -11
  102. data/test/test/region/shire.rb +58 -0
  103. data/test/test/region/swedish.rb +45 -0
  104. data/test/test/region/zoroastrian.rb +58 -0
  105. data/test/test/tmobjects.rb +74 -0
  106. data/test/test/tmposition.rb +468 -397
  107. data/when_exe.gemspec +2 -2
  108. metadata +49 -6
@@ -136,16 +136,12 @@ module When::V
136
136
  options[:exdate] = exdate
137
137
  When::Parts::Enumerator::Integrated.new(self, enumerators, *args)
138
138
  end
139
- if ::Object.const_defined?(:Date) && (args[0].kind_of?(Range) ? args[0].first : args[0]).kind_of?(::Date)
139
+ if ::Object.const_defined?(:Date) && ::Date.method_defined?(:+) && (args[0].kind_of?(Range) ? args[0].first : args[0]).kind_of?(::Date)
140
140
  enumerator.instance_eval %Q{
141
141
  alias :_succ_of_super :succ
142
142
  def succ
143
143
  result = _succ_of_super
144
- case result
145
- when When::TM::DateAndTime ; result.to_date_time
146
- when When::TM::CalDate ; result.to_date
147
- else ; result
148
- end
144
+ result.kind_of?(When::TimeValue) ? result.to_date_or_datetime : result
149
145
  end
150
146
  }
151
147
  end
@@ -1,1399 +1,1408 @@
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
9
- module Parts::Resource
10
-
11
- # option key for _m17n_form
12
- # @private
13
- FormOptions = [:precision, :camel, :method, :locale, :prefix]
14
-
15
- # When::Parts::Resource オブジェクトを分かりやすい文字列にして返します
16
- #
17
- # @return [String] 先頭部分を簡約表現にした IRI
18
- #
19
- def inspect
20
- return super unless @_pool
21
- expression = iri(true)
22
- expression == '' ? super : expression
23
- end
24
-
25
- #
26
- # オブジェクトの内容を Hash 化
27
- #
28
- # @param [String, Integer] options {When::TM::TemporalPosition#_to_h}に渡す
29
- # @param [Hash] options 下記のとおり
30
- # @option options [Numeric] :precision 指定があれば「イベント名(イベント時刻)」出力の時刻を指定の精度に丸める
31
- # @option options [Boolean] :camel true ならシンボルを camel case にする
32
- # @option options [Symbol] :method _to_hash_value で変換に用いるメソッド(:to_m17n, :iri など, 指定なしなら変換しない)
33
- # @option options [String] :locale 文字列化の locale(指定なしは M17nオブジェクトに変換)
34
- # @option options [Boolean] :prefix true ならIRI の先頭部分を簡約表現にする
35
- # @option options [Object] :その他 各クラス#_to_h を参照
36
- #
37
- # @return [Hash] (Whenモジュール内のクラスは文字列 or M17n化)
38
- #
39
- def to_h(options={})
40
- _m17n_form(_to_h(options), options.kind_of?(Hash) ? options : {})
41
- end
42
-
43
- #
44
- # オブジェクトの内容を JSON 化
45
- #
46
- # @param [Object] options #to_h を参照
47
- #
48
- # @return [String] to_h 結果を JSON文字列化したもの
49
- #
50
- def to_json(options={})
51
- options[:method] = :to_m17n unless options.key?(:method)
52
- JSON.dump(to_h(options))
53
- end
54
-
55
- #
56
- # _m17n_form のための要素生成
57
- # @private
58
- def _to_hash_value(options={})
59
- method = options[:method]
60
- if method.kind_of?(Symbol)
61
- if respond_to?(method, true) && method != :iri
62
- return send(method)
63
- elsif registered?
64
- return iri(options[:prefix])
65
- end
66
- end
67
- self
68
- end
69
-
70
- private
71
- #
72
- # 時間位置オブジェクトの内容を Hash 化
73
- #
74
- # @param [Object] options #to_h を参照
75
- #
76
- # @return [Hash]
77
- # 各クラスの HashProperty に列挙した属性のうち値が false/nil でないものを
78
- # 属性 => 値
79
- # とする Hash
80
- #
81
- def _to_h(options={})
82
- hash = {}
83
- self.class::HashProperty.each do |property|
84
- method, skip = property
85
- value = respond_to?(method, true) ? send(method) : skip
86
- hash[method] = value unless value == skip || value.class == skip
87
- end
88
- hash
89
- end
90
-
91
- #
92
- # element を 文字列(M17n), Numeric あるいはそれらの Hash や Array に変換したもの
93
- #
94
- # @param [Object] element 変換元
95
- # @param [Hash] options 下記の通り
96
- # @option options [Numeric] :precision 指定があれば「イベント名(イベント時刻)」出力の時刻を指定の精度に丸める
97
- # @option options [Boolean] :camel true ならシンボルを camel case にする
98
- # @option options [Symbol] :method _to_hash_value で変換に用いるメソッド(:to_m17n, :iri など, 指定なしなら変換しない)
99
- # @option options [String] :locale 文字列化の locale(指定なしは M17nオブジェクトに変換)
100
- # @option options [Boolean] :prefix true ならIRI の先頭部分を簡約表現にする
101
- #
102
- # @return [Hash, Array] 変換結果
103
- #
104
- # @note element.events のある日付は _event_form で変換する
105
- #
106
- def _m17n_form(element, options={})
107
- result = element.respond_to?(:_event_form) ? element._event_form(self, options[:precision]) :
108
- element.respond_to?(:_to_hash_value) ? element._to_hash_value(options) :
109
- element.respond_to?(:label) && element.label ? element.label :
110
- case element
111
- when Hash ; Hash[*(element.keys.inject([]) { |s, k|
112
- s + [_m17n_form(k, options), _m17n_form(element[k], options)]
113
- })]
114
- when Array ; element.map {|e| _m17n_form(e, options)}
115
- when Class ; When::Parts::Resource._path_with_prefix(element, options[:prefix])
116
- when Symbol ; options[:camel] ? element.to_s.split(/_/).map {|e| e.capitalize}.join('').to_sym : element
117
- when Numeric, FalseClass, TrueClass ; element
118
- else ; element.to_s
119
- end
120
- result = When::Locale.translate(result,options[:locale]) if options[:locale] && result.kind_of?(String)
121
- result
122
- end
123
- end
124
-
125
- module Coordinates
126
-
127
- class Pair
128
- #
129
- # to_h のための要素生成
130
- #
131
- # @param [Hash] options 下記のとおり
132
- # @option options [Symbol] :method :to_m17n なら to_s を返す、その他は self を返す
133
- #
134
- # @return [String, When::Coordinates::Pair]
135
- #
136
- # @private
137
- def _to_hash_value(options={})
138
- options[:method] == :to_m17n ? to_s : self
139
- end
140
-
141
- # When::Coordinates::Pair オブジェクトを分かりやすい文字列にして返します
142
- #
143
- # @return [String] to_s と同様
144
- #
145
- def inspect
146
- to_s
147
- end
148
- end
149
-
150
- class Residue
151
- # 多言語対応文字列化
152
- #
153
- # @return [When::BasicTypes::M17n]
154
- #
155
- def to_m17n
156
- return m17n(@remainder.to_s) unless label
157
- return label + "(#{difference})" unless @format
158
- (label[0...0] + @format) % [label, difference, difference+1]
159
- end
160
-
161
- # 文字列化
162
- #
163
- # @return [String]
164
- #
165
- def to_s
166
- return @remainder.to_s unless label
167
- return label.to_s + "(#{difference})" unless @format
168
- @format.to_s % [label.to_s, difference, difference+1]
169
- end
170
-
171
- #
172
- # week_included のための range の決定
173
- #
174
- # @return [Array<Range>]
175
- #
176
- # @private
177
- def _range_for_week_included(date, first, length, block_given=false)
178
- today = date.floor
179
- begun = today.succ & self >> first-1
180
- unless date.frame.equal?(begun.frame)
181
- begun = (date.frame ^ today).succ & self >> first-1
182
- middle = today
183
- end
184
- ended = begun.succ & self >> length-1
185
- middle && block_given ? [begun...middle, middle...ended] : [begun...ended]
186
- end
187
-
188
- #
189
- # week_included のためのコラムの生成
190
- #
191
- # @return [Array<Object>]
192
- #
193
- # @private
194
- def _column_for_week_included(base, range, opt, &block)
195
- range.inject([]) {|s,r| s + r.map { |date|
196
- yield(date, !opt.key?(:Range) || opt[:Range].include?(date.to_i) ? DAY : nil)
197
- }}
198
- end
199
- end
200
- end
201
-
202
- class CalendarNote::Week
203
-
204
- #
205
- # week_included のための range の決定
206
- #
207
- # @return [Array<Range>]
208
- #
209
- # @private
210
- def _range_for_week_included(date, first, length, block_given=false)
211
- begun = ended = nil
212
- if first <= 0
213
- it = enum_for(date.floor, :reverse)
214
- (1-first).times do
215
- begun = it.next
216
- end
217
- else
218
- it = enum_for(date.floor, :forward)
219
- first.times do
220
- begun = it.next
221
- end
222
- end
223
- it = enum_for(begun, :forward)
224
- (length+1).times do
225
- ended = it.next
226
- end
227
- [begun...ended]
228
- end
229
-
230
- #
231
- # week_included のためのコラムの生成
232
- #
233
- # @return [Array<Object>]
234
- #
235
- # @private
236
- def _column_for_week_included(base, range, opt, &block)
237
- count = 0
238
- limit = week(base)[:position][1]
239
- range.inject([]) {|s,r| s + r.map { |date|
240
- position = week(date, base)[:position][0]
241
- (position - count).times do
242
- yield(nil,nil)
243
- end
244
- count = position + 1
245
- yield(date, !opt.key?(:Range) || opt[:Range].include?(date.to_i) ? DAY : nil) if position < limit
246
- }}
247
- end
248
- end
249
-
250
- module TM
251
-
252
- class Calendar
253
-
254
- # TemporalPosition#strftime のためのデフォルト書式
255
- #
256
- # @return [String]
257
- #
258
- def strftime
259
- @strftime ||= '%Y-%m-%d'
260
- end
261
- end
262
-
263
- class TemporalPosition
264
-
265
- AMPM = ['AM', 'PM'].map {|half| When::Parts::Resource._instance('_m:CalendarFormats::' + half)}
266
- Format = {
267
- 'a' => ['%s', 'a'], 'A' => ['%s', 'A'], 'b' => ['%s', 'b'], 'B' => ['%s', 'B'],
268
- 'c' => When::Parts::Resource._instance('_m:CalendarFormats::DateTime'),
269
- 'C' => ['%02d', 'C'], 'd' => ['%02d', 'd'], 'D' => '%m/%d/%y', 'e' => ['%2d', 'd'],
270
- 'E' => ['%s', 'E'], 'F' => ['%s', 'F'], 'G' => ['%d', 'G'], 'g' => ['%02d', 'g'],
271
- 'h' => '%b', 'H' => ['%02d', 'H'], 'I' => ['%02d', 'I'], 'j' => ['%03d', 'j'],
272
- 'k' => ['%2d', 'H'], 'l' => ['%2d', 'I'], 'm' => ['%02d', 'm'], 'M' => ['%02d', 'M'],
273
- 'n' => '\n', 'p' => ['%s', 'p'], 'P' => ['%s', 'P'], 'q' => ['%01d', 'd'],
274
- 'r' => '%I:%M:%S %p', 'R' => '%H:%M', 's' => ['%d', 's'], 'S' => ['%02d', 'S'],
275
- 't' => '\t', 'T' => '%H:%M:%S', 'u' => ['%d', 'u'], 'U' => ['%02d', 'U'],
276
- 'V' => ['%02d', 'V'], 'w' => ['%d', 'w'], 'W' => ['%02d', 'W'],
277
- 'x' => When::Parts::Resource._instance('_m:CalendarFormats::Date'),
278
- 'X' => When::Parts::Resource._instance('_m:CalendarFormats::Time'),
279
- 'y' => ['%02d', 'y'], 'Y' => ['%4d', 'Y'], 'z' => ['%s', 'z'], 'Z' => ['%s', 'Z'],
280
- '+' => '%a %b %d %T %z %Y'
281
- }
282
-
283
- class << self
284
- # When::TM::TemporalPosition Class のグローバルな設定を行う
285
- #
286
- # @param [Hash] format strftime で用いる記号の定義
287
- #
288
- # @return [void]
289
- #
290
- # @note format の指定がない場合、format は Format(モジュール定数)と解釈する
291
- #
292
- def _setup_(format=nil)
293
- @format = format ? Format.merge(format) : Format
294
- end
295
-
296
- # 設定情報を取得する
297
- #
298
- # @return [Hash] 設定情報
299
- #
300
- def _setup_info
301
- {:format => format}
302
- end
303
-
304
- # strftime で用いる書式のハッシュ
305
- def format
306
- @format ||= Format
307
- end
308
- end
309
-
310
- # When::TM::TemporalPosition オブジェクトを分かりやすい文字列にして返します
311
- #
312
- # @return [String] to_s と同様
313
- #
314
- def inspect
315
- to_s
316
- end
317
-
318
- #
319
- # 暦法名
320
- #
321
- # @return [Array<Class>] Class 暦法のクラスオブジェクト
322
- #
323
- def calendar_name
324
- [self.class]
325
- end
326
-
327
- #
328
- # 時法名
329
- # @param [Boolean] prefix true ならIRI の先頭部分を簡約表現にする
330
- #
331
- # @return [Array<String>] String 時法の IRI
332
- #
333
- def clock_name(prefix=true)
334
- [clock.iri(prefix)]
335
- end
336
-
337
- #
338
- # 参照ラベル
339
- #
340
- # @return [When::BasicTypes::M17n]
341
- #
342
- def reference_label
343
- [When::BasicTypes::M17n.new(self.class.to_s.split(/::/)[-1])]
344
- end
345
-
346
- # 含まれる週
347
- #
348
- # @overload week_included(ord, wkst, opt, &block)
349
- # @param [Numeric, Range] ord 週の番号(default: 今週)
350
- # 今週を 0 とする週番号(Integer) または週番号の範囲(Range)
351
- # -1 - 先週
352
- # 0 - 今週
353
- # +1 - 来週
354
- # @param [String] wkst 週の開始曜日(defaultは 月曜)
355
- # @param [When::CalendarNote] wkst 暦注オブジェクト
356
- # @param [Array<When::CalendarNote, String>] wkst 暦注オブジェクトとそのイベントメソッド名
357
- # (暦注オブジェクトは、そのIRI文字列を指定しても良い)
358
- # @param [Hash] opt 下記の通り
359
- # @option opt [Range] :Range 上位繰り返し範囲(ユリウス通日...ユリウス通日)
360
- # @param [Block] block
361
- #
362
- # @note 引数 ord, wkst, opt はそのクラスで位置づけを判断するため、引数の順序は任意(省略も可)
363
- #
364
- # @return [Range] 含まれる週を範囲として表現する Range (block 指定なし)
365
- # @return [Array] 含まれる週の各日をブロックに渡した結果の Array (block 指定あり)
366
- #
367
- def week_included(*args, &block)
368
- begin
369
- first, length, wkst, opt = _range(args, 'MO')
370
- range = wkst._range_for_week_included(self, first, length, block_given?)
371
- rescue RangeError
372
- range = wkst._range_for_week_included(@frame ^ self, first, length)
373
- end
374
-
375
- return range.first unless block_given?
376
-
377
- wkst._column_for_week_included(self, range, opt, &block).unshift(yield(range[0].first, WEEK)).compact
378
- end
379
-
380
- # 含まれる月
381
- #
382
- # @overload month_included(ord, wkst, opt, block)
383
- # @param [Numeric, Range] ord 月の番号(default: 今月)
384
- # 今月を 0 とする月番号(Integer) または月番号の範囲(Range)
385
- # -1 - 先月
386
- # 0 - 今月
387
- # +1 - 来月
388
- # @param [String] wkst 週の開始曜日(defaultはなし)
389
- # @param [When::CalendarNote] wkst 暦注オブジェクト
390
- # @param [Array<When::CalendarNote, String>] wkst 暦注オブジェクトとそのイベントメソッド名
391
- # (暦注オブジェクトは、そのIRI文字列を指定しても良い)
392
- # @param [Hash] opt 下記の通り
393
- # @option opt [Range] :Range 上位繰り返し範囲(ユリウス通日...ユリウス通日)
394
- # @param [Block] block
395
- #
396
- # @note 引数 ord, wkst, opt はそのクラスで位置づけを判断するため、引数の順序は任意(省略も可)
397
- #
398
- # @return [Range] 含まれる月を範囲として表現する Range (block 指定なし)
399
- # @return [Array] 含まれる月の各日をブロックに渡した結果の Array (block 指定あり, wkst なし)
400
- # @return [Array<Array>] 含まれる月の各日をブロックに渡した結果の 七曜表(block 指定あり, wkst あり)
401
- #
402
- def month_included(*args, &block)
403
- first, length, wkst, opt = _range(args)
404
- if wkst
405
- (first...(first+length)).map {|i|
406
- begun = self.floor(MONTH,DAY) + When::TM::PeriodDuration.new([0,i,0])
407
- ended = begun + P1M
408
- ended = ended.prev until begun.cal_date[MONTH-1] == ended.cal_date[MONTH-1]
409
- if ended.to_i <= begun.to_i
410
- ended = begun
411
- loop do
412
- succ = ended.succ
413
- break unless succ.frame.equal?(begun.frame)
414
- ended = succ
415
- end
416
- end
417
- dates = [begun]
418
- loop do
419
- current = dates[-1].week_included(wkst)
420
- if current.last.to_i > ended.to_i
421
- dates[-1] = ended
422
- break (dates.map {|date| date.week_included(wkst, {:Range=>begun.to_i..ended.to_i}, &block)}).
423
- unshift(yield(begun, MONTH)).compact
424
- elsif wkst.kind_of?(When::Coordinates::Residue)
425
- dates << dates[-1] + wkst.duration
426
- else
427
- it = wkst.enum_for(dates[-1], :forward)
428
- begin
429
- date = it.next
430
- end while date.to_i == dates[-1].to_i
431
- date = date.to_cal_date unless date.instance_of?(TM::CalDate)
432
- dates << date
433
- end
434
- end
435
- }
436
- else
437
- begun = self.floor(MONTH,DAY) + When::TM::PeriodDuration.new([0, first, 0])
438
- ended = begun + When::TM::PeriodDuration.new([0, length, 0])
439
- loop do
440
- last = ended.prev
441
- break unless last.cal_date[MONTH-1] == ended.cal_date[MONTH-1]
442
- ended = last
443
- end
444
- if block_given?
445
- (begun...ended).map do |date|
446
- yield(date)
447
- end
448
- else
449
- begun...ended
450
- end
451
- end
452
- end
453
-
454
- # 含まれる年
455
- #
456
- # @overload month_included(ord, wkst, opt, block)
457
- # @param [Numeric, Range] ord 年の番号(default: 今年)
458
- # 今年を 0 とする年番号(Integer) または年番号の範囲(Range)
459
- # -1 - 先年
460
- # 0 - 今年
461
- # +1 - 来年
462
- # @param [String] wkst 週の開始曜日(defaultはなし)
463
- # @param [When::CalendarNote] wkst 暦注オブジェクト
464
- # @param [Array<When::CalendarNote, String>] wkst 暦注オブジェクトとそのイベントメソッド名
465
- # (暦注オブジェクトは、そのIRI文字列を指定しても良い)
466
- # @param [Hash] opt 下記の通り
467
- # @option opt [Range] :Range 上位繰り返し範囲(ユリウス通日...ユリウス通日)
468
- # @param [Block] block
469
- #
470
- # @note 引数 ord, wkst, opt はそのクラスで位置づけを判断するため、引数の順序は任意(省略も可)
471
- #
472
- # @return [Range] 含まれる年を範囲として表現する Range (block 指定なし)
473
- # @return [Array] 含まれる年の各日をブロックに渡した結果の Array (block 指定あり, wkst なし)
474
- # @return [Array<Array>] 含まれる年の各日をブロックに渡した結果の 七曜表(block 指定あり, wkst あり)
475
- #
476
- def year_included(*args, &block)
477
- first, length, wkst, opt = _range(args)
478
- if wkst
479
- (first...(first+length)).map {|i|
480
- begun = _force_euqal_year(i)
481
- ended = _force_euqal_year(i+1)
482
- current = begun
483
- result = [yield(begun, YEAR)]
484
- while current < ended do
485
- result << current.month_included(wkst, &block)
486
- current += P1M
487
- end
488
- result.compact
489
- }
490
- else
491
- begun = _force_euqal_year(first)
492
- ended = _force_euqal_year(first+length)
493
- if block_given?
494
- (begun...ended).map do |date|
495
- yield(date)
496
- end
497
- else
498
- begun...ended
499
- end
500
- end
501
- end
502
-
503
- # 指定の年初を探す
504
- def _force_euqal_year(diff)
505
- year = most_significant_coordinate * 1 + diff
506
- date = (self + When::TM::PeriodDuration.new([diff,0,0])).floor(YEAR,DAY)
507
- done = {}
508
- loop do
509
- case
510
- when date.most_significant_coordinate * 1 == year
511
- return date
512
- when date.most_significant_coordinate * 1 > year
513
- next_date = (date-When::P1Y).floor(YEAR,DAY)
514
- date = (date.to_i == next_date.to_i) ?
515
- (date-When::P1Y*2).floor(YEAR,DAY) :
516
- next_date
517
- else
518
- next_date = (date+When::P1Y).floor(YEAR,DAY)
519
- date = (date.to_i == next_date.to_i) ?
520
- (date+When::P1Y*2).floor(YEAR,DAY) :
521
- next_date
522
- end
523
- raise RangeError, "can't find target date: #{self} -> #{year}" if done.key?(date.to_i)
524
- done[date.to_i] = true
525
- end
526
- end
527
- private :_force_euqal_year
528
-
529
- # 範囲の取得
530
- def _range(args, wkst=nil)
531
- ord = 0
532
- opt = {}
533
- args.each do |arg|
534
- case arg
535
- when Integer, Range ; ord = arg
536
- when Hash ; opt = arg
537
- else ; wkst = arg
538
- end
539
- end
540
- wkst, method = wkst
541
- wkst = When::Coordinates::Residue.day_of_week(wkst) || When.CalendarNote(wkst) if wkst
542
- wkst = wkst[method] if method
543
- return ord, 1, wkst, opt if ord.kind_of?(Integer)
544
- length = ord.last - ord.first
545
- length += 1 unless ord.exclude_end?
546
- return ord.first, length, wkst, opt
547
- end
548
- private :_range
549
-
550
- #
551
- # 時間位置オブジェクトの暦注を取得し value を暦注の値 (String, When::BasicTypes::M17n or When::Coordinates::Residue)とする Hash で表現
552
- #
553
- # @param [String] options { :notes => String } という Hash の指定と等価
554
- # @param [Integer] options { :indices => Integer } という Hash の指定と等価
555
- # @param [Hash] options 下記のとおり
556
- # @option options [When::CalendarNote, String] :calendar_note 暦注を計算する暦注オブジェクトまたはそのIRI
557
- # @option options [Object] その他のキー {When::CalendarNote#notes} を参照
558
- #
559
- # @return [Array<Array<Hash{:note=>note, :value=>value}>>]
560
- # [ note [String, When::BasicTypes::M17n] 暦注名 ]
561
- # [ value [String, When::BasicTypes::M17n, When::Coordinates::Residue] 暦注の値 ]
562
- #
563
- def notes(options={})
564
- form_options = options.kind_of?(Hash) ? options : {}
565
- form_options[:method] = :to_m17n unless form_options.key?(:method)
566
- persistence = options.delete(:persistence) if options.kind_of?(Hash)
567
- retrieved = When::CalendarNote::NotesContainer.retrieve(persistence, self.to_i)
568
- return retrieved unless retrieved == false
569
- When::CalendarNote::NotesContainer.register(_m17n_form(_notes(options), form_options), persistence, self.to_i)
570
- end
571
-
572
- #
573
- # 時間位置オブジェクトの暦注を取得
574
- #
575
- # @param [String] options { :notes => String } という Hash の指定と等価
576
- # @param [Integer] options { :indices => Integer } という Hash の指定と等価
577
- # @param [Hash] options 下記のとおり
578
- # @option options [When::CalendarNote, String] :calendar_note 暦注を計算する暦注オブジェクトまたはそのIRI
579
- # @option options [Object] その他のキー {When::CalendarNote#notes} を参照
580
- #
581
- # @return [Array<Array<Hash{:note=>note, :value=>value}>>]
582
- # [ note [String, When::BasicTypes::M17n, When::Coordinates::Residue] 暦注名 ]
583
- # [ value [String, When::BasicTypes::M17n, When::Coordinates::Residue, When::TM::TemporalPosition] 暦注の値 ]
584
- #
585
- # @note
586
- # When::TM::TemporalPosition の場合、events[0] に暦注名の入ったその暦注に該当する日付である。
587
- # (例) Christian クラス easter を計算した場合、当該年の復活祭の日付オブジェクトが返る。
588
- # 暦注サブクラスの場合、要素が増えたり、:note の暦注要素の型が変わったりすることがある。
589
- #
590
- def _notes(options={})
591
- _calendar_note(options).notes(self, options)
592
- end
593
-
594
- #
595
- # 暦注の一致 or 不一致
596
- #
597
- # @param [String] options { :notes => String } または { :value => String } という Hash の指定と等価
598
- # (指定の notes が存在する場合は前者、しない場合は後者)
599
- # @param [Integer] options { :indices => Integer } という Hash の指定と等価
600
- # @param [Hash] options 下記のとおり
601
- # @option options [Object] :value 確認する暦注の値
602
- # @option options [Object] その他のキー {When::CalendarNote#notes} を参照
603
- #
604
- # @return [Boolean]
605
- # [ true - 暦注が一致 ]
606
- # [ false - 暦注が不一致 ]
607
- #
608
- def note?(options={})
609
- _calendar_note(options).note?(self, options)
610
- end
611
-
612
- # 指定の日時が指定イベントに該当するか?
613
- #
614
- # @overload is?(event=nil, options={})
615
- # @param [String] event options={:notes=>String} または {:notes=>String} または {:value=>String} という指定と等価
616
- # (指定の event が存在する場合は前者、指定の notes が存在する場合は中央、しない場合は後者)
617
- # @param [Integer] event options={ :indices=> Integer } という指定と等価
618
- # @param [Hash] options 下記のとおり
619
- # @option options [When::CalendarNote or String] :calendar_note 該当判断に用いる CalendarNoteオブジェクトまたはその IRI
620
- # @option options [String] :event 確認するイベント名
621
- # @option options [Object] :value 確認する暦注の値
622
- # @option options [Object] その他のキー {When::CalendarNote#notes} を参照
623
- #
624
- # @return [Boolean]
625
- # [ true - 該当する ]
626
- # [ false - 該当しない ]
627
- #
628
- def is?(*args)
629
- options = args.last.kind_of?(Hash) ? args.pop.dup : {}
630
- note = _calendar_note(options)
631
- event = args.first || options.delete(:event) || note.event
632
- return note.note?(self, options) unless options.empty?
633
- return note.note?(self, event) unless event.to_s =~ /\A([^\d]+)/ && note.respond_to?($1.downcase)
634
- return note.include?(self, event)
635
- end
636
-
637
- #
638
- # 時間位置オブジェクトの内容を Hash
639
- #
640
- # @param [String] options { :notes => String } という Hash の指定と等価
641
- # @param [Integer] options { :indices => Integer } という Hash の指定と等価
642
- # @param [Hash] options 下記のとおり
643
- # @option options [When::CalendarNote, String] :calendar_note 暦注を計算する暦注オブジェクトまたはそのIRI
644
- # @option options [Object] その他のキー {When::CalendarNote#notes} を参照
645
- #
646
- # @return [Hash]
647
- # - :sdn 日の通し番号 - ユリウス通日(Integer)
648
- # - :calendar calendar_name の結果 - Array<暦法または暦年代(, 付属情報..)>
649
- # - :notes Hash (の Array (の Array)) - _notes(options)
650
- # clock が定義されている場合、さらに下記も出力する
651
- # - :clock 時計(When::Parts::Timezone::Base)
652
- # - :clk_time to_clock_time の結果 - ( 日, 時, 分, 秒 )
653
- # - :dynamical dynamical_time /
654
- # - :universal universal_time / 秒
655
- #
656
- def _to_h(options={})
657
- hash = super.update({
658
- :sdn => to_i,
659
- :calendar => calendar_name,
660
- :notes => _notes(options)
661
- })
662
-
663
- hash.update({
664
- :clock => clock,
665
- :clk_time => to_clock_time,
666
- :dynamical => dynamical_time * clock.second,
667
- :universal => universal_time * clock.second
668
- }) if clock
669
- hash
670
- end
671
-
672
- # 多言語対応文字列化 - When.exe Standard Representation により多言語対応文字列化する
673
- #
674
- # @overload to_m17n()
675
- #
676
- # @return [When::BasicTypes::M17n]
677
- #
678
- def to_m17n(*args)
679
- return m17n(I[@indeterminated_position]) if [Unknown, Max, Min].include?(@indeterminated_position)
680
- return m17n(_to_s)
681
- end
682
- # @private
683
- alias :_to_s :to_s
684
-
685
- # 文字列化 - When.exe Standard Representation により文字列化する
686
- #
687
- # @overload to_s()
688
- #
689
- # @return [String]
690
- #
691
- def to_s(*args)
692
- to_m17n(*args).to_s
693
- end
694
-
695
- # caret 付きの frame 名
696
- #
697
- # @return [String]
698
- #
699
- # @note 暦年代付きかまたは frame がグレゴリオ暦の場合は空文字列を返す
700
- #
701
- def caret_frame
702
- prefix = When::Parts::Resource.base_uri + 'CalendarTypes/'
703
- path = frame.iri
704
- return '' if @calendar_era_name || path == prefix + 'Gregorian'
705
- path = path[prefix.length..-1] if path.index(prefix) == 0
706
- '^^' + path
707
- end
708
-
709
- # 指定の書式による多言語対応文字列化 - pattern で指定した書式で多言語対応文字列化する
710
- #
711
- # @param [When::BasicTypes::M17n] pattern 書式
712
- # @param [String, Array<String>] locale 文字列化を行う locale の指定(デフォルト : オブジェクト生成時に保持している locale すべて)
713
- #
714
- # @return [When::BasicTypes::M17n]
715
- #
716
- def strftime(pattern=@frame.strftime, locale=nil)
717
- pattern = m17n([pattern]*self.keys.length, nil, nil, {:locale=>self.keys}) if pattern.instance_of?(String)
718
- pattern._printf([], locale) do |k, *t|
719
- _strftime(k, pattern, [''])
720
- end
721
- end
722
-
723
- # strftime で扱う項の値を取得する
724
- #
725
- # @param [String] designator 項目名
726
- # @param [String] locale 文字列化を行う場合の locale の指定(デフォルト to_s(代表値))
727
- # @param [Integer] d 日付が'年月日'、時刻が'時分秒'でない表現のための桁位置変更指示
728
- # [ 年月に付く場合 - 大きいほうに位置をずらす ]
729
- # [ 分秒に付く場合 - 小さいほうに位置をずらす ]
730
- # @param [Integer] e 月の省略名の文字数
731
- #
732
- # @return [designator に依存]
733
- #
734
- def _term(designator, locale=nil, d=0, e=3)
735
- designator = When::Locale.translate(designator,locale)
736
- case designator
737
- # 現在のロケールにおける曜日の省略名
738
- when 'a' ; When.Resource('_co:Common::Abbr_Day')[to_i % 7].translate(locale)
739
- # 現在のロケールにおける曜日の完全な名前
740
- when 'A' ; When.Resource('_co:Common::Week')[to_i % 7].label.translate(locale)
741
- when 'b' ; (name(MONTH-d).translate(locale))[/\A.{1,#{e}}/] # 現在のロケールにおける月の省略名
742
- when 'B' ; (name(MONTH-d).translate(locale)) # 現在のロケールにおける月の完全な名前
743
- when 'C' ; year(d).div(100) # 世紀 (西暦年の上 2 桁)
744
- when 'd' ; day(d) # 月内通算日
745
- when 'E' ; Array(calendar_era_name)[0].translate(locale)# 年号
746
- when 'F' ; floor(DAY).to_m17n.translate(locale) # ISO 8601 形式の日付フォーマット
747
- when 'G' ; cwyear(d) # ISO 8601 週単位表記の年
748
- when 'g' ; cwyear(d) % 100 # ISO 8601 週単位表記の年の下2桁
749
- when 'H' ; hour(d) # 24 時間表記での時
750
- when 'I' ; (hour(d)-1) % 12 + 1 # 12 時間表記での時
751
- when 'j' ; yday(d) # 年の初めから通算の日数
752
- when 'm' ; month(d) #
753
- when 'M' ; minute(d) #
754
- when 'p' ; (AMPM[hour(d).to_i.div(12)].translate(locale)).upcase # 現在のロケールにおける「午前」「午後」に相当する文字列
755
- when 'P' ; (AMPM[hour(d).to_i.div(12)].translate(locale)).downcase # 前項を小文字で表記
756
- when 's' ; universal_time / Duration::SECOND # 紀元 (1970-01-01T00:00:00Z) からの秒数
757
- when 'S' ; second(d) # (10 進数表記)
758
- when 'u' ; cwday # 週の何番目の日か(月曜日を 1 とする)
759
- when 'U' ; yweek(6, 7, d) # 年の初めからの通算の週番号(日曜日始まり)
760
- when 'V' ; cweek(d) # ISO 8601 形式での年の始めからの週番号
761
- when 'w' ; wday # 週の何番目の日 か(日曜日を 0 とする)
762
- when 'W' ; yweek(0, 7, d) # 年の初めからの通算の週番号(月曜日始まり)
763
- when 'y' ; year(d) % 100 # 西暦の下2桁 (世紀部分を含まない年)
764
- when 'Y' ; year(d) # 世紀部分を含めた ( 4 桁の) 西暦年
765
- when 'z' ; clock.to_basic # +hhmm -hhmm の形式のタイムゾーン
766
- when 'Z' ; When::Locale.translate(clock.tzname[0],locale) # タイムゾーンまたはゾーン名または省略名
767
- else ; designator
768
- end
769
- end
770
-
771
- private
772
-
773
- # 指定の書式による多言語対応文字列化
774
- #
775
- # @param [String] locale 文字列化を行う locale
776
- # @param [When::BasicTypes::M17n] pattern 書式
777
- #
778
- # @return [Array] 書式と文字列化項目からなる配列
779
- #
780
- def _strftime(locale, pattern, t)
781
- format, *terms = t
782
- pattern = pattern.translate(locale) if pattern.kind_of?(When::BasicTypes::M17n)
783
- pattern.scan(/(%[O\d]*(?:\.(\d+))?.)|(.)/) do |c,e,s|
784
- case c
785
- when /\A%%/
786
- format += '%%'
787
- when /\A%/
788
- action = TemporalPosition.format[c[-1..-1]]
789
- case action
790
- when Array
791
- format += action[0]
792
- terms << _term(action[1], locale, c[1..-2].to_i, e||3)
793
- when String
794
- action = action.translate(locale) if action.kind_of?(When::BasicTypes::M17n)
795
- if (action =~ /%/)
796
- format, *terms = _strftime(locale, action, [format] + terms)
797
- else
798
- format += action
799
- end
800
- end
801
- else
802
- format += s
803
- end
804
- end
805
- [format] + terms
806
- end
807
-
808
- #
809
- # 使用する When::CalendarNote を決定する
810
- #
811
- # options に副作用があることに注意
812
- #
813
- def _calendar_note(options)
814
- calendar_note = options.delete(:calendar_note) if options.kind_of?(Hash)
815
- calendar_note ||= @frame ? @frame.note : 'JulianDay'
816
- When.CalendarNote(calendar_note)
817
- end
818
- end
819
-
820
- class JulianDate
821
-
822
- # 多言語対応文字列化 - ユリウス日を多言語対応文字列化する
823
- #
824
- # @param [Integer] precision どの桁まで多言語対応文字列化するか、分解能で指定する
825
- #
826
- # @return [When::BasicTypes::M17n]
827
- #
828
- def to_m17n(precision=@precision)
829
- return m17n(to_s(precision))
830
- end
831
-
832
- # 文字列化 - ユリウス日を文字列化する
833
- #
834
- # @param [Integer] precision どの桁まで多言語対応文字列化するか、分解能で指定する
835
- #
836
- # @return [String]
837
- #
838
- def to_s(precision=@precision)
839
- coordinate = (precision <= When::DAY) ? to_i : to_f
840
- coordinate.to_s
841
- end
842
- end
843
-
844
- class ClockTime
845
-
846
- # 要素の多言語対応文字列化
847
- #
848
- # @param [Integer] index 多言語対応文字列化する要素の指定
849
- # @param [When::BasicTypes::M17n] format 多言語対応文字列化の書式
850
- #
851
- # @return [When::BasicTypes::M17n]
852
- #
853
- def name(index, format=nil)
854
- digit = _digit(index) {|digit| digit > DAY}
855
- coordinate = @clk_time[digit]
856
- return m17n(format % coordinate) if format
857
-
858
- indices = @frame.indices[digit-1]
859
- if indices
860
- trunk = indices.trunk
861
- branch = indices.branch
862
- end
863
- format = branch ? m17n("%02d:") : "%02d"
864
- return m17n(format % coordinate) unless trunk
865
- trunk = trunk[coordinate * 1]
866
- return m17n(trunk) unless branch
867
- return trunk.prefix(branch[coordinate * 0])
868
- end
869
-
870
- # 多言語対応文字列化 - When.exe Standard Representation により多言語対応文字列化する
871
- #
872
- # @param [Integer] precision どの桁まで多言語対応文字列化するか、分解能で指定する
873
- #
874
- # @return [When::BasicTypes::M17n]
875
- #
876
- def to_m17n(precision=@precision)
877
- time = m17n('T' + _time_to_s(precision))
878
- if @frame
879
- time += @frame.zone unless Clock.is_local_time_set? && @frame.equal?(Clock.local_time)
880
- end
881
- return time
882
- end
883
-
884
- # 文字列化 - When.exe Standard Representation により文字列化する
885
- #
886
- # @param [Integer] precision どの桁まで多言語対応文字列化するか、分解能で指定する
887
- #
888
- # @return [String]
889
- #
890
- def to_s(precision=@precision)
891
- time = 'T' + _time_to_s(precision)
892
- if @frame
893
- time += @frame.zone unless Clock.is_local_time_set? && @frame.equal?(Clock.local_time)
894
- end
895
- return time
896
- end
897
-
898
- #
899
- #
900
- # @param [Integer] d 時刻が'時分秒'でない表現のための桁位置変更指示(小さいほうに位置をずらす)
901
- #
902
- # @return [Numeric] 自身の「時」
903
- #
904
- def hour(d=0)
905
- @clk_time[HOUR+d]
906
- end
907
-
908
- #
909
- #
910
- # @param [Integer] d 時刻が'時分秒'でない表現のための桁位置変更指示(小さいほうに位置をずらす)
911
- #
912
- #
913
- # @return [Numeric] 自身の「分」
914
- #
915
- def minute(d=0)
916
- @clk_time[MINUTE+d]
917
- end
918
- alias :min :minute
919
-
920
- #
921
- #
922
- # @param [Integer] d 時刻が'時分秒'でない表現のための桁位置変更指示(小さいほうに位置をずらす)
923
- #
924
- #
925
- # @return [Numeric] 自身の「秒」
926
- #
927
- def second(d=0)
928
- @clk_time[SECOND+d]
929
- end
930
- alias :sec :second
931
-
932
- #protected
933
- #
934
- # 時間帯以外の部分の文字列化
935
- #
936
- # @param [Integer] precision どの桁まで多言語対応文字列化するか、分解能で指定する
937
- #
938
- # @return [String]
939
- #
940
- # @private
941
- def _time_to_s(precision=@precision)
942
- terms = []
943
- format = ''
944
- format += Pair::DL2[@clk_time[0] * 0] || ':' if @frame.pair[0] || @clk_time[0].kind_of?(Pair)
945
-
946
- # 時分
947
- digits = [@clk_time.length-2, precision].min
948
- if digits > 0
949
- terms += @clk_time[1..-1]
950
- format += "%02d:" * digits
951
- format = format[0..-2] if precision == digits
952
- end
953
-
954
- # 秒
955
- digits = [precision - @clk_time.length + 1, STRING-SECOND].min
956
- if digits == 0
957
- format += "%02d"
958
- elsif digits > 0
959
- factor = 10**digits
960
- terms[-1] = ((@clk_time[-1] + 1E-6) * factor).floor.to_f / factor # 切り捨て(10で割る丸めガードあり)
961
- format += "%02.#{digits}f"
962
- end
963
-
964
- # 結果
965
- time = Pair._format([format] + terms)
966
- time.sub(/([^\d])(\d)\./, '\10\2.')
967
- end
968
-
969
- #
970
- # to_h のための要素生成
971
- # @private
972
- def _to_hash_value(options={})
973
- clk_time.map {|e| _m17n_form(e, options) }
974
- end
975
- end
976
-
977
- class CalDate
978
-
979
- #
980
- # 暦法名
981
- #
982
- # @return [Array] ( name, epoch, reverse, go back )
983
- # - name 暦法または暦年代 ({When::TM::Calendar}, {When::TM::CalendarEra})
984
- # - epoch 暦元 (Integer)
985
- # - reverse 暦年の順序 (Boolean)
986
- # [ false, nil 昇順 ]
987
- # [ true 降順 ]
988
- # - go back 参照イベントより前の暦日か(Boolean)
989
- # [ false, nil 否 ]
990
- # [ true 然り ]
991
- #
992
- def calendar_name
993
- void, epoch, reverse, back = @calendar_era_name
994
- name = [@calendar_era || @frame, epoch, reverse, back]
995
- name.pop until name[-1]
996
- return name
997
- end
998
-
999
- #
1000
- # 参照ラベル
1001
- #
1002
- # @return [When::BasicTypes::M17n]
1003
- #
1004
- def reference_label
1005
- return @calendar_era.hierarchy.map {|e| e.label} if @calendar_era
1006
- return [@frame.label] if @frame.label
1007
- [When::BasicTypes::M17n.new(@frame.class.to_s.split(/::/)[-1])]
1008
- end
1009
-
1010
- #
1011
- # Hash
1012
- #
1013
- # @param [String] options { :notes => String } という Hash の指定と等価
1014
- # @param [Integer] options { :indices => Integer } という Hash の指定と等価
1015
- # @param [Hash] options 下記のとおり
1016
- # @option options [When::CalendarNote, String] :calendar_note 暦注を計算する暦注オブジェクトまたはそのIRI
1017
- # @option options [Object] その他のキー {When::CalendarNote#notes} を参照
1018
- #
1019
- # @return [Hash]
1020
- # - :calendar calendar_name の結果 ( name, epoch, reverse, go back )
1021
- # - name 暦法または暦年代 ({When::TM::Calendar}, {When::TM::CalendarEra})
1022
- # - epoch 暦元 (Integer)
1023
- # - reverse 暦年の順序 (Boolean)
1024
- # [ false, nil 昇順 ]
1025
- # [ true 降順 ]
1026
- # - go back 参照イベントより前の暦日か(Boolean)
1027
- # [ false, nil 否 ]
1028
- # [ true 然り ]
1029
- # - :cal_date cal_date の内容 (year, month, day)
1030
- # [ year - ({Numeric}) ]
1031
- # [ month - ({Numeric}) ]
1032
- # [ day - ({Numeric}) ]
1033
- # - :clk_time to_clock_time の結果 ( 日, 時, 分, 秒 )
1034
- # - :notes Hash (の Array (の Array)) - _notes(options)
1035
- #
1036
- def _to_h(options={})
1037
- super.update({:cal_date=>@cal_date})
1038
- end
1039
-
1040
- # 要素の多言語対応文字列化
1041
- #
1042
- # @param [Integer] index 多言語対応文字列化する要素の指定
1043
- # @param [When::BasicTypes::M17n] format 多言語対応文字列化の書式
1044
- #
1045
- # @return [When::BasicTypes::M17n]
1046
- #
1047
- def name(index, format=nil)
1048
- digit = _digit(index) {|digit| digit <= DAY}
1049
- coordinate = @cal_date[digit-1]
1050
- return m17n(format % coordinate) if format
1051
-
1052
- indices = @frame.indices[digit-1]
1053
- if indices
1054
- trunk = indices.trunk
1055
- branch = indices.branch
1056
- end
1057
- format = branch ? m17n("%02d-") : "%02d"
1058
- return m17n(format % coordinate) unless trunk
1059
- trunk = trunk[coordinate * 1]
1060
- return m17n(trunk) unless branch
1061
- return trunk.prefix(branch[coordinate * 0||0])
1062
- end
1063
-
1064
- #
1065
- #
1066
- # @param [Integer] d 日付が'年月日'でない表現のための桁位置変更指示(大きいほうに位置をずらす)
1067
- #
1068
- # @return [Numeric] 自身の「日」
1069
- #
1070
- def day(d=0)
1071
- @cal_date[DAY-1-d]
1072
- end
1073
-
1074
- # 月内通日
1075
- #
1076
- # @param [Integer] d 日付が'年月日'でない表現のための桁位置変更指示(大きいほうに位置をずらす)
1077
- #
1078
- # @return [Numeric] 自身の「月内通日」(1始まり)
1079
- #
1080
- def mday(d=0)
1081
- to_i - floor(MONTH-d).to_i + 1
1082
- end
1083
-
1084
- # 年内通日
1085
- #
1086
- # @param [Integer] d 日付が'年月日'でない表現のための桁位置変更指示(大きいほうに位置をずらす)
1087
- #
1088
- # @return [Numeric] 自身の「年内通日」(1始まり)
1089
- #
1090
- def yday(d=0)
1091
- to_i - floor(YEAR-d).to_i + 1
1092
- end
1093
-
1094
- # 七曜
1095
- #
1096
- # @return [Numeric] 自身の「七曜」(日曜 0 始まり)
1097
- #
1098
- def wday
1099
- (to_i + 1) % 7
1100
- end
1101
-
1102
- # 七曜(暦週)
1103
- #
1104
- # @return [Numeric] 自身の「七曜」(月曜 1 始まり)
1105
- #
1106
- def cwday
1107
- (to_i % 7) + 1
1108
- end
1109
-
1110
- # 暦週
1111
- #
1112
- # @param [Integer] d 日付が'年月日'でない表現のための桁位置変更指示(大きいほうに位置をずらす)
1113
- #
1114
- # @return [Numeric] 自身の「暦週」
1115
- #
1116
- def cweek(d=0)
1117
- [1,0,-1].each do |i|
1118
- start = ((self + PeriodDuration.new(i, YEAR-d)).floor(YEAR-d,DAY) + PeriodDuration.new(4, DAY)) & Residue.new(0,7,-1)
1119
- return ((to_i - start.to_i).div 7) + 1 if self >= start
1120
- end
1121
- raise IndexError, 'Cannot decide year number'
1122
- end
1123
-
1124
- # 月内通週
1125
- #
1126
- # @param [Integer] w 週の最初の曜日(0:月,.., 6:日)
1127
- # @param [Integer] m 一週間の日数
1128
- # @param [Integer] d 日付が'年月日'でない表現のための桁位置変更指示(大きいほうに位置をずらす)
1129
- #
1130
- # @return [Numeric] 自身の「月内通週」(その月に完全に含まれる最初の週を1とする)
1131
- #
1132
- def mweek(w=6, m=7, d=0)
1133
- 1 + (to_i - (floor(MONTH-d,DAY) & Residue.new(w,m)).to_i).div(7)
1134
- end
1135
-
1136
- # 年内通週
1137
- #
1138
- # @param [Integer] w 週の最初の曜日(0:月,.., 6:日)
1139
- # @param [Integer] m 一週間の日数
1140
- # @param [Integer] d 日付が'年月日'でない表現のための桁位置変更指示(大きいほうに位置をずらす)
1141
- #
1142
- # @return [Numeric]
1143
- # 自身の「年内通週」(その年に完全に含まれる最初の週を1とする)
1144
- #
1145
- def yweek(w=6, m=7, d=0)
1146
- 1 + (to_i - (floor(YEAR-d,DAY) & Residue.new(w,m)).to_i).div(7)
1147
- end
1148
-
1149
- #
1150
- #
1151
- # @param [Integer] d 日付が'年月日'でない表現のための桁位置変更指示(大きいほうに位置をずらす)
1152
- #
1153
- # @return [Numeric] 自身の「月」
1154
- #
1155
- def month(d=0)
1156
- @cal_date[MONTH-1-d]
1157
- end
1158
- alias :mon :month
1159
-
1160
- # 年内通月
1161
- #
1162
- # @param [Integer] d1 日付が'年月日'でない表現のための桁位置変更指示-年用(大きいほうに位置をずらす)
1163
- # @param [Integer] d2 日付が'年月日'でない表現のための桁位置変更指示-月用(大きいほうに位置をずらす)
1164
- #
1165
- # @return [Numeric] 自身の「年内通月」(1始まり)
1166
- #
1167
- def ymon(d1=0, d2=0)
1168
- current = floor(YEAR-d1, MONTH-d2)
1169
- @frame._length(@cal_date[(YEAR-1-d1)...(MONTH-1-d2)]).times do |i|
1170
- return i+1 if current == self
1171
- current = current.succ
1172
- end
1173
- raise IndexError, 'Cannot decide month number'
1174
- end
1175
-
1176
- #
1177
- #
1178
- # @param [Integer] d 日付が'年月日'でない表現のための桁位置変更指示(大きいほうに位置をずらす)
1179
- #
1180
- # @return [Numeric] 自身の「年」
1181
- #
1182
- def year(d=0)
1183
- @cal_date[YEAR-1-d]
1184
- end
1185
-
1186
- # 暦週の年
1187
- #
1188
- # @param [Integer] d 日付が'年月日'でない表現のための桁位置変更指示(大きいほうに位置をずらす)
1189
- #
1190
- # @return [Numeric] 自身の「暦週の年」
1191
- #
1192
- def cwyear(d=0)
1193
- [1,0,-1].each do |i|
1194
- start = ((self + PeriodDuration.new(i, YEAR-d)).floor(YEAR-d,DAY) + PeriodDuration.new(4, DAY)) & Residue.new(0,7,-1)
1195
- return year(d)+i if self >= start
1196
- end
1197
- raise IndexError, 'Cannot decide year number'
1198
- end
1199
-
1200
- # 多言語対応文字列化 - When.exe Standard Representation により多言語対応文字列化する
1201
- #
1202
- # @param [Integer] precision どの桁まで多言語対応文字列化するか、分解能で指定する
1203
- # @param [false] round 常に切り捨てる(DateAndTimeとの互換性のためのダミーの引数)
1204
- #
1205
- # @return [When::BasicTypes::M17n]
1206
- #
1207
- def to_m17n(precision=@precision, round=false)
1208
- date = m17n(_date_to_s(precision))
1209
- return date unless @calendar_era
1210
- return _parent_labels.inject(m17n(@calendar_era_name[0])) {|era_name, parent|
1211
- era_name.prefix(m17n(parent) + '::')
1212
- } + date
1213
- end
1214
-
1215
- # 文字列化 - When.exe Standard Representation により文字列化する
1216
- #
1217
- # @param [Integer] precision どの桁まで多言語対応文字列化するか、分解能で指定する
1218
- # @param [false] round 常に切り捨てる(DateAndTimeとの互換性のためのダミーの引数)
1219
- #
1220
- # @return [String]
1221
- #
1222
- def to_s(precision=@precision, round=false)
1223
- date = _date_to_s(precision)
1224
- return date unless @calendar_era
1225
- return _parent_labels.inject(@calendar_era_name[0].to_s) {|era_name, parent|
1226
- parent.to_s + '::' + era_name
1227
- } + date
1228
- end
1229
-
1230
- # event を 文字列化 - 日時で与えられた event を文字列化する
1231
- #
1232
- # @param [When::TM::TemporalPosition] other 時系の歩度を比較する基準(nilは比較しない)
1233
- # @param [Numeric] round_precision イベント名(イベント)出力の場合の時刻の丸め位置(nilなら丸めない)
1234
- #
1235
- # @return [String]
1236
- #
1237
- # @note
1238
- # events 配列なし - 日時をそのまま文字列化
1239
- # 日時の精度が日より細かい - イベント名(イベント時刻)
1240
- # 日時の精度が日 - イベント名(当日までの経過日数)
1241
- #
1242
- def _event_form(other=nil, round_precision=nil)
1243
- return to_m17n unless events
1244
- return events[0] + '(' + _clk_time_for_inspect(round_precision).to_s(round_precision || precision)[/[:*=0-9]+/] + ')' if precision > When::DAY
1245
- return events[0] unless other
1246
- other = JulianDate.dynamical_time(other.dynamical_time,
1247
- {:time_standard=>time_standard}) unless time_standard.rate_of_clock == other.time_standard.rate_of_clock
1248
- events[0] + '(' + (other.to_i - to_i).to_s + ')'
1249
- end
1250
-
1251
- private
1252
-
1253
- # 日付の年号に曖昧性がある場合の親年号の label Array
1254
- #
1255
- # @return [Array<String>]
1256
- #
1257
- def _parent_labels
1258
- return [] unless (area = When::TM::CalendarEra[nil]) &&
1259
- (period = area[nil])
1260
- list = []
1261
- era = @calendar_era
1262
- while (labels = period[era.label.to_s]) &&
1263
- (epoch = labels[era.epoch_year]) &&
1264
- (epoch.size > 1) &&
1265
- (parent = era.parent).respond_to?(:epoch_year)
1266
- list << parent.label
1267
- era = parent
1268
- end
1269
- list
1270
- end
1271
-
1272
- # 日付の年号以外の部分を文字列化する
1273
- #
1274
- # @param [Integer] precision どの桁まで多言語対応文字列化するか、分解能で指定する
1275
- #
1276
- # @return [String]
1277
- #
1278
- def _date_to_s(precision)
1279
- # 準備
1280
- precision = [precision, 1 - @cal_date.length].max
1281
- precision = [precision, DAY].min
1282
- terms = []
1283
- ext_dg = [(@extra_year_digits||1).to_i, 0].max
1284
- year_dg = @frame.indices.length <= 2 ? 4 : 2
1285
-
1286
- #
1287
- year_by_epoch = @cal_date[0]
1288
- if @calendar_era_name
1289
- era, epoch, reverse = @calendar_era_name
1290
- year_in_term = reverse ? -year_by_epoch : year_by_epoch
1291
- year_by_calendar = epoch + year_by_epoch if epoch
1292
- terms << year_in_term
1293
- format = (0..99) === (year_in_term * 1) ? "%02d." : "%0#{year_dg}d."
1294
- if year_by_calendar && year_by_calendar != year_in_term
1295
- terms << (year_by_calendar * 1)
1296
- format += "(%0#{year_dg}d)"
1297
- end
1298
- else
1299
- terms << year_by_epoch
1300
- format = (0..(10**year_dg-1)) === (year_by_epoch * 1) ? "%0#{year_dg}d." : "%+0#{5+ext_dg}d."
1301
- end
1302
-
1303
- # 月日
1304
- ((1-@cal_date.length)..-1).each do |i|
1305
- break if (i >= precision)
1306
- terms << @cal_date[i]
1307
- format += "%02d."
1308
- end
1309
-
1310
- # 結果
1311
- date = Pair._format([format] + terms)
1312
- date.sub!(/([^\d])\(([-+\d]+)\)/, '(\2)\1') if era
1313
- date = date[0..-2] unless @frame.pair[precision-1] || date[-1..-1] != '.'
1314
- date.gsub!(/\./, '-') if (@frame.indices.length <= 3) && !era
1315
- return date
1316
- end
1317
- end
1318
-
1319
- class DateAndTime < CalDate
1320
-
1321
- # 要素の多言語対応文字列化
1322
- #
1323
- # @param [Integer] index 多言語対応文字列化する要素の指定
1324
- # @param [When::BasicTypes::M17n] format 多言語対応文字列化の書式
1325
- #
1326
- # @return [When::BasicTypes::M17n]
1327
- #
1328
- def name(index, format=nil)
1329
- digit = _digit(index)
1330
- (digit <= DAY) ? super : @clk_time.name(digit, format)
1331
- end
1332
-
1333
- # 多言語対応文字列化 - When.exe Standard Representation により多言語対応文字列化する
1334
- #
1335
- # @param [Integer] precision どの桁まで多言語対応文字列化するか、分解能で指定する
1336
- # @param [true, false] round 指定の桁までで丸める(true)か, 切り捨てる(false)か
1337
- # @note 丸めるのは precision が When::DAY よりも高精度の場合のみである
1338
- #
1339
- # @return [When::BasicTypes::M17n]
1340
- #
1341
- def to_m17n(precision=@precision, round=false)
1342
- super + _clk_time_for_inspect(round ? precision : nil).to_m17n(precision)
1343
- end
1344
-
1345
- # 文字列化 -When.exe Standard Representation により文字列化する
1346
- #
1347
- # @param [Integer] precision どの桁まで多言語対応文字列化するか、分解能で指定する
1348
- # @param [true, false] round 指定の桁までで丸める(true)か, 切り捨てる(false)か
1349
- # @note 丸めるのは precision が When::DAY よりも高精度の場合のみである
1350
- #
1351
- # @return [String]
1352
- #
1353
- def to_s(precision=@precision, round=false)
1354
- super + _clk_time_for_inspect(round ? precision : nil).to_s(precision)
1355
- end
1356
-
1357
- # 出力に使用する clk_time の作成
1358
- def _clk_time_for_inspect(precision)
1359
- return @clk_time unless precision && precision > When::DAY
1360
- base = self + When::TM::Duration.new(@clk_time.frame._round_value(precision))
1361
- base.clk_time.clk_time[When::HOUR] = @clk_time.clk_time[When::HOUR] + 1 unless self.to_i == base.to_i
1362
- return base.clk_time
1363
- end
1364
- private :_clk_time_for_inspect
1365
-
1366
- #
1367
- #
1368
- # @param [Integer] d 時刻が'時分秒'でない表現のための桁位置変更指示(小さいほうに位置をずらす)
1369
- #
1370
- # @return [Numeric] 自身の「時」
1371
- #
1372
- def hour(d=0)
1373
- @clk_time.hour(d)
1374
- end
1375
-
1376
- #
1377
- #
1378
- # @param [Integer] d 時刻が'時分秒'でない表現のための桁位置変更指示(小さいほうに位置をずらす)
1379
- #
1380
- # @return [Numeric] 自身の「分」
1381
- #
1382
- def minute(d=0)
1383
- @clk_time.minute(d)
1384
- end
1385
- alias :min :minute
1386
-
1387
- #
1388
- #
1389
- # @param [Integer] d 時刻が'時分秒'でない表現のための桁位置変更指示(小さいほうに位置をずらす)
1390
- #
1391
- # @return [Numeric] 自身の「秒」
1392
- #
1393
- def second(d=0)
1394
- @clk_time.second(d)
1395
- end
1396
- alias :sec :second
1397
- end
1398
- end
1399
- end
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
9
+ module Parts::Resource
10
+
11
+ # option key for _m17n_form
12
+ # @private
13
+ FormOptions = [:precision, :camel, :method, :locale, :prefix]
14
+
15
+ # When::Parts::Resource オブジェクトを分かりやすい文字列にして返します
16
+ #
17
+ # @return [String] 先頭部分を簡約表現にした IRI
18
+ #
19
+ def inspect
20
+ return super unless @_pool
21
+ expression = iri(true)
22
+ expression == '' ? super : When::EncodingConversion.to_external_encoding(expression)
23
+ end
24
+
25
+ #
26
+ # オブジェクトの内容を Hash 化
27
+ #
28
+ # @param [String, Integer] options {When::TM::TemporalPosition#_to_h}に渡す
29
+ # @param [Hash] options 下記のとおり
30
+ # @option options [Numeric] :precision 指定があれば「イベント名(イベント時刻)」出力の時刻を指定の精度に丸める
31
+ # @option options [Boolean] :camel true ならシンボルを camel case にする
32
+ # @option options [Symbol] :method _to_hash_value で変換に用いるメソッド(:to_m17n, :iri など, 指定なしなら変換しない)
33
+ # @option options [String] :locale 文字列化の locale(指定なしは M17nオブジェクトに変換)
34
+ # @option options [Boolean] :prefix true ならIRI の先頭部分を簡約表現にする
35
+ # @option options [Object] :その他 各クラス#_to_h を参照
36
+ #
37
+ # @return [Hash] (Whenモジュール内のクラスは文字列 or M17n化)
38
+ #
39
+ def to_h(options={})
40
+ _m17n_form(_to_h(options), options.kind_of?(Hash) ? options : {})
41
+ end
42
+
43
+ #
44
+ # オブジェクトの内容を JSON 化
45
+ #
46
+ # @param [Object] options #to_h を参照
47
+ #
48
+ # @return [String] to_h 結果を JSON文字列化したもの
49
+ #
50
+ def to_json(options={})
51
+ options[:method] = :to_m17n unless options.key?(:method)
52
+ JSON.dump(to_h(options))
53
+ end
54
+
55
+ #
56
+ # _m17n_form のための要素生成
57
+ # @private
58
+ def _to_hash_value(options={})
59
+ method = options[:method]
60
+ if method.kind_of?(Symbol)
61
+ if respond_to?(method, true) && method != :iri
62
+ return send(method)
63
+ elsif registered?
64
+ return iri(options[:prefix])
65
+ end
66
+ end
67
+ self
68
+ end
69
+
70
+ private
71
+ #
72
+ # 時間位置オブジェクトの内容を Hash 化
73
+ #
74
+ # @param [Object] options #to_h を参照
75
+ #
76
+ # @return [Hash]
77
+ # 各クラスの HashProperty に列挙した属性のうち値が false/nil でないものを
78
+ # 属性 => 値
79
+ # とする Hash
80
+ #
81
+ def _to_h(options={})
82
+ hash = {}
83
+ self.class::HashProperty.each do |property|
84
+ method, skip = property
85
+ value = respond_to?(method, true) ? send(method) : skip
86
+ hash[method] = value unless value == skip || value.class == skip
87
+ end
88
+ hash
89
+ end
90
+
91
+ #
92
+ # element を 文字列(M17n), Numeric あるいはそれらの Hash や Array に変換したもの
93
+ #
94
+ # @param [Object] element 変換元
95
+ # @param [Hash] options 下記の通り
96
+ # @option options [Numeric] :precision 指定があれば「イベント名(イベント時刻)」出力の時刻を指定の精度に丸める
97
+ # @option options [Boolean] :camel true ならシンボルを camel case にする
98
+ # @option options [Symbol] :method _to_hash_value で変換に用いるメソッド(:to_m17n, :iri など, 指定なしなら変換しない)
99
+ # @option options [String] :locale 文字列化の locale(指定なしは M17nオブジェクトに変換)
100
+ # @option options [Boolean] :prefix true ならIRI の先頭部分を簡約表現にする
101
+ #
102
+ # @return [Hash, Array] 変換結果
103
+ #
104
+ # @note element.events のある日付は _event_form で変換する
105
+ #
106
+ def _m17n_form(element, options={})
107
+ result = element.respond_to?(:_event_form) ? element._event_form(self, options[:precision]) :
108
+ element.respond_to?(:_to_hash_value) ? element._to_hash_value(options) :
109
+ element.respond_to?(:label) && element.label ? element.label :
110
+ case element
111
+ when Hash ; Hash[*(element.keys.inject([]) { |s, k|
112
+ s + [_m17n_form(k, options), _m17n_form(element[k], options)]
113
+ })]
114
+ when Array ; element.map {|e| _m17n_form(e, options)}
115
+ when Class ; When::Parts::Resource._path_with_prefix(element, options[:prefix])
116
+ when Symbol ; options[:camel] ? element.to_s.split(/_/).map {|e| e.capitalize}.join('').to_sym : element
117
+ when Numeric, FalseClass, TrueClass ; element
118
+ else ; element.to_s
119
+ end
120
+ result = When::Locale.translate(result,options[:locale]) if options[:locale] && result.kind_of?(String)
121
+ result
122
+ end
123
+ end
124
+
125
+ class Parts::Timezone
126
+ # When::Parts::Timezone オブジェクトを分かりやすい文字列にして返します
127
+ #
128
+ # @return [String] identifier と同様
129
+ #
130
+ alias :inspect :identifier
131
+ end
132
+
133
+ module Coordinates
134
+
135
+ class Pair
136
+ #
137
+ # to_h のための要素生成
138
+ #
139
+ # @param [Hash] options 下記のとおり
140
+ # @option options [Symbol] :method :to_m17n なら to_s を返す、その他は self を返す
141
+ #
142
+ # @return [String, When::Coordinates::Pair]
143
+ #
144
+ # @private
145
+ def _to_hash_value(options={})
146
+ options[:method] == :to_m17n ? to_s : self
147
+ end
148
+
149
+ # When::Coordinates::Pair オブジェクトを分かりやすい文字列にして返します
150
+ #
151
+ # @return [String] to_s と同様
152
+ #
153
+ def inspect
154
+ When::EncodingConversion.to_external_encoding(to_s)
155
+ end
156
+ end
157
+
158
+ class Residue
159
+ # 多言語対応文字列化
160
+ #
161
+ # @return [When::BasicTypes::M17n]
162
+ #
163
+ def to_m17n
164
+ return m17n(@remainder.to_s) unless label
165
+ return label + "(#{difference})" unless @format
166
+ (label[0...0] + @format) % [label, difference, difference+1]
167
+ end
168
+
169
+ # 文字列化
170
+ #
171
+ # @return [String]
172
+ #
173
+ def to_s
174
+ return @remainder.to_s unless label
175
+ return label.to_s + "(#{difference})" unless @format
176
+ @format.to_s % [label.to_s, difference, difference+1]
177
+ end
178
+
179
+ #
180
+ # week_included のための range の決定
181
+ #
182
+ # @return [Array<Range>]
183
+ #
184
+ # @private
185
+ def _range_for_week_included(date, first, length, block_given=false)
186
+ today = date.floor
187
+ begun = today.succ & self >> first-1
188
+ unless date.frame.equal?(begun.frame)
189
+ begun = (date.frame ^ today).succ & self >> first-1
190
+ middle = today
191
+ end
192
+ ended = begun.succ & self >> length-1
193
+ middle && block_given ? [begun...middle, middle...ended] : [begun...ended]
194
+ end
195
+
196
+ #
197
+ # week_included のためのコラムの生成
198
+ #
199
+ # @return [Array<Object>]
200
+ #
201
+ # @private
202
+ def _column_for_week_included(base, range, opt, &block)
203
+ range.inject([]) {|s,r| s + r.map { |date|
204
+ yield(date, !opt.key?(:Range) || opt[:Range].include?(date.to_i) ? DAY : nil)
205
+ }}
206
+ end
207
+ end
208
+ end
209
+
210
+ class CalendarNote::Week
211
+
212
+ #
213
+ # week_included のための range の決定
214
+ #
215
+ # @return [Array<Range>]
216
+ #
217
+ # @private
218
+ def _range_for_week_included(date, first, length, block_given=false)
219
+ begun = ended = nil
220
+ if first <= 0
221
+ it = enum_for(date.floor, :reverse)
222
+ (1-first).times do
223
+ begun = it.next
224
+ end
225
+ else
226
+ it = enum_for(date.floor, :forward)
227
+ first.times do
228
+ begun = it.next
229
+ end
230
+ end
231
+ it = enum_for(begun, :forward)
232
+ (length+1).times do
233
+ ended = it.next
234
+ end
235
+ [begun...ended]
236
+ end
237
+
238
+ #
239
+ # week_included のためのコラムの生成
240
+ #
241
+ # @return [Array<Object>]
242
+ #
243
+ # @private
244
+ def _column_for_week_included(base, range, opt, &block)
245
+ count = 0
246
+ limit = week(base)[:position][1]
247
+ range.inject([]) {|s,r| s + r.map { |date|
248
+ position = week(date, base)[:position][0]
249
+ (position - count).times do
250
+ yield(nil,nil)
251
+ end
252
+ count = position + 1
253
+ yield(date, !opt.key?(:Range) || opt[:Range].include?(date.to_i) ? DAY : nil) if position < limit
254
+ }}
255
+ end
256
+ end
257
+
258
+ module TM
259
+
260
+ class Calendar
261
+
262
+ # TemporalPosition#strftime のためのデフォルト書式
263
+ #
264
+ # @return [String]
265
+ #
266
+ def strftime
267
+ @strftime ||= '%Y-%m-%d'
268
+ end
269
+ end
270
+
271
+ class TemporalPosition
272
+
273
+ AMPM = ['AM', 'PM'].map {|half| When::Parts::Resource._instance('_m:CalendarFormats::' + half)}
274
+ Format = {
275
+ 'a' => ['%s', 'a'], 'A' => ['%s', 'A'], 'b' => ['%s', 'b'], 'B' => ['%s', 'B'],
276
+ 'c' => When::Parts::Resource._instance('_m:CalendarFormats::DateTime'),
277
+ 'C' => ['%02d', 'C'], 'd' => ['%02d', 'd'], 'D' => '%m/%d/%y', 'e' => ['%2d', 'd'],
278
+ 'E' => ['%s', 'E'], 'F' => ['%s', 'F'], 'G' => ['%d', 'G'], 'g' => ['%02d', 'g'],
279
+ 'h' => '%b', 'H' => ['%02d', 'H'], 'I' => ['%02d', 'I'], 'j' => ['%03d', 'j'],
280
+ 'k' => ['%2d', 'H'], 'l' => ['%2d', 'I'], 'm' => ['%02d', 'm'], 'M' => ['%02d', 'M'],
281
+ 'n' => '\n', 'p' => ['%s', 'p'], 'P' => ['%s', 'P'], 'q' => ['%01d', 'd'],
282
+ 'r' => '%I:%M:%S %p', 'R' => '%H:%M', 's' => ['%d', 's'], 'S' => ['%02d', 'S'],
283
+ 't' => '\t', 'T' => '%H:%M:%S', 'u' => ['%d', 'u'], 'U' => ['%02d', 'U'],
284
+ 'V' => ['%02d', 'V'], 'w' => ['%d', 'w'], 'W' => ['%02d', 'W'],
285
+ 'x' => When::Parts::Resource._instance('_m:CalendarFormats::Date'),
286
+ 'X' => When::Parts::Resource._instance('_m:CalendarFormats::Time'),
287
+ 'y' => ['%02d', 'y'], 'Y' => ['%4d', 'Y'], 'z' => ['%s', 'z'], 'Z' => ['%s', 'Z'],
288
+ '+' => '%a %b %d %T %z %Y'
289
+ }
290
+
291
+ class << self
292
+ # When::TM::TemporalPosition Class のグローバルな設定を行う
293
+ #
294
+ # @param [Hash] format strftime で用いる記号の定義
295
+ #
296
+ # @return [void]
297
+ #
298
+ # @note format の指定がない場合、format は Format(モジュール定数)と解釈する
299
+ #
300
+ def _setup_(format=nil)
301
+ @format = format ? Format.merge(format) : Format
302
+ end
303
+
304
+ # 設定情報を取得する
305
+ #
306
+ # @return [Hash] 設定情報
307
+ #
308
+ def _setup_info
309
+ {:format => format}
310
+ end
311
+
312
+ # strftime で用いる書式のハッシュ
313
+ def format
314
+ @format ||= Format
315
+ end
316
+ end
317
+
318
+ # When::TM::TemporalPosition オブジェクトを分かりやすい文字列にして返します
319
+ #
320
+ # @return [String] to_s と同様
321
+ #
322
+ def inspect
323
+ When::EncodingConversion.to_external_encoding(to_s)
324
+ end
325
+
326
+ #
327
+ # 暦法名
328
+ #
329
+ # @return [Array<Class>] Class 暦法のクラスオブジェクト
330
+ #
331
+ def calendar_name
332
+ [self.class]
333
+ end
334
+
335
+ #
336
+ # 時法名
337
+ # @param [Boolean] prefix true ならIRI の先頭部分を簡約表現にする
338
+ #
339
+ # @return [Array<String>] String 時法の IRI
340
+ #
341
+ def clock_name(prefix=true)
342
+ [clock.iri(prefix)]
343
+ end
344
+
345
+ #
346
+ # 参照ラベル
347
+ #
348
+ # @return [When::BasicTypes::M17n]
349
+ #
350
+ def reference_label
351
+ [When::BasicTypes::M17n.new(self.class.to_s.split(/::/)[-1])]
352
+ end
353
+
354
+ # 含まれる週
355
+ #
356
+ # @overload week_included(ord, wkst, opt, &block)
357
+ # @param [Numeric, Range] ord 週の番号(default: 今週)
358
+ # 今週を 0 とする週番号(Integer) または週番号の範囲(Range)
359
+ # -1 - 先週
360
+ # 0 - 今週
361
+ # +1 - 来週
362
+ # @param [String] wkst 週の開始曜日(defaultは 月曜)
363
+ # @param [When::CalendarNote] wkst 暦注オブジェクト
364
+ # @param [Array<When::CalendarNote, String>] wkst 暦注オブジェクトとそのイベントメソッド名
365
+ # (暦注オブジェクトは、そのIRI文字列を指定しても良い)
366
+ # @param [Hash] opt 下記の通り
367
+ # @option opt [Range] :Range 上位繰り返し範囲(ユリウス通日...ユリウス通日)
368
+ # @param [Block] block
369
+ #
370
+ # @note 引数 ord, wkst, opt はそのクラスで位置づけを判断するため、引数の順序は任意(省略も可)
371
+ #
372
+ # @return [Range] 含まれる週を範囲として表現する Range (block 指定なし)
373
+ # @return [Array] 含まれる週の各日をブロックに渡した結果の Array (block 指定あり)
374
+ #
375
+ def week_included(*args, &block)
376
+ begin
377
+ first, length, wkst, opt = _range(args, 'MO')
378
+ range = wkst._range_for_week_included(self, first, length, block_given?)
379
+ rescue RangeError
380
+ range = wkst._range_for_week_included(@frame ^ self, first, length)
381
+ end
382
+
383
+ return range.first unless block_given?
384
+
385
+ wkst._column_for_week_included(self, range, opt, &block).unshift(yield(range[0].first, WEEK)).compact
386
+ end
387
+
388
+ # 含まれる月
389
+ #
390
+ # @overload month_included(ord, wkst, opt, block)
391
+ # @param [Numeric, Range] ord 月の番号(default: 今月)
392
+ # 今月を 0 とする月番号(Integer) または月番号の範囲(Range)
393
+ # -1 - 先月
394
+ # 0 - 今月
395
+ # +1 - 来月
396
+ # @param [String] wkst 週の開始曜日(defaultはなし)
397
+ # @param [When::CalendarNote] wkst 暦注オブジェクト
398
+ # @param [Array<When::CalendarNote, String>] wkst 暦注オブジェクトとそのイベントメソッド名
399
+ # (暦注オブジェクトは、そのIRI文字列を指定しても良い)
400
+ # @param [Hash] opt 下記の通り
401
+ # @option opt [Range] :Range 上位繰り返し範囲(ユリウス通日...ユリウス通日)
402
+ # @param [Block] block
403
+ #
404
+ # @note 引数 ord, wkst, opt はそのクラスで位置づけを判断するため、引数の順序は任意(省略も可)
405
+ #
406
+ # @return [Range] 含まれる月を範囲として表現する Range (block 指定なし)
407
+ # @return [Array] 含まれる月の各日をブロックに渡した結果の Array (block 指定あり, wkst なし)
408
+ # @return [Array<Array>] 含まれる月の各日をブロックに渡した結果の 七曜表(block 指定あり, wkst あり)
409
+ #
410
+ def month_included(*args, &block)
411
+ first, length, wkst, opt = _range(args)
412
+ if wkst
413
+ (first...(first+length)).map {|i|
414
+ begun = self.floor(MONTH,DAY) + When::TM::PeriodDuration.new([0,i,0])
415
+ ended = begun + P1M
416
+ ended = ended.prev until begun.cal_date[MONTH-1] == ended.cal_date[MONTH-1]
417
+ if ended.to_i <= begun.to_i
418
+ ended = begun
419
+ loop do
420
+ succ = ended.succ
421
+ break unless succ.frame.equal?(begun.frame)
422
+ ended = succ
423
+ end
424
+ end
425
+ dates = [begun]
426
+ loop do
427
+ current = dates[-1].week_included(wkst)
428
+ if current.last.to_i > ended.to_i
429
+ dates[-1] = ended
430
+ break (dates.map {|date| date.week_included(wkst, {:Range=>begun.to_i..ended.to_i}, &block)}).
431
+ unshift(yield(begun, MONTH)).compact
432
+ elsif wkst.kind_of?(When::Coordinates::Residue)
433
+ dates << dates[-1] + wkst.duration
434
+ else
435
+ it = wkst.enum_for(dates[-1], :forward)
436
+ begin
437
+ date = it.next
438
+ end while date.to_i == dates[-1].to_i
439
+ date = date.to_cal_date unless date.instance_of?(TM::CalDate)
440
+ dates << date
441
+ end
442
+ end
443
+ }
444
+ else
445
+ begun = self.floor(MONTH,DAY) + When::TM::PeriodDuration.new([0, first, 0])
446
+ ended = begun + When::TM::PeriodDuration.new([0, length, 0])
447
+ loop do
448
+ last = ended.prev
449
+ break unless last.cal_date[MONTH-1] == ended.cal_date[MONTH-1]
450
+ ended = last
451
+ end
452
+ if block_given?
453
+ (begun...ended).map do |date|
454
+ yield(date)
455
+ end
456
+ else
457
+ begun...ended
458
+ end
459
+ end
460
+ end
461
+
462
+ # 含まれる年
463
+ #
464
+ # @overload month_included(ord, wkst, opt, block)
465
+ # @param [Numeric, Range] ord 年の番号(default: 今年)
466
+ # 今年を 0 とする年番号(Integer) または年番号の範囲(Range)
467
+ # -1 - 先年
468
+ # 0 - 今年
469
+ # +1 - 来年
470
+ # @param [String] wkst 週の開始曜日(defaultはなし)
471
+ # @param [When::CalendarNote] wkst 暦注オブジェクト
472
+ # @param [Array<When::CalendarNote, String>] wkst 暦注オブジェクトとそのイベントメソッド名
473
+ # (暦注オブジェクトは、そのIRI文字列を指定しても良い)
474
+ # @param [Hash] opt 下記の通り
475
+ # @option opt [Range] :Range 上位繰り返し範囲(ユリウス通日...ユリウス通日)
476
+ # @param [Block] block
477
+ #
478
+ # @note 引数 ord, wkst, opt はそのクラスで位置づけを判断するため、引数の順序は任意(省略も可)
479
+ #
480
+ # @return [Range] 含まれる年を範囲として表現する Range (block 指定なし)
481
+ # @return [Array] 含まれる年の各日をブロックに渡した結果の Array (block 指定あり, wkst なし)
482
+ # @return [Array<Array>] 含まれる年の各日をブロックに渡した結果の 七曜表(block 指定あり, wkst あり)
483
+ #
484
+ def year_included(*args, &block)
485
+ first, length, wkst, opt = _range(args)
486
+ if wkst
487
+ (first...(first+length)).map {|i|
488
+ begun = _force_euqal_year(i)
489
+ ended = _force_euqal_year(i+1)
490
+ current = begun
491
+ result = [yield(begun, YEAR)]
492
+ ended += P1M if ended.floor(MONTH).most_significant_coordinate * 1 == begun.most_significant_coordinate * 1
493
+ while current < ended do
494
+ result << current.month_included(wkst, &block)
495
+ current += P1M
496
+ end
497
+ result.compact
498
+ }
499
+ else
500
+ begun = _force_euqal_year(first)
501
+ ended = _force_euqal_year(first+length)
502
+ if block_given?
503
+ (begun...ended).map do |date|
504
+ yield(date)
505
+ end
506
+ else
507
+ begun...ended
508
+ end
509
+ end
510
+ end
511
+
512
+ # 指定の年初を探す
513
+ def _force_euqal_year(diff)
514
+ year = most_significant_coordinate * 1 + diff
515
+ date = (self + When::TM::PeriodDuration.new([diff,0,0])).floor(YEAR,DAY)
516
+ done = {}
517
+ loop do
518
+ case
519
+ when date.most_significant_coordinate * 1 == year
520
+ return date
521
+ when date.most_significant_coordinate * 1 > year
522
+ next_date = (date-When::P1Y).floor(YEAR,DAY)
523
+ date = (date.to_i == next_date.to_i) ?
524
+ (date-When::P1Y*2).floor(YEAR,DAY) :
525
+ next_date
526
+ else
527
+ next_date = (date+When::P1Y).floor(YEAR,DAY)
528
+ date = (date.to_i == next_date.to_i) ?
529
+ (date+When::P1Y*2).floor(YEAR,DAY) :
530
+ next_date
531
+ end
532
+ raise RangeError, "can't find target date: #{self} -> #{year}" if done.key?(date.to_i)
533
+ done[date.to_i] = true
534
+ end
535
+ end
536
+ private :_force_euqal_year
537
+
538
+ # 範囲の取得
539
+ def _range(args, wkst=nil)
540
+ ord = 0
541
+ opt = {}
542
+ args.each do |arg|
543
+ case arg
544
+ when Integer, Range ; ord = arg
545
+ when Hash ; opt = arg
546
+ else ; wkst = arg
547
+ end
548
+ end
549
+ wkst, method = wkst
550
+ wkst = When::Coordinates::Residue.day_of_week(wkst) || When.CalendarNote(wkst) if wkst
551
+ wkst = wkst[method] if method
552
+ return ord, 1, wkst, opt if ord.kind_of?(Integer)
553
+ length = ord.last - ord.first
554
+ length += 1 unless ord.exclude_end?
555
+ return ord.first, length, wkst, opt
556
+ end
557
+ private :_range
558
+
559
+ #
560
+ # 時間位置オブジェクトの暦注を取得し value を暦注の値 (String, When::BasicTypes::M17n or When::Coordinates::Residue)とする Hash で表現
561
+ #
562
+ # @param [String] options { :notes => String } という Hash の指定と等価
563
+ # @param [Integer] options { :indices => Integer } という Hash の指定と等価
564
+ # @param [Hash] options 下記のとおり
565
+ # @option options [When::CalendarNote, String] :calendar_note 暦注を計算する暦注オブジェクトまたはそのIRI
566
+ # @option options [Object] その他のキー {When::CalendarNote#notes} を参照
567
+ #
568
+ # @return [Array<Array<Hash{:note=>note, :value=>value}>>]
569
+ # [ note [String, When::BasicTypes::M17n] 暦注名 ]
570
+ # [ value [String, When::BasicTypes::M17n, When::Coordinates::Residue] 暦注の値 ]
571
+ #
572
+ def notes(options={})
573
+ form_options = options.kind_of?(Hash) ? options : {}
574
+ form_options[:method] = :to_m17n unless form_options.key?(:method)
575
+ persistence = options.delete(:persistence) if options.kind_of?(Hash)
576
+ retrieved = When::CalendarNote::NotesContainer.retrieve(persistence, self.to_i)
577
+ return retrieved unless retrieved == false
578
+ When::CalendarNote::NotesContainer.register(_m17n_form(_notes(options), form_options), persistence, self.to_i)
579
+ end
580
+
581
+ #
582
+ # 時間位置オブジェクトの暦注を取得
583
+ #
584
+ # @param [String] options { :notes => String } という Hash の指定と等価
585
+ # @param [Integer] options { :indices => Integer } という Hash の指定と等価
586
+ # @param [Hash] options 下記のとおり
587
+ # @option options [When::CalendarNote, String] :calendar_note 暦注を計算する暦注オブジェクトまたはそのIRI
588
+ # @option options [Object] その他のキー {When::CalendarNote#notes} を参照
589
+ #
590
+ # @return [Array<Array<Hash{:note=>note, :value=>value}>>]
591
+ # [ note [String, When::BasicTypes::M17n, When::Coordinates::Residue] 暦注名 ]
592
+ # [ value [String, When::BasicTypes::M17n, When::Coordinates::Residue, When::TM::TemporalPosition] 暦注の値 ]
593
+ #
594
+ # @note
595
+ # When::TM::TemporalPosition の場合、events[0] に暦注名の入ったその暦注に該当する日付である。
596
+ # (例) Christian クラス で easter を計算した場合、当該年の復活祭の日付オブジェクトが返る。
597
+ # 暦注サブクラスの場合、要素が増えたり、:note の暦注要素の型が変わったりすることがある。
598
+ #
599
+ def _notes(options={})
600
+ _calendar_note(options).notes(self, options)
601
+ end
602
+
603
+ #
604
+ # 暦注の一致 or 不一致
605
+ #
606
+ # @param [String] options { :notes => String } または { :value => String } という Hash の指定と等価
607
+ # (指定の notes が存在する場合は前者、しない場合は後者)
608
+ # @param [Integer] options { :indices => Integer } という Hash の指定と等価
609
+ # @param [Hash] options 下記のとおり
610
+ # @option options [Object] :value 確認する暦注の値
611
+ # @option options [Object] その他のキー {When::CalendarNote#notes} を参照
612
+ #
613
+ # @return [Boolean]
614
+ # [ true - 暦注が一致 ]
615
+ # [ false - 暦注が不一致 ]
616
+ #
617
+ def note?(options={})
618
+ _calendar_note(options).note?(self, options)
619
+ end
620
+
621
+ # 指定の日時が指定イベントに該当するか?
622
+ #
623
+ # @overload is?(event=nil, options={})
624
+ # @param [String] event options={:notes=>String} または {:notes=>String} または {:value=>String} という指定と等価
625
+ # (指定の event が存在する場合は前者、指定の notes が存在する場合は中央、しない場合は後者)
626
+ # @param [Integer] event options={ :indices=> Integer } という指定と等価
627
+ # @param [Hash] options 下記のとおり
628
+ # @option options [When::CalendarNote or String] :calendar_note 該当判断に用いる CalendarNoteオブジェクトまたはその IRI
629
+ # @option options [String] :event 確認するイベント名
630
+ # @option options [Object] :value 確認する暦注の値
631
+ # @option options [Object] その他のキー {When::CalendarNote#notes} を参照
632
+ #
633
+ # @return [Boolean]
634
+ # [ true - 該当する ]
635
+ # [ false - 該当しない ]
636
+ #
637
+ def is?(*args)
638
+ options = args.last.kind_of?(Hash) ? args.pop.dup : {}
639
+ note = _calendar_note(options)
640
+ event = args.first || options.delete(:event) || note.event
641
+ return note.note?(self, options) unless options.empty?
642
+ return note.note?(self, event) unless event.to_s =~ /\A([^\d]+)/ && note.respond_to?($1.downcase)
643
+ return note.include?(self, event)
644
+ end
645
+
646
+ #
647
+ # 時間位置オブジェクトの内容を Hash
648
+ #
649
+ # @param [String] options { :notes => String } という Hash の指定と等価
650
+ # @param [Integer] options { :indices => Integer } という Hash の指定と等価
651
+ # @param [Hash] options 下記のとおり
652
+ # @option options [When::CalendarNote, String] :calendar_note 暦注を計算する暦注オブジェクトまたはそのIRI
653
+ # @option options [Object] その他のキー {When::CalendarNote#notes} を参照
654
+ #
655
+ # @return [Hash]
656
+ # - :sdn 日の通し番号 - ユリウス通日(Integer)
657
+ # - :calendar calendar_name の結果 - Array<暦法または暦年代(, 付属情報..)>
658
+ # - :notes Hash (の Array (の Array)) - _notes(options)
659
+ # clock が定義されている場合、さらに下記も出力する
660
+ # - :clock 時計(When::Parts::Timezone::Base)
661
+ # - :clk_time to_clock_time の結果 - ( 日, 時, 分, 秒 )
662
+ # - :dynamical dynamical_time / 秒
663
+ # - :universal universal_time / 秒
664
+ #
665
+ def _to_h(options={})
666
+ hash = super.update({
667
+ :sdn => to_i,
668
+ :calendar => calendar_name,
669
+ :notes => _notes(options)
670
+ })
671
+
672
+ hash.update({
673
+ :clock => clock,
674
+ :clk_time => to_clock_time,
675
+ :dynamical => dynamical_time * clock.second,
676
+ :universal => universal_time * clock.second
677
+ }) if clock
678
+ hash
679
+ end
680
+
681
+ # 多言語対応文字列化 - When.exe Standard Representation により多言語対応文字列化する
682
+ #
683
+ # @overload to_m17n()
684
+ #
685
+ # @return [When::BasicTypes::M17n]
686
+ #
687
+ def to_m17n(*args)
688
+ return m17n(I[@indeterminated_position]) if [Unknown, Max, Min].include?(@indeterminated_position)
689
+ return m17n(_to_s)
690
+ end
691
+ # @private
692
+ alias :_to_s :to_s
693
+
694
+ # 文字列化 - When.exe Standard Representation により文字列化する
695
+ #
696
+ # @overload to_s()
697
+ #
698
+ # @return [String]
699
+ #
700
+ def to_s(*args)
701
+ to_m17n(*args).to_s
702
+ end
703
+
704
+ # caret 付きの frame
705
+ #
706
+ # @return [String]
707
+ #
708
+ # @note 暦年代付きかまたは frame がグレゴリオ暦の場合は空文字列を返す
709
+ #
710
+ def caret_frame
711
+ prefix = When::Parts::Resource.base_uri + 'CalendarTypes/'
712
+ path = frame.iri
713
+ return '' if @calendar_era_name || path == prefix + 'Gregorian'
714
+ path = path[prefix.length..-1] if path.index(prefix) == 0
715
+ '^^' + path
716
+ end
717
+
718
+ # 指定の書式による多言語対応文字列化 - pattern で指定した書式で多言語対応文字列化する
719
+ #
720
+ # @param [When::BasicTypes::M17n] pattern 書式
721
+ # @param [String, Array<String>] locale 文字列化を行う locale の指定(デフォルト : オブジェクト生成時に保持している locale すべて)
722
+ #
723
+ # @return [When::BasicTypes::M17n]
724
+ #
725
+ def strftime(pattern=@frame.strftime, locale=nil)
726
+ pattern = m17n([pattern]*self.keys.length, nil, nil, {:locale=>self.keys}) if pattern.instance_of?(String)
727
+ pattern._printf([], locale) do |k, *t|
728
+ _strftime(k, pattern, [''])
729
+ end
730
+ end
731
+
732
+ # strftime で扱う項の値を取得する
733
+ #
734
+ # @param [String] designator 項目名
735
+ # @param [String] locale 文字列化を行う場合の locale の指定(デフォルト to_s(代表値))
736
+ # @param [Integer] d 日付が'年月日'、時刻が'時分秒'でない表現のための桁位置変更指示
737
+ # [ 年月に付く場合 - 大きいほうに位置をずらす ]
738
+ # [ 分秒に付く場合 - 小さいほうに位置をずらす ]
739
+ # @param [Integer] e 月の省略名の文字数
740
+ #
741
+ # @return [designator に依存]
742
+ #
743
+ def _term(designator, locale=nil, d=0, e=3)
744
+ designator = When::Locale.translate(designator,locale)
745
+ case designator
746
+ # 現在のロケールにおける曜日の省略名
747
+ when 'a' ; When.Resource('_co:Common::Abbr_Day')[to_i % 7].translate(locale)
748
+ # 現在のロケールにおける曜日の完全な名前
749
+ when 'A' ; When.Resource('_co:Common::Week')[to_i % 7].label.translate(locale)
750
+ when 'b' ; (name(MONTH-d).translate(locale))[/\A.{1,#{e}}/] # 現在のロケールにおける月の省略名
751
+ when 'B' ; (name(MONTH-d).translate(locale)) # 現在のロケールにおける月の完全な名前
752
+ when 'C' ; year(d).div(100) # 世紀 (西暦年の上 2 桁)
753
+ when 'd' ; day(d) # 月内通算日
754
+ when 'E' ; Array(calendar_era_name)[0].translate(locale)# 年号
755
+ when 'F' ; floor(DAY).to_m17n.translate(locale) # ISO 8601 形式の日付フォーマット
756
+ when 'G' ; cwyear(d) # ISO 8601 週単位表記の年
757
+ when 'g' ; cwyear(d) % 100 # ISO 8601 週単位表記の年の下2桁
758
+ when 'H' ; hour(d) # 24 時間表記での時
759
+ when 'I' ; (hour(d)-1) % 12 + 1 # 12 時間表記での時
760
+ when 'j' ; yday(d) # 年の初めから通算の日数
761
+ when 'm' ; month(d) #
762
+ when 'M' ; minute(d) #
763
+ when 'p' ; (AMPM[hour(d).to_i.div(12)].translate(locale)).upcase # 現在のロケールにおける「午前」「午後」に相当する文字列
764
+ when 'P' ; (AMPM[hour(d).to_i.div(12)].translate(locale)).downcase # 前項を小文字で表記
765
+ when 's' ; universal_time / Duration::SECOND # 紀元 (1970-01-01T00:00:00Z) からの秒数
766
+ when 'S' ; second(d) # 秒 (10 進数表記)
767
+ when 'u' ; cwday # 週の何番目の日か(月曜日を 1 とする)
768
+ when 'U' ; yweek(6, 7, d) # 年の初めからの通算の週番号(日曜日始まり)
769
+ when 'V' ; cweek(d) # ISO 8601 形式での年の始めからの週番号
770
+ when 'w' ; wday # 週の何番目の日 か(日曜日を 0 とする)
771
+ when 'W' ; yweek(0, 7, d) # 年の初めからの通算の週番号(月曜日始まり)
772
+ when 'y' ; year(d) % 100 # 西暦の下2桁 (世紀部分を含まない年)
773
+ when 'Y' ; year(d) # 世紀部分を含めた ( 4 桁の) 西暦年
774
+ when 'z' ; clock.to_basic # +hhmm や -hhmm の形式のタイムゾーン
775
+ when 'Z' ; When::Locale.translate(clock.tzname[0],locale) # タイムゾーンまたはゾーン名または省略名
776
+ else ; designator
777
+ end
778
+ end
779
+
780
+ private
781
+
782
+ # 指定の書式による多言語対応文字列化
783
+ #
784
+ # @param [String] locale 文字列化を行う locale
785
+ # @param [When::BasicTypes::M17n] pattern 書式
786
+ #
787
+ # @return [Array] 書式と文字列化項目からなる配列
788
+ #
789
+ def _strftime(locale, pattern, t)
790
+ format, *terms = t
791
+ pattern = pattern.translate(locale) if pattern.kind_of?(When::BasicTypes::M17n)
792
+ pattern.scan(/(%[O\d]*(?:\.(\d+))?.)|(.)/) do |c,e,s|
793
+ case c
794
+ when /\A%%/
795
+ format += '%%'
796
+ when /\A%/
797
+ action = TemporalPosition.format[c[-1..-1]]
798
+ case action
799
+ when Array
800
+ format += action[0]
801
+ terms << _term(action[1], locale, c[1..-2].to_i, e||3)
802
+ when String
803
+ action = action.translate(locale) if action.kind_of?(When::BasicTypes::M17n)
804
+ if (action =~ /%/)
805
+ format, *terms = _strftime(locale, action, [format] + terms)
806
+ else
807
+ format += action
808
+ end
809
+ end
810
+ else
811
+ format += s
812
+ end
813
+ end
814
+ [format] + terms
815
+ end
816
+
817
+ #
818
+ # 使用する When::CalendarNote を決定する
819
+ #
820
+ # options に副作用があることに注意
821
+ #
822
+ def _calendar_note(options)
823
+ calendar_note = options.delete(:calendar_note) if options.kind_of?(Hash)
824
+ calendar_note ||= @frame ? @frame.note : 'JulianDay'
825
+ When.CalendarNote(calendar_note)
826
+ end
827
+ end
828
+
829
+ class JulianDate
830
+
831
+ # 多言語対応文字列化 - ユリウス日を多言語対応文字列化する
832
+ #
833
+ # @param [Integer] precision どの桁まで多言語対応文字列化するか、分解能で指定する
834
+ #
835
+ # @return [When::BasicTypes::M17n]
836
+ #
837
+ def to_m17n(precision=@precision)
838
+ return m17n(to_s(precision))
839
+ end
840
+
841
+ # 文字列化 - ユリウス日を文字列化する
842
+ #
843
+ # @param [Integer] precision どの桁まで多言語対応文字列化するか、分解能で指定する
844
+ #
845
+ # @return [String]
846
+ #
847
+ def to_s(precision=@precision)
848
+ coordinate = (precision <= When::DAY) ? to_i : to_f
849
+ coordinate.to_s
850
+ end
851
+ end
852
+
853
+ class ClockTime
854
+
855
+ # 要素の多言語対応文字列化
856
+ #
857
+ # @param [Integer] index 多言語対応文字列化する要素の指定
858
+ # @param [When::BasicTypes::M17n] format 多言語対応文字列化の書式
859
+ #
860
+ # @return [When::BasicTypes::M17n]
861
+ #
862
+ def name(index, format=nil)
863
+ digit = _digit(index) {|digit| digit > DAY}
864
+ coordinate = @clk_time[digit]
865
+ return m17n(format % coordinate) if format
866
+
867
+ indices = @frame.indices[digit-1]
868
+ if indices
869
+ trunk = indices.trunk
870
+ branch = indices.branch
871
+ end
872
+ format = branch ? m17n("%02d:") : "%02d"
873
+ return m17n(format % coordinate) unless trunk
874
+ trunk = trunk[coordinate * 1]
875
+ return m17n(trunk) unless branch
876
+ return trunk.prefix(branch[coordinate * 0])
877
+ end
878
+
879
+ # 多言語対応文字列化 - When.exe Standard Representation により多言語対応文字列化する
880
+ #
881
+ # @param [Integer] precision どの桁まで多言語対応文字列化するか、分解能で指定する
882
+ #
883
+ # @return [When::BasicTypes::M17n]
884
+ #
885
+ def to_m17n(precision=@precision)
886
+ time = m17n('T' + _time_to_s(precision))
887
+ if @frame
888
+ time += @frame.zone unless Clock.is_local_time_set? && @frame.equal?(Clock.local_time)
889
+ end
890
+ return time
891
+ end
892
+
893
+ # 文字列化 - When.exe Standard Representation により文字列化する
894
+ #
895
+ # @param [Integer] precision どの桁まで多言語対応文字列化するか、分解能で指定する
896
+ #
897
+ # @return [String]
898
+ #
899
+ def to_s(precision=@precision)
900
+ time = 'T' + _time_to_s(precision)
901
+ if @frame
902
+ time += @frame.zone unless Clock.is_local_time_set? && @frame.equal?(Clock.local_time)
903
+ end
904
+ return time
905
+ end
906
+
907
+ # 時
908
+ #
909
+ # @param [Integer] d 時刻が'時分秒'でない表現のための桁位置変更指示(小さいほうに位置をずらす)
910
+ #
911
+ # @return [Numeric] 自身の「時」
912
+ #
913
+ def hour(d=0)
914
+ @clk_time[HOUR+d]
915
+ end
916
+
917
+ # 分
918
+ #
919
+ # @param [Integer] d 時刻が'時分秒'でない表現のための桁位置変更指示(小さいほうに位置をずらす)
920
+ #
921
+ #
922
+ # @return [Numeric] 自身の「分」
923
+ #
924
+ def minute(d=0)
925
+ @clk_time[MINUTE+d]
926
+ end
927
+ alias :min :minute
928
+
929
+ # 秒
930
+ #
931
+ # @param [Integer] d 時刻が'時分秒'でない表現のための桁位置変更指示(小さいほうに位置をずらす)
932
+ #
933
+ #
934
+ # @return [Numeric] 自身の「秒」
935
+ #
936
+ def second(d=0)
937
+ @clk_time[SECOND+d]
938
+ end
939
+ alias :sec :second
940
+
941
+ #protected
942
+ #
943
+ # 時間帯以外の部分の文字列化
944
+ #
945
+ # @param [Integer] precision どの桁まで多言語対応文字列化するか、分解能で指定する
946
+ #
947
+ # @return [String]
948
+ #
949
+ # @private
950
+ def _time_to_s(precision=@precision)
951
+ terms = []
952
+ format = ''
953
+ format += Pair::DL2[@clk_time[0] * 0] || ':' if @frame.pair[0] || @clk_time[0].kind_of?(Pair)
954
+
955
+ # 時分
956
+ digits = [@clk_time.length-2, precision].min
957
+ if digits > 0
958
+ terms += @clk_time[1..-1]
959
+ format += "%02d:" * digits
960
+ format = format[0..-2] if precision == digits
961
+ end
962
+
963
+ # 秒
964
+ digits = [precision - @clk_time.length + 1, STRING-SECOND].min
965
+ if digits == 0
966
+ format += "%02d"
967
+ elsif digits > 0
968
+ factor = 10**digits
969
+ terms[-1] = ((@clk_time[-1] + 1E-6) * factor).floor.to_f / factor # 切り捨て(10で割る丸めガードあり)
970
+ format += "%02.#{digits}f"
971
+ end
972
+
973
+ # 結果
974
+ time = Pair._format([format] + terms)
975
+ time.sub(/([^\d])(\d)\./, '\10\2.')
976
+ end
977
+
978
+ #
979
+ # to_h のための要素生成
980
+ # @private
981
+ def _to_hash_value(options={})
982
+ clk_time.map {|e| _m17n_form(e, options) }
983
+ end
984
+ end
985
+
986
+ class CalDate
987
+
988
+ #
989
+ # 暦法名
990
+ #
991
+ # @return [Array] ( name, epoch, reverse, go back )
992
+ # - name 暦法または暦年代 ({When::TM::Calendar}, {When::TM::CalendarEra})
993
+ # - epoch 暦元 (Integer)
994
+ # - reverse 暦年の順序 (Boolean)
995
+ # [ false, nil 昇順 ]
996
+ # [ true 降順 ]
997
+ # - go back 参照イベントより前の暦日か(Boolean)
998
+ # [ false, nil 否 ]
999
+ # [ true 然り ]
1000
+ #
1001
+ def calendar_name
1002
+ void, epoch, reverse, back = @calendar_era_name
1003
+ name = [@calendar_era || @frame, epoch, reverse, back]
1004
+ name.pop until name[-1]
1005
+ return name
1006
+ end
1007
+
1008
+ #
1009
+ # 参照ラベル
1010
+ #
1011
+ # @return [When::BasicTypes::M17n]
1012
+ #
1013
+ def reference_label
1014
+ return @calendar_era.hierarchy.map {|e| e.label} if @calendar_era
1015
+ return [@frame.label] if @frame.label
1016
+ [When::BasicTypes::M17n.new(@frame.class.to_s.split(/::/)[-1])]
1017
+ end
1018
+
1019
+ #
1020
+ # Hash
1021
+ #
1022
+ # @param [String] options { :notes => String } という Hash の指定と等価
1023
+ # @param [Integer] options { :indices => Integer } という Hash の指定と等価
1024
+ # @param [Hash] options 下記のとおり
1025
+ # @option options [When::CalendarNote, String] :calendar_note 暦注を計算する暦注オブジェクトまたはそのIRI
1026
+ # @option options [Object] その他のキー {When::CalendarNote#notes} を参照
1027
+ #
1028
+ # @return [Hash]
1029
+ # - :calendar calendar_name の結果 ( name, epoch, reverse, go back )
1030
+ # - name 暦法または暦年代 ({When::TM::Calendar}, {When::TM::CalendarEra})
1031
+ # - epoch 暦元 (Integer)
1032
+ # - reverse 暦年の順序 (Boolean)
1033
+ # [ false, nil 昇順 ]
1034
+ # [ true 降順 ]
1035
+ # - go back 参照イベントより前の暦日か(Boolean)
1036
+ # [ false, nil 否 ]
1037
+ # [ true 然り ]
1038
+ # - :cal_date cal_date の内容 (year, month, day)
1039
+ # [ year - 年 ({Numeric}) ]
1040
+ # [ month - 月 ({Numeric}) ]
1041
+ # [ day - 日 ({Numeric}) ]
1042
+ # - :clk_time to_clock_time の結果 ( 日, 時, 分, 秒 )
1043
+ # - :notes Hash (の Array (の Array)) - _notes(options)
1044
+ #
1045
+ def _to_h(options={})
1046
+ super.update({:cal_date=>@cal_date})
1047
+ end
1048
+
1049
+ # 要素の多言語対応文字列化
1050
+ #
1051
+ # @param [Integer] index 多言語対応文字列化する要素の指定
1052
+ # @param [When::BasicTypes::M17n] format 多言語対応文字列化の書式
1053
+ #
1054
+ # @return [When::BasicTypes::M17n]
1055
+ #
1056
+ def name(index, format=nil)
1057
+ digit = _digit(index) {|digit| digit <= DAY}
1058
+ coordinate = @cal_date[digit-1]
1059
+ return m17n(format % coordinate) if format
1060
+
1061
+ indices = @frame.indices[digit-1]
1062
+ if indices
1063
+ trunk = indices.trunk
1064
+ branch = indices.branch
1065
+ end
1066
+ format = branch ? m17n("%02d-") : "%02d"
1067
+ return m17n(format % coordinate) unless trunk
1068
+ trunk = trunk[coordinate * 1]
1069
+ return m17n(trunk) unless branch
1070
+ return trunk.prefix(branch[coordinate * 0||0])
1071
+ end
1072
+
1073
+ # 日
1074
+ #
1075
+ # @param [Integer] d 日付が'年月日'でない表現のための桁位置変更指示(大きいほうに位置をずらす)
1076
+ #
1077
+ # @return [Numeric] 自身の「日」
1078
+ #
1079
+ def day(d=0)
1080
+ @cal_date[DAY-1-d]
1081
+ end
1082
+
1083
+ # 月内通日
1084
+ #
1085
+ # @param [Integer] d 日付が'年月日'でない表現のための桁位置変更指示(大きいほうに位置をずらす)
1086
+ #
1087
+ # @return [Numeric] 自身の「月内通日」(1始まり)
1088
+ #
1089
+ def mday(d=0)
1090
+ to_i - floor(MONTH-d).to_i + 1
1091
+ end
1092
+
1093
+ # 年内通日
1094
+ #
1095
+ # @param [Integer] d 日付が'年月日'でない表現のための桁位置変更指示(大きいほうに位置をずらす)
1096
+ #
1097
+ # @return [Numeric] 自身の「年内通日」(1始まり)
1098
+ #
1099
+ def yday(d=0)
1100
+ to_i - floor(YEAR-d).to_i + 1
1101
+ end
1102
+
1103
+ # 七曜
1104
+ #
1105
+ # @return [Numeric] 自身の「七曜」(日曜 0 始まり)
1106
+ #
1107
+ def wday
1108
+ (to_i + 1) % 7
1109
+ end
1110
+
1111
+ # 七曜(暦週)
1112
+ #
1113
+ # @return [Numeric] 自身の「七曜」(月曜 1 始まり)
1114
+ #
1115
+ def cwday
1116
+ (to_i % 7) + 1
1117
+ end
1118
+
1119
+ # 暦週
1120
+ #
1121
+ # @param [Integer] d 日付が'年月日'でない表現のための桁位置変更指示(大きいほうに位置をずらす)
1122
+ #
1123
+ # @return [Numeric] 自身の「暦週」
1124
+ #
1125
+ def cweek(d=0)
1126
+ [1,0,-1].each do |i|
1127
+ start = ((self + PeriodDuration.new(i, YEAR-d)).floor(YEAR-d,DAY) + PeriodDuration.new(4, DAY)) & Residue.new(0,7,-1)
1128
+ return ((to_i - start.to_i).div 7) + 1 if self >= start
1129
+ end
1130
+ raise IndexError, 'Cannot decide year number'
1131
+ end
1132
+
1133
+ # 月内通週
1134
+ #
1135
+ # @param [Integer] w 週の最初の曜日(0:月,.., 6:日)
1136
+ # @param [Integer] m 一週間の日数
1137
+ # @param [Integer] d 日付が'年月日'でない表現のための桁位置変更指示(大きいほうに位置をずらす)
1138
+ #
1139
+ # @return [Numeric] 自身の「月内通週」(その月に完全に含まれる最初の週を1とする)
1140
+ #
1141
+ def mweek(w=6, m=7, d=0)
1142
+ 1 + (to_i - (floor(MONTH-d,DAY) & Residue.new(w,m)).to_i).div(7)
1143
+ end
1144
+
1145
+ # 年内通週
1146
+ #
1147
+ # @param [Integer] w 週の最初の曜日(0:月,.., 6:日)
1148
+ # @param [Integer] m 一週間の日数
1149
+ # @param [Integer] d 日付が'年月日'でない表現のための桁位置変更指示(大きいほうに位置をずらす)
1150
+ #
1151
+ # @return [Numeric]
1152
+ # 自身の「年内通週」(その年に完全に含まれる最初の週を1とする)
1153
+ #
1154
+ def yweek(w=6, m=7, d=0)
1155
+ 1 + (to_i - (floor(YEAR-d,DAY) & Residue.new(w,m)).to_i).div(7)
1156
+ end
1157
+
1158
+ #
1159
+ #
1160
+ # @param [Integer] d 日付が'年月日'でない表現のための桁位置変更指示(大きいほうに位置をずらす)
1161
+ #
1162
+ # @return [Numeric] 自身の「月」
1163
+ #
1164
+ def month(d=0)
1165
+ @cal_date[MONTH-1-d]
1166
+ end
1167
+ alias :mon :month
1168
+
1169
+ # 年内通月
1170
+ #
1171
+ # @param [Integer] d1 日付が'年月日'でない表現のための桁位置変更指示-年用(大きいほうに位置をずらす)
1172
+ # @param [Integer] d2 日付が'年月日'でない表現のための桁位置変更指示-月用(大きいほうに位置をずらす)
1173
+ #
1174
+ # @return [Numeric] 自身の「年内通月」(1始まり)
1175
+ #
1176
+ def ymon(d1=0, d2=0)
1177
+ current = floor(YEAR-d1, MONTH-d2)
1178
+ @frame._length(@cal_date[(YEAR-1-d1)...(MONTH-1-d2)]).times do |i|
1179
+ return i+1 if current == self
1180
+ current = current.succ
1181
+ end
1182
+ raise IndexError, 'Cannot decide month number'
1183
+ end
1184
+
1185
+ # 年
1186
+ #
1187
+ # @param [Integer] d 日付が'年月日'でない表現のための桁位置変更指示(大きいほうに位置をずらす)
1188
+ #
1189
+ # @return [Numeric] 自身の「年」
1190
+ #
1191
+ def year(d=0)
1192
+ @cal_date[YEAR-1-d]
1193
+ end
1194
+
1195
+ # 暦週の年
1196
+ #
1197
+ # @param [Integer] d 日付が'年月日'でない表現のための桁位置変更指示(大きいほうに位置をずらす)
1198
+ #
1199
+ # @return [Numeric] 自身の「暦週の年」
1200
+ #
1201
+ def cwyear(d=0)
1202
+ [1,0,-1].each do |i|
1203
+ start = ((self + PeriodDuration.new(i, YEAR-d)).floor(YEAR-d,DAY) + PeriodDuration.new(4, DAY)) & Residue.new(0,7,-1)
1204
+ return year(d)+i if self >= start
1205
+ end
1206
+ raise IndexError, 'Cannot decide year number'
1207
+ end
1208
+
1209
+ # 多言語対応文字列化 - When.exe Standard Representation により多言語対応文字列化する
1210
+ #
1211
+ # @param [Integer] precision どの桁まで多言語対応文字列化するか、分解能で指定する
1212
+ # @param [false] round 常に切り捨てる(DateAndTimeとの互換性のためのダミーの引数)
1213
+ #
1214
+ # @return [When::BasicTypes::M17n]
1215
+ #
1216
+ def to_m17n(precision=@precision, round=false)
1217
+ date = m17n(_date_to_s(precision))
1218
+ return date unless @calendar_era
1219
+ return _parent_labels.inject(m17n(@calendar_era_name[0])) {|era_name, parent|
1220
+ era_name.prefix(m17n(parent) + '::')
1221
+ } + date
1222
+ end
1223
+
1224
+ # 文字列化 - When.exe Standard Representation により文字列化する
1225
+ #
1226
+ # @param [Integer] precision どの桁まで多言語対応文字列化するか、分解能で指定する
1227
+ # @param [false] round 常に切り捨てる(DateAndTimeとの互換性のためのダミーの引数)
1228
+ #
1229
+ # @return [String]
1230
+ #
1231
+ def to_s(precision=@precision, round=false)
1232
+ date = _date_to_s(precision)
1233
+ return date unless @calendar_era
1234
+ return _parent_labels.inject(@calendar_era_name[0].to_s) {|era_name, parent|
1235
+ parent.to_s + '::' + era_name
1236
+ } + date
1237
+ end
1238
+
1239
+ # event を 文字列化 - 日時で与えられた event を文字列化する
1240
+ #
1241
+ # @param [When::TM::TemporalPosition] other 時系の歩度を比較する基準(nilは比較しない)
1242
+ # @param [Numeric] round_precision イベント名(イベント)出力の場合の時刻の丸め位置(nilなら丸めない)
1243
+ #
1244
+ # @return [String]
1245
+ #
1246
+ # @note
1247
+ # events 配列なし - 日時をそのまま文字列化
1248
+ # 日時の精度が日より細かい - イベント名(イベント時刻)
1249
+ # 日時の精度が日 - イベント名(当日までの経過日数)
1250
+ #
1251
+ def _event_form(other=nil, round_precision=nil)
1252
+ return to_m17n unless events
1253
+ return events[0] + '(' + _clk_time_for_inspect(round_precision).to_s(round_precision || precision)[/[:*=0-9]+/] + ')' if precision > When::DAY
1254
+ return events[0] unless other
1255
+ other = JulianDate.dynamical_time(other.dynamical_time,
1256
+ {:time_standard=>time_standard}) unless time_standard.rate_of_clock == other.time_standard.rate_of_clock
1257
+ events[0] + '(' + (other.to_i - to_i).to_s + ')'
1258
+ end
1259
+
1260
+ private
1261
+
1262
+ # 日付の年号に曖昧性がある場合の親年号の label の Array
1263
+ #
1264
+ # @return [Array<String>]
1265
+ #
1266
+ def _parent_labels
1267
+ return [] unless (area = When::TM::CalendarEra[nil]) &&
1268
+ (period = area[nil])
1269
+ list = []
1270
+ era = @calendar_era
1271
+ while (labels = period[era.label.to_s]) &&
1272
+ (epoch = labels[era.epoch_year]) &&
1273
+ (epoch.size > 1) &&
1274
+ (parent = era.parent).respond_to?(:epoch_year)
1275
+ list << parent.label
1276
+ era = parent
1277
+ end
1278
+ list
1279
+ end
1280
+
1281
+ # 日付の年号以外の部分を文字列化する
1282
+ #
1283
+ # @param [Integer] precision どの桁まで多言語対応文字列化するか、分解能で指定する
1284
+ #
1285
+ # @return [String]
1286
+ #
1287
+ def _date_to_s(precision)
1288
+ # 準備
1289
+ precision = [precision, 1 - @cal_date.length].max
1290
+ precision = [precision, DAY].min
1291
+ terms = []
1292
+ ext_dg = [(@extra_year_digits||1).to_i, 0].max
1293
+ year_dg = @frame.indices.length <= 2 ? 4 : 2
1294
+
1295
+ #
1296
+ year_by_epoch = @cal_date[0]
1297
+ if @calendar_era_name
1298
+ era, epoch, reverse = @calendar_era_name
1299
+ year_in_term = reverse ? -year_by_epoch : year_by_epoch
1300
+ year_by_calendar = epoch + year_by_epoch if epoch
1301
+ terms << year_in_term
1302
+ format = (0..99) === (year_in_term * 1) ? "%02d." : "%0#{year_dg}d."
1303
+ if year_by_calendar && year_by_calendar != year_in_term
1304
+ terms << (year_by_calendar * 1)
1305
+ format += "(%0#{year_dg}d)"
1306
+ end
1307
+ else
1308
+ terms << year_by_epoch
1309
+ format = (0..(10**year_dg-1)) === (year_by_epoch * 1) ? "%0#{year_dg}d." : "%+0#{5+ext_dg}d."
1310
+ end
1311
+
1312
+ # 月日
1313
+ ((1-@cal_date.length)..-1).each do |i|
1314
+ break if (i >= precision)
1315
+ terms << @cal_date[i]
1316
+ format += "%02d."
1317
+ end
1318
+
1319
+ # 結果
1320
+ date = Pair._format([format] + terms)
1321
+ date.sub!(/([^\d])\(([-+\d]+)\)/, '(\2)\1') if era
1322
+ date = date[0..-2] unless @frame.pair[precision-1] || date[-1..-1] != '.'
1323
+ date.gsub!(/\./, '-') if (@frame.indices.length <= 3) && !era
1324
+ return date
1325
+ end
1326
+ end
1327
+
1328
+ class DateAndTime < CalDate
1329
+
1330
+ # 要素の多言語対応文字列化
1331
+ #
1332
+ # @param [Integer] index 多言語対応文字列化する要素の指定
1333
+ # @param [When::BasicTypes::M17n] format 多言語対応文字列化の書式
1334
+ #
1335
+ # @return [When::BasicTypes::M17n]
1336
+ #
1337
+ def name(index, format=nil)
1338
+ digit = _digit(index)
1339
+ (digit <= DAY) ? super : @clk_time.name(digit, format)
1340
+ end
1341
+
1342
+ # 多言語対応文字列化 - When.exe Standard Representation により多言語対応文字列化する
1343
+ #
1344
+ # @param [Integer] precision どの桁まで多言語対応文字列化するか、分解能で指定する
1345
+ # @param [true, false] round 指定の桁までで丸める(true)か, 切り捨てる(false)か
1346
+ # @note 丸めるのは precision が When::DAY よりも高精度の場合のみである
1347
+ #
1348
+ # @return [When::BasicTypes::M17n]
1349
+ #
1350
+ def to_m17n(precision=@precision, round=false)
1351
+ super + _clk_time_for_inspect(round ? precision : nil).to_m17n(precision)
1352
+ end
1353
+
1354
+ # 文字列化 -When.exe Standard Representation により文字列化する
1355
+ #
1356
+ # @param [Integer] precision どの桁まで多言語対応文字列化するか、分解能で指定する
1357
+ # @param [true, false] round 指定の桁までで丸める(true)か, 切り捨てる(false)か
1358
+ # @note 丸めるのは precision が When::DAY よりも高精度の場合のみである
1359
+ #
1360
+ # @return [String]
1361
+ #
1362
+ def to_s(precision=@precision, round=false)
1363
+ super + _clk_time_for_inspect(round ? precision : nil).to_s(precision)
1364
+ end
1365
+
1366
+ # 出力に使用する clk_time の作成
1367
+ def _clk_time_for_inspect(precision)
1368
+ return @clk_time unless precision && precision > When::DAY
1369
+ base = self + When::TM::Duration.new(@clk_time.frame._round_value(precision))
1370
+ base.clk_time.clk_time[When::HOUR] = @clk_time.clk_time[When::HOUR] + 1 unless self.to_i == base.to_i
1371
+ return base.clk_time
1372
+ end
1373
+ private :_clk_time_for_inspect
1374
+
1375
+ # 時
1376
+ #
1377
+ # @param [Integer] d 時刻が'時分秒'でない表現のための桁位置変更指示(小さいほうに位置をずらす)
1378
+ #
1379
+ # @return [Numeric] 自身の「時」
1380
+ #
1381
+ def hour(d=0)
1382
+ @clk_time.hour(d)
1383
+ end
1384
+
1385
+ #
1386
+ #
1387
+ # @param [Integer] d 時刻が'時分秒'でない表現のための桁位置変更指示(小さいほうに位置をずらす)
1388
+ #
1389
+ # @return [Numeric] 自身の「分」
1390
+ #
1391
+ def minute(d=0)
1392
+ @clk_time.minute(d)
1393
+ end
1394
+ alias :min :minute
1395
+
1396
+ #
1397
+ #
1398
+ # @param [Integer] d 時刻が'時分秒'でない表現のための桁位置変更指示(小さいほうに位置をずらす)
1399
+ #
1400
+ # @return [Numeric] 自身の「秒」
1401
+ #
1402
+ def second(d=0)
1403
+ @clk_time.second(d)
1404
+ end
1405
+ alias :sec :second
1406
+ end
1407
+ end
1408
+ end