zakuro 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../../era/western'
4
+ require_relative './full_range'
5
+ require_relative '../base/multi_gengou_roller'
6
+ require_relative '../base/year'
7
+ require_relative '../../../output/response'
8
+ require_relative '../../../output/logger'
9
+
10
+ # :nodoc:
11
+ module Zakuro
12
+ # :nodoc:
13
+ module Senmyou
14
+ #
15
+ # SingleDaySpecifier 一日検索
16
+ #
17
+ module SingleDaySpecifier
18
+ # @return [Logger] ロガー
19
+ LOGGER = Logger.new(location: 'specifier')
20
+
21
+ #
22
+ # 取得する
23
+ #
24
+ # @param [Western::Calendar] date 西暦日
25
+ #
26
+ # @return [Response::SingleDay] 和暦日
27
+ #
28
+ def self.get(date:)
29
+ years = FullRange.new(start_date: date).get
30
+
31
+ year = specify_year(years: years, date: date)
32
+
33
+ year = transfer(year: year, date: date)
34
+
35
+ month, first_date = specify_month(year: year, date: date)
36
+
37
+ Response::SingleDay.save_single_day(
38
+ param: Response::SingleDay::Param.new(
39
+ year: year, month: month,
40
+ date: date, days: date - first_date
41
+ )
42
+ )
43
+ end
44
+
45
+ #
46
+ # 年を特定する
47
+ #
48
+ # @param [Array<Year>] years 範囲
49
+ # @param [Western::Calendar] date 西暦日
50
+ #
51
+ # @return [Year] 対象年
52
+ #
53
+ def self.specify_year(years:, date:)
54
+ years.reverse_each do |year|
55
+ return year if date >= year.new_year_date
56
+ end
57
+
58
+ raise ArgumentError, "invalid year range. date: #{date.format}"
59
+ end
60
+
61
+ #
62
+ # 改元する
63
+ #
64
+ # @param [Year] year 年
65
+ # @param [Western::Calendar] date 西暦日
66
+ #
67
+ # @return [Year] 改元後の年
68
+ #
69
+ def self.transfer(year:, date:)
70
+ multi_gengou = MultiGengouRoller.transfer(multi_gengou: year.multi_gengou, date: date)
71
+ Year.new(multi_gengou: multi_gengou, new_year_date: year.new_year_date,
72
+ months: year.months, total_days: year.total_days)
73
+ end
74
+
75
+ # :reek:TooManyStatements { max_statements: 7 }
76
+
77
+ #
78
+ # 月を特定する
79
+ #
80
+ # @param [Year] year 年
81
+ # @param [Western::Calendar] date 西暦日
82
+ #
83
+ # @return [Month] 対象月
84
+ # @return [Western::Calendar] 月初日
85
+ #
86
+ def self.specify_month(year:, date:)
87
+ current_month_date = year.new_year_date.clone
88
+ next_month_date = current_month_date.clone
89
+ year.months.each do |month|
90
+ next_month_date += month.days
91
+ return month, current_month_date if next_month_date > date
92
+
93
+ current_month_date = next_month_date.clone
94
+ end
95
+
96
+ raise ArgumentError, "invalid month range. date: #{date.format}"
97
+ end
98
+ end
99
+ end
100
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zakuro
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - pldb
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-08-01 00:00:00.000000000 Z
11
+ date: 2020-10-05 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: mainly lunar solar calendar
14
14
  email:
@@ -23,10 +23,12 @@ files:
23
23
  - ".rubocop.yml"
24
24
  - Gemfile
25
25
  - LICENSE.txt
26
+ - Makefile
26
27
  - README.md
27
28
  - Rakefile
28
29
  - bin/console
29
30
  - bin/setup
31
+ - doc/gengou.md
30
32
  - images/12月以降の入定気.png
31
33
  - images/12月以降の月の進退.png
32
34
  - images/source/description.numbers
@@ -58,7 +60,8 @@ files:
58
60
  - lib/zakuro/version/kansei/kansei.rb
59
61
  - lib/zakuro/version/senmyou/README.md
60
62
  - lib/zakuro/version/senmyou/base/era.rb
61
- - lib/zakuro/version/senmyou/base/gengou.rb
63
+ - lib/zakuro/version/senmyou/base/multi_gengou.rb
64
+ - lib/zakuro/version/senmyou/base/multi_gengou_roller.rb
62
65
  - lib/zakuro/version/senmyou/base/remainder.rb
63
66
  - lib/zakuro/version/senmyou/base/solar_term.rb
64
67
  - lib/zakuro/version/senmyou/base/year.rb
@@ -69,8 +72,9 @@ files:
69
72
  - lib/zakuro/version/senmyou/stella/solar_average.rb
70
73
  - lib/zakuro/version/senmyou/stella/solar_orbit.rb
71
74
  - lib/zakuro/version/senmyou/stella/winter_solstice.rb
72
- - lib/zakuro/version/senmyou/summary/annual_data.rb
73
- - lib/zakuro/version/senmyou/summary/gengou_data.rb
75
+ - lib/zakuro/version/senmyou/summary/annual_range.rb
76
+ - lib/zakuro/version/senmyou/summary/full_range.rb
77
+ - lib/zakuro/version/senmyou/summary/specifier.rb
74
78
  - lib/zakuro/version/taien/taien.rb
75
79
  - lib/zakuro/version/tenpou/tenpou.rb
76
80
  - lib/zakuro/version_factory.rb
@@ -83,7 +87,7 @@ metadata:
83
87
  homepage_uri: https://github.com/pldb/zakuro
84
88
  source_code_uri: https://github.com/pldb/zakuro
85
89
  changelog_uri: https://github.com/pldb/zakuro
86
- post_install_message:
90
+ post_install_message:
87
91
  rdoc_options: []
88
92
  require_paths:
89
93
  - lib
@@ -98,8 +102,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
98
102
  - !ruby/object:Gem::Version
99
103
  version: '0'
100
104
  requirements: []
101
- rubygems_version: 3.0.3
102
- signing_key:
105
+ rubygems_version: 3.1.2
106
+ signing_key:
103
107
  specification_version: 4
104
108
  summary: japanese calendar library.
105
109
  test_files: []
@@ -1,210 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative './era'
4
-
5
- # :nodoc:
6
- module Zakuro
7
- # :nodoc:
8
- module Senmyou
9
- #
10
- # Gengou 元号
11
- #
12
- class Gengou
13
- # @return [Japan::Gengou] 元号(1行目)
14
- attr_reader :first_line
15
- # @return [Japan::Gengou] 元号(2行目)
16
- attr_reader :second_line
17
- # @return [Integer] 年の日数
18
- attr_reader :total_days
19
- # @return [Western::Calendar] 元号内での最過去日(2つの元号が重複した場合はより過去の日となる)/ 次の元号年の年初(1月1日)
20
- attr_reader :first_date
21
-
22
- #
23
- # 初期化
24
- #
25
- # @note (see #next_year)
26
- # 次年度以降の first_date はその元号の1年目の最初の日を設定する
27
- #
28
- # @param [Western::Calendar] date 対象日
29
- # @param [Japan::Gengou] first_line 元号(1行目)
30
- # * 計算結果を持ち越すため、自クラスでの初期化時のみ使用する
31
- # @param [Japan::Gengou] second_line 元号(2行目)
32
- # * 計算結果を持ち越すため、自クラスでの初期化時のみ使用する
33
- #
34
- def initialize(date: Era::START_DATE, first_line: Japan::Gengou.new,
35
- second_line: Japan::Gengou.new)
36
- @total_days = 0
37
-
38
- if Gengou.first_called?(first_line: first_line,
39
- second_line: second_line)
40
- initialize_first_called(date: date)
41
- return
42
- end
43
- @first_line = first_line
44
- @second_line = second_line
45
- @first_date = date.clone
46
- end
47
-
48
- #
49
- # 初期化で最初の呼び出しかどうかを判定する
50
- #
51
- # @note 以下の前提がある
52
- # * 初回呼び出しでは first_line/second_line を引数に指定しない(情報がないのでできない)
53
- # * 次回以降の呼び出し( next_year ) では計算済みのfirst_line/second_lineを渡す
54
- #
55
- # @param [Japan::Gengou] first_line 元号(1行目)
56
- # @param [Japan::Gengou] second_line 元号(2行目)
57
- #
58
- # @return [True] 初回呼び出し
59
- # @return [False] 次回以降の呼び出し
60
- #
61
- def self.first_called?(first_line:, second_line:)
62
- first_line.invalid? && second_line.invalid?
63
- end
64
-
65
- #
66
- # 初期化(初回呼び出し)
67
- #
68
- # @param [Western::Calendar] date 日付
69
- #
70
- def initialize_first_called(date:)
71
- raise ArgumentError, 'invalid senmyou date' unless Era.include?(date: date)
72
-
73
- # 2つの元号が重なった時に、元号の開始日が最も古い日
74
- @first_date = choise_oldest_gengou_date(
75
- first_line: Era.first(start_date: date),
76
- second_line: Era.second(start_date: date)
77
- )
78
- @first_line = Era.first(start_date: @first_date)
79
- @second_line = Era.second(start_date: @first_date)
80
-
81
- nil
82
- end
83
-
84
- #
85
- # 十干十二支を取得する
86
- #
87
- # @return [String] 十干十二支
88
- #
89
- def zodiac_name
90
- Era.zodiac_name(western_year: @first_date.year)
91
- end
92
-
93
- #
94
- # 年の日数に加算する
95
- #
96
- # @param [Integer] days 日数
97
- #
98
- def add_days(days: 0)
99
- @total_days += days
100
-
101
- nil
102
- end
103
-
104
- #
105
- # 次の年にする
106
- #
107
- # @return [Gengou] 次の年の元号
108
- #
109
- def next_year
110
- next_date = @first_date.clone + @total_days
111
- first = Gengou.next_first_line(gengou: @first_line, date: next_date)
112
- second = Gengou.next_second_line(gengou: @second_line, date: next_date)
113
-
114
- first, second = Gengou.swap_two_gengou_on_last_period(first: first,
115
- second: second)
116
-
117
- Gengou.new(date: next_date,
118
- first_line: first, second_line: second)
119
- end
120
-
121
- #
122
- # 南北朝の終末処理をする
123
- #
124
- # @note 特別対応。北朝の "明徳" を4年から主流にする(2行目から1行目にする)
125
- #
126
- # @param [Japan::Gengou] first 元号(1行目)
127
- # @param [Japan::Gengou] second 元号(2行目)
128
- #
129
- # @return [Array<Japan::Gengou>] 元号(1行目), 元号(2行目)
130
- #
131
- def self.swap_two_gengou_on_last_period(first:, second:)
132
- if first.name == second.name
133
- first = second
134
- second = Japan::Gengou.new
135
- end
136
- [first, second]
137
- end
138
-
139
- #
140
- # 元号(1行目)を次の年にする
141
- #
142
- # @param [Japan::Gengou] gengou 元号(1行目)
143
- # @param [Western::Calendar] date 日付
144
- #
145
- # @return [Japan::Gengou] 翌年の元号(1行目)
146
- #
147
- def self.next_first_line(gengou:, date:)
148
- return Era.first(start_date: date) unless gengou.include?(date: date)
149
-
150
- next_gengou = gengou.clone
151
- next_gengou.next_year
152
- next_gengou
153
- end
154
-
155
- #
156
- # 元号(2行目)を次の年にする
157
- #
158
- # @param [Japan::Gengou] gengou 元号(2行目)
159
- # @param [Western::Calendar] date 日付
160
- #
161
- # @return [Japan::Gengou] 翌年の元号(2行目)
162
- #
163
- def self.next_second_line(gengou:, date:)
164
- return Era.second(start_date: date) unless gengou.include?(date: date)
165
-
166
- next_gengou = gengou.clone
167
- next_gengou.next_year
168
- next_gengou
169
- end
170
-
171
- #
172
- # 元号内での最過去日を求める
173
- # @note 2つの元号が重複した場合はより過去の日となる
174
- #
175
- # @param [Japan::Gengou] first_line 元号(1行目)
176
- # @param [Japan::Gengou] second_line 元号(2行目)
177
- #
178
- # @return [Western::Calendar] 最過去日
179
- #
180
- def choise_oldest_gengou_date(first_line: @first_line,
181
- second_line: @second_line)
182
- first_start_date = first_line.start_date.clone
183
- second_start_date = second_line.start_date.clone
184
- # first_lineは常に存在する
185
- return first_start_date if second_line.invalid?
186
-
187
- first_start_date < second_start_date ? first_start_date : second_start_date
188
- end
189
-
190
- #
191
- # 元号内での最未来日を求める
192
- # @note 2つの元号が重複した場合はより未来の日となる
193
- #
194
- # @param [Japan::Gengou] first_line 元号(1行目)
195
- # @param [Japan::Gengou] second_line 元号(2行目)
196
- #
197
- # @return [Western::Calendar] 最未来日
198
- #
199
- def choise_newest_gengou_date(first_line: @first_line,
200
- second_line: @second_line)
201
- first_end_date = first_line.end_date.clone
202
- second_end_date = second_line.end_date.clone
203
- # first_lineは常に存在する
204
- return first_end_date if second_line.invalid?
205
-
206
- first_end_date > second_end_date ? first_end_date : second_end_date
207
- end
208
- end
209
- end
210
- end
@@ -1,294 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../../../era/western'
4
- require_relative 'annual_data'
5
- require_relative '../../../output/response'
6
- require_relative '../base/era'
7
- require_relative '../base/gengou'
8
- require_relative '../base/year'
9
-
10
- # :nodoc:
11
- module Zakuro
12
- # :nodoc:
13
- module Senmyou
14
- #
15
- # GengouData 元号の年情報
16
- #
17
- module GengouData
18
- def self.get_ancient_date(date: Western::Calendar.new)
19
- SingleDay.get_ancient_date(date: date)
20
- end
21
-
22
- #
23
- # SingleDay 1日データ
24
- #
25
- module SingleDay
26
- #
27
- # 1日データを取得する
28
- #
29
- # @param [Western::Calendar] date 年月日情報(西暦)
30
- #
31
- # @return [Response::SingleDay] 1日データ
32
- #
33
- def self.get_ancient_date(date: Western::Calendar.new)
34
- raise ArgumentError, 'invalid senmyou date' unless Era.include?(date: date)
35
-
36
- target = get_target(year_list: get_year_list(date: date), date: date)
37
-
38
- Response::SingleDay.save_single_day(
39
- param: Response::SingleDay::Param.new(
40
- year: target.year, month: target.month,
41
- date: target.date, days: target.days
42
- )
43
- )
44
- end
45
-
46
- #
47
- # Target 対象
48
- #
49
- class Target
50
- # @return [Year] 年
51
- attr_reader :year
52
- # @return [Month] 月
53
- attr_reader :month
54
- # @return [Western::Calendar] 日
55
- attr_reader :date
56
- # @return [Integer] 月初からの日数
57
- attr_reader :days
58
-
59
- #
60
- # 初期化
61
- #
62
- # @param [Year] year 年
63
- # @param [Month] month 月
64
- # @param [Western::Calendar] date 日
65
- # @param [Integer] days 月初からの日数
66
- #
67
- def initialize(year:, month:, date:, days:)
68
- @year = year
69
- @month = month
70
- @date = date
71
- @days = days
72
- end
73
- end
74
-
75
- #
76
- # MonthSearchResult 1年内に該当する月を検索した結果
77
- #
78
- class MonthSearchResult
79
- # @return [Month] 月
80
- attr_reader :target_month
81
- # @return [Western::Calendar] 月初日
82
- attr_reader :first_date
83
- # @return [True] 該当データ引き当て済
84
- # @return [False] 該当データ引き当てなし
85
- attr_reader :breaked
86
-
87
- #
88
- # 初期化
89
- #
90
- # @param [Month] target_month 月
91
- # @param [Western::Calendar] first_date 月初日
92
- # @param [True, False] breaked 該当データ引き当て
93
- #
94
- def initialize(target_month: Month.new,
95
- first_date: Western::Calendar.new, breaked:)
96
- @target_month = target_month
97
- @first_date = first_date
98
- @breaked = breaked
99
- end
100
- end
101
-
102
- #
103
- # 指定日に関連する暦の範囲だけ年データを生成する
104
- #
105
- # @param [Western::Calendar] date 西暦日
106
- #
107
- # @return [Array<Year>] 年データ
108
- #
109
- def self.get_year_list(date:)
110
- # 元号の最初の年月日を取る
111
- gengou = Gengou.new(date: date.clone)
112
-
113
- # 南北朝には元号が2つ並び、必ずしも範囲が重ならないケースもある
114
- # 対象日付に重なる元号から論理和の範囲を取り、処理漏れがないようにする
115
- start_date = gengou.first_date.clone
116
- # 最後の年は翌年から今年の冬至を求めるため範囲を1年広げる
117
- newest_date = gengou.choise_newest_gengou_date.next_year
118
-
119
- Series.get_year_list(
120
- start_gengou: gengou, start_date: start_date, end_date: newest_date
121
- )
122
- end
123
-
124
- #
125
- # 対象を引き当てる
126
- #
127
- # @param [Array<Year>] year_list 年データ
128
- # @param [Western::Calendar] date 西暦日
129
- #
130
- # @return [Target] 対象
131
- #
132
- def self.get_target(year_list:, date:)
133
- # 対象年/対象月を引き当てる
134
- year_list.each do |year|
135
- result = get_target_month(date: date, year: year)
136
-
137
- next unless result.breaked
138
-
139
- return Target.new(
140
- year: year, month: result.target_month, date: date,
141
- # 対象日に調整する
142
- days: date - result.first_date
143
- )
144
- end
145
-
146
- raise ArgumentError, "invalid range: #{date.format}"
147
- end
148
-
149
- # :reek:TooManyStatements { max_statements: 6 }
150
-
151
- #
152
- # 対象の月を引き当てる
153
- #
154
- # @param [Western::Calendar] date 西暦日
155
- # @param [Year] year 年
156
- #
157
- # @return [MonthSearchResult] 1年内に該当する月を検索した結果
158
- #
159
- def self.get_target_month(date:, year:)
160
- first_date = year.gengou.first_date.clone
161
- year.months.each do |month|
162
- # 月末の日付を超える場合
163
- next_first_date = first_date.clone + month.days
164
- if date < next_first_date
165
- return MonthSearchResult.new(target_month: month,
166
- first_date: first_date, breaked: true)
167
- end
168
- first_date = next_first_date
169
- end
170
- MonthSearchResult.new(breaked: false)
171
- end
172
- end
173
-
174
- #
175
- # Series 和暦時系列データ
176
- #
177
- module Series
178
- # :reek:TooManyInstanceVariables { max_instance_variables: 6 }
179
-
180
- #
181
- # TimeAdvance 時間進行
182
- #
183
- class TimeAdvance
184
- #
185
- # 初期化
186
- #
187
- # @param [Gengou] start_gengou 開始元号
188
- # @param [Western::Calendar] start_date 開始日
189
- # @param [Western::Calendar] end_date 終了日
190
- #
191
- def initialize(start_gengou:, start_date:, end_date:)
192
- @current_date = start_date.clone
193
- @end_date = end_date
194
- @year_list = []
195
- @western_year = start_date.year
196
- @year = Year.new(gengou: start_gengou)
197
- end
198
-
199
- #
200
- # 年データを収集する
201
- #
202
- # @return [Array<Year>] 年データ
203
- #
204
- def collect_year_list
205
- push_current_year
206
-
207
- # 2年目以降
208
- while @current_date <= @end_date
209
- compensate_last_year
210
-
211
- push_current_year
212
- end
213
-
214
- @year_list
215
- end
216
-
217
- private
218
-
219
- #
220
- # 1年データを収集する
221
- #
222
- # @return [Array<Month>] 1年データ
223
- #
224
- def collect_annual_data
225
- AnnualData.collect_annual_data_after_last_november_1st(
226
- western_year: @western_year
227
- )
228
- end
229
-
230
- #
231
- # 昨年データの不足分を補完する
232
- # 昨年11月1日から今年1月1日の前日のデータを1年前データとする
233
- #
234
- # @return [<Type>] <description>
235
- #
236
- def compensate_last_year
237
- last_year = @year_list[@year_list.size - 1]
238
- collect_annual_data.each do |month|
239
- next unless month.is_last_year
240
-
241
- # 昨年の月データのみ
242
- last_year.push(month: month)
243
- @current_date += month.days
244
- end
245
- end
246
-
247
- # :reek:TooManyStatements { max_statements: 7 }
248
-
249
- #
250
- # 当年データを生成する
251
- #
252
- def push_current_year
253
- next_year
254
- collect_annual_data.each do |month|
255
- next if month.is_last_year
256
-
257
- @year.push(month: month)
258
- @current_date += month.days
259
- end
260
- @year_list.push(@year)
261
-
262
- @western_year += 1
263
- end
264
-
265
- #
266
- # 次の元号年を取得する
267
- #
268
- def next_year
269
- return if @year_list.empty?
270
-
271
- @year = Year.new(gengou: @year.gengou.next_year)
272
- end
273
- end
274
-
275
- #
276
- # 期間内の年データ全てを返す
277
- #
278
- # @param [Gengou] start_gengou 開始元号
279
- # @param [Western::Calendar] start_date 開始日
280
- # @param [Western::Calendar] end_date 終了日
281
- #
282
- # @return [Array<Year>] 年データ
283
- #
284
- def self.get_year_list(start_gengou:, start_date:, end_date:)
285
- advance = TimeAdvance.new(
286
- start_gengou: start_gengou, start_date: start_date, end_date: end_date
287
- )
288
-
289
- advance.collect_year_list
290
- end
291
- end
292
- end
293
- end
294
- end