when_exe 0.3.7 → 0.3.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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