zakuro 0.1.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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