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.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -0
  3. data/README.md +102 -42
  4. data/doc/operation.md +25 -0
  5. data/doc/operation/csv/month.csv +202 -0
  6. data/doc/operation/operation.xlsx +0 -0
  7. data/doc/operation/transfer.rb +77 -0
  8. data/lib/zakuro/calculation/base/multi_gengou.rb +101 -0
  9. data/lib/zakuro/calculation/base/multi_gengou_roller.rb +218 -0
  10. data/lib/zakuro/calculation/base/year.rb +107 -0
  11. data/lib/zakuro/calculation/cycle/abstract_remainder.rb +459 -0
  12. data/lib/zakuro/calculation/cycle/abstract_solar_term.rb +151 -0
  13. data/lib/zakuro/calculation/cycle/zodiac.rb +106 -0
  14. data/lib/zakuro/calculation/monthly/first_day.rb +45 -0
  15. data/lib/zakuro/calculation/monthly/initialized_month.rb +120 -0
  16. data/lib/zakuro/calculation/monthly/month.rb +184 -0
  17. data/lib/zakuro/calculation/monthly/month_label.rb +88 -0
  18. data/lib/zakuro/calculation/monthly/operated_month.rb +201 -0
  19. data/lib/zakuro/calculation/range/full_range.rb +210 -0
  20. data/lib/zakuro/calculation/range/operated_range.rb +134 -0
  21. data/lib/zakuro/calculation/range/operated_solar_terms.rb +201 -0
  22. data/lib/zakuro/calculation/range/transfer/western_date_allocation.rb +76 -0
  23. data/lib/zakuro/calculation/range/transfer/year_boundary.rb +142 -0
  24. data/lib/zakuro/calculation/specifier/single_day.rb +109 -0
  25. data/lib/zakuro/calculation/summary/single.rb +129 -0
  26. data/lib/zakuro/condition.rb +17 -13
  27. data/lib/zakuro/era/japan/gengou.rb +106 -0
  28. data/lib/zakuro/era/japan/gengou/parser.rb +167 -0
  29. data/lib/zakuro/era/japan/gengou/type.rb +178 -0
  30. data/lib/zakuro/era/japan/gengou/validator.rb +236 -0
  31. data/lib/zakuro/era/japan/reki.rb +91 -0
  32. data/lib/zakuro/era/{gengou → japan/yaml}/set-001-until-south.yaml +0 -0
  33. data/lib/zakuro/era/{gengou → japan/yaml}/set-002-from-north.yaml +0 -0
  34. data/lib/zakuro/era/{gengou → japan/yaml}/set-003-modern.yaml +1 -1
  35. data/lib/zakuro/era/western.rb +1 -1
  36. data/lib/zakuro/merchant.rb +2 -2
  37. data/lib/zakuro/operation/month/parser.rb +373 -0
  38. data/lib/zakuro/operation/month/type.rb +453 -0
  39. data/lib/zakuro/operation/month/validator.rb +802 -0
  40. data/lib/zakuro/operation/operation.rb +66 -0
  41. data/lib/zakuro/operation/yaml/month.yaml +6452 -0
  42. data/lib/zakuro/output/error.rb +7 -4
  43. data/lib/zakuro/output/logger.rb +50 -47
  44. data/lib/zakuro/output/response.rb +146 -143
  45. data/lib/zakuro/result/core.rb +52 -0
  46. data/lib/zakuro/result/data.rb +187 -0
  47. data/lib/zakuro/result/operation.rb +114 -0
  48. data/lib/zakuro/result/result.rb +37 -0
  49. data/lib/zakuro/{output → tools}/stringifier.rb +16 -9
  50. data/lib/zakuro/tools/typeof.rb +33 -0
  51. data/lib/zakuro/version.rb +1 -1
  52. data/lib/zakuro/version/abstract_version.rb +1 -1
  53. data/lib/zakuro/version/context.rb +23 -0
  54. data/lib/zakuro/version/senmyou/cycle/remainder.rb +63 -0
  55. data/lib/zakuro/version/senmyou/cycle/solar_term.rb +31 -0
  56. data/lib/zakuro/version/senmyou/monthly/lunar_phase.rb +186 -182
  57. data/lib/zakuro/version/senmyou/range/annual_range.rb +164 -0
  58. data/lib/zakuro/version/senmyou/senmyou.rb +10 -4
  59. data/lib/zakuro/version/senmyou/stella/lunar_orbit.rb +7 -7
  60. data/lib/zakuro/version/senmyou/stella/solar_average.rb +103 -138
  61. data/lib/zakuro/version/senmyou/stella/solar_location.rb +213 -0
  62. data/lib/zakuro/version/senmyou/stella/solar_orbit.rb +6 -191
  63. data/lib/zakuro/version/senmyou/stella/winter_solstice.rb +4 -4
  64. data/lib/zakuro/version/version_class_resolver.rb +62 -0
  65. data/lib/zakuro/version_factory.rb +3 -3
  66. metadata +49 -20
  67. data/lib/zakuro/cycle/abstract_remainder.rb +0 -457
  68. data/lib/zakuro/cycle/zodiac.rb +0 -103
  69. data/lib/zakuro/era/japan.rb +0 -660
  70. data/lib/zakuro/output/result.rb +0 -219
  71. data/lib/zakuro/version/senmyou/base/era.rb +0 -83
  72. data/lib/zakuro/version/senmyou/base/multi_gengou.rb +0 -98
  73. data/lib/zakuro/version/senmyou/base/multi_gengou_roller.rb +0 -205
  74. data/lib/zakuro/version/senmyou/base/remainder.rb +0 -60
  75. data/lib/zakuro/version/senmyou/base/solar_term.rb +0 -66
  76. data/lib/zakuro/version/senmyou/base/year.rb +0 -104
  77. data/lib/zakuro/version/senmyou/monthly/month.rb +0 -122
  78. data/lib/zakuro/version/senmyou/summary/annual_range.rb +0 -186
  79. data/lib/zakuro/version/senmyou/summary/full_range.rb +0 -216
  80. data/lib/zakuro/version/senmyou/summary/specifier.rb +0 -100
@@ -0,0 +1,164 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../../output/logger'
4
+ require_relative '../cycle/remainder'
5
+ require_relative '../cycle/solar_term'
6
+ require_relative '../../../calculation/monthly/initialized_month'
7
+ require_relative '../monthly/lunar_phase'
8
+ require_relative '../stella/solar_orbit'
9
+ require_relative '../stella/solar_average'
10
+ require_relative '../stella/solar_location'
11
+ require_relative '../stella/lunar_orbit'
12
+
13
+ # :nodoc:
14
+ module Zakuro
15
+ # :nodoc:
16
+ module Senmyou
17
+ # :nodoc:
18
+ module Range
19
+ #
20
+ # AnnualRange 年間範囲
21
+ #
22
+ module AnnualRange
23
+ # @return [Output::Logger] ロガー
24
+ LOGGER = Output::Logger.new(location: 'annual_range')
25
+
26
+ # :reek:TooManyStatements { max_statements: 6 }
27
+
28
+ #
29
+ # 11月定朔(冬至が含まれる月の1日:補正済)を求める
30
+ #
31
+ # @param [Integer] western_year 西暦年
32
+ #
33
+ # @return [Remainder] 11月定朔
34
+ #
35
+ def self.calc_last_november_1st(western_year:)
36
+ # 天正閏余
37
+ winter_solstice_age = \
38
+ WinterSolstice.calc_moon_age(western_year: western_year)
39
+ # 11月経朔
40
+ november_1st = \
41
+ WinterSolstice.calc_averaged_last_november_1st(western_year: western_year)
42
+ # 11月定朔
43
+
44
+ # 補正
45
+ correction_value = correction_value_on_last_november_1st(
46
+ winter_solstice_age: winter_solstice_age,
47
+ western_year: western_year
48
+ )
49
+
50
+ result = november_1st.add(Cycle::Remainder.new(day: 0, minute: correction_value,
51
+ second: 0))
52
+ # 進朔
53
+ result.up_on_new_moon!
54
+ result
55
+ end
56
+
57
+ # :reek:TooManyStatements { max_statements: 6 }
58
+
59
+ #
60
+ # 一覧取得する
61
+ #
62
+ # * 対象年に対して、前年11月-当年11月までを出力する
63
+ # * 対象年(西暦)と計算年(元号x年)の紐付けは行わない
64
+ #
65
+ # @param [Integer] western_year 西暦年
66
+ #
67
+ # @return [Array<Month>] 1年データ
68
+ #
69
+ def self.collect_annual_range_after_last_november_1st(western_year:)
70
+ annual_range = initialized_annual_range(western_year: western_year)
71
+
72
+ apply_big_and_small_of_the_month(annual_range: annual_range)
73
+
74
+ solar_average = SolarAverage.new(western_year: western_year)
75
+ solar_average.set(annual_range: annual_range)
76
+
77
+ # 月間隔を取得するためだけの末尾要素を削除
78
+ annual_range.pop
79
+
80
+ initialize_month_label(annual_range: annual_range)
81
+ end
82
+
83
+ #
84
+ # 11月定朔の補正値を求める
85
+ #
86
+ # @param [Remainder] winter_solstice_age 天正閏余
87
+ # @param [Integer] western_year 西暦年
88
+ #
89
+ # @return [Integer] 補正値
90
+ #
91
+ def self.correction_value_on_last_november_1st(winter_solstice_age:, western_year:)
92
+ # 補正
93
+ solar_term = Cycle::SolarTerm.new(
94
+ remainder: winter_solstice_age
95
+ )
96
+ solar_term = \
97
+ SolarLocation.get(
98
+ solar_term: solar_term
99
+ )
100
+
101
+ moon_remainder, is_forward = LunarOrbit.calc_moon_point(
102
+ remainder: winter_solstice_age, western_year: western_year
103
+ )
104
+
105
+ SolarOrbit.calc_sun_orbit_value(solar_term: solar_term) +
106
+ LunarOrbit.calc_moon_orbit_value(remainder_month: moon_remainder,
107
+ is_forward: is_forward)
108
+ end
109
+ private_class_method :correction_value_on_last_november_1st
110
+
111
+ #
112
+ # 1年データを取得する
113
+ #
114
+ # @param [Integer] western_year 西暦年
115
+ #
116
+ # @return [Array<Month>] 1年データ
117
+ #
118
+ def self.initialized_annual_range(western_year:)
119
+ result = []
120
+ lunar_phase = Monthly::LunarPhase.new(western_year: western_year)
121
+
122
+ # 14ヶ月分を生成する(閏年で最大13ヶ月 + 末月の大小/二十四節気を求めるために必要な月)
123
+ (0..13).each do |_index|
124
+ adjusted = lunar_phase.next_month
125
+
126
+ result.push(
127
+ Calculation::Monthly::InitializedMonth.new(
128
+ month_label: Calculation::Monthly::MonthLabel.new,
129
+ first_day: Calculation::Monthly::FirstDay.new(remainder: adjusted),
130
+ phase_index: 0
131
+ )
132
+ )
133
+ end
134
+
135
+ result
136
+ end
137
+ private_class_method :initialized_annual_range
138
+
139
+ #
140
+ # 1年データの各月に月の大小を設定する
141
+ #
142
+ # @param [Array<Month>] annual_range 1年データ
143
+ #
144
+ def self.apply_big_and_small_of_the_month(annual_range:)
145
+ # NOTE: 最後の月は処理できない(=計算外の余分な月が最後に必要である)
146
+ annual_range.each_cons(2) do |(current_month, next_month)|
147
+ current_month.eval_many_days(next_month_day: next_month.remainder.day)
148
+ end
149
+ end
150
+ private_class_method :apply_big_and_small_of_the_month
151
+
152
+ #
153
+ # 月表示情報を更新する
154
+ #
155
+ # @param [Array<Month>] annual_range 1年データ
156
+ #
157
+ def self.initialize_month_label(annual_range:)
158
+ annual_range.each(&:rename_month_label_by_solar_term)
159
+ end
160
+ private_class_method :initialize_month_label
161
+ end
162
+ end
163
+ end
164
+ end
@@ -1,9 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'date'
4
- require_relative '../abstract_version'
5
4
  require_relative '../../era/western'
6
- require_relative 'summary/specifier'
5
+ require_relative '../abstract_version'
6
+ require_relative '../context'
7
+ require_relative '../../calculation/summary/single'
7
8
 
8
9
  # :nodoc:
9
10
  module Zakuro
@@ -18,16 +19,21 @@ module Zakuro
18
19
  # @return [True] リリースあり
19
20
  RELEASE = true
20
21
 
22
+ # @return [String] 暦クラス名
23
+ VERSION_NAME = 'Senmyou'
24
+
21
25
  #
22
26
  # 西暦日から和暦日に変換する
23
27
  #
24
28
  # @param [Date] western_date 西暦日
25
29
  #
26
- # @return [Result::SingleDay] 和暦日
30
+ # @return [Result::Single] 和暦日
27
31
  #
28
32
  def self.to_japan_date(western_date:)
29
33
  date = Western::Calendar.create(date: western_date)
30
- SingleDaySpecifier.get(date: date)
34
+
35
+ context = Context.new(version_name: VERSION_NAME)
36
+ Calculation::Summary::Single.get(context: context, date: date)
31
37
  end
32
38
  end
33
39
  end
@@ -13,7 +13,7 @@ module Zakuro
13
13
  # @return [Integer] 暦中日
14
14
  # @note ANOMALISTIC_MONTH の半分に相当する
15
15
  HALF_ANOMALISTIC_MONTH = \
16
- LunarRemainder.new(day: 13, minute: 6529, second: 9.5)
16
+ Cycle::LunarRemainder.new(day: 13, minute: 6529, second: 9.5)
17
17
 
18
18
  #
19
19
  # Adjustment 補正値情報
@@ -122,7 +122,7 @@ module Zakuro
122
122
  # @return [True] 正しくない
123
123
  #
124
124
  def self.valid?(remainder:)
125
- return if remainder.is_a?(LunarRemainder)
125
+ return if remainder.is_a?(Cycle::LunarRemainder)
126
126
 
127
127
  raise ArgumentError, "unmatch parameter type: #{remainder.class}"
128
128
  end
@@ -193,7 +193,7 @@ module Zakuro
193
193
  { |key, _| key.match(/^#{prefix}_#{format('%<day>02d', day: day)}_.*/) }
194
194
 
195
195
  targets.each do |key, value|
196
- # NOTE 境界値は上から順に引き当てた方を返す(7日の境界値7465は上のキーで返す)
196
+ # NOTE: 境界値は上から順に引き当てた方を返す(7日の境界値7465は上のキーで返す)
197
197
  matched, diff = \
198
198
  extract_data_from_moon_adjustment_key(key, minute)
199
199
  # 小余の下げ幅
@@ -255,7 +255,7 @@ module Zakuro
255
255
  #
256
256
  # 天正冬至(入暦前回未計算)を求める
257
257
  #
258
- # @param [Remainder] winter_solstice_age 昨年冬至
258
+ # @param [Remainder] winter_solstice_age 天正閏余
259
259
  # @param [Integer] western_year 西暦年
260
260
  #
261
261
  # @return [LunarRemainder] 入暦
@@ -272,14 +272,14 @@ module Zakuro
272
272
  total_year * WinterSolstice::YEAR - winter_solstice_age.to_minute
273
273
 
274
274
  remainder_month = \
275
- LunarRemainder.new(total: (total_day % ANOMALISTIC_MONTH))
275
+ Cycle::LunarRemainder.new(total: (total_day % ANOMALISTIC_MONTH))
276
276
 
277
277
  remainder_month, is_forward = decrease_moon_point(
278
278
  remainder_month: remainder_month,
279
279
  remainder_limit: HALF_ANOMALISTIC_MONTH, is_forward: true
280
280
  )
281
281
 
282
- remainder_month.add!(Remainder.new(day: 1, minute: 0, second: 0))
282
+ remainder_month.add!(Cycle::Remainder.new(day: 1, minute: 0, second: 0))
283
283
 
284
284
  [remainder_month, is_forward]
285
285
  end
@@ -302,7 +302,7 @@ module Zakuro
302
302
  remainder_month, is_forward = \
303
303
  decrease_moon_point(
304
304
  remainder_month: remainder,
305
- remainder_limit: Remainder.new(day: 14, minute: 6529, second: 0),
305
+ remainder_limit: Cycle::Remainder.new(day: 14, minute: 6529, second: 0),
306
306
  is_forward: is_forward
307
307
  )
308
308
 
@@ -7,198 +7,163 @@ module Zakuro
7
7
  #
8
8
  # SolarAverage 常気(太陽軌道平均)
9
9
  #
10
- module SolarAverage
10
+ class SolarAverage
11
11
  # @return [Remainder] 気策(24分の1年)
12
- SOLAR_TERM_AVERAGE = Remainder.new(day: 15, minute: 1835, second: 5)
13
-
14
- # :reek:TooManyStatements { max_statements: 6 }
12
+ SOLAR_TERM_AVERAGE = Cycle::Remainder.new(day: 15, minute: 1835, second: 5)
15
13
 
16
14
  #
17
- # 冬至から数えた1年データの月ごとに二十四節気を割り当てる
15
+ # 初期化
18
16
  #
19
17
  # @param [Integer] western_year 西暦年
20
- # @param [Array<Month>] annual_range 1年データ
21
- #
22
- # @return [Array<Month>] 1年データ
23
18
  #
24
- def self.set_solar_terms_into_annual_range(western_year:, annual_range:)
25
- # 天正冬至
26
- winter_solstice = WinterSolstice.calc(western_year: western_year)
27
-
28
- # 前年冬至からの二十四節気
29
- solar_terms = collect_solar_terms_from_last_winter_solstice(
30
- winter_solstice: winter_solstice
31
- )
32
-
33
- apply_solar_terms_from_last_winter_solstice(annual_range: annual_range,
34
- solar_terms: solar_terms)
35
-
36
- # 前後の二十四節気
37
- rest_solar_terms = \
38
- collect_solar_terms_before_and_after(solar_terms: solar_terms)
39
-
40
- apply_solar_terms_before_and_after(annual_range: annual_range,
41
- rest_solar_terms: rest_solar_terms)
42
-
43
- annual_range
19
+ def initialize(western_year:)
20
+ @solar_term = SolarAverage.first_solar_term(western_year: western_year)
44
21
  end
45
22
 
46
- # :reek:TooManyStatements { max_statements: 6 }
47
-
48
23
  #
49
- # 前年冬至から当年大雪までの二十四節気を計算する
24
+ # 冬至から数えた1年データの月ごとに二十四節気を割り当てる
50
25
  #
51
- # @param [Remainder] winter_solstice 冬至
26
+ # @param [Array<Month>] annual_range 1年データ
52
27
  #
53
- # @return [Array<Remainder>] 二十四節気
28
+ # @return [Array<Month>] 1年データ
54
29
  #
55
- def self.collect_solar_terms_from_last_winter_solstice(winter_solstice:)
56
- result = []
57
- term = winter_solstice
58
- (0...24).each do |_i|
59
- result.push(term)
60
- term = term.add(SOLAR_TERM_AVERAGE)
30
+ def set(annual_range:)
31
+ # 次月と比較しながら当月の二十四節気を決める
32
+ # NOTE: 最後の月は処理できない(=計算外の余分な月が最後に必要である)
33
+ annual_range.each_cons(2) do |(current_month, next_month)|
34
+ set_solar_term(
35
+ current_month: current_month,
36
+ next_month: next_month
37
+ )
61
38
  end
62
39
 
63
- result
40
+ annual_range
64
41
  end
65
- private_class_method :collect_solar_terms_from_last_winter_solstice
66
-
67
- # :reek:TooManyStatements { max_statements: 9 }
68
42
 
69
43
  #
70
- # 各月の二十四節気を設定する
44
+ # 計算開始する二十四節気を求める
71
45
  #
72
- # @param [Array<Month>] annual_range 1年データ
73
- # @param [Array<Remainder>] solar_terms 1年データ内の全二十四節気
46
+ # @param [Integer] western_year 西暦年
74
47
  #
75
- def self.apply_solar_terms_from_last_winter_solstice(annual_range:,
76
- solar_terms:)
77
-
78
- c_idx = 0
79
- st_idx = 0
80
- month_size = annual_range.size
48
+ # @return [SolarTerm] 二十四節気
49
+ #
50
+ def self.first_solar_term(western_year:)
51
+ # 天正冬至
52
+ winter_solstice = WinterSolstice.calc(western_year: western_year)
81
53
 
82
- while c_idx < month_size && st_idx < solar_terms.size
83
- raise StandardError, "month is over. idx: #{c_idx}" if c_idx >= month_size
54
+ # 二十四節気(冬至)
55
+ solar_term = Cycle::SolarTerm.new(index: 0, remainder: winter_solstice)
84
56
 
85
- current_month = annual_range[c_idx]
86
- next_month = annual_range[c_idx + 1]
87
- solar_term = solar_terms[st_idx]
57
+ first_solar_term_index = SolarAverage.calc_fist_solar_term_index(western_year: western_year)
88
58
 
89
- if in_range_solar_term?(target: solar_term, min: current_month.remainder,
90
- max: next_month.remainder)
91
- set_solar_term(month: current_month,
92
- solar_term: solar_term, solar_term_index: st_idx)
93
- st_idx += 1
94
- next
95
- end
59
+ # 対象の二十四節気まで戻す
60
+ solar_term.prev_by_index(first_solar_term_index)
96
61
 
97
- # 一度も割り当てがない場合は二十四節気を進める
98
- if current_month.empty_solar_term?
99
- st_idx += 1
100
- next
101
- end
102
-
103
- c_idx += 1
104
- end
62
+ solar_term
105
63
  end
106
- private_class_method :apply_solar_terms_from_last_winter_solstice
107
64
 
108
65
  #
109
- # 1年データ内の二十四節気の前後を収集する
66
+ # 計算開始する二十四節気番号を求める
110
67
  #
111
- # @param [Array<Remainder>] solar_terms 1年データ内の全二十四節気
68
+ # * 前提として入定気は冬至の手前にある
69
+ # * 例えば、定気が大雪であれば入定気は大雪の範囲内にある
70
+ # * 入定気は、定気の開始位置に重複しない限り、常に定気より後にある
71
+ # * 基本的に定気の一つ前から起算すれば、当時から求めた11月(閏10/閏11月)に二十四節気を割り当てられる
112
72
  #
113
- # @return [Hash<Integer, Hash<Symbol, Integer>>, Hash<Integer, Hash<Symbol, Remainder>>] 前後
73
+ # @param [Integer] western_year 西暦年
74
+ #
75
+ # @return [Integer] 二十四節気番号
114
76
  #
115
- def self.collect_solar_terms_before_and_after(solar_terms:)
116
- raise ArgumentError, 'parameter must be 24 solar terms' unless solar_terms.size == 24
77
+ def self.calc_fist_solar_term_index(western_year:)
78
+ # 天正閏余
79
+ winter_solstice_age = \
80
+ WinterSolstice.calc_moon_age(western_year: western_year)
117
81
 
118
- touji = solar_terms[-1].add(SOLAR_TERM_AVERAGE)
119
- {
120
- # 前年大雪
121
- 23 => { index: 0, solar_term: solar_terms[0].sub(SOLAR_TERM_AVERAGE) },
122
- # 当年冬至
123
- 0 => { index: -2, solar_term: touji },
124
- # 当年小寒
125
- 1 => { index: -2, solar_term: touji.add(SOLAR_TERM_AVERAGE) }
126
- }
127
- end
128
- private_class_method :collect_solar_terms_before_and_after
82
+ # 入定気を求める
83
+ solar_location = SolarLocation.get(
84
+ solar_term: Cycle::SolarTerm.new(remainder: winter_solstice_age)
85
+ )
129
86
 
130
- # :reek:TooManyStatements { max_statements: 6 }
87
+ solar_term_index = solar_location.index
131
88
 
132
- #
133
- # 1年データ前後の二十四節気を適用する
134
- #
135
- # @param [Array<Month>] annual_range 1年データ
136
- # @param [Hash<Integer, Hash<Symbol, Integer>>, Hash<Integer, Hash<Symbol, Remainder>>]
137
- # rest_solar_terms 前後
138
- #
139
- def self.apply_solar_terms_before_and_after(annual_range:, rest_solar_terms:)
140
- rest_solar_terms.each do |key, value|
141
- index = value[:index]
142
- solar_term = value[:solar_term]
143
- data = annual_range[index]
144
- next unless in_range_solar_term?(
145
- target: solar_term,
146
- min: data.remainder, max: annual_range[index + 1].remainder
147
- )
89
+ # 入定気の一つ後の二十四節気まで戻す(ただし11月経朔が二十四節気上にある場合は戻さない)
90
+ solar_term_index += 1 unless solar_location.remainder == Cycle::Remainder.new(total: 0)
148
91
 
149
- set_solar_term(month: data,
150
- solar_term: solar_term, solar_term_index: key)
151
- end
92
+ solar_term_index
152
93
  end
153
- private_class_method :apply_solar_terms_before_and_after
154
94
 
155
95
  # :reek:TooManyStatements { max_statements: 7 }
156
96
 
157
97
  #
158
- # 月内(currentからnextの間)に二十四節気があるか
98
+ # 月内(当月朔日から当月末日(来月朔日の前日)の間)に二十四節気があるか
159
99
  # @note 大余60で一巡するため 以下2パターンがある
160
- # * current(min) <= next(max) : (二十四節気) >= current && (二十四節気) < next
161
- # * current(min) > next(max) : (二十四節気) >= current || (二十四節気) < next
100
+ # * current_month <= next_month : (二十四節気) >= current_month && (二十四節気) < next_month
101
+ # * current_month > next_month : (二十四節気) >= current_month || (二十四節気) < next_month
162
102
  #
163
- # @param [Remainder] target 対象の二十四節気
164
- # @param [Remainder] min 月初
165
- # @param [Remainder] max 月末
103
+ # @param [Remainder] solar_term 二十四節気
104
+ # @param [Remainder] current_month 月初
105
+ # @param [Remainder] next_month 月末
166
106
  #
167
107
  # @return [True] 対象の二十四節気がある
168
108
  # @return [False] 対象の二十四節気がない
169
109
  #
170
- def self.in_range_solar_term?(target:, min:, max:)
110
+ def self.in_solar_term?(solar_term:, current_month:, next_month:)
171
111
  # 大余で比較する
172
- target_time = target.day
173
- min_time = min.day
174
- max_time = max.day
175
- min_over = (target_time >= min_time)
176
- max_under = (target_time < max_time)
112
+ target_time = solar_term.day
113
+ current_month_time = current_month.day
114
+ next_month_time = next_month.day
115
+ current_month_over = (target_time >= current_month_time)
116
+ next_month_under = (target_time < next_month_time)
177
117
 
178
- (min_time <= max_time ? min_over && max_under : min_over || max_under)
118
+ return current_month_over && next_month_under if current_month_time <= next_month_time
119
+
120
+ current_month_over || next_month_under
179
121
  end
180
- private_class_method :in_range_solar_term?
122
+
123
+ private
124
+
125
+ # :reek:TooManyStatements { max_statements: 8 }
181
126
 
182
127
  #
183
128
  # 二十四節気を設定する
184
129
  #
185
- # @param [Month] month
186
- # @param [Remainder] solar_term 二十四節気
187
- # @param [Integer] solar_term_index 連番(二十四節気)
188
- #
189
- def self.set_solar_term(month:, solar_term:, solar_term_index:)
190
- term = SolarTerm.new(remainder: solar_term, index: solar_term_index)
191
- if solar_term_index.even?
192
- # 中気
193
- month.even_term = term
194
- else
195
- # 節気
196
- month.odd_term = term
130
+ # @param [Month] current_month 当月
131
+ # @param [Month] next_month 次月
132
+ #
133
+ def set_solar_term(current_month:, next_month:)
134
+ # 安全策として無限ループは回避する
135
+ # * 最大試行回数:4回(設定なし => 設定あり => 設定あり => 設定なし)
136
+ # * 閏月は1回しか設定しない
137
+ # * 最大2回設定する(中気・節気)
138
+ (0..3).each do |_index|
139
+ in_range = SolarAverage.in_solar_term?(
140
+ solar_term: @solar_term.remainder, current_month: current_month.remainder,
141
+ next_month: next_month.remainder
142
+ )
143
+
144
+ # 範囲外
145
+ unless in_range
146
+ # 1つ以上設定されていれば切り上げる(一つ飛ばしで二十四節気を設定することはない)
147
+ break unless current_month.empty_solar_term?
148
+
149
+ next_solar_term
150
+ next
151
+ end
152
+
153
+ current_month.add_term(term: @solar_term.clone)
154
+ next_solar_term
155
+
156
+ # 宣明暦は最大2つまで
157
+ break if current_month.solar_term_size == 2
197
158
  end
159
+ end
198
160
 
199
- nil
161
+ #
162
+ # 次の二十四節気に移る
163
+ #
164
+ def next_solar_term
165
+ @solar_term.next!
200
166
  end
201
- private_class_method :set_solar_term
202
167
  end
203
168
  end
204
169
  end