zakuro 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. checksums.yaml +4 -4
  2. data/lib/zakuro/calculation/base/multi_gengou.rb +101 -0
  3. data/lib/zakuro/calculation/base/multi_gengou_roller.rb +218 -0
  4. data/lib/zakuro/calculation/base/year.rb +107 -0
  5. data/lib/zakuro/calculation/cycle/abstract_remainder.rb +471 -0
  6. data/lib/zakuro/calculation/cycle/abstract_solar_term.rb +173 -0
  7. data/lib/zakuro/calculation/cycle/zodiac.rb +106 -0
  8. data/lib/zakuro/calculation/monthly/abstract_lunar_phase.rb +169 -0
  9. data/lib/zakuro/calculation/monthly/first_day.rb +45 -0
  10. data/lib/zakuro/calculation/monthly/initialized_month.rb +125 -0
  11. data/lib/zakuro/calculation/monthly/month.rb +187 -0
  12. data/lib/zakuro/calculation/monthly/month_label.rb +88 -0
  13. data/lib/zakuro/calculation/monthly/operated_month.rb +209 -0
  14. data/lib/zakuro/calculation/range/full_range.rb +210 -0
  15. data/lib/zakuro/calculation/range/medieval_annual_range.rb +105 -0
  16. data/lib/zakuro/calculation/range/operated_range.rb +144 -0
  17. data/lib/zakuro/calculation/range/operated_solar_terms.rb +201 -0
  18. data/lib/zakuro/calculation/range/transfer/western_date_allocation.rb +82 -0
  19. data/lib/zakuro/calculation/range/transfer/year_boundary.rb +146 -0
  20. data/lib/zakuro/calculation/specifier/single_day.rb +109 -0
  21. data/lib/zakuro/calculation/stella/lunar/abstract_location.rb +76 -0
  22. data/lib/zakuro/calculation/stella/lunar/choukei_value.rb +52 -0
  23. data/lib/zakuro/calculation/stella/solar/abstract_average.rb +117 -0
  24. data/lib/zakuro/calculation/stella/solar/abstract_location.rb +187 -0
  25. data/lib/zakuro/calculation/stella/solar/choukei_value.rb +136 -0
  26. data/lib/zakuro/calculation/summary/single.rb +129 -0
  27. data/lib/zakuro/calculation/type/old_float.rb +69 -0
  28. data/lib/zakuro/merchant.rb +2 -2
  29. data/lib/zakuro/operation/month/parser.rb +1 -1
  30. data/lib/zakuro/operation/month/type.rb +5 -10
  31. data/lib/zakuro/output/error.rb +7 -6
  32. data/lib/zakuro/output/logger.rb +50 -49
  33. data/lib/zakuro/output/response.rb +145 -144
  34. data/lib/zakuro/tools/typeof.rb +2 -2
  35. data/lib/zakuro/version.rb +1 -1
  36. data/lib/zakuro/version/abstract_version.rb +1 -1
  37. data/lib/zakuro/version/context.rb +23 -0
  38. data/lib/zakuro/version/gihou/const/number.rb +55 -0
  39. data/lib/zakuro/version/gihou/const/remainder.rb +56 -0
  40. data/lib/zakuro/version/gihou/cycle/remainder.rb +61 -0
  41. data/lib/zakuro/version/gihou/cycle/solar_term.rb +34 -0
  42. data/lib/zakuro/version/gihou/gihou.rb +23 -2
  43. data/lib/zakuro/version/gihou/monthly/lunar_phase.rb +106 -0
  44. data/lib/zakuro/version/gihou/range/annual_range.rb +39 -0
  45. data/lib/zakuro/version/gihou/stella/lunar/adjustment.rb +250 -0
  46. data/lib/zakuro/version/gihou/stella/lunar/localization.rb +44 -0
  47. data/lib/zakuro/version/gihou/stella/lunar/location.rb +86 -0
  48. data/lib/zakuro/version/gihou/stella/lunar/value.rb +74 -0
  49. data/lib/zakuro/version/gihou/stella/origin/average_november.rb +34 -0
  50. data/lib/zakuro/version/gihou/stella/origin/lunar_age.rb +62 -0
  51. data/lib/zakuro/version/gihou/stella/origin/winter_solstice.rb +55 -0
  52. data/lib/zakuro/version/gihou/stella/solar/adjustment.rb +93 -0
  53. data/lib/zakuro/version/gihou/stella/solar/average.rb +97 -0
  54. data/lib/zakuro/version/gihou/stella/solar/interval.rb +108 -0
  55. data/lib/zakuro/version/gihou/stella/solar/location.rb +61 -0
  56. data/lib/zakuro/version/gihou/stella/solar/value.rb +36 -0
  57. data/lib/zakuro/version/senmyou/const/number.rb +51 -0
  58. data/lib/zakuro/version/senmyou/const/remainder.rb +49 -0
  59. data/lib/zakuro/version/senmyou/cycle/remainder.rb +61 -0
  60. data/lib/zakuro/version/senmyou/cycle/solar_term.rb +34 -0
  61. data/lib/zakuro/version/senmyou/monthly/lunar_phase.rb +80 -195
  62. data/lib/zakuro/version/senmyou/range/annual_range.rb +25 -170
  63. data/lib/zakuro/version/senmyou/senmyou.rb +10 -4
  64. data/lib/zakuro/version/senmyou/stella/lunar/adjustment.rb +237 -0
  65. data/lib/zakuro/version/senmyou/stella/lunar/localization.rb +44 -0
  66. data/lib/zakuro/version/senmyou/stella/lunar/location.rb +93 -0
  67. data/lib/zakuro/version/senmyou/stella/lunar/value.rb +66 -0
  68. data/lib/zakuro/version/senmyou/stella/origin/average_november.rb +34 -0
  69. data/lib/zakuro/version/senmyou/stella/origin/lunar_age.rb +62 -0
  70. data/lib/zakuro/version/senmyou/stella/origin/winter_solstice.rb +55 -0
  71. data/lib/zakuro/version/senmyou/stella/solar/adjustment.rb +93 -0
  72. data/lib/zakuro/version/senmyou/stella/solar/average.rb +97 -0
  73. data/lib/zakuro/version/senmyou/stella/solar/interval.rb +103 -0
  74. data/lib/zakuro/version/senmyou/stella/solar/location.rb +61 -0
  75. data/lib/zakuro/version/senmyou/stella/solar/value.rb +39 -0
  76. data/lib/zakuro/version/version_class_resolver.rb +66 -0
  77. data/lib/zakuro/version_factory.rb +2 -2
  78. metadata +64 -24
  79. data/lib/zakuro/cycle/abstract_remainder.rb +0 -456
  80. data/lib/zakuro/cycle/zodiac.rb +0 -103
  81. data/lib/zakuro/version/senmyou/base/era.rb +0 -83
  82. data/lib/zakuro/version/senmyou/base/multi_gengou.rb +0 -98
  83. data/lib/zakuro/version/senmyou/base/multi_gengou_roller.rb +0 -217
  84. data/lib/zakuro/version/senmyou/base/remainder.rb +0 -60
  85. data/lib/zakuro/version/senmyou/base/solar_term.rb +0 -86
  86. data/lib/zakuro/version/senmyou/base/year.rb +0 -104
  87. data/lib/zakuro/version/senmyou/monthly/first_day.rb +0 -44
  88. data/lib/zakuro/version/senmyou/monthly/initialized_month.rb +0 -48
  89. data/lib/zakuro/version/senmyou/monthly/month.rb +0 -181
  90. data/lib/zakuro/version/senmyou/monthly/month_label.rb +0 -87
  91. data/lib/zakuro/version/senmyou/monthly/operated_month.rb +0 -167
  92. data/lib/zakuro/version/senmyou/range/full_range.rb +0 -324
  93. data/lib/zakuro/version/senmyou/range/operated_range.rb +0 -126
  94. data/lib/zakuro/version/senmyou/range/operated_solar_terms.rb +0 -181
  95. data/lib/zakuro/version/senmyou/specifier/single_day_specifier.rb +0 -102
  96. data/lib/zakuro/version/senmyou/stella/lunar_orbit.rb +0 -332
  97. data/lib/zakuro/version/senmyou/stella/solar_average.rb +0 -214
  98. data/lib/zakuro/version/senmyou/stella/solar_orbit.rb +0 -394
  99. data/lib/zakuro/version/senmyou/stella/winter_solstice.rb +0 -106
  100. data/lib/zakuro/version/senmyou/summary/single.rb +0 -125
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d08bb0a2c54dc9063ff82a701ea1f37cc9df43a8a4b4fad26d8dd9245ddde625
4
- data.tar.gz: 566e821086421324a1ad61752c7e743a0a15d52d06cd3b83c60fb366f8424cbe
3
+ metadata.gz: a4269bda9e7a1bc90589d072ac97a0acc089f098a5b1e8bbe6d04d661407c256
4
+ data.tar.gz: cb8821e9f1f9692a867c4baec73ce515281d3bf4ef8a04db676909d03cd3b7b0
5
5
  SHA512:
6
- metadata.gz: 759f9d80603988387f6f896fc0d0fcc0800e75879055350aee6ce2c2e862e9f81b4e0e59aacf5b1a84bcf8244ce68db8576eb4562148189fe9d5ce3d6c525d49
7
- data.tar.gz: 56e35d9ec9f2445fd063500032d4eec965faed3165d6d04882491a73ccb9b7419a14b5b1e54e801bd8cf6a0130cc1bbd1a7de1ff674f87be9ddd8e271624153c
6
+ metadata.gz: f4acc077c7191f18601765cc81668660f4fe0af9dbeecf0af74cf0841f20546a0792484bbcc9bf8c490f62065ef8b32c9268def780037ec62739665823950d47
7
+ data.tar.gz: 97ea77400bd644d2c84e08e4d3056ee121563e5d52e1b418dfb57e50cbf5c741f4dde1954d4951460618b5c5837bc13103f8ae7857075b159a307986e2fb39af
@@ -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,471 @@
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
+ # @note 切り捨て前に繰り上げる
338
+ #
339
+ # @return [Integer] 小余(秒切り捨て)
340
+ #
341
+ def floor_minute
342
+ result = @minute + @second / @base_minute
343
+ result.floor
344
+ end
345
+
346
+ #
347
+ # 大余に四捨五入した結果を返す(秒は除外する)
348
+ #
349
+ # @return [AbstractRemainder] 大余
350
+ #
351
+ def round
352
+ day = @day
353
+ day += 1 if @minute >= (@base_day / 2)
354
+
355
+ initialize(day, 0, 0)
356
+ end
357
+
358
+ #
359
+ # 文字化する
360
+ #
361
+ # @return [String] 文字化
362
+ #
363
+ def to_s
364
+ "大余(日): #{@day}, 小余(分): #{@minute}, 小余(秒): #{@second}"
365
+ end
366
+
367
+ #
368
+ # 特定の文字フォーマットにして出力する
369
+ #
370
+ # @param [String] form フォーマット(大余、小余、秒それぞれを%dで指定する)
371
+ #
372
+ # @return [String] フォーマットした結果
373
+ #
374
+ def format(form: '%d-%d')
375
+ return '' if invalid?
376
+
377
+ super(form, @day, @minute, @second)
378
+ end
379
+
380
+ private
381
+
382
+ def carry!(day, minute, second)
383
+ @day, @minute, @second = carry(day, minute, second)
384
+
385
+ self
386
+ end
387
+
388
+ # 繰り上げ、繰り下げ
389
+ def carry(param_day, param_minute, param_second)
390
+ # NOTE: 計算方法としてマイナスでも徐算・剰余算の結果をプラス同様に扱う
391
+ minute, second = carry_second(param_minute, param_second)
392
+
393
+ day, minute = carry_minute(param_day, minute)
394
+
395
+ day = carry_day(day, @limited)
396
+
397
+ [day, minute, second]
398
+ end
399
+
400
+ def carry_second(param_minute, param_second)
401
+ sign = param_second.negative? ? -1 : 1
402
+ abs = sign * param_second
403
+ minute = param_minute + (sign * (abs / @base_minute).floor)
404
+ second = sign * (abs % @base_minute)
405
+
406
+ if sign.negative?
407
+ second += @base_minute
408
+ minute -= 1
409
+ end
410
+
411
+ [minute, second]
412
+ end
413
+
414
+ def carry_minute(param_day, param_minute)
415
+ sign = param_minute.negative? ? -1 : 1
416
+ abs = sign * param_minute
417
+
418
+ day = param_day + (sign * (abs / @base_day).floor)
419
+ minute = sign * (abs % @base_day)
420
+
421
+ if sign.negative?
422
+ minute += @base_day
423
+ day -= 1
424
+ end
425
+
426
+ [day, minute]
427
+ end
428
+
429
+ def carry_day(day, limited)
430
+ sign = day.negative? ? -1 : 1
431
+ abs = sign * day
432
+ carried = sign * (abs % @base_limit) if limited
433
+ carried += @base_limit if sign.negative?
434
+ carried
435
+ end
436
+
437
+ def up?(other)
438
+ invalid?(param: other)
439
+ day = other.day
440
+ minute = other.minute
441
+ return true if @day > day
442
+ return false if @day < day
443
+
444
+ return true if @minute > minute
445
+ return false if @minute < minute
446
+
447
+ @second > other.second
448
+ end
449
+
450
+ def eql?(other)
451
+ invalid?(param: other)
452
+
453
+ (@day == other.day && @minute == other.minute && @second == other.second)
454
+ end
455
+
456
+ def down?(other)
457
+ invalid?(param: other)
458
+ day = other.day
459
+ minute = other.minute
460
+ return true if @day < day
461
+ return false if @day > day
462
+
463
+ return true if @minute < minute
464
+ return false if @minute > minute
465
+
466
+ @second < other.second
467
+ end
468
+ end
469
+ end
470
+ end
471
+ end