zakuro 0.0.2 → 0.1.3
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.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -0
- data/README.md +102 -42
- data/doc/operation.md +25 -0
- data/doc/operation/csv/month.csv +202 -0
- data/doc/operation/operation.xlsx +0 -0
- data/doc/operation/transfer.rb +77 -0
- data/lib/zakuro/calculation/base/multi_gengou.rb +101 -0
- data/lib/zakuro/calculation/base/multi_gengou_roller.rb +218 -0
- data/lib/zakuro/calculation/base/year.rb +107 -0
- data/lib/zakuro/calculation/cycle/abstract_remainder.rb +459 -0
- data/lib/zakuro/calculation/cycle/abstract_solar_term.rb +151 -0
- data/lib/zakuro/calculation/cycle/zodiac.rb +106 -0
- data/lib/zakuro/calculation/monthly/first_day.rb +45 -0
- data/lib/zakuro/calculation/monthly/initialized_month.rb +120 -0
- data/lib/zakuro/calculation/monthly/month.rb +184 -0
- data/lib/zakuro/calculation/monthly/month_label.rb +88 -0
- data/lib/zakuro/calculation/monthly/operated_month.rb +201 -0
- data/lib/zakuro/calculation/range/full_range.rb +210 -0
- data/lib/zakuro/calculation/range/operated_range.rb +134 -0
- data/lib/zakuro/calculation/range/operated_solar_terms.rb +201 -0
- data/lib/zakuro/calculation/range/transfer/western_date_allocation.rb +76 -0
- data/lib/zakuro/calculation/range/transfer/year_boundary.rb +142 -0
- data/lib/zakuro/calculation/specifier/single_day.rb +109 -0
- data/lib/zakuro/calculation/summary/single.rb +129 -0
- data/lib/zakuro/condition.rb +17 -13
- data/lib/zakuro/era/japan/gengou.rb +106 -0
- data/lib/zakuro/era/japan/gengou/parser.rb +167 -0
- data/lib/zakuro/era/japan/gengou/type.rb +178 -0
- data/lib/zakuro/era/japan/gengou/validator.rb +236 -0
- data/lib/zakuro/era/japan/reki.rb +91 -0
- data/lib/zakuro/era/{gengou → japan/yaml}/set-001-until-south.yaml +0 -0
- data/lib/zakuro/era/{gengou → japan/yaml}/set-002-from-north.yaml +0 -0
- data/lib/zakuro/era/{gengou → japan/yaml}/set-003-modern.yaml +1 -1
- data/lib/zakuro/era/western.rb +1 -1
- data/lib/zakuro/merchant.rb +2 -2
- data/lib/zakuro/operation/month/parser.rb +373 -0
- data/lib/zakuro/operation/month/type.rb +453 -0
- data/lib/zakuro/operation/month/validator.rb +802 -0
- data/lib/zakuro/operation/operation.rb +66 -0
- data/lib/zakuro/operation/yaml/month.yaml +6452 -0
- data/lib/zakuro/output/error.rb +7 -4
- data/lib/zakuro/output/logger.rb +50 -47
- data/lib/zakuro/output/response.rb +146 -143
- data/lib/zakuro/result/core.rb +52 -0
- data/lib/zakuro/result/data.rb +187 -0
- data/lib/zakuro/result/operation.rb +114 -0
- data/lib/zakuro/result/result.rb +37 -0
- data/lib/zakuro/{output → tools}/stringifier.rb +16 -9
- data/lib/zakuro/tools/typeof.rb +33 -0
- data/lib/zakuro/version.rb +1 -1
- data/lib/zakuro/version/abstract_version.rb +1 -1
- data/lib/zakuro/version/context.rb +23 -0
- data/lib/zakuro/version/senmyou/cycle/remainder.rb +63 -0
- data/lib/zakuro/version/senmyou/cycle/solar_term.rb +31 -0
- data/lib/zakuro/version/senmyou/monthly/lunar_phase.rb +186 -182
- data/lib/zakuro/version/senmyou/range/annual_range.rb +164 -0
- data/lib/zakuro/version/senmyou/senmyou.rb +10 -4
- data/lib/zakuro/version/senmyou/stella/lunar_orbit.rb +7 -7
- data/lib/zakuro/version/senmyou/stella/solar_average.rb +103 -138
- data/lib/zakuro/version/senmyou/stella/solar_location.rb +213 -0
- data/lib/zakuro/version/senmyou/stella/solar_orbit.rb +6 -191
- data/lib/zakuro/version/senmyou/stella/winter_solstice.rb +4 -4
- data/lib/zakuro/version/version_class_resolver.rb +62 -0
- data/lib/zakuro/version_factory.rb +3 -3
- metadata +49 -20
- data/lib/zakuro/cycle/abstract_remainder.rb +0 -457
- data/lib/zakuro/cycle/zodiac.rb +0 -103
- data/lib/zakuro/era/japan.rb +0 -660
- data/lib/zakuro/output/result.rb +0 -219
- data/lib/zakuro/version/senmyou/base/era.rb +0 -83
- data/lib/zakuro/version/senmyou/base/multi_gengou.rb +0 -98
- data/lib/zakuro/version/senmyou/base/multi_gengou_roller.rb +0 -205
- data/lib/zakuro/version/senmyou/base/remainder.rb +0 -60
- data/lib/zakuro/version/senmyou/base/solar_term.rb +0 -66
- data/lib/zakuro/version/senmyou/base/year.rb +0 -104
- data/lib/zakuro/version/senmyou/monthly/month.rb +0 -122
- data/lib/zakuro/version/senmyou/summary/annual_range.rb +0 -186
- data/lib/zakuro/version/senmyou/summary/full_range.rb +0 -216
- data/lib/zakuro/version/senmyou/summary/specifier.rb +0 -100
@@ -0,0 +1,101 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../era/japan/gengou'
|
4
|
+
require_relative '../../era/western'
|
5
|
+
|
6
|
+
# :nodoc:
|
7
|
+
module Zakuro
|
8
|
+
# :nodoc:
|
9
|
+
module Calculation
|
10
|
+
# :nodoc:
|
11
|
+
module Base
|
12
|
+
#
|
13
|
+
# MultiGengou 複数元号
|
14
|
+
#
|
15
|
+
class MultiGengou
|
16
|
+
# @return [Japan::Gengou] 元号(1行目)
|
17
|
+
attr_reader :first_line
|
18
|
+
# @return [Japan::Gengou] 元号(2行目)
|
19
|
+
attr_reader :second_line
|
20
|
+
# @return [Western::Calendar] 元旦
|
21
|
+
attr_reader :new_year_date
|
22
|
+
|
23
|
+
def initialize(first_line: Japan::Gengou.new, second_line: Japan::Gengou.new,
|
24
|
+
new_year_date: Western::Calendar.new)
|
25
|
+
@first_line = first_line
|
26
|
+
@second_line = second_line
|
27
|
+
@new_year_date = new_year_date
|
28
|
+
end
|
29
|
+
|
30
|
+
# :reek:TooManyStatements { max_statements: 7 }
|
31
|
+
|
32
|
+
#
|
33
|
+
# 改元する
|
34
|
+
#
|
35
|
+
# @param [Japan::Gengou] first_line 元号(1行目)
|
36
|
+
# @param [Japan::Gengou] second_line 元号(2行目)
|
37
|
+
#
|
38
|
+
# @return [MultiGengou] 自身
|
39
|
+
#
|
40
|
+
def transfer(first_line: Japan::Gengou.new, second_line: Japan::Gengou.new)
|
41
|
+
cloned_first_line = first_line.clone
|
42
|
+
cloned_second_line = second_line.clone
|
43
|
+
|
44
|
+
if integrated?(first_line: cloned_first_line, second_line: cloned_second_line)
|
45
|
+
@first_line = @second_line.clone
|
46
|
+
@second_line = cloned_second_line
|
47
|
+
end
|
48
|
+
|
49
|
+
@first_line = cloned_first_line if @first_line.name != first_line.name
|
50
|
+
@second_line = cloned_second_line if @second_line.name != second_line.name
|
51
|
+
|
52
|
+
self
|
53
|
+
end
|
54
|
+
|
55
|
+
#
|
56
|
+
# 次年にする
|
57
|
+
#
|
58
|
+
# @param [Japan::Gengou] first_line 元号(1行目)
|
59
|
+
# @param [Japan::Gengou] second_line 元号(2行目)
|
60
|
+
#
|
61
|
+
# @return [MultiGengou] 自身
|
62
|
+
#
|
63
|
+
def next_year
|
64
|
+
@first_line.next_year
|
65
|
+
@second_line.next_year
|
66
|
+
|
67
|
+
self
|
68
|
+
end
|
69
|
+
|
70
|
+
#
|
71
|
+
# ディープコピー
|
72
|
+
#
|
73
|
+
# @param [MultiGengou] obj 自身
|
74
|
+
#
|
75
|
+
def initialize_copy(obj)
|
76
|
+
@first_line = obj.first_line.clone
|
77
|
+
@second_line = obj.second_line.clone
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
#
|
83
|
+
# 複数元号を統一するかどうか
|
84
|
+
#
|
85
|
+
# @param [Japan::Gengou] first_line 元号(1行目)
|
86
|
+
# @param [Japan::Gengou] second_line 元号(2行目)
|
87
|
+
#
|
88
|
+
# @return [True] 統一する
|
89
|
+
# @return [False] 統一しない
|
90
|
+
#
|
91
|
+
def integrated?(first_line: Japan::Gengou.new, second_line: Japan::Gengou.new)
|
92
|
+
return false if @second_line.name != first_line.name
|
93
|
+
|
94
|
+
return false unless second_line.invalid?
|
95
|
+
|
96
|
+
true
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,218 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative './multi_gengou'
|
4
|
+
|
5
|
+
require_relative '../../era/japan/gengou'
|
6
|
+
|
7
|
+
# :nodoc:
|
8
|
+
module Zakuro
|
9
|
+
# :nodoc:
|
10
|
+
module Calculation
|
11
|
+
# :nodoc:
|
12
|
+
module Base
|
13
|
+
#
|
14
|
+
# MultiGengouRoller 改元処理
|
15
|
+
#
|
16
|
+
class MultiGengouRoller
|
17
|
+
# @return [MultiGengou] 複数元号
|
18
|
+
attr_reader :multi_gengou
|
19
|
+
# @return [Western::Calendar] 元旦(元号が2つある場合は再過去の日付になる)
|
20
|
+
attr_reader :oldest_date
|
21
|
+
# @return [Western::Calendar] 元号内での最未来日(元号が2つある場合は再未来の日付になる)
|
22
|
+
attr_reader :newest_date
|
23
|
+
# @return [Western::Calendar] 現在日
|
24
|
+
attr_reader :current_date
|
25
|
+
|
26
|
+
def initialize(start_date: Western::Calendar.new, end_date: Western::Calendar.new)
|
27
|
+
end_date = start_date if end_date.invalid?
|
28
|
+
|
29
|
+
@oldest_date = MultiGengouRoller.choise_oldest_gengou_date(
|
30
|
+
first_line: MultiGengouRoller.first_line(date: start_date),
|
31
|
+
second_line: MultiGengouRoller.second_line(date: start_date)
|
32
|
+
)
|
33
|
+
@current_date = @oldest_date.clone
|
34
|
+
@newest_date = MultiGengouRoller.choise_newest_gengou_date(
|
35
|
+
first_line: MultiGengouRoller.first_line(date: end_date),
|
36
|
+
second_line: MultiGengouRoller.second_line(date: end_date)
|
37
|
+
)
|
38
|
+
|
39
|
+
@multi_gengou = MultiGengou.new(
|
40
|
+
first_line: current_first_line,
|
41
|
+
second_line: current_second_line,
|
42
|
+
new_year_date: @oldest_date
|
43
|
+
)
|
44
|
+
end
|
45
|
+
|
46
|
+
#
|
47
|
+
# 現在日付を未来に進める
|
48
|
+
#
|
49
|
+
# @param [<Type>] days <description>
|
50
|
+
#
|
51
|
+
# @return [<Type>] <description>
|
52
|
+
#
|
53
|
+
def next(days: 0)
|
54
|
+
@current_date += days
|
55
|
+
end
|
56
|
+
|
57
|
+
#
|
58
|
+
# 現在日から元号(1行目)を取得する
|
59
|
+
#
|
60
|
+
# @return [Japan::Gengou] 元号(1行目)
|
61
|
+
#
|
62
|
+
def current_first_line
|
63
|
+
MultiGengouRoller.first_line(date: @current_date)
|
64
|
+
end
|
65
|
+
|
66
|
+
#
|
67
|
+
# 現在日から元号(2行目)を取得する
|
68
|
+
#
|
69
|
+
# @return [Japan::Gengou] 元号(2行目)
|
70
|
+
#
|
71
|
+
def current_second_line
|
72
|
+
MultiGengouRoller.second_line(date: @current_date)
|
73
|
+
end
|
74
|
+
|
75
|
+
#
|
76
|
+
# 改元する
|
77
|
+
#
|
78
|
+
# @return [MultiGengou] 複数元号
|
79
|
+
#
|
80
|
+
def transfer
|
81
|
+
MultiGengouRoller.transfer(multi_gengou: @multi_gengou, date: @current_date)
|
82
|
+
end
|
83
|
+
|
84
|
+
#
|
85
|
+
# 次年にする
|
86
|
+
#
|
87
|
+
# @return [MultiGengou] 複数元号
|
88
|
+
#
|
89
|
+
def next_year
|
90
|
+
@multi_gengou.next_year
|
91
|
+
end
|
92
|
+
|
93
|
+
#
|
94
|
+
# 元号(1行目)を取得する
|
95
|
+
#
|
96
|
+
# @return [Japan::Gengou] 元号(1行目)
|
97
|
+
#
|
98
|
+
def self.first_line(date: Western::Calender.new)
|
99
|
+
Japan::GengouResource.first_line(date: date)
|
100
|
+
end
|
101
|
+
|
102
|
+
#
|
103
|
+
# 元号(2行目)を取得する
|
104
|
+
#
|
105
|
+
# @return [Japan::Gengou] 元号(2行目)
|
106
|
+
#
|
107
|
+
def self.second_line(date: Western::Calender.new)
|
108
|
+
Japan::GengouResource.second_line(date: date)
|
109
|
+
end
|
110
|
+
|
111
|
+
#
|
112
|
+
# 改元する
|
113
|
+
#
|
114
|
+
# @param [MultiGengou] multi_gengou 複数元号
|
115
|
+
# @param [Western::Calendar] date 対象日
|
116
|
+
#
|
117
|
+
# @return [MultiGengou] 改元済み複数元号
|
118
|
+
#
|
119
|
+
def self.transfer(multi_gengou:, date:)
|
120
|
+
multi_gengou.transfer(
|
121
|
+
first_line: first_line(date: date),
|
122
|
+
second_line: second_line(date: date)
|
123
|
+
)
|
124
|
+
|
125
|
+
multi_gengou
|
126
|
+
end
|
127
|
+
|
128
|
+
#
|
129
|
+
# 現在日からみて直近の未来に対する元号の切替前日を求める
|
130
|
+
# @note 2つの元号が重複した場合はより過去の日となる
|
131
|
+
#
|
132
|
+
# @param [Japan::Gengou] first_line 元号(1行目)
|
133
|
+
# @param [Japan::Gengou] second_line 元号(2行目)
|
134
|
+
#
|
135
|
+
# @return [Western::Calendar] 元号の切替前日
|
136
|
+
#
|
137
|
+
def choise_nearest_end_date
|
138
|
+
condition = lambda do |first_date, second_date|
|
139
|
+
first_date < second_date ? first_date : second_date
|
140
|
+
end
|
141
|
+
|
142
|
+
second_line = current_second_line
|
143
|
+
|
144
|
+
MultiGengouRoller.choise_date(condition: condition, second_line: second_line,
|
145
|
+
first_date: current_first_line.end_date.clone,
|
146
|
+
second_date: second_line.end_date.clone)
|
147
|
+
end
|
148
|
+
|
149
|
+
#
|
150
|
+
# 最過去の元旦を求める
|
151
|
+
# @note 2つの元号が重複した場合はより過去の日となる
|
152
|
+
#
|
153
|
+
# @param [Japan::Gengou] first_line 元号(1行目)
|
154
|
+
# @param [Japan::Gengou] second_line 元号(2行目)
|
155
|
+
#
|
156
|
+
# @return [Western::Calendar] 最過去の元旦
|
157
|
+
#
|
158
|
+
def self.choise_oldest_gengou_date(first_line:, second_line:)
|
159
|
+
condition = lambda do |first_date, second_date|
|
160
|
+
first_date < second_date ? first_date : second_date
|
161
|
+
end
|
162
|
+
choise_date(condition: condition, second_line: second_line,
|
163
|
+
first_date: first_line.new_year_date.clone,
|
164
|
+
second_date: second_line.new_year_date.clone)
|
165
|
+
end
|
166
|
+
|
167
|
+
#
|
168
|
+
# 元号内での最未来日を求める
|
169
|
+
# @note 2つの元号が重複した場合はより未来の日となる
|
170
|
+
#
|
171
|
+
# @param [Japan::Gengou] first_line 元号(1行目)
|
172
|
+
# @param [Japan::Gengou] second_line 元号(2行目)
|
173
|
+
#
|
174
|
+
# @return [Western::Calendar] 最未来日
|
175
|
+
#
|
176
|
+
def self.choise_newest_gengou_date(first_line:, second_line:)
|
177
|
+
condition = lambda do |first_date, second_date|
|
178
|
+
first_date > second_date ? first_date : second_date
|
179
|
+
end
|
180
|
+
choise_date(condition: condition, second_line: second_line,
|
181
|
+
first_date: first_line.end_date.clone,
|
182
|
+
second_date: second_line.end_date.clone)
|
183
|
+
end
|
184
|
+
|
185
|
+
# :reek:LongParameterList {max_params: 4}
|
186
|
+
|
187
|
+
#
|
188
|
+
# 条件を元に日付を求める
|
189
|
+
#
|
190
|
+
# @param [Proc] condition 比較条件
|
191
|
+
# @param [Japan::Gengou] second_line 元号(2行目)
|
192
|
+
# @param [Western::Calendar] first_date 比較対象(1行目)
|
193
|
+
# @param [Western::Calendar] second_date 比較対象(2行目)
|
194
|
+
#
|
195
|
+
# @return [Western::Calendar] 比較結果
|
196
|
+
#
|
197
|
+
def self.choise_date(condition:, second_line:, first_date:, second_date:)
|
198
|
+
# first_lineは常に存在する
|
199
|
+
return first_date if second_line.invalid?
|
200
|
+
|
201
|
+
condition.call(first_date, second_date)
|
202
|
+
end
|
203
|
+
|
204
|
+
#
|
205
|
+
# ディープコピー
|
206
|
+
#
|
207
|
+
# @param [MultiGengou] obj 自身
|
208
|
+
#
|
209
|
+
def initialize_copy(obj)
|
210
|
+
@oldest_date = obj.oldest_date.clone
|
211
|
+
@current_date = obj.current_date.clone
|
212
|
+
@newest_date = obj.newest_date.clone
|
213
|
+
@multi_gengou = obj.multi_gengou.clone
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../cycle/zodiac'
|
4
|
+
|
5
|
+
# :nodoc:
|
6
|
+
module Zakuro
|
7
|
+
# :nodoc:
|
8
|
+
module Calculation
|
9
|
+
# :nodoc:
|
10
|
+
module Base
|
11
|
+
#
|
12
|
+
# Year 年
|
13
|
+
#
|
14
|
+
class Year
|
15
|
+
# @return [Gengou] 元号
|
16
|
+
attr_reader :multi_gengou
|
17
|
+
# @return [Array<Month>] 年内の全ての月
|
18
|
+
attr_reader :months
|
19
|
+
# @return [Integer] 年の日数
|
20
|
+
attr_reader :total_days
|
21
|
+
# @return [Western::Calendar] 元旦
|
22
|
+
attr_reader :new_year_date
|
23
|
+
|
24
|
+
#
|
25
|
+
# 初期化
|
26
|
+
#
|
27
|
+
# @param [Gengou] multi_gengou 元号
|
28
|
+
#
|
29
|
+
def initialize(multi_gengou: MultiGengou.new, new_year_date: Western::Calendar.new,
|
30
|
+
months: [], total_days: 0)
|
31
|
+
@multi_gengou = multi_gengou
|
32
|
+
@months = months
|
33
|
+
@new_year_date = new_year_date
|
34
|
+
@total_days = total_days
|
35
|
+
end
|
36
|
+
|
37
|
+
#
|
38
|
+
# 年の日数を確定する
|
39
|
+
#
|
40
|
+
def commit
|
41
|
+
@total_days = 0
|
42
|
+
months.each do |month|
|
43
|
+
@total_days += month.days
|
44
|
+
end
|
45
|
+
|
46
|
+
self
|
47
|
+
end
|
48
|
+
|
49
|
+
#
|
50
|
+
# 次年にする
|
51
|
+
#
|
52
|
+
# @param [Japan::Gengou] first_line 元号(1行目)
|
53
|
+
# @param [Japan::Gengou] second_line 元号(2行目)
|
54
|
+
#
|
55
|
+
# @return [MultiGengou] 自身
|
56
|
+
#
|
57
|
+
def next_year
|
58
|
+
@multi_gengou.next_year
|
59
|
+
|
60
|
+
@new_year_date += @total_days
|
61
|
+
@total_days = 0
|
62
|
+
|
63
|
+
self
|
64
|
+
end
|
65
|
+
|
66
|
+
#
|
67
|
+
# 十干十二支を取得する
|
68
|
+
#
|
69
|
+
# @return [String] 十干十二支
|
70
|
+
#
|
71
|
+
def zodiac_name
|
72
|
+
Cycle::Zodiac.year_name(western_year: @new_year_date.year)
|
73
|
+
end
|
74
|
+
|
75
|
+
#
|
76
|
+
# 月を追加する
|
77
|
+
#
|
78
|
+
# @param [Month] month 月
|
79
|
+
#
|
80
|
+
def push(month:)
|
81
|
+
return if duplicated?(month: month)
|
82
|
+
|
83
|
+
@months.push(month)
|
84
|
+
|
85
|
+
nil
|
86
|
+
end
|
87
|
+
|
88
|
+
#
|
89
|
+
# すでに登録済みの月と重複しているか判定する
|
90
|
+
#
|
91
|
+
# @note 昨年11月1日から今年1月1日の前日までで、去年データと重複する場合は登録スキップする
|
92
|
+
#
|
93
|
+
# @param [Month] month 月
|
94
|
+
#
|
95
|
+
# @return [True] 重複している
|
96
|
+
# @return [True] 重複していない
|
97
|
+
#
|
98
|
+
def duplicated?(month:)
|
99
|
+
@months.each do |existed|
|
100
|
+
return true if existed.same?(other: month)
|
101
|
+
end
|
102
|
+
false
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,459 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# :nodoc:
|
4
|
+
module Zakuro
|
5
|
+
# :nodoc:
|
6
|
+
module Calculation
|
7
|
+
# :nodoc:
|
8
|
+
module Cycle
|
9
|
+
#
|
10
|
+
# 大余小余(時刻情報)
|
11
|
+
# @abstract 大余小余計算に必要な処理を行う、暦に依存しない汎用的なクラス
|
12
|
+
#
|
13
|
+
class AbstractRemainder # rubocop:disable Metrics/ClassLength
|
14
|
+
# @return [Integer] 大余上限
|
15
|
+
LIMIT = 60
|
16
|
+
|
17
|
+
# @return [Integer] 大余("日"に相当)
|
18
|
+
attr_reader :day
|
19
|
+
# @return [Integer] 小余("分"に相当)
|
20
|
+
attr_reader :minute
|
21
|
+
# @return [Integer] 秒
|
22
|
+
attr_reader :second
|
23
|
+
# @return [Integer] 繰り上げなしの小余
|
24
|
+
attr_reader :base_limit
|
25
|
+
# @return [Integer] 1大余に必要な小余(暦によって基数が異なる)
|
26
|
+
attr_reader :base_day
|
27
|
+
# @return [Integer] 1小余に必要な秒(暦によって基数が異なる)
|
28
|
+
attr_reader :base_minute
|
29
|
+
# 繰り上げ有無
|
30
|
+
# @return [True] 繰り上げあり
|
31
|
+
# @return [False] 繰り上げなし
|
32
|
+
attr_reader :limited
|
33
|
+
|
34
|
+
# :reek:instanceVariableAssumption
|
35
|
+
# rubocop:disable Metrics/ParameterLists
|
36
|
+
|
37
|
+
#
|
38
|
+
# 初期化
|
39
|
+
#
|
40
|
+
# @param [Integer] base_day 1大余に必要な小余(暦によって基数が異なる)
|
41
|
+
# @param [Integer] base_mitune 1小余に必要な秒(暦によって基数が異なる)
|
42
|
+
# @param [Integer] day 大余("日"に相当)
|
43
|
+
# @param [Integer] minute 小余("分"に相当)
|
44
|
+
# @param [Integer] second 秒
|
45
|
+
# @param [Integer] total 繰り上げなしの小余
|
46
|
+
#
|
47
|
+
def initialize(base_day: -1, base_mitune: -1, day: -1, minute: -1, second: -1, total: -1)
|
48
|
+
@base_limit = LIMIT
|
49
|
+
@base_day = base_day
|
50
|
+
@base_minute = base_mitune
|
51
|
+
@limited = true
|
52
|
+
|
53
|
+
set(day: day, minute: minute, second: second, total: total)
|
54
|
+
end
|
55
|
+
# rubocop:enable Metrics/ParameterLists
|
56
|
+
|
57
|
+
#
|
58
|
+
# 値を設定する
|
59
|
+
#
|
60
|
+
# @param [Integer] day 大余("日"に相当)
|
61
|
+
# @param [Integer] minute 小余("分"に相当)
|
62
|
+
# @param [Integer] second 秒
|
63
|
+
# @param [Integer] total 繰り上げなしの小余
|
64
|
+
#
|
65
|
+
# @return [AbstractRemainder] 自身の参照
|
66
|
+
#
|
67
|
+
def set(day: -1, minute: -1, second: -1, total: -1)
|
68
|
+
@day = day
|
69
|
+
@minute = minute
|
70
|
+
@second = second
|
71
|
+
|
72
|
+
if total != -1
|
73
|
+
@day = (total.to_f / @base_day).floor
|
74
|
+
@minute = (total % @base_day)
|
75
|
+
@second = 0
|
76
|
+
end
|
77
|
+
|
78
|
+
self
|
79
|
+
end
|
80
|
+
|
81
|
+
#
|
82
|
+
# 繰り上げ処理を外す
|
83
|
+
#
|
84
|
+
# @return [AbstractRemainder] 自身の参照
|
85
|
+
#
|
86
|
+
def lift_limit
|
87
|
+
@limited = false
|
88
|
+
|
89
|
+
self
|
90
|
+
end
|
91
|
+
|
92
|
+
#
|
93
|
+
# 繰り上げ処理を設定する
|
94
|
+
#
|
95
|
+
# @return [AbstractRemainder] 自身の参照
|
96
|
+
#
|
97
|
+
def set_limit
|
98
|
+
@limited = true
|
99
|
+
|
100
|
+
self
|
101
|
+
end
|
102
|
+
|
103
|
+
#
|
104
|
+
# 無効かどうか
|
105
|
+
#
|
106
|
+
# @param [AbstractRemainder] param 自クラスのインスタンス(デフォルトは自身の参照)
|
107
|
+
#
|
108
|
+
# @return [True] 無効
|
109
|
+
# @return [False] 有効
|
110
|
+
#
|
111
|
+
def invalid?(param: self)
|
112
|
+
raise ArgumentError, 'unmatch parameter type' unless param.is_a?(AbstractRemainder)
|
113
|
+
|
114
|
+
param.day == -1 || param.minute == -1 || param.second == -1
|
115
|
+
end
|
116
|
+
|
117
|
+
#
|
118
|
+
# 十干十二支名
|
119
|
+
#
|
120
|
+
# @return [String] 十干十二支名
|
121
|
+
#
|
122
|
+
def zodiac_name
|
123
|
+
Cycle::Zodiac.day_name(day: @day)
|
124
|
+
end
|
125
|
+
|
126
|
+
#
|
127
|
+
# 日が同じ十干かどうか(大小の月判定)
|
128
|
+
#
|
129
|
+
# @param [Integer] other 大余
|
130
|
+
#
|
131
|
+
# @return [True] 当月朔日と翌月朔日が同じ十干(「大」の月)
|
132
|
+
# @return [False] 当月朔日と翌月朔日が異なる十干(「小」の月)
|
133
|
+
#
|
134
|
+
def same_remainder_divided_by_ten?(other:)
|
135
|
+
day = @day % LIMIT
|
136
|
+
|
137
|
+
(day % 10) == (other % 10)
|
138
|
+
end
|
139
|
+
|
140
|
+
#
|
141
|
+
# (非破壊的に)加算する
|
142
|
+
#
|
143
|
+
# @param [AbstractRemainder] other 他の大余小余
|
144
|
+
#
|
145
|
+
# @return [AbstractRemainder] 加算結果
|
146
|
+
#
|
147
|
+
def add(other)
|
148
|
+
invalid?(param: other)
|
149
|
+
day = @day + other.day
|
150
|
+
minute = @minute + other.minute
|
151
|
+
second = @second + other.second
|
152
|
+
day, minute, second = carry(day, minute, second)
|
153
|
+
|
154
|
+
clone.set(day: day, minute: minute, second: second)
|
155
|
+
end
|
156
|
+
|
157
|
+
#
|
158
|
+
# (破壊的に)加算する
|
159
|
+
#
|
160
|
+
# @param [AbstractRemainder] other 他の大余小余
|
161
|
+
#
|
162
|
+
# @return [AbstractRemainder] 加算結果
|
163
|
+
#
|
164
|
+
def add!(other)
|
165
|
+
result = add(other)
|
166
|
+
@day = result.day
|
167
|
+
@minute = result.minute
|
168
|
+
@second = result.second
|
169
|
+
|
170
|
+
self
|
171
|
+
end
|
172
|
+
|
173
|
+
#
|
174
|
+
# (非破壊的に)除算する
|
175
|
+
#
|
176
|
+
# @param [AbstractRemainder] other 他の大余小余
|
177
|
+
#
|
178
|
+
# @return [AbstractRemainder] 除算結果
|
179
|
+
#
|
180
|
+
def sub(other)
|
181
|
+
invalid?(param: other)
|
182
|
+
day = @day - other.day
|
183
|
+
minute = @minute - other.minute
|
184
|
+
second = @second - other.second
|
185
|
+
day, minute, second = carry(day, minute, second)
|
186
|
+
|
187
|
+
clone.set(day: day, minute: minute, second: second)
|
188
|
+
end
|
189
|
+
|
190
|
+
#
|
191
|
+
# (破壊的に)除算する
|
192
|
+
#
|
193
|
+
# @param [AbstractRemainder] other 他の大余小余
|
194
|
+
#
|
195
|
+
# @return [AbstractRemainder] 除算結果
|
196
|
+
#
|
197
|
+
def sub!(other)
|
198
|
+
result = sub(other)
|
199
|
+
@day = result.day
|
200
|
+
@minute = result.minute
|
201
|
+
@second = result.second
|
202
|
+
|
203
|
+
self
|
204
|
+
end
|
205
|
+
|
206
|
+
#
|
207
|
+
# 大小比較(>)
|
208
|
+
#
|
209
|
+
# @param [AbstractRemainder] other 他の大余小余
|
210
|
+
#
|
211
|
+
# @return [True] より大きい
|
212
|
+
# @return [False] 以下
|
213
|
+
#
|
214
|
+
def >(other)
|
215
|
+
up?(other)
|
216
|
+
end
|
217
|
+
|
218
|
+
#
|
219
|
+
# 大小比較(>=)
|
220
|
+
#
|
221
|
+
# @param [AbstractRemainder] other 他の大余小余
|
222
|
+
#
|
223
|
+
# @return [True] 以上
|
224
|
+
# @return [False] より小さい
|
225
|
+
#
|
226
|
+
def >=(other)
|
227
|
+
up?(other) || \
|
228
|
+
(@day == other.day && @minute == other.minute && @second == other.second)
|
229
|
+
end
|
230
|
+
|
231
|
+
#
|
232
|
+
# 大小比較(<)
|
233
|
+
#
|
234
|
+
# @param [AbstractRemainder] other 他の大余小余
|
235
|
+
#
|
236
|
+
# @return [True] より小さい
|
237
|
+
# @return [False] 以上
|
238
|
+
#
|
239
|
+
def <(other)
|
240
|
+
down?(other)
|
241
|
+
end
|
242
|
+
|
243
|
+
#
|
244
|
+
# 大小比較(<=)
|
245
|
+
#
|
246
|
+
# @param [AbstractRemainder] other 他の大余小余
|
247
|
+
#
|
248
|
+
# @return [True] 以下
|
249
|
+
# @return [False] より大きい
|
250
|
+
#
|
251
|
+
def <=(other)
|
252
|
+
down?(other) || \
|
253
|
+
(@day == other.day && @minute == other.minute && @second == other.second)
|
254
|
+
end
|
255
|
+
|
256
|
+
#
|
257
|
+
# 大小比較(==)
|
258
|
+
#
|
259
|
+
# @param [AbstractRemainder] other 他の大余小余
|
260
|
+
#
|
261
|
+
# @return [True] 等しい
|
262
|
+
# @return [False] 等しくない
|
263
|
+
#
|
264
|
+
def ==(other)
|
265
|
+
eql?(other)
|
266
|
+
end
|
267
|
+
|
268
|
+
#
|
269
|
+
# 大小比較(!=)
|
270
|
+
#
|
271
|
+
# @param [AbstractRemainder] other 他の大余小余
|
272
|
+
#
|
273
|
+
# @return [True] 等しくない
|
274
|
+
# @return [False] 等しい
|
275
|
+
#
|
276
|
+
def !=(other)
|
277
|
+
!eql?(other)
|
278
|
+
end
|
279
|
+
|
280
|
+
# 進朔
|
281
|
+
# @see 進朔 http://eco.mtk.nao.ac.jp/koyomi/wiki/C2C0B1A2C2C0CDDBCEF12FBFCABAF3.html
|
282
|
+
# 進朔とは、朔の瞬間が1日の3/4すなわち夕方以降となる場合に、その日ではなく1日進めて翌日を1日目にする方法のことです。
|
283
|
+
# 進朔するかどうかの基準時刻を進朔限といいます。宣明暦では1日8400分ですから、進朔限は6300分で、それ以降だと進朔されます。
|
284
|
+
|
285
|
+
#
|
286
|
+
# (非破壊的に)進朔する
|
287
|
+
#
|
288
|
+
# @see http://eco.mtk.nao.ac.jp/koyomi/wiki/C2C0B1A2C2C0CDDBCEF12FBFCABAF3.html
|
289
|
+
#
|
290
|
+
# 進朔とは、朔の瞬間が1日の3/4すなわち夕方以降となる場合に、その日ではなく1日進めて翌日を1日目にする方法のことです。
|
291
|
+
# 進朔するかどうかの基準時刻を進朔限といいます。宣明暦では1日8400分ですから、進朔限は6300分で、それ以降だと進朔されます。
|
292
|
+
#
|
293
|
+
# @return [AbstractRemainder] 進朔結果
|
294
|
+
#
|
295
|
+
def up_on_new_moon
|
296
|
+
cloned = clone
|
297
|
+
limit = (base_day * 3) / 4
|
298
|
+
if @minute >= limit
|
299
|
+
day, minute, second = carry((@day + 1), @minute, @second)
|
300
|
+
return cloned.set(day: day, minute: minute, second: second)
|
301
|
+
end
|
302
|
+
|
303
|
+
cloned
|
304
|
+
end
|
305
|
+
|
306
|
+
#
|
307
|
+
# (破壊的に)進朔する
|
308
|
+
#
|
309
|
+
# @see http://eco.mtk.nao.ac.jp/koyomi/wiki/C2C0B1A2C2C0CDDBCEF12FBFCABAF3.html
|
310
|
+
#
|
311
|
+
# 進朔とは、朔の瞬間が1日の3/4すなわち夕方以降となる場合に、その日ではなく1日進めて翌日を1日目にする方法のことです。
|
312
|
+
# 進朔するかどうかの基準時刻を進朔限といいます。宣明暦では1日8400分ですから、進朔限は6300分で、それ以降だと進朔されます。
|
313
|
+
#
|
314
|
+
# @return [AbstractRemainder] 進朔結果
|
315
|
+
#
|
316
|
+
def up_on_new_moon!
|
317
|
+
result = up_on_new_moon
|
318
|
+
@day = result.day
|
319
|
+
@minute = result.minute
|
320
|
+
@second = result.second
|
321
|
+
|
322
|
+
self
|
323
|
+
end
|
324
|
+
|
325
|
+
#
|
326
|
+
# 小余に揃えた結果を返す(秒は除外する)
|
327
|
+
#
|
328
|
+
# @return [Integer] 小余
|
329
|
+
#
|
330
|
+
def to_minute
|
331
|
+
@day * @base_day + @minute
|
332
|
+
end
|
333
|
+
|
334
|
+
#
|
335
|
+
# 大余に四捨五入した結果を返す(秒は除外する)
|
336
|
+
#
|
337
|
+
# @return [AbstractRemainder] 大余
|
338
|
+
#
|
339
|
+
def round
|
340
|
+
day = @day
|
341
|
+
day += 1 if @minute >= (@base_day / 2)
|
342
|
+
|
343
|
+
initialize(day, 0, 0)
|
344
|
+
end
|
345
|
+
|
346
|
+
#
|
347
|
+
# 文字化する
|
348
|
+
#
|
349
|
+
# @return [String] 文字化
|
350
|
+
#
|
351
|
+
def to_s
|
352
|
+
"大余(日): #{@day}, 小余(分): #{@minute}, 小余(秒): #{@second}"
|
353
|
+
end
|
354
|
+
|
355
|
+
#
|
356
|
+
# 特定の文字フォーマットにして出力する
|
357
|
+
#
|
358
|
+
# @param [String] form フォーマット(大余、小余、秒それぞれを%dで指定する)
|
359
|
+
#
|
360
|
+
# @return [String] フォーマットした結果
|
361
|
+
#
|
362
|
+
def format(form: '%d-%d')
|
363
|
+
return '' if invalid?
|
364
|
+
|
365
|
+
super(form, @day, @minute, @second)
|
366
|
+
end
|
367
|
+
|
368
|
+
private
|
369
|
+
|
370
|
+
def carry!(day, minute, second)
|
371
|
+
@day, @minute, @second = carry(day, minute, second)
|
372
|
+
|
373
|
+
self
|
374
|
+
end
|
375
|
+
|
376
|
+
# 繰り上げ、繰り下げ
|
377
|
+
def carry(param_day, param_minute, param_second)
|
378
|
+
# NOTE: 計算方法としてマイナスでも徐算・剰余算の結果をプラス同様に扱う
|
379
|
+
minute, second = carry_second(param_minute, param_second)
|
380
|
+
|
381
|
+
day, minute = carry_minute(param_day, minute)
|
382
|
+
|
383
|
+
day = carry_day(day, @limited)
|
384
|
+
|
385
|
+
[day, minute, second]
|
386
|
+
end
|
387
|
+
|
388
|
+
def carry_second(param_minute, param_second)
|
389
|
+
sign = param_second.negative? ? -1 : 1
|
390
|
+
abs = sign * param_second
|
391
|
+
minute = param_minute + (sign * (abs / @base_minute).floor)
|
392
|
+
second = sign * (abs % @base_minute)
|
393
|
+
|
394
|
+
if sign.negative?
|
395
|
+
second += @base_minute
|
396
|
+
minute -= 1
|
397
|
+
end
|
398
|
+
|
399
|
+
[minute, second]
|
400
|
+
end
|
401
|
+
|
402
|
+
def carry_minute(param_day, param_minute)
|
403
|
+
sign = param_minute.negative? ? -1 : 1
|
404
|
+
abs = sign * param_minute
|
405
|
+
|
406
|
+
day = param_day + (sign * (abs / @base_day).floor)
|
407
|
+
minute = sign * (abs % @base_day)
|
408
|
+
|
409
|
+
if sign.negative?
|
410
|
+
minute += @base_day
|
411
|
+
day -= 1
|
412
|
+
end
|
413
|
+
|
414
|
+
[day, minute]
|
415
|
+
end
|
416
|
+
|
417
|
+
def carry_day(day, limited)
|
418
|
+
sign = day.negative? ? -1 : 1
|
419
|
+
abs = sign * day
|
420
|
+
carried = sign * (abs % @base_limit) if limited
|
421
|
+
carried += @base_limit if sign.negative?
|
422
|
+
carried
|
423
|
+
end
|
424
|
+
|
425
|
+
def up?(other)
|
426
|
+
invalid?(param: other)
|
427
|
+
day = other.day
|
428
|
+
minute = other.minute
|
429
|
+
return true if @day > day
|
430
|
+
return false if @day < day
|
431
|
+
|
432
|
+
return true if @minute > minute
|
433
|
+
return false if @minute < minute
|
434
|
+
|
435
|
+
@second > other.second
|
436
|
+
end
|
437
|
+
|
438
|
+
def eql?(other)
|
439
|
+
invalid?(param: other)
|
440
|
+
|
441
|
+
(@day == other.day && @minute == other.minute && @second == other.second)
|
442
|
+
end
|
443
|
+
|
444
|
+
def down?(other)
|
445
|
+
invalid?(param: other)
|
446
|
+
day = other.day
|
447
|
+
minute = other.minute
|
448
|
+
return true if @day < day
|
449
|
+
return false if @day > day
|
450
|
+
|
451
|
+
return true if @minute < minute
|
452
|
+
return false if @minute > minute
|
453
|
+
|
454
|
+
@second < other.second
|
455
|
+
end
|
456
|
+
end
|
457
|
+
end
|
458
|
+
end
|
459
|
+
end
|