when_exe 0.2.100 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE.ja.txt +25 -25
- data/LICENSE.txt +31 -31
- data/bin/irb.rc +5 -0
- data/bin/locales.rb +2 -2
- data/bin/when.rb +16 -0
- data/bin/when.rb.config +7 -0
- data/lib/when_exe.rb +616 -14
- data/lib/when_exe/basictypes.rb +615 -0
- data/lib/when_exe/calendartypes.rb +1700 -0
- data/lib/when_exe/coordinates.rb +1936 -0
- data/lib/when_exe/core/compatibility.rb +54 -0
- data/lib/when_exe/core/duration.rb +72 -72
- data/lib/when_exe/core/extension.rb +382 -0
- data/lib/when_exe/ephemeris.rb +1845 -0
- data/lib/when_exe/googlecalendar.rb +140 -0
- data/lib/when_exe/icalendar.rb +1587 -0
- data/lib/when_exe/inspect.rb +1237 -0
- data/lib/when_exe/locales/af.rb +90 -0
- data/lib/when_exe/locales/ar.rb +145 -0
- data/lib/when_exe/locales/az.rb +90 -0
- data/lib/when_exe/locales/bg.rb +90 -0
- data/lib/when_exe/locales/bn.rb +94 -0
- data/lib/when_exe/locales/bs.rb +121 -0
- data/lib/when_exe/locales/ca.rb +92 -0
- data/lib/when_exe/locales/cs.rb +107 -0
- data/lib/when_exe/locales/cy.rb +150 -0
- data/lib/when_exe/locales/da.rb +84 -0
- data/lib/when_exe/locales/de.rb +92 -0
- data/lib/when_exe/locales/de_AT.rb +92 -0
- data/lib/when_exe/locales/de_CH.rb +92 -0
- data/lib/when_exe/locales/el.rb +93 -0
- data/lib/when_exe/locales/en.rb +88 -0
- data/lib/when_exe/locales/en_AU.rb +88 -0
- data/lib/when_exe/locales/en_CA.rb +88 -0
- data/lib/when_exe/locales/en_GB.rb +88 -0
- data/lib/when_exe/locales/en_IN.rb +88 -0
- data/lib/when_exe/locales/en_NZ.rb +88 -0
- data/lib/when_exe/locales/eo.rb +89 -0
- data/lib/when_exe/locales/es.rb +84 -0
- data/lib/when_exe/locales/es_419.rb +84 -0
- data/lib/when_exe/locales/es_AR.rb +84 -0
- data/lib/when_exe/locales/es_CL.rb +84 -0
- data/lib/when_exe/locales/es_CO.rb +84 -0
- data/lib/when_exe/locales/es_MX.rb +84 -0
- data/lib/when_exe/locales/es_PE.rb +85 -0
- data/lib/when_exe/locales/es_VE.rb +84 -0
- data/lib/when_exe/locales/et.rb +94 -0
- data/lib/when_exe/locales/eu.rb +95 -0
- data/lib/when_exe/locales/fa.rb +80 -0
- data/lib/when_exe/locales/fi.rb +89 -0
- data/lib/when_exe/locales/fr.rb +88 -0
- data/lib/when_exe/locales/fr_CA.rb +88 -0
- data/lib/when_exe/locales/fr_CH.rb +88 -0
- data/lib/when_exe/locales/gl.rb +81 -0
- data/lib/when_exe/locales/he.rb +84 -0
- data/lib/when_exe/locales/hi.rb +80 -0
- data/lib/when_exe/locales/hi_IN.rb +84 -0
- data/lib/when_exe/locales/hr.rb +128 -0
- data/lib/when_exe/locales/hu.rb +84 -0
- data/lib/when_exe/locales/id.rb +89 -0
- data/lib/when_exe/locales/is.rb +89 -0
- data/lib/when_exe/locales/it.rb +87 -0
- data/lib/when_exe/locales/it_CH.rb +87 -0
- data/lib/when_exe/locales/ja.rb +78 -0
- data/lib/when_exe/locales/kn.rb +86 -0
- data/lib/when_exe/locales/ko.rb +78 -0
- data/lib/when_exe/locales/links.rb +2342 -0
- data/lib/when_exe/locales/lo.rb +123 -0
- data/lib/when_exe/locales/locales.rb +91 -0
- data/lib/when_exe/locales/lt.rb +111 -0
- data/lib/when_exe/locales/lv.rb +118 -0
- data/lib/when_exe/locales/mk.rb +93 -0
- data/lib/when_exe/locales/mn.rb +80 -0
- data/lib/when_exe/locales/nb.rb +81 -0
- data/lib/when_exe/locales/ne.rb +81 -0
- data/lib/when_exe/locales/nl.rb +92 -0
- data/lib/when_exe/locales/nn.rb +73 -0
- data/lib/when_exe/locales/or.rb +84 -0
- data/lib/when_exe/locales/pl.rb +128 -0
- data/lib/when_exe/locales/pt.rb +88 -0
- data/lib/when_exe/locales/pt_BR.rb +88 -0
- data/lib/when_exe/locales/rm.rb +143 -0
- data/lib/when_exe/locales/ro.rb +105 -0
- data/lib/when_exe/locales/ru.rb +128 -0
- data/lib/when_exe/locales/sk.rb +109 -0
- data/lib/when_exe/locales/sl.rb +122 -0
- data/lib/when_exe/locales/sr.rb +122 -0
- data/lib/when_exe/locales/sv.rb +83 -0
- data/lib/when_exe/locales/sw.rb +89 -0
- data/lib/when_exe/locales/th.rb +78 -0
- data/lib/when_exe/locales/tl.rb +99 -0
- data/lib/when_exe/locales/tr.rb +96 -0
- data/lib/when_exe/locales/uk.rb +128 -0
- data/lib/when_exe/locales/uz.rb +128 -0
- data/lib/when_exe/locales/vi.rb +94 -0
- data/lib/when_exe/locales/wo.rb +82 -0
- data/lib/when_exe/locales/zh_CN.rb +77 -0
- data/lib/when_exe/locales/zh_HK.rb +77 -0
- data/lib/when_exe/locales/zh_TW.rb +77 -0
- data/lib/when_exe/mini_application.rb +252 -0
- data/lib/when_exe/parts/enumerator.rb +472 -0
- data/lib/when_exe/parts/geometric_complex.rb +379 -0
- data/lib/when_exe/parts/locale.rb +513 -0
- data/lib/when_exe/parts/method_cash.rb +207 -0
- data/lib/when_exe/parts/resource.rb +806 -0
- data/lib/when_exe/parts/timezone.rb +182 -0
- data/lib/when_exe/region/bahai.rb +145 -0
- data/lib/when_exe/region/balinese.rb +627 -0
- data/lib/when_exe/region/chinese.rb +896 -0
- data/lib/when_exe/region/chinese_calendar.rb +919 -0
- data/lib/when_exe/region/chinese_epoch.rb +1245 -0
- data/lib/when_exe/region/christian.rb +644 -0
- data/lib/when_exe/region/far_east.rb +192 -0
- data/lib/when_exe/region/french.rb +66 -0
- data/lib/when_exe/region/geologicalage.rb +639 -0
- data/lib/when_exe/region/indian.rb +1066 -0
- data/lib/when_exe/region/iranian.rb +66 -0
- data/lib/when_exe/region/islamic.rb +105 -0
- data/lib/when_exe/region/japanese.rb +851 -0
- data/lib/when_exe/region/japanese_notes.rb +964 -0
- data/lib/when_exe/region/japanese_residues.rb +1149 -0
- data/lib/when_exe/region/javanese.rb +228 -0
- data/lib/when_exe/region/jewish.rb +127 -0
- data/lib/when_exe/region/korean.rb +267 -0
- data/lib/when_exe/region/m17n.rb +115 -0
- data/lib/when_exe/region/martian.rb +215 -0
- data/lib/when_exe/region/mayan.rb +122 -0
- data/lib/when_exe/region/moon.rb +333 -0
- data/lib/when_exe/region/nihon_shoki.rb +73 -0
- data/lib/when_exe/region/planets.rb +585 -0
- data/lib/when_exe/region/pope.rb +298 -0
- data/lib/when_exe/region/residue.rb +229 -0
- data/lib/when_exe/region/roman.rb +325 -0
- data/lib/when_exe/region/ryukyu.rb +98 -0
- data/lib/when_exe/region/shire.rb +254 -0
- data/lib/when_exe/region/sun.rb +210 -0
- data/lib/when_exe/region/thai.rb +227 -0
- data/lib/when_exe/region/tibetan.rb +233 -0
- data/lib/when_exe/region/v50.rb +111 -0
- data/lib/when_exe/region/vietnamese.rb +173 -0
- data/lib/when_exe/region/world.rb +197 -0
- data/lib/when_exe/timestandard.rb +547 -0
- data/lib/when_exe/tmduration.rb +330 -330
- data/lib/when_exe/tmobjects.rb +1295 -0
- data/lib/when_exe/tmposition.rb +1955 -0
- data/lib/when_exe/tmreference.rb +1547 -0
- data/lib/when_exe/version.rb +10 -3
- data/link_to_online_documents +4 -0
- data/test/examples/JapanHolidays.ics +456 -0
- data/test/examples/Millennium.ics +17 -0
- data/test/examples/NewYork.ics +61 -0
- data/test/examples/Residue.m17n +135 -0
- data/test/examples/Spatial.m17n +179 -0
- data/test/examples/Terms.m17n +39 -0
- data/test/examples/Test.ics +53 -0
- data/test/examples/USA-DST.ics +61 -0
- data/test/examples/geometric_complex.rb +41 -0
- data/test/examples/sample.xml +14 -0
- data/test/examples/today.rb +61 -0
- data/test/test.rb +54 -19
- data/test/test.rb.config +1 -0
- data/test/test/basictypes.rb +368 -0
- data/test/test/calendartypes.rb +57 -0
- data/test/test/coordinates.rb +380 -0
- data/test/test/ephemeris.rb +127 -0
- data/test/test/googlecalendar.rb +167 -0
- data/test/test/icalendar.rb +848 -0
- data/test/test/inspect.rb +115 -0
- data/test/test/parts.rb +480 -0
- data/test/test/region/chinese.rb +161 -0
- data/test/test/region/french.rb +33 -0
- data/test/test/region/geologicalage.rb +14 -0
- data/test/test/region/indian.rb +55 -0
- data/test/test/region/iran.rb +54 -0
- data/test/test/region/islamic.rb +18 -0
- data/test/test/region/japanese.rb +62 -0
- data/test/test/region/jewish.rb +61 -0
- data/test/test/region/m17n.rb +181 -0
- data/test/test/region/mayan.rb +78 -0
- data/test/test/region/moon.rb +14 -0
- data/test/test/region/planets.rb +14 -0
- data/test/test/region/residue.rb +123 -0
- data/test/test/region/sun.rb +14 -0
- data/test/test/region/thai.rb +94 -0
- data/test/test/region/tibetan.rb +30 -0
- data/test/test/tmobjects.rb +356 -57
- data/test/test/tmposition.rb +237 -0
- data/test/test/tmreference.rb +95 -0
- data/when_exe.gemspec +2 -2
- metadata +187 -7
- data/doc/COPYING +0 -31
- data/doc/COPYING.ja +0 -25
- data/doc/document_url +0 -1
|
@@ -0,0 +1,1936 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
=begin
|
|
3
|
+
Copyright (C) 2011-2013 Takashi SUGA
|
|
4
|
+
|
|
5
|
+
You may use and/or modify this file according to the license described in the LICENSE.txt file included in this archive.
|
|
6
|
+
=end
|
|
7
|
+
|
|
8
|
+
#
|
|
9
|
+
# 座標の記述に用いる諸オブジェクト
|
|
10
|
+
#
|
|
11
|
+
module When::Coordinates
|
|
12
|
+
# 変換テーブル
|
|
13
|
+
PRECISION = {'YEAR'=>When::YEAR, 'MONTH' =>When::MONTH, 'WEEK' =>When::WEEK, 'DAY' =>When::DAY,
|
|
14
|
+
'HOUR'=>When::HOUR, 'MINUTE'=>When::MINUTE, 'SECOND'=>When::SECOND, 'SYSTEM'=>When::SYSTEM}
|
|
15
|
+
PERIOD = {'P1Y' =>When::YEAR, 'P1M' =>When::MONTH, 'P1W' =>When::WEEK, 'P1D' =>When::DAY,
|
|
16
|
+
'PT1H'=>When::HOUR, 'PT1M' =>When::MINUTE, 'PT1S' =>When::SECOND,
|
|
17
|
+
'1Y' =>When::YEAR, '1M' =>When::MONTH, '1W' =>When::WEEK, '1D' =>When::DAY,
|
|
18
|
+
'1h' =>When::HOUR, '1m' =>When::MINUTE, '1s' =>When::SECOND}
|
|
19
|
+
VALUE = {'DATE'=>When::DAY, 'TIME' =>When::SYSTEM, 'DATE-TIME'=>When::SYSTEM} # RFC 5545
|
|
20
|
+
PRECISION_NAME = PRECISION.invert
|
|
21
|
+
PERIOD_NAME = {When::YEAR=>'P1Y' , When::MONTH=>'P1M', When::WEEK =>'P1W', When::DAY=>'P1D',
|
|
22
|
+
When::HOUR=>'PT1H', When::MINUTE=>'PT1M', When::SECOND=>'PT1S'}
|
|
23
|
+
MATCH = {'NS'=>/(N|S|北緯|南緯)/, 'EW'=>/(E|W|東経|西経)/}
|
|
24
|
+
|
|
25
|
+
# 60進->10進変換
|
|
26
|
+
#
|
|
27
|
+
# @param [String] src 60進法で表した方向付きの数値
|
|
28
|
+
# @param [String] dir 方向 ('NS' または 'EW')
|
|
29
|
+
#
|
|
30
|
+
# @return [Numeric] 10進変換した数値 (src が nil なら0.0を、Numeric ならそのままsrcを返す)
|
|
31
|
+
#
|
|
32
|
+
def self.to_deg(src, dir)
|
|
33
|
+
case src
|
|
34
|
+
when String
|
|
35
|
+
src = src.gsub(/_+/,'').gsub(/@/, '.')
|
|
36
|
+
return src.to_f unless (src =~ MATCH[dir])
|
|
37
|
+
sign = ($1 == dir[1..1]) ? -1 : +1
|
|
38
|
+
value = src.gsub(MATCH[dir], '').strip
|
|
39
|
+
if ((value + "00000") =~ /^(\d+)\.(\d{2})(\d{2})(\d+)$/)
|
|
40
|
+
deg, min, sec, frac = $~[1..4]
|
|
41
|
+
sec += "." + frac
|
|
42
|
+
else
|
|
43
|
+
deg, min, sec = value.split(/[^\d.]+/)
|
|
44
|
+
end
|
|
45
|
+
return sign * (deg.to_i + (min||0).to_f/60 + (sec||0).to_f/3600)
|
|
46
|
+
when NilClass
|
|
47
|
+
0.0
|
|
48
|
+
when Numeric
|
|
49
|
+
src
|
|
50
|
+
else
|
|
51
|
+
raise TypeError, "Invalid Location Type"
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# 10進->60進変換
|
|
56
|
+
#
|
|
57
|
+
# @param [Numeric] src 数値
|
|
58
|
+
# @param [String] dir 方向 ('NS' または 'EW')
|
|
59
|
+
#
|
|
60
|
+
# @return [String] 60進変換した数値
|
|
61
|
+
#
|
|
62
|
+
def self.to_dms(src, dir)
|
|
63
|
+
dir = (src >= 0) ? dir[0..0] : dir[1..1]
|
|
64
|
+
deg, min = src.abs.divmod(1)
|
|
65
|
+
min, sec = (60*min).divmod(1)
|
|
66
|
+
sec = (60*sec).floor
|
|
67
|
+
(['N','S'].include?(dir) ? "%02d.%02d%02d%s" : "%03d.%02d%02d%s") % [deg, min, sec, dir]
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
#
|
|
71
|
+
# 剰余類
|
|
72
|
+
#
|
|
73
|
+
class Residue < When::BasicTypes::Object
|
|
74
|
+
|
|
75
|
+
LabelProperty = 'label'
|
|
76
|
+
|
|
77
|
+
class << self
|
|
78
|
+
#
|
|
79
|
+
# 曜日(剰余類)
|
|
80
|
+
#
|
|
81
|
+
# @param [Numeric] day 月曜を 0 とする七曜(剰余類)を返します
|
|
82
|
+
# @param [String] day 最初の3文字から決定した七曜(剰余類)を返します。
|
|
83
|
+
# 一致する七曜(剰余類)がない場合、名前の一致するその他の剰余類を探して返します。
|
|
84
|
+
#
|
|
85
|
+
# @return [When::Coordinates::Residue]
|
|
86
|
+
#
|
|
87
|
+
def day_of_week(day)
|
|
88
|
+
return day if day.kind_of?(self)
|
|
89
|
+
|
|
90
|
+
day ||= 0
|
|
91
|
+
week = When.Resource('_co:CommonResidue::Week').child
|
|
92
|
+
case day
|
|
93
|
+
when Numeric ; return week[day]
|
|
94
|
+
when String ;
|
|
95
|
+
else ; return nil
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
match = day[/^...|^.{1,2}$/]
|
|
99
|
+
if match
|
|
100
|
+
week.size.times do |i|
|
|
101
|
+
return week[i] if week[i].label.=~(/^#{match}/i)
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
ObjectSpace.each_object(self) do |object|
|
|
106
|
+
return object if object.registered? && object.label.=~(/^#{day}$/)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
return nil
|
|
110
|
+
end
|
|
111
|
+
alias :to_residue :day_of_week
|
|
112
|
+
|
|
113
|
+
# 汎用の mod
|
|
114
|
+
#
|
|
115
|
+
# @param [Numeric] nn 被除数
|
|
116
|
+
# @param [Block] dd 手続き
|
|
117
|
+
#
|
|
118
|
+
# nn = rem + dd(quot)
|
|
119
|
+
#
|
|
120
|
+
# div = dd(quot+1)-dd(quot)
|
|
121
|
+
#
|
|
122
|
+
# となるように rem, div, quot を決めたい手続き
|
|
123
|
+
#
|
|
124
|
+
# @return [Array<Numeric>] [ quot, rem, div ]
|
|
125
|
+
# nn を dd で「割った」商(quot), 余り(rem)および除数(div)を返します。
|
|
126
|
+
# remは非負、quotは Integer。
|
|
127
|
+
#
|
|
128
|
+
def mod(nn, &dd)
|
|
129
|
+
u = dd.call(0)
|
|
130
|
+
y = ((nn-u)*256).divmod(dd.call(256)-u)[0] - 1
|
|
131
|
+
w1, w2 = dd.call(y), dd.call(y+1)
|
|
132
|
+
until w1 <= nn && nn < w2
|
|
133
|
+
if w2 <= nn then y, w1, w2 = y+1, w2, dd.call(y+2)
|
|
134
|
+
else y, w1, w2 = y-1, dd.call(y-1), w1
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
return y, nn-w1, w2-w1
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# 中国剰余
|
|
141
|
+
#
|
|
142
|
+
# @param [Array<Numeric>] a [ num, den ] den で割って num 余ることを示す配列
|
|
143
|
+
# @param [Array<Numeric>] b [ num, den ] den で割って num 余ることを示す配列
|
|
144
|
+
#
|
|
145
|
+
# @return [Array<Numeric>] a と b の条件をともに満たす [ num, den ]
|
|
146
|
+
#
|
|
147
|
+
def _china(a, b)
|
|
148
|
+
b, a = a, b if (a[1] <= b[1])
|
|
149
|
+
g, p, q = _gcd(a[1], b[1])
|
|
150
|
+
return [((b[0]*a[1]*q-a[0]*b[1]*p)*(a[1]*q-b[1]*p)) % (a[1]*b[1]), a[1]*b[1]] if (g == 1)
|
|
151
|
+
r = a[0] % g
|
|
152
|
+
s = b[0] % g
|
|
153
|
+
return nil unless (r == s)
|
|
154
|
+
m = _china([(a[0]-r).div(g), a[1].div(g)], [(b[0]-s).div(g), b[1].div(g)])
|
|
155
|
+
return nil unless (m)
|
|
156
|
+
return [m[0]*g+r, m[1]*g]
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
private
|
|
160
|
+
|
|
161
|
+
# 最大公約数
|
|
162
|
+
def _gcd(a,b)
|
|
163
|
+
c, x = a.divmod(b)
|
|
164
|
+
g = [[a, 1, 0],
|
|
165
|
+
[b, c, 1]]
|
|
166
|
+
|
|
167
|
+
until (x == 0) do
|
|
168
|
+
k = g[1][0].div(x)
|
|
169
|
+
g << [x, k * g[1][1] + g[0][1], k * g[1][2] + g[0][2]]
|
|
170
|
+
g.shift
|
|
171
|
+
x = g[0][0] % g[1][0]
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
return [g[1][0]] + g[0][1..2]
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# 剰余
|
|
179
|
+
#
|
|
180
|
+
# @return [Numeric]
|
|
181
|
+
#
|
|
182
|
+
attr_accessor :remainder
|
|
183
|
+
protected :remainder=
|
|
184
|
+
|
|
185
|
+
# 法
|
|
186
|
+
#
|
|
187
|
+
# @return [Integer] (>0)
|
|
188
|
+
#
|
|
189
|
+
attr_reader :divisor
|
|
190
|
+
|
|
191
|
+
# 繰り上がり
|
|
192
|
+
#
|
|
193
|
+
# @return [Integer]
|
|
194
|
+
#
|
|
195
|
+
attr_accessor :carry
|
|
196
|
+
protected :carry=
|
|
197
|
+
|
|
198
|
+
# 単位
|
|
199
|
+
#
|
|
200
|
+
# @return [Hash] { String=>Numeric }
|
|
201
|
+
#
|
|
202
|
+
# Example : { 'day'=>11, 'year'=4 }
|
|
203
|
+
#
|
|
204
|
+
# 通日に適用するときは、11 ずらして計算 - 甲子日 = ユリウス日 11 + 60n
|
|
205
|
+
#
|
|
206
|
+
# 通年に適用するときは、 4 ずらして計算 - 甲子年 = 西暦 4 + 60n
|
|
207
|
+
#
|
|
208
|
+
attr_reader :units
|
|
209
|
+
|
|
210
|
+
# units の指定
|
|
211
|
+
#
|
|
212
|
+
# @param [String] arg あらかじめ units に指定した単位を用いる
|
|
213
|
+
#
|
|
214
|
+
# @return [When::Coordinates::Residue]
|
|
215
|
+
#
|
|
216
|
+
def to(arg)
|
|
217
|
+
return nil unless @units[arg]
|
|
218
|
+
self.class.new(@remainder, @divisor, @carry, {arg=>@units[arg]})
|
|
219
|
+
end
|
|
220
|
+
alias :/ :to
|
|
221
|
+
|
|
222
|
+
# オブジェクトの単位
|
|
223
|
+
#
|
|
224
|
+
# @return [String] 現在使用中の単位を返す
|
|
225
|
+
#
|
|
226
|
+
def event
|
|
227
|
+
keys = @units.keys
|
|
228
|
+
return (keys.size == 1) ? keys[0] : 'day'
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
# remainder の指定
|
|
232
|
+
#
|
|
233
|
+
# @param [Numeric] remainder 指定値を@remainderとする
|
|
234
|
+
# @param [String] remainder When::Parts::Resource の has-a 関係によりString に対応する子供オブジェクトを取得
|
|
235
|
+
#
|
|
236
|
+
# @return [When::Coordinates::Residue]
|
|
237
|
+
#
|
|
238
|
+
def [](remainder)
|
|
239
|
+
return super if !remainder.kind_of?(Numeric) || (child && child.length == @divisor)
|
|
240
|
+
return self if remainder == 0 && !child
|
|
241
|
+
remainder *= 1
|
|
242
|
+
return self.class.new(@remainder+remainder, @divisor, @carry, @label, @format, @units) unless (child && child.length > 0)
|
|
243
|
+
carry, remainder = (@remainder+remainder).divmod(@divisor)
|
|
244
|
+
base = child.reverse.each do |residue|
|
|
245
|
+
break residue if residue.remainder <= remainder
|
|
246
|
+
end
|
|
247
|
+
raise ArgumentError, "remainder out of range: #{remainder}" unless base.kind_of?(self.class)
|
|
248
|
+
base = base.dup
|
|
249
|
+
base.remainder = remainder
|
|
250
|
+
base.carry += carry
|
|
251
|
+
return base
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
# 典型的なイベントの発生間隔
|
|
255
|
+
#
|
|
256
|
+
# @param [String] event
|
|
257
|
+
#
|
|
258
|
+
# @return [When::TM::PeriodDuration]
|
|
259
|
+
#
|
|
260
|
+
def duration(event=self.event)
|
|
261
|
+
When::TM::PeriodDuration.new(@divisor, When::Coordinates::PRECISION[event.upcase])
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
# 派生オブジェクトと元オブジェクトの remainder の差
|
|
265
|
+
# (派生オブジェクトとは、元オブジェクトに[]演算を施して @remainder を変えたオブジェクト)
|
|
266
|
+
#
|
|
267
|
+
# @return [Integer]
|
|
268
|
+
#
|
|
269
|
+
# 派生オブジェクトでない場合 : 自身の remainder
|
|
270
|
+
#
|
|
271
|
+
# 派生オブジェクトである場合 : 派生オブジェクトと元オブジェクトの remainder の差
|
|
272
|
+
#
|
|
273
|
+
def difference
|
|
274
|
+
@difference ||= (registered? || iri !~ /:/) ? @remainder : @remainder - When.Resource(iri).remainder
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
# remainderの加算
|
|
278
|
+
#
|
|
279
|
+
# other : Numeric
|
|
280
|
+
#
|
|
281
|
+
# @return [When::Coordinates::Residue]
|
|
282
|
+
#
|
|
283
|
+
def +(other)
|
|
284
|
+
carry, remainder = (@remainder + other).divmod(@divisor)
|
|
285
|
+
return self.class.new(remainder, @divisor, @carry+carry, @units)
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
# remainderの減算
|
|
289
|
+
#
|
|
290
|
+
# @param [Numeric] other
|
|
291
|
+
#
|
|
292
|
+
# @return [When::Coordinates::Residue]
|
|
293
|
+
#
|
|
294
|
+
def -(other)
|
|
295
|
+
carry, remainder = (@remainder - other).divmod(@divisor)
|
|
296
|
+
return self.class.new(remainder, @divisor, @carry+carry, @units)
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
# carryの加算
|
|
300
|
+
#
|
|
301
|
+
# @param [Numeric] other
|
|
302
|
+
#
|
|
303
|
+
# @return [When::Coordinates::Residue]
|
|
304
|
+
#
|
|
305
|
+
def >>(other)
|
|
306
|
+
return self.class.new(@remainder, @divisor, @carry+other, @units)
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
# carryの減算
|
|
310
|
+
#
|
|
311
|
+
# @param [Numeric] other
|
|
312
|
+
#
|
|
313
|
+
# @return [When::Coordinates::Residue]
|
|
314
|
+
#
|
|
315
|
+
def <<(other)
|
|
316
|
+
return self.class.new(@remainder, @divisor, @carry-other, @units)
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
# 剰余類の共通集合
|
|
320
|
+
#
|
|
321
|
+
# @param [When::Coordinates::Residue] other
|
|
322
|
+
#
|
|
323
|
+
# @return [When::Coordinates::Residue]
|
|
324
|
+
#
|
|
325
|
+
def &(other)
|
|
326
|
+
case other
|
|
327
|
+
when Residue
|
|
328
|
+
if self.units == other.units
|
|
329
|
+
m = self.class._china([@remainder, @divisor], [other.remainder, other.divisor])
|
|
330
|
+
u = units.dup
|
|
331
|
+
else
|
|
332
|
+
keys = units.keys & other.units.keys
|
|
333
|
+
keys = ['day'] if keys == []
|
|
334
|
+
return nil unless (keys.size==1)
|
|
335
|
+
self_base = self.units[keys[0]] || 0
|
|
336
|
+
other_base = other.units[keys[0]] || 0
|
|
337
|
+
m = self.class._china([@remainder, @divisor],
|
|
338
|
+
[(other.remainder+other_base-self_base) % other.divisor, other.divisor])
|
|
339
|
+
u = {keys[0]=>self_base}
|
|
340
|
+
end
|
|
341
|
+
return nil unless (m)
|
|
342
|
+
return self.class.new(m[0], m[1], @carry, u)
|
|
343
|
+
when Pair
|
|
344
|
+
return Pair.new(self & other.trunk, other.branch)
|
|
345
|
+
when Numeric
|
|
346
|
+
keys = @units.keys
|
|
347
|
+
d = (keys.size == 1) ? @units[keys[0]] : (@units['day']||0)
|
|
348
|
+
c, m = (other-d).divmod(@divisor)
|
|
349
|
+
c += 1 if (m > @remainder)
|
|
350
|
+
return (c + @carry) * @divisor + @remainder + d
|
|
351
|
+
else
|
|
352
|
+
position = When::TM::Position.any_other(other)
|
|
353
|
+
raise TypeError, "Can't convert #{other.class} to When::TM::TemporalPosition" unless position
|
|
354
|
+
return position & self
|
|
355
|
+
end
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
# 剰余
|
|
359
|
+
#
|
|
360
|
+
# @param [When::TM::TemporalPosition, Numeric, When::Coordinates::Pair] other
|
|
361
|
+
#
|
|
362
|
+
# @return ['other' と同じクラス]
|
|
363
|
+
#
|
|
364
|
+
def %(other)
|
|
365
|
+
case other
|
|
366
|
+
when Pair
|
|
367
|
+
return Pair.new(self % other.trunk, other.branch)
|
|
368
|
+
when Numeric
|
|
369
|
+
keys = @units.keys
|
|
370
|
+
d = (keys.size == 1) ? @units[keys[0]] : (@units['day']||0)
|
|
371
|
+
return (other-d) % @divisor
|
|
372
|
+
else
|
|
373
|
+
position = When::TM::Position.any_other(other)
|
|
374
|
+
raise TypeError, "Can't convert #{other.class} to When::TM::TemporalPosition" unless position
|
|
375
|
+
return self[position % self]
|
|
376
|
+
end
|
|
377
|
+
end
|
|
378
|
+
|
|
379
|
+
# Enumerator の生成
|
|
380
|
+
#
|
|
381
|
+
# @overload initialize()
|
|
382
|
+
#
|
|
383
|
+
# @overload initialize(range, count_limit=nil)
|
|
384
|
+
# @param [Range, When::Parts::GeometricComplex] range 始点-range.first, 終点-range.last
|
|
385
|
+
# @param [Integer] count_limit 繰り返し回数(デフォルトは指定なし)
|
|
386
|
+
#
|
|
387
|
+
# @overload initialize(first, direction, count_limit)
|
|
388
|
+
# @param [When::TM::TemporalPosition] first 始点
|
|
389
|
+
# @param [Symbol] direction :forward - 昇順, :reverse - 降順
|
|
390
|
+
# @param [Integer] count_limit 繰り返し回数(デフォルトは指定なし)
|
|
391
|
+
#
|
|
392
|
+
# @return [When::Coordinates::Residue::BestRationalApproximations] 引数なしの場合
|
|
393
|
+
# @return [When::Coordinates::Residue::Enumerator] 引数ありの場合
|
|
394
|
+
#
|
|
395
|
+
def _enumerator(*args)
|
|
396
|
+
length = args.length
|
|
397
|
+
length -= 1 if args[-1].kind_of?(Hash)
|
|
398
|
+
args.unshift(self)
|
|
399
|
+
(length==0) ? BestRationalApproximations.new(self, *args) : Enumerator.new(*args)
|
|
400
|
+
end
|
|
401
|
+
alias :to_enum :_enumerator
|
|
402
|
+
alias :enum_for :_enumerator
|
|
403
|
+
|
|
404
|
+
# オブジェクトの生成
|
|
405
|
+
#
|
|
406
|
+
# @overload initialize(remainder, divisor, carry=0, label=nil, format=nil, units={})
|
|
407
|
+
# @param [Numeric] remainder 剰余
|
|
408
|
+
# @param [Integer] divisor 法
|
|
409
|
+
# @param [Integer] carry 繰り上がり
|
|
410
|
+
# @param [String, When::BasicTypes::M17n] label 名前
|
|
411
|
+
# @param [String, When::BasicTypes::M17n] format 名前の書式
|
|
412
|
+
# @param [Hash] units 単位(下記の通り)
|
|
413
|
+
# @option units [Numeric] 'day' 通日に対して使用する場合のオフセット
|
|
414
|
+
# @option units [Numeric] 'year' 通年に対して使用する場合のオフセット
|
|
415
|
+
#
|
|
416
|
+
def initialize(*args)
|
|
417
|
+
# units の取得
|
|
418
|
+
options =_get_options(args).dup
|
|
419
|
+
units = {}
|
|
420
|
+
list = []
|
|
421
|
+
options.each_pair do |key, value|
|
|
422
|
+
if (PRECISION[key.upcase])
|
|
423
|
+
list << key
|
|
424
|
+
units[key.downcase] = _to_num(value)
|
|
425
|
+
end
|
|
426
|
+
end
|
|
427
|
+
list.each do |key|
|
|
428
|
+
options.delete(key)
|
|
429
|
+
end
|
|
430
|
+
options['units'] ||= {}
|
|
431
|
+
options['units'].update(units)
|
|
432
|
+
_set_variables(options)
|
|
433
|
+
@units ||= {}
|
|
434
|
+
|
|
435
|
+
# その他の変数
|
|
436
|
+
remainder, divisor, carry, label, format = args
|
|
437
|
+
@label = label || @label
|
|
438
|
+
@label = m17n(@label, nil, nil, options) if (@label)
|
|
439
|
+
@format = format || @format
|
|
440
|
+
@format = m17n(@format, nil, nil, options) if (@format)
|
|
441
|
+
_sequence
|
|
442
|
+
@remainder = _to_num(remainder || @remainder)
|
|
443
|
+
@divisor = _to_num(divisor || @divisor )
|
|
444
|
+
@carry = _to_num(carry || @carry )
|
|
445
|
+
raise RangeError, "Divisor shoud be Positive Numeric" if (@divisor <= 0)
|
|
446
|
+
carry, @remainder = @remainder.divmod(@divisor)
|
|
447
|
+
@carry += carry
|
|
448
|
+
end
|
|
449
|
+
|
|
450
|
+
private
|
|
451
|
+
|
|
452
|
+
# その他のメソッド
|
|
453
|
+
#
|
|
454
|
+
# When::Coordinate::Residue で定義されていないメソッドは
|
|
455
|
+
# 指定の桁での剰余算とみなす
|
|
456
|
+
#
|
|
457
|
+
def method_missing(name, *args, &block)
|
|
458
|
+
self[args[0] % self.to(name.to_s.downcase)]
|
|
459
|
+
end
|
|
460
|
+
|
|
461
|
+
# 数値化
|
|
462
|
+
def _to_num(s)
|
|
463
|
+
case s
|
|
464
|
+
when Numeric ; return s
|
|
465
|
+
when nil ; return 0
|
|
466
|
+
when /\.|E/ ; return s.to_f
|
|
467
|
+
else ; return s.to_i
|
|
468
|
+
end
|
|
469
|
+
end
|
|
470
|
+
|
|
471
|
+
#
|
|
472
|
+
# 最良近似分数の系列を生成する Enumerator
|
|
473
|
+
#
|
|
474
|
+
class BestRationalApproximations < When::Parts::Enumerator
|
|
475
|
+
|
|
476
|
+
# Enumerator の巻き戻し
|
|
477
|
+
#
|
|
478
|
+
# @return [void]
|
|
479
|
+
#
|
|
480
|
+
def _rewind
|
|
481
|
+
@z = @x/@y
|
|
482
|
+
@k = @z.floor
|
|
483
|
+
@p = [1,@k]
|
|
484
|
+
@q = [0, 1]
|
|
485
|
+
super
|
|
486
|
+
end
|
|
487
|
+
|
|
488
|
+
# 最良近似分数を生成する
|
|
489
|
+
#
|
|
490
|
+
# @return [Array<Numeric>] ( remainder, divisor, error )
|
|
491
|
+
# [ remainder (Integer) 分子 ]
|
|
492
|
+
# [ divisor (Integer) 分母 ]
|
|
493
|
+
# [ error (Float) 誤差 ]
|
|
494
|
+
#
|
|
495
|
+
def succ
|
|
496
|
+
value = @current
|
|
497
|
+
if (@z==@k) ||
|
|
498
|
+
(@count_limit.kind_of?(Numeric) && @count >= @count_limit) ||
|
|
499
|
+
(@error.kind_of?(Numeric) && @e && @error >= @e.abs)
|
|
500
|
+
@current = nil
|
|
501
|
+
else
|
|
502
|
+
@z = 1.0/(@z-@k)
|
|
503
|
+
@k = @z.floor
|
|
504
|
+
@e = @p[1].to_f/@q[1]-@x.to_f/@y
|
|
505
|
+
@current = [@p[1], @q[1], @e]
|
|
506
|
+
@p = [@p[1], @p[1]*@k + @p[0]]
|
|
507
|
+
@q = [@q[1], @q[1]*@k + @q[0]]
|
|
508
|
+
@count += 1
|
|
509
|
+
end
|
|
510
|
+
return value
|
|
511
|
+
end
|
|
512
|
+
|
|
513
|
+
# オブジェクトの生成
|
|
514
|
+
#
|
|
515
|
+
# @overload initialize(parent, options={})
|
|
516
|
+
# @param [When::Coordinates::Residue] parent 生成元の剰余類オブジェクト
|
|
517
|
+
# @param [Hash] options 下記の通り
|
|
518
|
+
# @option options [Numeric] :error 収束とみなす誤差(デフォルト 1E-5)
|
|
519
|
+
# @option options [Integer] :count_limit 最大繰り返し回数
|
|
520
|
+
#
|
|
521
|
+
def initialize(*args)
|
|
522
|
+
@y = args[0].divisor
|
|
523
|
+
@x = args[0].remainder + @y * args[0].carry
|
|
524
|
+
super
|
|
525
|
+
@error = @options[:error] || 1e-15
|
|
526
|
+
@count_limit = @options[:count_limit]
|
|
527
|
+
end
|
|
528
|
+
end
|
|
529
|
+
|
|
530
|
+
#
|
|
531
|
+
# 指定の剰余となる通日or通年を生成する Enumerator
|
|
532
|
+
#
|
|
533
|
+
class Enumerator < When::Parts::Enumerator
|
|
534
|
+
|
|
535
|
+
#
|
|
536
|
+
# 次の通日or通年を得る
|
|
537
|
+
#
|
|
538
|
+
# @return [When::TM::TemporalPosition]
|
|
539
|
+
#
|
|
540
|
+
def succ
|
|
541
|
+
value = @current
|
|
542
|
+
@current = (@count_limit.kind_of?(Numeric) && @count >= @count_limit) ? nil :
|
|
543
|
+
(@current==:first) ? @first :
|
|
544
|
+
(@direction==:forward) ? @first & @parent >> @count : @first & @parent << @count
|
|
545
|
+
@count += 1
|
|
546
|
+
return value
|
|
547
|
+
end
|
|
548
|
+
|
|
549
|
+
# オブジェクトの生成
|
|
550
|
+
#
|
|
551
|
+
# @overload initialize(parent, range, count_limit=nil)
|
|
552
|
+
# @param [When::Coordinates::Residue] parent 生成元の剰余類オブジェクト
|
|
553
|
+
# @param [Range, When::Parts::GeometricComplex] range 始点-range.first, 終点-range.last
|
|
554
|
+
# @param [Integer] count_limit 繰り返し回数(デフォルトは指定なし)
|
|
555
|
+
#
|
|
556
|
+
# @overload initialize(parent, first, direction, count_limit)
|
|
557
|
+
# @param [When::Coordinates::Residue] parent 生成元の剰余類オブジェクト
|
|
558
|
+
# @param [When::TM::TemporalPosition] first 始点
|
|
559
|
+
# @param [Symbol] direction :forward - 昇順, :reverse - 降順
|
|
560
|
+
# @param [Integer] count_limit 繰り返し回数(デフォルトは指定なし)
|
|
561
|
+
#
|
|
562
|
+
def initialize(*args)
|
|
563
|
+
case args[1]
|
|
564
|
+
when When::TimeValue
|
|
565
|
+
first = args[1] & args[0]
|
|
566
|
+
first = args[1] & (args[0] << 1) if args[2] == :reverse && first > args[1]
|
|
567
|
+
args[1] = first
|
|
568
|
+
when Range
|
|
569
|
+
first = args[1].first & args[0]
|
|
570
|
+
args[1] = (args[1].exclude_end?) ? (first...args[1].last) : (first..args[1].last)
|
|
571
|
+
else
|
|
572
|
+
raise TypeError, "Second Argument should be 'When::TM::(Temporal)Position'"
|
|
573
|
+
end
|
|
574
|
+
@period = When::TM::PeriodDuration.new(args[0].divisor,
|
|
575
|
+
When::Coordinates::PRECISION[args[0].units] || When::DAY)
|
|
576
|
+
super(*args)
|
|
577
|
+
end
|
|
578
|
+
end
|
|
579
|
+
end
|
|
580
|
+
|
|
581
|
+
# 暦座標
|
|
582
|
+
#
|
|
583
|
+
# 暦座標の特性を定義する
|
|
584
|
+
#
|
|
585
|
+
class Index < When::BasicTypes::Object
|
|
586
|
+
|
|
587
|
+
# 日時要素の要素数
|
|
588
|
+
#
|
|
589
|
+
# @return [Integer]
|
|
590
|
+
#
|
|
591
|
+
# 「時」なら 24, 「分」なら 60
|
|
592
|
+
#
|
|
593
|
+
# 日数や太陰太陽暦の月数のように不定の場合は nil
|
|
594
|
+
#
|
|
595
|
+
attr_reader :unit
|
|
596
|
+
|
|
597
|
+
# 日時要素の下限
|
|
598
|
+
#
|
|
599
|
+
# @return [Integer]
|
|
600
|
+
#
|
|
601
|
+
# 年月日は 1, 時分秒は 0
|
|
602
|
+
#
|
|
603
|
+
attr_reader :base
|
|
604
|
+
|
|
605
|
+
# 日時要素名(幹)
|
|
606
|
+
#
|
|
607
|
+
# @return [When::BasicTypes::M17n]
|
|
608
|
+
#
|
|
609
|
+
# 月の名称の配列などに用いる
|
|
610
|
+
#
|
|
611
|
+
attr_reader :trunk
|
|
612
|
+
|
|
613
|
+
# 座標値のシフト
|
|
614
|
+
#
|
|
615
|
+
# @return [Integer](デフォルト 0)
|
|
616
|
+
#
|
|
617
|
+
# 月 - 名称を trunk 配列の何番目(0オリジン)からとるかを指定
|
|
618
|
+
#
|
|
619
|
+
# 日 - 剰余類のシフトを指定
|
|
620
|
+
#
|
|
621
|
+
attr_reader :shift
|
|
622
|
+
|
|
623
|
+
# 日時要素名(枝)
|
|
624
|
+
#
|
|
625
|
+
# @return [Hash] { Numeric=>When::BasicTypes::M17n }
|
|
626
|
+
#
|
|
627
|
+
# When::Coordinates::Pair の branch の値からprefix
|
|
628
|
+
#
|
|
629
|
+
# (「閏」などの文字列)を引くための Hash
|
|
630
|
+
#
|
|
631
|
+
attr_reader :branch
|
|
632
|
+
|
|
633
|
+
# 日時要素名(幹枝)
|
|
634
|
+
#
|
|
635
|
+
# @return [Hash] { When::Coordinates::Pair=>When::BasicTypes::M17n }
|
|
636
|
+
#
|
|
637
|
+
# When::Coordinates::Pair から 日時要素名を引くための Hash
|
|
638
|
+
#
|
|
639
|
+
# 初期化時に @trunk, @branch から自動的に生成する
|
|
640
|
+
#
|
|
641
|
+
attr_reader :trunk_branch
|
|
642
|
+
|
|
643
|
+
# インデクス(幹枝)
|
|
644
|
+
#
|
|
645
|
+
# @return [Hash] { String=>When::Coordinates::Pair }
|
|
646
|
+
#
|
|
647
|
+
# 日時要素名から When::Coordinates::Pair を引くための Hash
|
|
648
|
+
#
|
|
649
|
+
# 初期化時に @trunk, @branch から自動的に生成する
|
|
650
|
+
#
|
|
651
|
+
attr_reader :index
|
|
652
|
+
|
|
653
|
+
# @private
|
|
654
|
+
def self.precision(specification)
|
|
655
|
+
return specification.to_i if (specification.kind_of?(Numeric))
|
|
656
|
+
return (PRECISION[specification] || VALUE[specification] || When::SYSTEM)
|
|
657
|
+
end
|
|
658
|
+
|
|
659
|
+
private
|
|
660
|
+
|
|
661
|
+
def _normalize(args=[], options={})
|
|
662
|
+
label, unit, base, trunk, shift, branch = args
|
|
663
|
+
label ||= @label
|
|
664
|
+
unit ||= @unit
|
|
665
|
+
base ||= @base || 1
|
|
666
|
+
shift ||= @shift || 0
|
|
667
|
+
@label = m17n(label, nil, nil, @options) if label
|
|
668
|
+
@unit = unit.to_i if unit
|
|
669
|
+
@base = base.to_i
|
|
670
|
+
@trunk = trunk if trunk
|
|
671
|
+
@shift = shift.to_i
|
|
672
|
+
@branch = branch if branch
|
|
673
|
+
@keys = []
|
|
674
|
+
if (@trunk)
|
|
675
|
+
if (@trunk.kind_of?(Array))
|
|
676
|
+
m17n = {}
|
|
677
|
+
@trunk.length.times do |i|
|
|
678
|
+
m17n[(i-@shift) % @trunk.length + @base] = @trunk[i]
|
|
679
|
+
end
|
|
680
|
+
@trunk = m17n
|
|
681
|
+
end
|
|
682
|
+
raise TypeError, "Trunk must be Hash" unless @trunk.kind_of?(Hash)
|
|
683
|
+
@trunk.values.each do |v|
|
|
684
|
+
@keys |= v.keys if v.kind_of?(When::Parts::Locale)
|
|
685
|
+
end
|
|
686
|
+
end
|
|
687
|
+
if (@branch)
|
|
688
|
+
if (@branch.kind_of?(Array))
|
|
689
|
+
m17n = {}
|
|
690
|
+
@branch.length.times do |i|
|
|
691
|
+
m17n[i] = @branch[i]
|
|
692
|
+
end
|
|
693
|
+
@branch = m17n
|
|
694
|
+
end
|
|
695
|
+
raise TypeError, "Branch must be Hash" unless @branch.kind_of?(Hash)
|
|
696
|
+
@branch.values.each do |v|
|
|
697
|
+
@keys |= v.keys if v.kind_of?(When::Parts::Locale)
|
|
698
|
+
end
|
|
699
|
+
end
|
|
700
|
+
@trunk_branch = {}
|
|
701
|
+
@index = {}
|
|
702
|
+
if @trunk
|
|
703
|
+
if @branch
|
|
704
|
+
@trunk.keys.each do |t|
|
|
705
|
+
@branch.keys.each do |b|
|
|
706
|
+
@trunk_branch[Pair._en_pair(t,b)] = @trunk[t].prefix(@branch[b])
|
|
707
|
+
end
|
|
708
|
+
end
|
|
709
|
+
else
|
|
710
|
+
@trunk_branch = @trunk
|
|
711
|
+
end
|
|
712
|
+
@trunk_branch.each_pair do |k,v|
|
|
713
|
+
v.values.each do |s|
|
|
714
|
+
@index[s] = k
|
|
715
|
+
end
|
|
716
|
+
end
|
|
717
|
+
end
|
|
718
|
+
end
|
|
719
|
+
end
|
|
720
|
+
|
|
721
|
+
# 暦座標値
|
|
722
|
+
#
|
|
723
|
+
# 暦座標の値を表現する
|
|
724
|
+
#
|
|
725
|
+
class Pair < Numeric
|
|
726
|
+
DL0 = {'-'=> 0, '.'=> 0, ':'=> 0, ','=> 0, ' '=> 0, '@'=>-2 }
|
|
727
|
+
DL1 = {'!'=>-2.5, '%'=>-2, '&'=>-1.5, '*'=>-1, '+'=>-0.5,
|
|
728
|
+
'<'=> 0.5, '='=> 1, '>'=> 1.5, '?'=> 2 }
|
|
729
|
+
DL2 = DL1.invert
|
|
730
|
+
|
|
731
|
+
class << self
|
|
732
|
+
#
|
|
733
|
+
# source を Numeric に変換する
|
|
734
|
+
#
|
|
735
|
+
# @param [Object] source
|
|
736
|
+
# @param [Numeric] default source が nil の場合の代替値
|
|
737
|
+
#
|
|
738
|
+
# @return [Numeric]
|
|
739
|
+
#
|
|
740
|
+
def _en_number(source, default=0)
|
|
741
|
+
return default unless(source)
|
|
742
|
+
integer = source.to_i
|
|
743
|
+
float = source.to_f
|
|
744
|
+
return (integer==float) ? integer : float
|
|
745
|
+
end
|
|
746
|
+
|
|
747
|
+
#
|
|
748
|
+
# (source, branch) を When::Coordinates::Pair に変換する
|
|
749
|
+
#
|
|
750
|
+
# @param [Object] source
|
|
751
|
+
# @param [Numeric] branch
|
|
752
|
+
#
|
|
753
|
+
# @return [When::Coordinates::Pair]
|
|
754
|
+
#
|
|
755
|
+
def _force_pair(source, branch=nil)
|
|
756
|
+
case source
|
|
757
|
+
when self
|
|
758
|
+
return source
|
|
759
|
+
when Numeric
|
|
760
|
+
return new(_en_number(source), branch)
|
|
761
|
+
when String
|
|
762
|
+
tail = source[-1..-1]
|
|
763
|
+
branch = DL0[tail] || DL1[tail]
|
|
764
|
+
source = (branch) ? source[0..-2] : source.dup
|
|
765
|
+
trunk = (source =~ /\.|E/i) ? source.to_f : source.to_i
|
|
766
|
+
return new(trunk, branch)
|
|
767
|
+
else
|
|
768
|
+
raise TypeError, "Irregal type for #{self} :#{source}"
|
|
769
|
+
end
|
|
770
|
+
end
|
|
771
|
+
|
|
772
|
+
#
|
|
773
|
+
# branch が有効なら (source, branch) を When::Coordinates::Pair に変換する。
|
|
774
|
+
#
|
|
775
|
+
# @param [Object] trunk
|
|
776
|
+
# @param [Numeric, String] branch
|
|
777
|
+
#
|
|
778
|
+
# @return [trunk自体] branch が無効
|
|
779
|
+
# @return [When::Coordinates::Pair] branch が有効(非0)
|
|
780
|
+
#
|
|
781
|
+
def _en_pair(trunk, branch=nil)
|
|
782
|
+
return trunk if (trunk.kind_of?(self))
|
|
783
|
+
branch = DL0[branch] || DL1[branch] || branch
|
|
784
|
+
trunk = _en_number(trunk) if (trunk)
|
|
785
|
+
return trunk unless (branch && branch != 0)
|
|
786
|
+
return new(trunk, branch)
|
|
787
|
+
end
|
|
788
|
+
|
|
789
|
+
#
|
|
790
|
+
# When::Coordinates::Pair の trunk と branch の和をとって Numeric 化する
|
|
791
|
+
#
|
|
792
|
+
# @param [When::Coordinates::Pair] source trunk と branch の和を返す
|
|
793
|
+
# @param [Array] source 各要素を _de_pair した Arrayを返す
|
|
794
|
+
# @param [その他 Numeric] source をそのまま返す
|
|
795
|
+
#
|
|
796
|
+
# @return [Numeric, Array<Numeric>]
|
|
797
|
+
#
|
|
798
|
+
def _de_pair(source)
|
|
799
|
+
case source
|
|
800
|
+
when Array
|
|
801
|
+
return (source.map!{|v| _de_pair(v)})
|
|
802
|
+
when self
|
|
803
|
+
return source.sum
|
|
804
|
+
when Numeric
|
|
805
|
+
return source
|
|
806
|
+
else
|
|
807
|
+
raise TypeError, "Irregal type for #{self}"
|
|
808
|
+
end
|
|
809
|
+
end
|
|
810
|
+
|
|
811
|
+
#
|
|
812
|
+
# 文字列を When::Coordinates::Pair のArray 化する
|
|
813
|
+
#
|
|
814
|
+
# @param [String] source
|
|
815
|
+
#
|
|
816
|
+
# @return [Array<When::Coordinates::Pair>]
|
|
817
|
+
#
|
|
818
|
+
def _en_pair_array(source)
|
|
819
|
+
source = $1 if (source=~/^\s*\[?(.+?)\]?\s*$/)
|
|
820
|
+
source.split(/,/).map {|v|
|
|
821
|
+
v =~ /^\s*(.+?)([^\d\s])?\s*$/
|
|
822
|
+
_en_pair($1, $2)
|
|
823
|
+
}
|
|
824
|
+
end
|
|
825
|
+
|
|
826
|
+
#
|
|
827
|
+
# 日付を When::Coordinates::Pair のArray 化する
|
|
828
|
+
#
|
|
829
|
+
# @param [String] source
|
|
830
|
+
#
|
|
831
|
+
# @return [Array<When::Coordinates::Pair>]
|
|
832
|
+
#
|
|
833
|
+
def _en_pair_date_time(source)
|
|
834
|
+
source = $1 if source =~ /^\s*\[(.+)\]\s*$/
|
|
835
|
+
trunk, branch, *rest = source.strip.split(/([^\d])/)
|
|
836
|
+
if trunk == ''
|
|
837
|
+
sign = branch
|
|
838
|
+
trunk, branch, *rest = rest
|
|
839
|
+
trunk = sign + trunk if trunk
|
|
840
|
+
end
|
|
841
|
+
pairs = []
|
|
842
|
+
while (trunk)
|
|
843
|
+
pairs << _en_pair(trunk, branch)
|
|
844
|
+
trunk, branch, *rest = rest
|
|
845
|
+
end
|
|
846
|
+
return pairs
|
|
847
|
+
end
|
|
848
|
+
|
|
849
|
+
#
|
|
850
|
+
# branch文字を意識して、書式文字列により When::Coordinates::Pair の Array を文字列化
|
|
851
|
+
#
|
|
852
|
+
# @overload _format(format, list)
|
|
853
|
+
# @param [String] format 書式文字列
|
|
854
|
+
# @param [Array] list 書式に従って文字列化されるオブジェクトの Array
|
|
855
|
+
#
|
|
856
|
+
# @return [String]
|
|
857
|
+
#
|
|
858
|
+
def _format(m17ns)
|
|
859
|
+
index = 1
|
|
860
|
+
m17ns[0].scan(/(%(?:(\d)\$)?[-+0# ]?[*\d.$]*[cspdiuboxXfgeEG])([-.:])?|(%%|.)/).inject('') { |form, m17n|
|
|
861
|
+
t,i,s,c = m17n
|
|
862
|
+
case t
|
|
863
|
+
when '%0s'
|
|
864
|
+
m17n[index..index] = nil
|
|
865
|
+
when nil
|
|
866
|
+
form += c
|
|
867
|
+
else
|
|
868
|
+
suffix = DL2[m17ns[i ? i.to_i : index]*0] || s if s
|
|
869
|
+
form += t + ({nil=>'', '%'=>'%%'}[suffix] || suffix)
|
|
870
|
+
index += t.length - t.gsub(/\*/,'').length + 1
|
|
871
|
+
end
|
|
872
|
+
form
|
|
873
|
+
} % m17ns[1..-1].map { |v| v.kind_of?(self) ? v.trunk : v }
|
|
874
|
+
end
|
|
875
|
+
end
|
|
876
|
+
|
|
877
|
+
#
|
|
878
|
+
# 暦要素の幹
|
|
879
|
+
#
|
|
880
|
+
# @return [Numeric] 年番号,月番号,日番号など暦要素の幹となる部分
|
|
881
|
+
#
|
|
882
|
+
attr_accessor :trunk
|
|
883
|
+
|
|
884
|
+
#
|
|
885
|
+
# 暦要素の枝
|
|
886
|
+
#
|
|
887
|
+
# @return [Numeric] 暦要素のうち(閏であるかなど)幹で表現しきれない枝の部分
|
|
888
|
+
#
|
|
889
|
+
attr_accessor :branch
|
|
890
|
+
|
|
891
|
+
#
|
|
892
|
+
# 暦要素の幹と枝の和
|
|
893
|
+
#
|
|
894
|
+
# @return [Numeric]
|
|
895
|
+
#
|
|
896
|
+
# @note
|
|
897
|
+
# 個別の実装において、本変数が When::TM::Calendar や When::TM::Clock が扱うべき
|
|
898
|
+
# 座標値を表すように配慮されている。
|
|
899
|
+
#
|
|
900
|
+
# 例: 会計年度など年の変わり目が暦年と異なる場合、trunk+=1, branch-=1 として、
|
|
901
|
+
# trunk が会計年度, sum が暦年を表現するようにできる。この場合、trunk は表記上の
|
|
902
|
+
# 年、branch は会計年度と暦年にずれがあるという情報を表現していることになる。
|
|
903
|
+
#
|
|
904
|
+
attr_reader :sum
|
|
905
|
+
|
|
906
|
+
#
|
|
907
|
+
# trunk の更新
|
|
908
|
+
#
|
|
909
|
+
# @param [Numeric] trunk 新しい trunk
|
|
910
|
+
#
|
|
911
|
+
# @return [When::Coordinates::Pair] 更新結果
|
|
912
|
+
#
|
|
913
|
+
def trunk=(trunk)
|
|
914
|
+
@trunk = trunk
|
|
915
|
+
_normalize
|
|
916
|
+
self
|
|
917
|
+
end
|
|
918
|
+
|
|
919
|
+
#
|
|
920
|
+
# branch の更新
|
|
921
|
+
#
|
|
922
|
+
# @param [Numeric] branch新しい branch
|
|
923
|
+
#
|
|
924
|
+
# @return [When::Coordinates::Pair] 更新結果
|
|
925
|
+
#
|
|
926
|
+
def branch=(branch)
|
|
927
|
+
@branch = branch
|
|
928
|
+
_normalize
|
|
929
|
+
self
|
|
930
|
+
end
|
|
931
|
+
|
|
932
|
+
# 属性 @sum を取得する
|
|
933
|
+
#
|
|
934
|
+
# @return [Numeric]
|
|
935
|
+
#
|
|
936
|
+
# @note
|
|
937
|
+
# When::Coordinates::Pair 以外の Numeric では、単項演算 + は恒等変換になる。
|
|
938
|
+
# このため、When::TM::Calendar や When::TM::Clock の実装は、暦要素が When::Coordinates::Pair か
|
|
939
|
+
# 否かを判断することなく、暦要素に単項演算 + を施すことによって、必要な暦要素を取得できる。
|
|
940
|
+
def +@
|
|
941
|
+
return @sum
|
|
942
|
+
end
|
|
943
|
+
|
|
944
|
+
# trunk の符号を反転する
|
|
945
|
+
#
|
|
946
|
+
# @return [When::Coordinates::Pair] Pair.new(-@trunk, @branch)
|
|
947
|
+
#
|
|
948
|
+
def -@
|
|
949
|
+
return self.class.new(-(@trunk||0), @branch)
|
|
950
|
+
end
|
|
951
|
+
|
|
952
|
+
# @trunk, @branch を取得する
|
|
953
|
+
#
|
|
954
|
+
# @param [Integer] other (1, 0, -1)
|
|
955
|
+
#
|
|
956
|
+
# @return [Numeric]
|
|
957
|
+
# [ other == 1 - @trunk ]
|
|
958
|
+
# [ other == 0 - @branch ]
|
|
959
|
+
# [ other == -1 - -@trunk ]
|
|
960
|
+
#
|
|
961
|
+
# @note
|
|
962
|
+
# When::Coordinates::Pair 以外の Numeric では、1 による乗算は恒等変換になる。
|
|
963
|
+
# また、0 による乗算は恒に 0になる。
|
|
964
|
+
# このため、When::TM::Calendar や When::TM::Clock の実装は、暦要素が When::Coordinates::Pair か
|
|
965
|
+
# 否かを判断することなく、暦要素に 1 による乗算を施すことによって、trunk に相当する値を、
|
|
966
|
+
# 0 による乗算を施すことによって、branch に相当する値を取得できる。
|
|
967
|
+
def *(other)
|
|
968
|
+
case other
|
|
969
|
+
when 1 ; @trunk
|
|
970
|
+
when 0 ; @branch
|
|
971
|
+
when -1 ; -@trunk
|
|
972
|
+
else ; raise ArgumentError, "Irregal designation : #{other}"
|
|
973
|
+
end
|
|
974
|
+
end
|
|
975
|
+
|
|
976
|
+
# 加算
|
|
977
|
+
#
|
|
978
|
+
# @param [Numeric] other
|
|
979
|
+
#
|
|
980
|
+
# @return [When::Coordinates::Pair]
|
|
981
|
+
# other が When::Coordinates::Pair でない場合、trunk に対する加算となる
|
|
982
|
+
#
|
|
983
|
+
def +(other)
|
|
984
|
+
return self.class.new((@trunk||0) + other, @branch) unless other.kind_of?(self.class)
|
|
985
|
+
return self.class.new((@trunk||0) + (other.trunk||0), (@branch||0) + (other.branch||0))
|
|
986
|
+
end
|
|
987
|
+
|
|
988
|
+
# 減算
|
|
989
|
+
#
|
|
990
|
+
# @param [Numeric] other
|
|
991
|
+
#
|
|
992
|
+
# @return [When::Coordinates::Pair]
|
|
993
|
+
# other が When::Coordinates::Pair でない場合、trunk に対する減算となる
|
|
994
|
+
#
|
|
995
|
+
def -(other)
|
|
996
|
+
return self.class.new((@trunk||0) - other, @branch) unless other.kind_of?(self.class)
|
|
997
|
+
return self.class.new((@trunk||0) - (other.trunk||0), (@branch||0) - (other.branch||0))
|
|
998
|
+
end
|
|
999
|
+
|
|
1000
|
+
# 商と剰余
|
|
1001
|
+
#
|
|
1002
|
+
# @param [Numeric] other
|
|
1003
|
+
#
|
|
1004
|
+
# @return [When::Coordinates::Pair]
|
|
1005
|
+
# trunk に対する divmod となる
|
|
1006
|
+
#
|
|
1007
|
+
def divmod(other)
|
|
1008
|
+
div, mod = (@trunk||0).divmod(other)
|
|
1009
|
+
return div, self.class.new(mod, @branch)
|
|
1010
|
+
end
|
|
1011
|
+
|
|
1012
|
+
# 剰余
|
|
1013
|
+
#
|
|
1014
|
+
# @param [Numeric] other
|
|
1015
|
+
#
|
|
1016
|
+
# @return [When::Coordinates::Pair]
|
|
1017
|
+
# trunk に対する % となる
|
|
1018
|
+
#
|
|
1019
|
+
def %(other)
|
|
1020
|
+
self.class.new((@trunk||0) % other, @branch)
|
|
1021
|
+
end
|
|
1022
|
+
|
|
1023
|
+
# 比較
|
|
1024
|
+
#
|
|
1025
|
+
# @param [Numeric] other
|
|
1026
|
+
#
|
|
1027
|
+
# @return [Integer] (負,0,正)
|
|
1028
|
+
# trunk の比較が優先される
|
|
1029
|
+
#
|
|
1030
|
+
def <=>(other)
|
|
1031
|
+
other = self.class._force_pair(other)
|
|
1032
|
+
(@trunk <=> other.trunk).nonzero? || ((@branch||0) <=> (other.branch||0))
|
|
1033
|
+
end
|
|
1034
|
+
|
|
1035
|
+
# 文字列化
|
|
1036
|
+
#
|
|
1037
|
+
# @param [String] zero @branch == 0 を表現する文字列
|
|
1038
|
+
#
|
|
1039
|
+
# @return [String]
|
|
1040
|
+
#
|
|
1041
|
+
def to_s(zero='')
|
|
1042
|
+
return @trunk.to_s + (((@branch||0)==0) ? zero : DL2[@branch])
|
|
1043
|
+
end
|
|
1044
|
+
|
|
1045
|
+
# 強制型変換
|
|
1046
|
+
# @private
|
|
1047
|
+
def coerce(other)
|
|
1048
|
+
[self.class._force_pair(other), self]
|
|
1049
|
+
end
|
|
1050
|
+
|
|
1051
|
+
private
|
|
1052
|
+
|
|
1053
|
+
# オブジェクトの生成
|
|
1054
|
+
#
|
|
1055
|
+
# @param [Numeric] trunk 幹
|
|
1056
|
+
# @param [Numeric] branch 枝
|
|
1057
|
+
#
|
|
1058
|
+
def initialize(trunk, branch=nil)
|
|
1059
|
+
@trunk = trunk
|
|
1060
|
+
@branch = branch
|
|
1061
|
+
_normalize
|
|
1062
|
+
end
|
|
1063
|
+
|
|
1064
|
+
def _normalize
|
|
1065
|
+
@trunk = @trunk.to_i if (@trunk.kind_of?(Float) && @trunk.to_i == @trunk.to_f)
|
|
1066
|
+
@sum = @trunk
|
|
1067
|
+
if (@branch.kind_of?(Numeric))
|
|
1068
|
+
@branch = @branch.to_i if (@branch.to_i == @branch.to_f)
|
|
1069
|
+
@sum += @branch if (@trunk)
|
|
1070
|
+
end
|
|
1071
|
+
end
|
|
1072
|
+
|
|
1073
|
+
# その他のメソッド
|
|
1074
|
+
# When::Coordinates:Pair で定義されていないメソッドは
|
|
1075
|
+
# 処理を @sum (type:Numeric) に委譲する
|
|
1076
|
+
#
|
|
1077
|
+
def method_missing(name, *args, &block)
|
|
1078
|
+
@sum.send(name.to_sym, *args, &block)
|
|
1079
|
+
end
|
|
1080
|
+
end
|
|
1081
|
+
|
|
1082
|
+
# 暦座標値
|
|
1083
|
+
#
|
|
1084
|
+
# 閏秒のある暦座標の値を表現する
|
|
1085
|
+
#
|
|
1086
|
+
class LeapSeconds < Pair
|
|
1087
|
+
|
|
1088
|
+
#
|
|
1089
|
+
# 閏秒の単位 / When::TM::Duration::SYSTEM
|
|
1090
|
+
#
|
|
1091
|
+
# @return [Numeric]
|
|
1092
|
+
#
|
|
1093
|
+
attr_reader :second
|
|
1094
|
+
|
|
1095
|
+
#
|
|
1096
|
+
# trunk の整数部
|
|
1097
|
+
#
|
|
1098
|
+
# @return [Integer]
|
|
1099
|
+
#
|
|
1100
|
+
attr_reader :int
|
|
1101
|
+
|
|
1102
|
+
#
|
|
1103
|
+
# trunk の小数部
|
|
1104
|
+
#
|
|
1105
|
+
# @return [Float]
|
|
1106
|
+
#
|
|
1107
|
+
attr_reader :frac
|
|
1108
|
+
|
|
1109
|
+
# 加算
|
|
1110
|
+
#
|
|
1111
|
+
# @param [Numeric] other
|
|
1112
|
+
#
|
|
1113
|
+
# @return [When::Coordinates::LeapSeconds]
|
|
1114
|
+
# other が When::Coordinates::LeapSeconds でない場合、trunk に対する加算となる
|
|
1115
|
+
#
|
|
1116
|
+
def +(other)
|
|
1117
|
+
return self.class.new(@trunk + +other, @branch, @second) unless other.kind_of?(self.class)
|
|
1118
|
+
return self.class.new(@trunk + other.trunk, @branch + other.branch, @second)
|
|
1119
|
+
end
|
|
1120
|
+
|
|
1121
|
+
# 減算
|
|
1122
|
+
#
|
|
1123
|
+
# @param [Numeric] other
|
|
1124
|
+
#
|
|
1125
|
+
# @return [When::Coordinates::LeapSeconds]
|
|
1126
|
+
# other が When::Coordinates::LeapSeconds でない場合、trunk に対する減算となる
|
|
1127
|
+
#
|
|
1128
|
+
def -(other)
|
|
1129
|
+
return self.class.new(@trunk - +other, @branch, @second) unless other.kind_of?(self.class)
|
|
1130
|
+
return self.class.new(@trunk - other.trunk, @branch - other.branch, @second)
|
|
1131
|
+
end
|
|
1132
|
+
|
|
1133
|
+
# 商と剰余
|
|
1134
|
+
#
|
|
1135
|
+
# @param [Numeric] other
|
|
1136
|
+
#
|
|
1137
|
+
# @return [When::Coordinates::LeapSeconds]
|
|
1138
|
+
# trunk に対する divmod となる
|
|
1139
|
+
#
|
|
1140
|
+
def divmod(other)
|
|
1141
|
+
div, mod = @trunk.divmod(other)
|
|
1142
|
+
return div, self.class.new(mod, @branch, @second)
|
|
1143
|
+
end
|
|
1144
|
+
|
|
1145
|
+
# 比較
|
|
1146
|
+
#
|
|
1147
|
+
# @param [Numeric] other
|
|
1148
|
+
#
|
|
1149
|
+
# @return [Integer] (負,0,正)
|
|
1150
|
+
# trunk の整数部, branch, trunk の小数部の順に比較する
|
|
1151
|
+
#
|
|
1152
|
+
def <=>(other)
|
|
1153
|
+
other = self.class.new(+other, 0, @second) unless other.kind_of?(self.class)
|
|
1154
|
+
raise ArgumentError, "length of unit 'second' mismatch" unless @second == other.second
|
|
1155
|
+
(@int <=> other.int).nonzero? || (@branch <=> other.branch).nonzero? || (@frac <=> other.frac)
|
|
1156
|
+
end
|
|
1157
|
+
|
|
1158
|
+
# 文字列化
|
|
1159
|
+
#
|
|
1160
|
+
# @param [String] zero @branch==0 を表現する文字列
|
|
1161
|
+
#
|
|
1162
|
+
# @return [String]
|
|
1163
|
+
#
|
|
1164
|
+
def to_s(zero='')
|
|
1165
|
+
return @trunk.to_s + (@branch==0 ? zero : DL2[(@branch/@second).floor])
|
|
1166
|
+
end
|
|
1167
|
+
|
|
1168
|
+
# 強制型変換
|
|
1169
|
+
# @private
|
|
1170
|
+
def coerce(other)
|
|
1171
|
+
[self.class.new(other, 0, @second), self]
|
|
1172
|
+
end
|
|
1173
|
+
|
|
1174
|
+
# オブジェクトの生成
|
|
1175
|
+
#
|
|
1176
|
+
# @param [Numeric] trunk 幹
|
|
1177
|
+
# @param [Numeric] branch 枝
|
|
1178
|
+
# @param [Numeric] second 閏秒の単位
|
|
1179
|
+
#
|
|
1180
|
+
def initialize(trunk, branch, second)
|
|
1181
|
+
@second = second
|
|
1182
|
+
@int, @frac = trunk.divmod(second)
|
|
1183
|
+
super(trunk, branch)
|
|
1184
|
+
end
|
|
1185
|
+
end
|
|
1186
|
+
|
|
1187
|
+
#
|
|
1188
|
+
# 空間位置
|
|
1189
|
+
#
|
|
1190
|
+
class Spatial < When::BasicTypes::Object
|
|
1191
|
+
|
|
1192
|
+
LabelProperty = 'label'
|
|
1193
|
+
|
|
1194
|
+
include When::Ephemeris
|
|
1195
|
+
|
|
1196
|
+
# Degree / Internal Location Unit(16")
|
|
1197
|
+
#
|
|
1198
|
+
# (3600 を 2 の因数で割りつくした値を単位とする)
|
|
1199
|
+
DEGREE = 225
|
|
1200
|
+
|
|
1201
|
+
# 黄道座標 (ecliptic coordinate system)
|
|
1202
|
+
ECLIPTIC = 0
|
|
1203
|
+
|
|
1204
|
+
# 赤道座標 (equatorial coordinate system)
|
|
1205
|
+
EQUATORIAL = 1
|
|
1206
|
+
|
|
1207
|
+
# 地平座標 (horizontal coordinate system)
|
|
1208
|
+
HORIZONTAL = 2
|
|
1209
|
+
|
|
1210
|
+
# 惑星中心の高度
|
|
1211
|
+
CENTER = :center
|
|
1212
|
+
|
|
1213
|
+
# 北緯を正とする緯度 / 16秒
|
|
1214
|
+
#
|
|
1215
|
+
# @return [Numeric]
|
|
1216
|
+
#
|
|
1217
|
+
attr_reader :lat
|
|
1218
|
+
|
|
1219
|
+
# 東経を正とする経度 / 16秒
|
|
1220
|
+
#
|
|
1221
|
+
# @return [Numeric]
|
|
1222
|
+
#
|
|
1223
|
+
attr_reader :long
|
|
1224
|
+
|
|
1225
|
+
# 高度 / m
|
|
1226
|
+
#
|
|
1227
|
+
# @return [Numeric]
|
|
1228
|
+
# @return [:Center] 天体の中心の場合
|
|
1229
|
+
#
|
|
1230
|
+
attr_reader :alt
|
|
1231
|
+
|
|
1232
|
+
# 座標系
|
|
1233
|
+
#
|
|
1234
|
+
# @return [When::Ephemeris::Datum]
|
|
1235
|
+
#
|
|
1236
|
+
attr_reader :datum
|
|
1237
|
+
|
|
1238
|
+
# 参照
|
|
1239
|
+
#
|
|
1240
|
+
# @return [String] URI
|
|
1241
|
+
#
|
|
1242
|
+
attr_reader :ref
|
|
1243
|
+
|
|
1244
|
+
# 時間帯(オプショナル)
|
|
1245
|
+
#
|
|
1246
|
+
# @return [TZInfo::CountryTimezone]
|
|
1247
|
+
#
|
|
1248
|
+
# TZInfoライブラリから経緯度を取得して使用する
|
|
1249
|
+
#
|
|
1250
|
+
attr_reader :tz
|
|
1251
|
+
|
|
1252
|
+
# 観測地の地心距離 / kmを返します。
|
|
1253
|
+
#
|
|
1254
|
+
# @return [Numeric]
|
|
1255
|
+
#
|
|
1256
|
+
def obserber_distance
|
|
1257
|
+
l = PI / (90 * DEGREE) * @lat
|
|
1258
|
+
@datum.surface_radius * (@datum.shape[0]+@datum.shape[1]*cos(l)+@datum.shape[2]*cos(2*l))
|
|
1259
|
+
end
|
|
1260
|
+
|
|
1261
|
+
# 観測地での‘大地’の視半径
|
|
1262
|
+
#
|
|
1263
|
+
# @return [Numeric]
|
|
1264
|
+
#
|
|
1265
|
+
def horizon
|
|
1266
|
+
# 地面以下なら 90度とみなす
|
|
1267
|
+
return 0.25 if @alt == :Center || @alt <= 0
|
|
1268
|
+
|
|
1269
|
+
# 観測地の地心距離 / m
|
|
1270
|
+
r = obserber_distance * 1000.0
|
|
1271
|
+
|
|
1272
|
+
# 大気効果
|
|
1273
|
+
air_effect = @datum.air[1] * @alt / (@datum.air[2] * @alt + r)
|
|
1274
|
+
|
|
1275
|
+
# ‘大地’の視半径
|
|
1276
|
+
asin((1.0+air_effect) * r / (r+@alt)) / CIRCLE
|
|
1277
|
+
end
|
|
1278
|
+
|
|
1279
|
+
# 観測地の地方恒星時 / 時を返します。
|
|
1280
|
+
#
|
|
1281
|
+
# @param [Numeric] t ユリウス日(Terrestrial Time)
|
|
1282
|
+
# @param [When::TM::TemporalPosition] t
|
|
1283
|
+
#
|
|
1284
|
+
# @return [Numeric]
|
|
1285
|
+
#
|
|
1286
|
+
def local_sidereal_time(t)
|
|
1287
|
+
t = +t
|
|
1288
|
+
c = julian_century_from_2000(t)
|
|
1289
|
+
result = @datum.sid[0] + c * (@datum.sid[1] + c * @datum.sid[2]) + @long / (15.0 * DEGREE)
|
|
1290
|
+
result += (cosc(obl(c)) * delta_p(c) +
|
|
1291
|
+
(t-When::TimeStandard.delta_t_observed(t)/86400+0.5) % 1) * 24 if @datum.kind_of?(Earth)
|
|
1292
|
+
result
|
|
1293
|
+
end
|
|
1294
|
+
|
|
1295
|
+
# 観測地の日心三次元座標(黄道座標)
|
|
1296
|
+
#
|
|
1297
|
+
# @param [Numeric] t ユリウス日(Terrestrial Time)
|
|
1298
|
+
# @param [When::TM::TemporalPosition] t
|
|
1299
|
+
#
|
|
1300
|
+
# @return [Numeric]
|
|
1301
|
+
#
|
|
1302
|
+
def _coords(t)
|
|
1303
|
+
t = +t
|
|
1304
|
+
@datum._coords(t) + _coords_diff(t)
|
|
1305
|
+
end
|
|
1306
|
+
|
|
1307
|
+
private
|
|
1308
|
+
|
|
1309
|
+
# 要素の正規化
|
|
1310
|
+
def _normalize(args=[], options={})
|
|
1311
|
+
@lat = When::Coordinates.to_deg(@lat, 'NS') * DEGREE if @lat
|
|
1312
|
+
@long = When::Coordinates.to_deg(@long, 'EW') * DEGREE if @long
|
|
1313
|
+
@alt = (@alt) ? @alt.to_f : 0.0
|
|
1314
|
+
@datum = When.Resource(@datum || 'Earth', '_ep:')
|
|
1315
|
+
if @tz.kind_of?(String)
|
|
1316
|
+
@label ||= @tz
|
|
1317
|
+
@tz = When::Parts::Timezone.tz_info[@tz]
|
|
1318
|
+
end
|
|
1319
|
+
if @tz
|
|
1320
|
+
@lat ||= @tz.latitude * DEGREE
|
|
1321
|
+
@long ||= @tz.longitude * DEGREE
|
|
1322
|
+
end
|
|
1323
|
+
@lat ||= 0.0
|
|
1324
|
+
@long ||= 0.0
|
|
1325
|
+
end
|
|
1326
|
+
|
|
1327
|
+
# 観測地の惑星中心を原点とする三次元座標
|
|
1328
|
+
#
|
|
1329
|
+
# @param [Numeric] t ユリウス日(Terrestrial Time)
|
|
1330
|
+
# @param [When::TM::TemporalPosition] t
|
|
1331
|
+
# @param [Integer] system : 座標系
|
|
1332
|
+
# [ ECLIPTIC = 黄道座標 ]
|
|
1333
|
+
# [ EQUATORIAL = 赤道座標 ]
|
|
1334
|
+
# [ HORIZONTAL = 地平座標 ]
|
|
1335
|
+
#
|
|
1336
|
+
def _coords_diff(t, system=ECLIPTIC)
|
|
1337
|
+
return Coords.polar(0,0,0) if alt == :Center
|
|
1338
|
+
t = +t
|
|
1339
|
+
lat = @lat.to_f / DEGREE
|
|
1340
|
+
coords = Coords.polar(
|
|
1341
|
+
local_sidereal_time(t) / 24.0,
|
|
1342
|
+
(lat + @datum.shape[3] * sind(2*lat)) / 360.0,
|
|
1343
|
+
(obserber_distance + @alt) / AU)
|
|
1344
|
+
case system
|
|
1345
|
+
when ECLIPTIC ; coords.r_to_y(t, @datum)
|
|
1346
|
+
when EQUATORIAL ; coords
|
|
1347
|
+
when HORIZONTAL ; coords.r_to_h(t, self)
|
|
1348
|
+
end
|
|
1349
|
+
end
|
|
1350
|
+
|
|
1351
|
+
# その他のメソッド
|
|
1352
|
+
# When::Coordinates::Spatial で定義されていないメソッドは
|
|
1353
|
+
# 処理を @datum (type: When::Ephemeris::Datum) に委譲する
|
|
1354
|
+
#
|
|
1355
|
+
def method_missing(name, *args, &block)
|
|
1356
|
+
@datum.send(name.to_sym, self, *args, &block)
|
|
1357
|
+
end
|
|
1358
|
+
|
|
1359
|
+
module Normalize
|
|
1360
|
+
|
|
1361
|
+
private
|
|
1362
|
+
|
|
1363
|
+
# 位置情報
|
|
1364
|
+
#
|
|
1365
|
+
# @return [When::Coordinates::Spatial]
|
|
1366
|
+
#
|
|
1367
|
+
attr_reader :location
|
|
1368
|
+
|
|
1369
|
+
# 時差情報
|
|
1370
|
+
#
|
|
1371
|
+
# @return [Array<Numeric>]
|
|
1372
|
+
#
|
|
1373
|
+
attr_reader :timezone
|
|
1374
|
+
|
|
1375
|
+
# 日時要素の境界オブジェクト
|
|
1376
|
+
#
|
|
1377
|
+
# @return [When::CalendarTypes::Border]
|
|
1378
|
+
#
|
|
1379
|
+
attr_reader :border
|
|
1380
|
+
|
|
1381
|
+
# 境界計算用の計算オブジェクト
|
|
1382
|
+
#
|
|
1383
|
+
# @return [When::Ephemeris::Formula]
|
|
1384
|
+
#
|
|
1385
|
+
attr_reader :formula
|
|
1386
|
+
|
|
1387
|
+
#
|
|
1388
|
+
# Temporal Module の Spatial Parts の初期化
|
|
1389
|
+
#
|
|
1390
|
+
def _normalize_spatial
|
|
1391
|
+
|
|
1392
|
+
# Location
|
|
1393
|
+
if ((@location||@long||@lat).kind_of?(String))
|
|
1394
|
+
@location ||= "_l:long=#{@long||0}&lat=#{@lat||0}"
|
|
1395
|
+
@location = When.Resource(@location)
|
|
1396
|
+
end
|
|
1397
|
+
|
|
1398
|
+
# Timezone
|
|
1399
|
+
if respond_to?(:timezone)
|
|
1400
|
+
@timezone ||= @location ? @location.long / (Spatial::DEGREE * 15) : 9.0
|
|
1401
|
+
@timezone = @timezone.kind_of?(String) ? @timezone.split(/,/) : Array(@timezone)
|
|
1402
|
+
@timezone = @timezone.map {|v| v.to_f / 24}
|
|
1403
|
+
(1...@timezone.size).each do |i|
|
|
1404
|
+
@timezone[i] += @timezone[i-1]
|
|
1405
|
+
end
|
|
1406
|
+
end
|
|
1407
|
+
|
|
1408
|
+
# Border
|
|
1409
|
+
if (@border.kind_of?(String))
|
|
1410
|
+
@border = When.Calendar(
|
|
1411
|
+
case @border
|
|
1412
|
+
when /\([-\d]+?\)/ ; "_c:MultiBorder?borders=#{@border}"
|
|
1413
|
+
when /^[^A-Z_]/i ; "_c:Border?border=#{@border}"
|
|
1414
|
+
else ; @border
|
|
1415
|
+
end)
|
|
1416
|
+
end
|
|
1417
|
+
|
|
1418
|
+
# Formula
|
|
1419
|
+
instance_eval('class << self; attr_reader :formula; end') # if @location && @border
|
|
1420
|
+
if respond_to?(:formula)
|
|
1421
|
+
instance_eval('class << self; include When::Ephemeris::Formula::Methods; end')
|
|
1422
|
+
@formula ||= When::Ephemeris::Formula.new({:location=>@location})
|
|
1423
|
+
@formula = When.Resource(Array(@formula), '_ep:')
|
|
1424
|
+
end
|
|
1425
|
+
end
|
|
1426
|
+
end
|
|
1427
|
+
end
|
|
1428
|
+
|
|
1429
|
+
#
|
|
1430
|
+
# 暦座標を扱う処理をまとめたモジュール
|
|
1431
|
+
#
|
|
1432
|
+
# When::TM::Calendar と When::TM::Clock に共通する処理だが、ISO 19108 で両者の
|
|
1433
|
+
# 直接の superclass である、When::TM::ReferenceSystem は、これらの処理を持たない
|
|
1434
|
+
# こととなっているため、When::TM::Calendar と When::TM::Clock の共通部分を
|
|
1435
|
+
# モジュールとしてまとめた。
|
|
1436
|
+
#
|
|
1437
|
+
module Temporal
|
|
1438
|
+
|
|
1439
|
+
include When::Parts::MethodCash
|
|
1440
|
+
include When::Coordinates::Spatial::Normalize
|
|
1441
|
+
|
|
1442
|
+
# @private
|
|
1443
|
+
HashProperty =
|
|
1444
|
+
[[:origin_of_MSC, 0], [:origin_of_LSC, 0], [:index_of_MSC, 0], [:_diff_to_CE, 0],
|
|
1445
|
+
:unit, :base, :pair, :note,
|
|
1446
|
+
:location, :timezone, :border, :formula]
|
|
1447
|
+
|
|
1448
|
+
# 年/日の原点(origin of most significant coordinate)
|
|
1449
|
+
#
|
|
1450
|
+
# @return [Integer]
|
|
1451
|
+
#
|
|
1452
|
+
attr_reader :origin_of_MSC
|
|
1453
|
+
|
|
1454
|
+
# 日/秒の原点(origin of least significant coordinate)
|
|
1455
|
+
#
|
|
1456
|
+
# @return [Integer]
|
|
1457
|
+
#
|
|
1458
|
+
attr_reader :origin_of_LSC
|
|
1459
|
+
|
|
1460
|
+
# インデクスオブジェクト
|
|
1461
|
+
#
|
|
1462
|
+
# @return [Array<When::Coordinates::Index>]
|
|
1463
|
+
#
|
|
1464
|
+
attr_reader :indices
|
|
1465
|
+
|
|
1466
|
+
# 年/日のインデクス(index of most significant coordinate)
|
|
1467
|
+
#
|
|
1468
|
+
# @return [Integer]
|
|
1469
|
+
#
|
|
1470
|
+
attr_reader :index_of_MSC
|
|
1471
|
+
|
|
1472
|
+
# 日時要素の要素数
|
|
1473
|
+
#
|
|
1474
|
+
# @return [Array<Integer, nil>]
|
|
1475
|
+
#
|
|
1476
|
+
# Ex. [nil, 12], [nil, 24, 60, 60]
|
|
1477
|
+
#
|
|
1478
|
+
# 初期化時に indices から自動生成する
|
|
1479
|
+
#
|
|
1480
|
+
attr_reader :unit
|
|
1481
|
+
|
|
1482
|
+
# 日時要素の下限
|
|
1483
|
+
#
|
|
1484
|
+
# @return [Array<Integer, nil>]
|
|
1485
|
+
#
|
|
1486
|
+
# Ex. [nil, 1, 1], [nil, 0, 0, 0]
|
|
1487
|
+
#
|
|
1488
|
+
# 初期化時に indices から自動生成する
|
|
1489
|
+
#
|
|
1490
|
+
attr_reader :base
|
|
1491
|
+
|
|
1492
|
+
# 日時要素がPairであるべきか
|
|
1493
|
+
#
|
|
1494
|
+
# @return [Array<Boolean>]
|
|
1495
|
+
#
|
|
1496
|
+
# Ex. [false] * 3, [false] * 4
|
|
1497
|
+
#
|
|
1498
|
+
# 初期化時に indices から自動生成する
|
|
1499
|
+
#
|
|
1500
|
+
attr_reader :pair
|
|
1501
|
+
|
|
1502
|
+
# 代表暦注
|
|
1503
|
+
#
|
|
1504
|
+
# @return [When::CalendarTypes::CalendarNote]
|
|
1505
|
+
# @return [Array<Array<klass, Array<klass, method, block>>>] 最外側のArray要素は年・月・日に対応
|
|
1506
|
+
#
|
|
1507
|
+
# klass [String, When::CalendarTypes::CalendarNote, When::Coordinates::Residue]
|
|
1508
|
+
#
|
|
1509
|
+
# method [String, Symbol] (デフォルト 'day', 'month' or 'year' (対応する桁による))
|
|
1510
|
+
#
|
|
1511
|
+
# block [Block] (デフォルト なし)
|
|
1512
|
+
#
|
|
1513
|
+
def note
|
|
1514
|
+
@note = When.CalendarNote(@note) if @note.kind_of?(String)
|
|
1515
|
+
@note
|
|
1516
|
+
end
|
|
1517
|
+
|
|
1518
|
+
#
|
|
1519
|
+
# 日時要素の正規化
|
|
1520
|
+
#
|
|
1521
|
+
# @param [Array<Numeric>] source 正規化しようとしている日時要素の Array
|
|
1522
|
+
# @param [Array<Numeric>] other 日時要素ごとに加減算を行う場合、加減算量の Array を指定する
|
|
1523
|
+
# @param [Block] block
|
|
1524
|
+
# @note
|
|
1525
|
+
# 日付要素と時刻要素に関連がある場合、block を指定して、両者の
|
|
1526
|
+
# 情報をやり取りする( yield で通日を渡し、通日を返してもらう)。
|
|
1527
|
+
#
|
|
1528
|
+
# 例1: 夏時間制を採用している場合、日付によって時刻の正規化の仕方が影響を受ける
|
|
1529
|
+
#
|
|
1530
|
+
# 例2: 日の境界が日没の場合、当該時刻が日没の前か後かで日付が変わる
|
|
1531
|
+
#
|
|
1532
|
+
# @return [Array<Numeric>] 正規化された日時要素の Array
|
|
1533
|
+
#
|
|
1534
|
+
# 日時要素は、それぞれの When::TM::Calendar や When::TM::Clock の実装に応じて有効な値となっている。
|
|
1535
|
+
#
|
|
1536
|
+
def _validate(source, other=nil, &block)
|
|
1537
|
+
return _encode(_decode(source, other, &block))
|
|
1538
|
+
end
|
|
1539
|
+
|
|
1540
|
+
# 期間指定用 Array の桁数合わせ
|
|
1541
|
+
#
|
|
1542
|
+
# @param [Array<Numeric>] period
|
|
1543
|
+
#
|
|
1544
|
+
# @return [Array<Numeric>] 桁数合わせをした Array
|
|
1545
|
+
#
|
|
1546
|
+
def _arrange_length(period)
|
|
1547
|
+
return period unless period.kind_of?(Array)
|
|
1548
|
+
diff = @indices.length - period.length + 1
|
|
1549
|
+
return period if (diff == 0)
|
|
1550
|
+
return (diff > 0) ? Array.new(diff, 0) + period : period[(-diff)..-1]
|
|
1551
|
+
end
|
|
1552
|
+
|
|
1553
|
+
# 西暦との差
|
|
1554
|
+
#
|
|
1555
|
+
# @return [Integer] 暦法の年の桁と西暦とのずれ
|
|
1556
|
+
#
|
|
1557
|
+
def _diff_to_CE
|
|
1558
|
+
@_diff_to_CE ||= @epoch_in_CE ? @epoch_in_CE - @origin_of_MSC : 0
|
|
1559
|
+
end
|
|
1560
|
+
|
|
1561
|
+
# protected
|
|
1562
|
+
|
|
1563
|
+
#
|
|
1564
|
+
# 日時要素の encode
|
|
1565
|
+
#
|
|
1566
|
+
# @param [Array<Numeric>] source 日時要素の内部表現に対応する Array
|
|
1567
|
+
#
|
|
1568
|
+
# @return [Array<Numeric>] 日時要素の外部表現に対応する Array
|
|
1569
|
+
#
|
|
1570
|
+
def _encode(source, border=@border)
|
|
1571
|
+
# source は非破壊
|
|
1572
|
+
date = source.dup
|
|
1573
|
+
|
|
1574
|
+
# 外部表現に戻す
|
|
1575
|
+
date[0] = +date[0]
|
|
1576
|
+
(@base.length-1).downto(@unit.length-1) do |i|
|
|
1577
|
+
date[i] = _from_index(date[0..i]) || date[i] + (@base[i]||0)
|
|
1578
|
+
end
|
|
1579
|
+
date[0] = source[0]
|
|
1580
|
+
|
|
1581
|
+
# 結果を反映
|
|
1582
|
+
date = border._adjust_epoch(date, self) if border
|
|
1583
|
+
_encode_upper_structure(date)
|
|
1584
|
+
end
|
|
1585
|
+
|
|
1586
|
+
private
|
|
1587
|
+
|
|
1588
|
+
#
|
|
1589
|
+
# 日時要素の decode
|
|
1590
|
+
#
|
|
1591
|
+
# @param [Array<Numeric>] source 日時要素の外部表現に対応する Array
|
|
1592
|
+
#
|
|
1593
|
+
# @return [Array<Numeric>] 日時要素の内部表現に対応する Array
|
|
1594
|
+
#
|
|
1595
|
+
def _decode(source, other=nil)
|
|
1596
|
+
|
|
1597
|
+
# other の正規化
|
|
1598
|
+
period = (other) ? other.dup : Array.new(@indices.length+1,0)
|
|
1599
|
+
|
|
1600
|
+
# 上の位の集約
|
|
1601
|
+
date = _decode_upper_structure(source.dup)
|
|
1602
|
+
if ((@index_of_MSC > 0) && other)
|
|
1603
|
+
u = 1
|
|
1604
|
+
s = period[@index_of_MSC]
|
|
1605
|
+
(@index_of_MSC-1).downto(0) do |i|
|
|
1606
|
+
u *= @indices[i].unit
|
|
1607
|
+
s += u * period[i]
|
|
1608
|
+
end
|
|
1609
|
+
period = [s] + period[(@index_of_MSC+1)..-1]
|
|
1610
|
+
end
|
|
1611
|
+
|
|
1612
|
+
# 下の位の既定値
|
|
1613
|
+
unless date[1] || !@border
|
|
1614
|
+
date[0...@base.length] = @border.border([date[0]], self)
|
|
1615
|
+
end
|
|
1616
|
+
|
|
1617
|
+
# 要素数固定部分の正規化(上 -> 下) - ISO8601 の 小数要素(ex. "T23:20.8")の処理
|
|
1618
|
+
carry = 0
|
|
1619
|
+
@unit.length.times do |i|
|
|
1620
|
+
if carry == 0
|
|
1621
|
+
break unless date[i]
|
|
1622
|
+
else
|
|
1623
|
+
date[i] ||= 0
|
|
1624
|
+
date[i] += carry * unit[i]
|
|
1625
|
+
end
|
|
1626
|
+
if (date[i].kind_of?(Integer))
|
|
1627
|
+
carry = 0
|
|
1628
|
+
else
|
|
1629
|
+
if i < @unit.length-1
|
|
1630
|
+
carry = (date[i].kind_of?(Pair) ? date[i].trunk : date[i]) % 1
|
|
1631
|
+
date[i] -= carry
|
|
1632
|
+
end
|
|
1633
|
+
date[i] = date[i].to_i if date[i].kind_of?(Float) && date[i] == date[i].to_i
|
|
1634
|
+
end
|
|
1635
|
+
end
|
|
1636
|
+
|
|
1637
|
+
# 要素数固定部分の正規化(下 -> 上)
|
|
1638
|
+
carry = 0
|
|
1639
|
+
(@unit.length-1).downto(1) do |i|
|
|
1640
|
+
if date[i]
|
|
1641
|
+
digit = date[i] + ((other || date[i]>=0) ? period[i]-@base[i] : @unit[i])
|
|
1642
|
+
else
|
|
1643
|
+
digit = period[i]
|
|
1644
|
+
end
|
|
1645
|
+
carry, date[i] = (digit + carry).divmod(@unit[i])
|
|
1646
|
+
end
|
|
1647
|
+
year = date[0] + period[0] + carry
|
|
1648
|
+
|
|
1649
|
+
# 要素数可変部分の正規化
|
|
1650
|
+
limit = @base.length-1
|
|
1651
|
+
count = nil
|
|
1652
|
+
date[0] = +year
|
|
1653
|
+
if (@base.length > @unit.length)
|
|
1654
|
+
@unit.length.upto(limit) do |i|
|
|
1655
|
+
len = _length(date[0...i])
|
|
1656
|
+
if date[i]
|
|
1657
|
+
plus = date[i]>=0
|
|
1658
|
+
digit = !plus ? +date[i] : _to_index(date[0..i]) || +date[i] - @base[i]
|
|
1659
|
+
digit += (plus || other) ? period[i] : len
|
|
1660
|
+
else
|
|
1661
|
+
digit = period[i]
|
|
1662
|
+
end
|
|
1663
|
+
|
|
1664
|
+
if (i==limit) then
|
|
1665
|
+
# 最下位
|
|
1666
|
+
if ((0...len) === digit)
|
|
1667
|
+
# 要素が範囲内
|
|
1668
|
+
date[i] = digit
|
|
1669
|
+
elsif other && other[i] == 0
|
|
1670
|
+
# 要素が範囲外で、加算自体はあるが“日”の加算なし
|
|
1671
|
+
date[i] = len-1
|
|
1672
|
+
else
|
|
1673
|
+
# 要素が範囲外で、加算自体がないか“日”の加算あり
|
|
1674
|
+
date[i] = 0
|
|
1675
|
+
count = _coordinates_to_number(*date)+digit
|
|
1676
|
+
count = yield(count) if block_given?
|
|
1677
|
+
date = _number_to_coordinates(count)
|
|
1678
|
+
end
|
|
1679
|
+
|
|
1680
|
+
else
|
|
1681
|
+
# 最下位以外
|
|
1682
|
+
# 要素が大きすぎる場合
|
|
1683
|
+
while (digit >= len) do
|
|
1684
|
+
digit -= len
|
|
1685
|
+
carry = 1
|
|
1686
|
+
(i-1).downto(1) do |k|
|
|
1687
|
+
if (date[k] >= _length(date[0...k])-1)
|
|
1688
|
+
date[k] = 0
|
|
1689
|
+
carry = 1
|
|
1690
|
+
else
|
|
1691
|
+
date[k] += 1
|
|
1692
|
+
carry = 0
|
|
1693
|
+
break
|
|
1694
|
+
end
|
|
1695
|
+
end
|
|
1696
|
+
date[0] += carry
|
|
1697
|
+
len = _length(date[0...i])
|
|
1698
|
+
end
|
|
1699
|
+
|
|
1700
|
+
# 要素が小さすぎる場合
|
|
1701
|
+
while (digit < 0) do
|
|
1702
|
+
date[i-1] -= 1
|
|
1703
|
+
digit += _length(date[0...i])
|
|
1704
|
+
(i-1).downto(1) do |k|
|
|
1705
|
+
break if (date[k] >= 0)
|
|
1706
|
+
date[k-1] -= 1
|
|
1707
|
+
date[k] = _length(date[0...k]) - 1
|
|
1708
|
+
end
|
|
1709
|
+
end
|
|
1710
|
+
|
|
1711
|
+
# 要素が範囲内
|
|
1712
|
+
date[i] = digit
|
|
1713
|
+
end
|
|
1714
|
+
end
|
|
1715
|
+
end
|
|
1716
|
+
date[0] = year + (date[0] - +year)
|
|
1717
|
+
|
|
1718
|
+
# 時刻部分による補正が入る場合
|
|
1719
|
+
if (block_given? && !count)
|
|
1720
|
+
count = _coordinates_to_number(*date)
|
|
1721
|
+
modified = yield(count)
|
|
1722
|
+
date = _number_to_coordinates(modified) unless (count == modified)
|
|
1723
|
+
end
|
|
1724
|
+
|
|
1725
|
+
# 結果を返す
|
|
1726
|
+
return date
|
|
1727
|
+
end
|
|
1728
|
+
|
|
1729
|
+
#
|
|
1730
|
+
# 日時要素の下限を取得する
|
|
1731
|
+
#
|
|
1732
|
+
# @param [Array<Numeric>] date 日時要素
|
|
1733
|
+
#
|
|
1734
|
+
# @return [Integer] 日時要素の下限
|
|
1735
|
+
#
|
|
1736
|
+
def _base(date)
|
|
1737
|
+
return @base[date.length]
|
|
1738
|
+
end
|
|
1739
|
+
|
|
1740
|
+
#
|
|
1741
|
+
# 日時要素の番号から要素を取得する配列を返す
|
|
1742
|
+
#
|
|
1743
|
+
#def _ids(date)
|
|
1744
|
+
# return nil
|
|
1745
|
+
#end
|
|
1746
|
+
|
|
1747
|
+
#
|
|
1748
|
+
# 日時要素の要素数を取得する(直下の要素)
|
|
1749
|
+
#
|
|
1750
|
+
#def _length(date)
|
|
1751
|
+
# return @unit[date.length]
|
|
1752
|
+
#end
|
|
1753
|
+
|
|
1754
|
+
#
|
|
1755
|
+
# 日時要素の要素数を取得する(全要素)
|
|
1756
|
+
#
|
|
1757
|
+
# @param [Array<Numeric>] date 日時要素(内部表現)
|
|
1758
|
+
#
|
|
1759
|
+
# @return [Integer] 日時要素の要素数
|
|
1760
|
+
# @note 一般に date が 1要素ならその要素の年の日数、2要素ならその要素の年月の日数になる。
|
|
1761
|
+
#
|
|
1762
|
+
def _sum_(date)
|
|
1763
|
+
return @unit[date.length..-1].inject(1) {|p, u| p * u }
|
|
1764
|
+
end
|
|
1765
|
+
|
|
1766
|
+
def _normalize_temporal
|
|
1767
|
+
|
|
1768
|
+
# method cash
|
|
1769
|
+
@_m_cash_lock_ = Mutex.new if When.multi_thread
|
|
1770
|
+
|
|
1771
|
+
# Spatial Parts
|
|
1772
|
+
_normalize_spatial
|
|
1773
|
+
|
|
1774
|
+
# Origin and Upper Digits
|
|
1775
|
+
@origin_of_MSC ||= - +@border.behavior if @border
|
|
1776
|
+
@origin_of_MSC = Pair._en_number(@origin_of_MSC)
|
|
1777
|
+
@origin_of_LSC = Pair._en_number(@origin_of_LSC)
|
|
1778
|
+
@index_of_MSC = Pair._en_number(@index_of_MSC)
|
|
1779
|
+
if (@index_of_MSC != 0)
|
|
1780
|
+
class << self; include OriginAndUpperDigits; end
|
|
1781
|
+
elsif (@origin_of_MSC != 0)
|
|
1782
|
+
class << self; include OriginOnly; end
|
|
1783
|
+
end
|
|
1784
|
+
|
|
1785
|
+
# unit
|
|
1786
|
+
@unit = [nil]
|
|
1787
|
+
(@index_of_MSC...@indices.length).each do |i|
|
|
1788
|
+
break unless @indices[i].unit
|
|
1789
|
+
@unit << @indices[i].unit
|
|
1790
|
+
end
|
|
1791
|
+
|
|
1792
|
+
# base & pair
|
|
1793
|
+
@base = [nil]
|
|
1794
|
+
@pair = [false]
|
|
1795
|
+
(@index_of_MSC...@indices.length).each do |i|
|
|
1796
|
+
raise ArgumentError, "Base not defined" unless @indices[i].base
|
|
1797
|
+
@base << @indices[i].base
|
|
1798
|
+
@pair << (@indices[i].branch != nil)
|
|
1799
|
+
end
|
|
1800
|
+
class << self; include IndexConversion; end unless @pair.uniq == [false]
|
|
1801
|
+
|
|
1802
|
+
# note
|
|
1803
|
+
@note ||= 'DefaultNotes'
|
|
1804
|
+
|
|
1805
|
+
# keys
|
|
1806
|
+
@keys = @indices.inject(label.instance_of?(When::Parts::Locale) ? label.keys : []) {|key, index| key |= index.keys}
|
|
1807
|
+
end
|
|
1808
|
+
|
|
1809
|
+
# 何もしない
|
|
1810
|
+
def _return_nil(source); nil end
|
|
1811
|
+
alias :_from_index :_return_nil
|
|
1812
|
+
alias :_to_index :_return_nil
|
|
1813
|
+
|
|
1814
|
+
def _do_nothing(source); source end
|
|
1815
|
+
alias :_encode_upper_structure :_do_nothing
|
|
1816
|
+
alias :_decode_upper_structure :_do_nothing
|
|
1817
|
+
|
|
1818
|
+
# @private
|
|
1819
|
+
module IndexConversion
|
|
1820
|
+
#
|
|
1821
|
+
# indexのPair化
|
|
1822
|
+
#
|
|
1823
|
+
# @param [Array<Numeric>] date 最下位が index になっている日時要素
|
|
1824
|
+
#
|
|
1825
|
+
# @return [When::Coordinates::Pair] 最下位の index に対応する When::Coordinates::Pair
|
|
1826
|
+
#
|
|
1827
|
+
def _from_index(date)
|
|
1828
|
+
return nil unless @pair[date.size-1]
|
|
1829
|
+
ids = _ids(date[0..-2])
|
|
1830
|
+
m = ids[date[-1]] if (ids)
|
|
1831
|
+
return Pair._force_pair(m) if (ids && m)
|
|
1832
|
+
return Pair.new(+date[-1]+@base[date.length-1], 0)
|
|
1833
|
+
end
|
|
1834
|
+
|
|
1835
|
+
#
|
|
1836
|
+
# Pairのindex化
|
|
1837
|
+
#
|
|
1838
|
+
# @param [Array<Numeric>] date 最下位が When::Coordinates::Pair になっている日時要素
|
|
1839
|
+
#
|
|
1840
|
+
# @return [When::Coordinates::Pair] 最下位の When::Coordinates::Pair に対応する index
|
|
1841
|
+
#
|
|
1842
|
+
def _to_index(date)
|
|
1843
|
+
return nil unless @pair[date.size-1]
|
|
1844
|
+
ids = _ids(date[0..-2])
|
|
1845
|
+
i = ids.index(date[-1]) if ids
|
|
1846
|
+
return i if i
|
|
1847
|
+
return nil unless ids && date[-1].kind_of?(Pair)
|
|
1848
|
+
digit = Pair.new(date[-1].trunk, date[-1].branch)
|
|
1849
|
+
while digit.branch > 0
|
|
1850
|
+
digit.branch -= 1
|
|
1851
|
+
i = ids.index(digit)
|
|
1852
|
+
return i + date[-1].branch - digit.branch if i
|
|
1853
|
+
end
|
|
1854
|
+
return nil
|
|
1855
|
+
end
|
|
1856
|
+
end
|
|
1857
|
+
|
|
1858
|
+
alias :_method_missing :method_missing
|
|
1859
|
+
|
|
1860
|
+
# その他のメソッド
|
|
1861
|
+
# When::Coordinates::Temporal で定義されていないメソッドは
|
|
1862
|
+
# 処理を @note or @formula[0] (When::Ephemeris::Formula) に委譲する
|
|
1863
|
+
#
|
|
1864
|
+
def method_missing(name, *args, &block)
|
|
1865
|
+
return @note.send(name.to_sym, *(args + [self]), &block) if note.respond_to?(name)
|
|
1866
|
+
forward = forwarded_formula(name, args[0]) if self.respond_to?(:forwarded_formula, true)
|
|
1867
|
+
return forward.send(name.to_sym, *args, &block) if forward
|
|
1868
|
+
_method_missing(name, *args, &block)
|
|
1869
|
+
end
|
|
1870
|
+
|
|
1871
|
+
# @private
|
|
1872
|
+
module OriginOnly
|
|
1873
|
+
# 上の位の付加
|
|
1874
|
+
#
|
|
1875
|
+
# @param [Array<Numeric>] source 日時要素の内部表現に対応する Array
|
|
1876
|
+
#
|
|
1877
|
+
# @return [Array<Numeric>] 日時要素の外部表現に対応する Array
|
|
1878
|
+
#
|
|
1879
|
+
def _encode_upper_structure(source)
|
|
1880
|
+
date = source.dup
|
|
1881
|
+
date[0] += @origin_of_MSC
|
|
1882
|
+
return date
|
|
1883
|
+
end
|
|
1884
|
+
|
|
1885
|
+
# 上の位の除去
|
|
1886
|
+
#
|
|
1887
|
+
# @param [Array<Numeric>] source 日時要素の外部表現に対応する Array
|
|
1888
|
+
#
|
|
1889
|
+
# @return [Array<Numeric>] 日時要素の内部表現に対応する Array
|
|
1890
|
+
#
|
|
1891
|
+
def _decode_upper_structure(source)
|
|
1892
|
+
date = source.dup
|
|
1893
|
+
date[0] -= @origin_of_MSC
|
|
1894
|
+
return date
|
|
1895
|
+
end
|
|
1896
|
+
end
|
|
1897
|
+
|
|
1898
|
+
# @private
|
|
1899
|
+
module OriginAndUpperDigits
|
|
1900
|
+
# 上の位の付加
|
|
1901
|
+
#
|
|
1902
|
+
# @param [Array<Numeric>] source 日時要素の内部表現に対応する Array
|
|
1903
|
+
#
|
|
1904
|
+
# @return [Array<Numeric>] 日時要素の外部表現に対応する Array
|
|
1905
|
+
#
|
|
1906
|
+
def _encode_upper_structure(source)
|
|
1907
|
+
date = source.dup
|
|
1908
|
+
date[0] += @origin_of_MSC
|
|
1909
|
+
@index_of_MSC.downto(1) do |i|
|
|
1910
|
+
carry, date[0] = (+date[0]).divmod(@indices[i-1].unit)
|
|
1911
|
+
date[0] += @indices[i-1].base
|
|
1912
|
+
date.unshift(carry)
|
|
1913
|
+
end
|
|
1914
|
+
return date
|
|
1915
|
+
end
|
|
1916
|
+
|
|
1917
|
+
# 上の位の除去
|
|
1918
|
+
#
|
|
1919
|
+
# @param [Array<Numeric>] source 日時要素の外部表現に対応する Array
|
|
1920
|
+
#
|
|
1921
|
+
# @return [Array<Numeric>] 日時要素の内部表現に対応する Array
|
|
1922
|
+
#
|
|
1923
|
+
def _decode_upper_structure(source)
|
|
1924
|
+
date = source.dup
|
|
1925
|
+
u = 1
|
|
1926
|
+
s = 0
|
|
1927
|
+
@index_of_MSC.downto(1) do |i|
|
|
1928
|
+
s += u * (+date[i] - @indices[i-1].base) if (date[i])
|
|
1929
|
+
u *= @indices[i-1].unit
|
|
1930
|
+
end
|
|
1931
|
+
date[@index_of_MSC] = s + u * (+date[0]) - @origin_of_MSC
|
|
1932
|
+
return date[@index_of_MSC..-1]
|
|
1933
|
+
end
|
|
1934
|
+
end
|
|
1935
|
+
end
|
|
1936
|
+
end
|