zakuro 0.1.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) 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 +484 -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 +78 -0
  22. data/lib/zakuro/calculation/stella/lunar/choukei_value.rb +71 -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/era/japan/reki.rb +1 -1
  29. data/lib/zakuro/merchant.rb +2 -2
  30. data/lib/zakuro/output/error.rb +7 -6
  31. data/lib/zakuro/output/logger.rb +50 -49
  32. data/lib/zakuro/output/response.rb +145 -144
  33. data/lib/zakuro/tools/typeof.rb +2 -2
  34. data/lib/zakuro/version.rb +1 -1
  35. data/lib/zakuro/version/abstract_version.rb +1 -1
  36. data/lib/zakuro/version/context.rb +23 -0
  37. data/lib/zakuro/version/daien/const/number.rb +55 -0
  38. data/lib/zakuro/version/daien/const/remainder.rb +53 -0
  39. data/lib/zakuro/version/daien/cycle/remainder.rb +59 -0
  40. data/lib/zakuro/version/daien/cycle/solar_term.rb +34 -0
  41. data/lib/zakuro/version/daien/daien.rb +36 -0
  42. data/lib/zakuro/version/daien/monthly/lunar_phase.rb +106 -0
  43. data/lib/zakuro/version/daien/range/annual_range.rb +39 -0
  44. data/lib/zakuro/version/daien/stella/lunar/adjustment.rb +240 -0
  45. data/lib/zakuro/version/daien/stella/lunar/localization.rb +44 -0
  46. data/lib/zakuro/version/daien/stella/lunar/location.rb +80 -0
  47. data/lib/zakuro/version/daien/stella/lunar/value.rb +75 -0
  48. data/lib/zakuro/version/daien/stella/origin/average_november.rb +34 -0
  49. data/lib/zakuro/version/daien/stella/origin/lunar_age.rb +62 -0
  50. data/lib/zakuro/version/daien/stella/origin/winter_solstice.rb +55 -0
  51. data/lib/zakuro/version/daien/stella/solar/adjustment.rb +93 -0
  52. data/lib/zakuro/version/daien/stella/solar/average.rb +98 -0
  53. data/lib/zakuro/version/daien/stella/solar/interval.rb +108 -0
  54. data/lib/zakuro/version/daien/stella/solar/location.rb +61 -0
  55. data/lib/zakuro/version/daien/stella/solar/value.rb +36 -0
  56. data/lib/zakuro/version/gihou/const/number.rb +55 -0
  57. data/lib/zakuro/version/gihou/const/remainder.rb +54 -0
  58. data/lib/zakuro/version/gihou/cycle/remainder.rb +56 -0
  59. data/lib/zakuro/version/gihou/cycle/solar_term.rb +34 -0
  60. data/lib/zakuro/version/gihou/gihou.rb +23 -2
  61. data/lib/zakuro/version/gihou/monthly/lunar_phase.rb +106 -0
  62. data/lib/zakuro/version/gihou/range/annual_range.rb +39 -0
  63. data/lib/zakuro/version/gihou/stella/lunar/adjustment.rb +250 -0
  64. data/lib/zakuro/version/gihou/stella/lunar/localization.rb +44 -0
  65. data/lib/zakuro/version/gihou/stella/lunar/location.rb +80 -0
  66. data/lib/zakuro/version/gihou/stella/lunar/value.rb +75 -0
  67. data/lib/zakuro/version/gihou/stella/origin/average_november.rb +34 -0
  68. data/lib/zakuro/version/gihou/stella/origin/lunar_age.rb +62 -0
  69. data/lib/zakuro/version/gihou/stella/origin/winter_solstice.rb +55 -0
  70. data/lib/zakuro/version/gihou/stella/solar/adjustment.rb +93 -0
  71. data/lib/zakuro/version/gihou/stella/solar/average.rb +97 -0
  72. data/lib/zakuro/version/gihou/stella/solar/interval.rb +108 -0
  73. data/lib/zakuro/version/gihou/stella/solar/location.rb +61 -0
  74. data/lib/zakuro/version/gihou/stella/solar/value.rb +36 -0
  75. data/lib/zakuro/version/senmyou/const/number.rb +51 -0
  76. data/lib/zakuro/version/senmyou/const/remainder.rb +47 -0
  77. data/lib/zakuro/version/senmyou/cycle/remainder.rb +56 -0
  78. data/lib/zakuro/version/senmyou/cycle/solar_term.rb +34 -0
  79. data/lib/zakuro/version/senmyou/monthly/lunar_phase.rb +80 -195
  80. data/lib/zakuro/version/senmyou/range/annual_range.rb +25 -145
  81. data/lib/zakuro/version/senmyou/senmyou.rb +10 -4
  82. data/lib/zakuro/version/senmyou/stella/lunar/adjustment.rb +237 -0
  83. data/lib/zakuro/version/senmyou/stella/lunar/localization.rb +44 -0
  84. data/lib/zakuro/version/senmyou/stella/lunar/location.rb +87 -0
  85. data/lib/zakuro/version/senmyou/stella/lunar/value.rb +67 -0
  86. data/lib/zakuro/version/senmyou/stella/origin/average_november.rb +34 -0
  87. data/lib/zakuro/version/senmyou/stella/origin/lunar_age.rb +62 -0
  88. data/lib/zakuro/version/senmyou/stella/origin/winter_solstice.rb +55 -0
  89. data/lib/zakuro/version/senmyou/stella/solar/adjustment.rb +93 -0
  90. data/lib/zakuro/version/senmyou/stella/solar/average.rb +97 -0
  91. data/lib/zakuro/version/senmyou/stella/solar/interval.rb +103 -0
  92. data/lib/zakuro/version/senmyou/stella/solar/location.rb +61 -0
  93. data/lib/zakuro/version/senmyou/stella/solar/value.rb +39 -0
  94. data/lib/zakuro/version/version_class_resolver.rb +70 -0
  95. data/lib/zakuro/version_factory.rb +3 -3
  96. metadata +83 -28
  97. data/lib/zakuro/cycle/abstract_remainder.rb +0 -456
  98. data/lib/zakuro/cycle/zodiac.rb +0 -103
  99. data/lib/zakuro/version/senmyou/base/era.rb +0 -83
  100. data/lib/zakuro/version/senmyou/base/multi_gengou.rb +0 -98
  101. data/lib/zakuro/version/senmyou/base/multi_gengou_roller.rb +0 -217
  102. data/lib/zakuro/version/senmyou/base/remainder.rb +0 -60
  103. data/lib/zakuro/version/senmyou/base/solar_term.rb +0 -148
  104. data/lib/zakuro/version/senmyou/base/year.rb +0 -104
  105. data/lib/zakuro/version/senmyou/monthly/first_day.rb +0 -44
  106. data/lib/zakuro/version/senmyou/monthly/initialized_month.rb +0 -119
  107. data/lib/zakuro/version/senmyou/monthly/month.rb +0 -181
  108. data/lib/zakuro/version/senmyou/monthly/month_label.rb +0 -87
  109. data/lib/zakuro/version/senmyou/monthly/operated_month.rb +0 -196
  110. data/lib/zakuro/version/senmyou/range/full_range.rb +0 -194
  111. data/lib/zakuro/version/senmyou/range/operated_range.rb +0 -126
  112. data/lib/zakuro/version/senmyou/range/operated_solar_terms.rb +0 -181
  113. data/lib/zakuro/version/senmyou/range/western_date_allocation.rb +0 -68
  114. data/lib/zakuro/version/senmyou/range/year_boundary.rb +0 -138
  115. data/lib/zakuro/version/senmyou/specifier/single_day_specifier.rb +0 -102
  116. data/lib/zakuro/version/senmyou/stella/lunar_orbit.rb +0 -332
  117. data/lib/zakuro/version/senmyou/stella/solar_average.rb +0 -169
  118. data/lib/zakuro/version/senmyou/stella/solar_location.rb +0 -213
  119. data/lib/zakuro/version/senmyou/stella/solar_orbit.rb +0 -213
  120. data/lib/zakuro/version/senmyou/stella/winter_solstice.rb +0 -106
  121. data/lib/zakuro/version/senmyou/summary/single.rb +0 -125
  122. data/lib/zakuro/version/taien/taien.rb +0 -19
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fd8b402a7084ab57e0424c65d9851cc72f759b81f6f9b4c7f1e71afcda27d561
4
- data.tar.gz: f204f25a8a6addad96556cb9376b406d6c1285375e79c693169d3095b6f5b387
3
+ metadata.gz: 73a145098928102269c600528b1552422d174c88a14baa83f8cc426deaa2ee43
4
+ data.tar.gz: 55d493cccce632e6d654394bee779be3756a628cf747d6c064583cc8c244ab55
5
5
  SHA512:
6
- metadata.gz: a7c7c8b0fef50d3da9f45701883ec271f3c000676a4a70e1d0c73ae4b15249e6a2cd57be47bd01a9ad6109da9b6593745ccc348c83d32743a09442bf7a922343
7
- data.tar.gz: c5e6aa6ef4b4cc21814859753bf8bfd02be637173011bc6a2eb3dd28f4cfe1505d9faeb6544759f3f92543a8ee35820c73d54811a48d9d47ab645d38a995ed16
6
+ metadata.gz: 9df9ca681cf42f72b574b888123d40a2368218c9077f7c03415ec4e50219489d16b8e5f285c1c17cdad3f88bae1c8ea460920c2469c17f381adf4bc54d654033
7
+ data.tar.gz: 8eb61f2f32029e649f2faf75e3d4592daf9c2b2da82216143f5586712f0d1fe50088677bed35e980a3e2ddf2a1be3712f101c4486dfa32261efd3ce5da9bf4d7
@@ -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,484 @@
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
+ # * 十干十二支(60日)を上限とした「日時分秒」の情報で、日付(date)/時刻(time)と部分的に重なる概念
14
+ # * 「15日1012分5秒」のような形式で表される
15
+ # * 分の上限で大余に繰り上げる
16
+ # * 秒の上限で1分に繰り上げる
17
+ #
18
+ class AbstractRemainder # rubocop:disable Metrics/ClassLength
19
+ # @return [Integer] 大余上限
20
+ LIMIT = 60
21
+
22
+ # @return [Integer] 大余("日"に相当)
23
+ attr_reader :day
24
+ # @return [Integer] 小余("分"に相当)
25
+ attr_reader :minute
26
+ # @return [Integer] 秒
27
+ attr_reader :second
28
+ # @return [Integer] 繰り上げなしの小余
29
+ attr_reader :base_limit
30
+ # @return [Integer] 1大余に必要な小余(暦によって基数が異なる)
31
+ attr_reader :base_day
32
+ # @return [Integer] 1小余に必要な秒(暦によって基数が異なる)
33
+ attr_reader :base_minute
34
+ # 繰り上げ有無
35
+ # @return [True] 繰り上げあり
36
+ # @return [False] 繰り上げなし
37
+ attr_reader :limited
38
+
39
+ # :reek:instanceVariableAssumption
40
+ # rubocop:disable Metrics/ParameterLists
41
+
42
+ #
43
+ # 初期化
44
+ #
45
+ # @param [Integer] base_day 1大余に必要な小余(暦によって基数が異なる)
46
+ # @param [Integer] base_mitune 1小余に必要な秒(暦によって基数が異なる)
47
+ # @param [Integer] day 大余("日"に相当)
48
+ # @param [Integer] minute 小余("分"に相当)
49
+ # @param [Integer] second 秒
50
+ # @param [Integer] total 繰り上げなしの小余
51
+ #
52
+ def initialize(base_day: -1, base_mitune: -1, day: -1, minute: -1, second: -1, total: -1)
53
+ @base_limit = LIMIT
54
+ @base_day = base_day
55
+ @base_minute = base_mitune
56
+ @limited = true
57
+
58
+ set(day: day, minute: minute, second: second, total: total)
59
+ end
60
+ # rubocop:enable Metrics/ParameterLists
61
+
62
+ #
63
+ # 値を設定する
64
+ #
65
+ # @param [Integer] day 大余("日"に相当)
66
+ # @param [Integer] minute 小余("分"に相当)
67
+ # @param [Integer] second 秒
68
+ # @param [Integer] total 繰り上げなしの小余
69
+ #
70
+ # @return [AbstractRemainder] 自身の参照
71
+ #
72
+ def set(day: -1, minute: -1, second: -1, total: -1)
73
+ @day = day
74
+ @minute = minute
75
+ @second = second
76
+
77
+ if total != -1
78
+ @day = (total.to_f / @base_day).floor
79
+ @minute = (total % @base_day)
80
+ @second = 0
81
+ end
82
+
83
+ self
84
+ end
85
+
86
+ #
87
+ # 繰り上げ処理を外す
88
+ #
89
+ # @return [AbstractRemainder] 自身の参照
90
+ #
91
+ def lift_limit
92
+ @limited = false
93
+
94
+ self
95
+ end
96
+
97
+ #
98
+ # 繰り上げ処理を設定する
99
+ #
100
+ # @return [AbstractRemainder] 自身の参照
101
+ #
102
+ def set_limit
103
+ @limited = true
104
+
105
+ self
106
+ end
107
+
108
+ #
109
+ # 無効かどうか
110
+ #
111
+ # @param [AbstractRemainder] param 自クラスのインスタンス(デフォルトは自身の参照)
112
+ #
113
+ # @return [True] 無効
114
+ # @return [False] 有効
115
+ #
116
+ def invalid?(param: self)
117
+ raise ArgumentError, 'unmatch parameter type' unless param.is_a?(AbstractRemainder)
118
+
119
+ param.day == -1 || param.minute == -1 || param.second == -1
120
+ end
121
+
122
+ #
123
+ # 十干十二支名
124
+ #
125
+ # @return [String] 十干十二支名
126
+ #
127
+ def zodiac_name
128
+ Cycle::Zodiac.day_name(day: @day)
129
+ end
130
+
131
+ #
132
+ # 日が同じ十干かどうか(大小の月判定)
133
+ #
134
+ # @param [Integer] other 大余
135
+ #
136
+ # @return [True] 当月朔日と翌月朔日が同じ十干(「大」の月)
137
+ # @return [False] 当月朔日と翌月朔日が異なる十干(「小」の月)
138
+ #
139
+ def same_remainder_divided_by_ten?(other:)
140
+ day = @day % LIMIT
141
+
142
+ (day % 10) == (other % 10)
143
+ end
144
+
145
+ #
146
+ # (非破壊的に)加算する
147
+ #
148
+ # @param [AbstractRemainder] other 他の大余小余
149
+ #
150
+ # @return [AbstractRemainder] 加算結果
151
+ #
152
+ def add(other)
153
+ invalid?(param: other)
154
+ day = @day + other.day
155
+ minute = @minute + other.minute
156
+ second = @second + other.second
157
+ day, minute, second = carry(day, minute, second)
158
+
159
+ clone.set(day: day, minute: minute, second: second)
160
+ end
161
+
162
+ #
163
+ # (破壊的に)加算する
164
+ #
165
+ # @param [AbstractRemainder] other 他の大余小余
166
+ #
167
+ # @return [AbstractRemainder] 加算結果
168
+ #
169
+ def add!(other)
170
+ result = add(other)
171
+ @day = result.day
172
+ @minute = result.minute
173
+ @second = result.second
174
+
175
+ self
176
+ end
177
+
178
+ #
179
+ # (非破壊的に)除算する
180
+ #
181
+ # @param [AbstractRemainder] other 他の大余小余
182
+ #
183
+ # @return [AbstractRemainder] 除算結果
184
+ #
185
+ def sub(other)
186
+ invalid?(param: other)
187
+ day = @day - other.day
188
+ minute = @minute - other.minute
189
+ second = @second - other.second
190
+ day, minute, second = carry(day, minute, second)
191
+
192
+ clone.set(day: day, minute: minute, second: second)
193
+ end
194
+
195
+ #
196
+ # (破壊的に)除算する
197
+ #
198
+ # @param [AbstractRemainder] other 他の大余小余
199
+ #
200
+ # @return [AbstractRemainder] 除算結果
201
+ #
202
+ def sub!(other)
203
+ result = sub(other)
204
+ @day = result.day
205
+ @minute = result.minute
206
+ @second = result.second
207
+
208
+ self
209
+ end
210
+
211
+ #
212
+ # 大小比較(>)
213
+ #
214
+ # @param [AbstractRemainder] other 他の大余小余
215
+ #
216
+ # @return [True] より大きい
217
+ # @return [False] 以下
218
+ #
219
+ def >(other)
220
+ up?(other)
221
+ end
222
+
223
+ #
224
+ # 大小比較(>=)
225
+ #
226
+ # @param [AbstractRemainder] other 他の大余小余
227
+ #
228
+ # @return [True] 以上
229
+ # @return [False] より小さい
230
+ #
231
+ def >=(other)
232
+ up?(other) || eql?(other)
233
+ end
234
+
235
+ #
236
+ # 大小比較(<)
237
+ #
238
+ # @param [AbstractRemainder] other 他の大余小余
239
+ #
240
+ # @return [True] より小さい
241
+ # @return [False] 以上
242
+ #
243
+ def <(other)
244
+ down?(other)
245
+ end
246
+
247
+ #
248
+ # 大小比較(<=)
249
+ #
250
+ # @param [AbstractRemainder] other 他の大余小余
251
+ #
252
+ # @return [True] 以下
253
+ # @return [False] より大きい
254
+ #
255
+ def <=(other)
256
+ down?(other) || eql?(other)
257
+ end
258
+
259
+ #
260
+ # 大小比較(==)
261
+ #
262
+ # @param [AbstractRemainder] other 他の大余小余
263
+ #
264
+ # @return [True] 等しい
265
+ # @return [False] 等しくない
266
+ #
267
+ def ==(other)
268
+ eql?(other)
269
+ end
270
+
271
+ #
272
+ # 大小比較(!=)
273
+ #
274
+ # @param [AbstractRemainder] other 他の大余小余
275
+ #
276
+ # @return [True] 等しくない
277
+ # @return [False] 等しい
278
+ #
279
+ def !=(other)
280
+ !eql?(other)
281
+ end
282
+
283
+ # 進朔
284
+ # @see 進朔 http://eco.mtk.nao.ac.jp/koyomi/wiki/C2C0B1A2C2C0CDDBCEF12FBFCABAF3.html
285
+ # 進朔とは、朔の瞬間が1日の3/4すなわち夕方以降となる場合に、その日ではなく1日進めて翌日を1日目にする方法のことです。
286
+ # 進朔するかどうかの基準時刻を進朔限といいます。宣明暦では1日8400分ですから、進朔限は6300分で、それ以降だと進朔されます。
287
+
288
+ #
289
+ # (非破壊的に)進朔する
290
+ #
291
+ # @see http://eco.mtk.nao.ac.jp/koyomi/wiki/C2C0B1A2C2C0CDDBCEF12FBFCABAF3.html
292
+ #
293
+ # 進朔とは、朔の瞬間が1日の3/4すなわち夕方以降となる場合に、その日ではなく1日進めて翌日を1日目にする方法のことです。
294
+ # 進朔するかどうかの基準時刻を進朔限といいます。宣明暦では1日8400分ですから、進朔限は6300分で、それ以降だと進朔されます。
295
+ #
296
+ # @return [AbstractRemainder] 進朔結果
297
+ #
298
+ def up_on_new_moon
299
+ cloned = clone
300
+ limit = (base_day * 3) / 4
301
+ if @minute >= limit
302
+ day, minute, second = carry((@day + 1), @minute, @second)
303
+ return cloned.set(day: day, minute: minute, second: second)
304
+ end
305
+
306
+ cloned
307
+ end
308
+
309
+ #
310
+ # (破壊的に)進朔する
311
+ #
312
+ # @see http://eco.mtk.nao.ac.jp/koyomi/wiki/C2C0B1A2C2C0CDDBCEF12FBFCABAF3.html
313
+ #
314
+ # 進朔とは、朔の瞬間が1日の3/4すなわち夕方以降となる場合に、その日ではなく1日進めて翌日を1日目にする方法のことです。
315
+ # 進朔するかどうかの基準時刻を進朔限といいます。宣明暦では1日8400分ですから、進朔限は6300分で、それ以降だと進朔されます。
316
+ #
317
+ # @return [AbstractRemainder] 進朔結果
318
+ #
319
+ def up_on_new_moon!
320
+ result = up_on_new_moon
321
+ @day = result.day
322
+ @minute = result.minute
323
+ @second = result.second
324
+
325
+ self
326
+ end
327
+
328
+ #
329
+ # 小余に揃えた結果を返す(秒は除外する)
330
+ #
331
+ # @return [Integer] 小余
332
+ #
333
+ def to_minute
334
+ @day * @base_day + @minute
335
+ end
336
+
337
+ #
338
+ # 小余(秒切り捨て)を返す
339
+ #
340
+ # @note 切り捨て前に繰り上げる
341
+ #
342
+ # @return [Integer] 小余(秒切り捨て)
343
+ #
344
+ def floor_minute
345
+ result = float_minute
346
+ result.floor
347
+ end
348
+
349
+ #
350
+ # 秒を含めた小余を返す
351
+ #
352
+ # @return [Float] 小余
353
+ #
354
+ def float_minute
355
+ @minute + @second.to_f / @base_minute
356
+ end
357
+
358
+ #
359
+ # 大余に四捨五入した結果を返す(秒は除外する)
360
+ #
361
+ # @return [AbstractRemainder] 大余
362
+ #
363
+ def round
364
+ day = @day
365
+ day += 1 if @minute >= (@base_day / 2)
366
+
367
+ initialize(day, 0, 0)
368
+ end
369
+
370
+ #
371
+ # 文字化する
372
+ #
373
+ # @return [String] 文字化
374
+ #
375
+ def to_s
376
+ "大余(日): #{@day}, 小余(分): #{@minute}, 小余(秒): #{@second}"
377
+ end
378
+
379
+ #
380
+ # 特定の文字フォーマットにして出力する
381
+ #
382
+ # @param [String] form フォーマット(大余、小余、秒それぞれを%dで指定する)
383
+ #
384
+ # @return [String] フォーマットした結果
385
+ #
386
+ def format(form: '%d-%d')
387
+ return '' if invalid?
388
+
389
+ super(form, @day, @minute, @second)
390
+ end
391
+
392
+ #
393
+ # 繰り上げる
394
+ #
395
+ # @return [AbstractRemainder] 繰り上げ結果
396
+ #
397
+ def carry!
398
+ @day, @minute, @second = carry(@day, @minute, @second)
399
+
400
+ self
401
+ end
402
+
403
+ private
404
+
405
+ # 繰り上げ、繰り下げ
406
+ def carry(param_day, param_minute, param_second)
407
+ # NOTE: 計算方法としてマイナスでも徐算・剰余算の結果をプラス同様に扱う
408
+ minute, second = carry_second(param_minute, param_second)
409
+
410
+ day, minute = carry_minute(param_day, minute)
411
+
412
+ day = carry_day(day, @limited)
413
+
414
+ [day, minute, second]
415
+ end
416
+
417
+ def carry_second(param_minute, param_second)
418
+ sign = param_second.negative? ? -1 : 1
419
+ abs = sign * param_second
420
+ minute = param_minute + (sign * (abs / @base_minute).floor)
421
+ second = sign * (abs % @base_minute)
422
+
423
+ if sign.negative?
424
+ second += @base_minute
425
+ minute -= 1
426
+ end
427
+
428
+ [minute, second]
429
+ end
430
+
431
+ def carry_minute(param_day, param_minute)
432
+ sign = param_minute.negative? ? -1 : 1
433
+ abs = sign * param_minute
434
+
435
+ day = param_day + (sign * (abs / @base_day).floor)
436
+ minute = sign * (abs % @base_day)
437
+
438
+ if sign.negative?
439
+ minute += @base_day
440
+ day -= 1
441
+ end
442
+
443
+ [day, minute]
444
+ end
445
+
446
+ def carry_day(day, limited)
447
+ sign = day.negative? ? -1 : 1
448
+ abs = sign * day
449
+ carried = sign * (abs % @base_limit) if limited
450
+ carried += @base_limit if sign.negative?
451
+ carried
452
+ end
453
+
454
+ def up?(other)
455
+ invalid?(param: other)
456
+ day = other.day
457
+ minute = other.float_minute
458
+
459
+ return true if @day > day
460
+ return false if @day < day
461
+
462
+ float_minute > minute
463
+ end
464
+
465
+ def eql?(other)
466
+ invalid?(param: other)
467
+
468
+ (@day == other.day && float_minute == other.float_minute)
469
+ end
470
+
471
+ def down?(other)
472
+ invalid?(param: other)
473
+ day = other.day
474
+ minute = other.float_minute
475
+
476
+ return true if @day < day
477
+ return false if @day > day
478
+
479
+ float_minute < minute
480
+ end
481
+ end
482
+ end
483
+ end
484
+ end