zakuro 0.4.0 → 0.5.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.
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ # :nodoc:
4
+ module Zakuro
5
+ # :nodoc:
6
+ module Genka
7
+ #
8
+ # Const 定数
9
+ #
10
+ module Const
11
+ #
12
+ # Number 数値
13
+ #
14
+ module Number
15
+ #
16
+ # Cycle 周期
17
+ #
18
+ module Cycle
19
+ # @return [Integer] 日法(1日=752分)
20
+ DAY = 752
21
+ # @return [Integer] 度法(1日=304分)
22
+ TERM_DAY = 304
23
+ # @return [Integer] 朔望月
24
+ SYNODIC_MONTH = 22_207
25
+ end
26
+
27
+ #
28
+ # 累積
29
+ #
30
+ module Stack
31
+ # @return [Integer] 積年(甲子夜半朔旦冬至〜暦の開始前)
32
+ TOTAL_YEAR = 5703
33
+ # @return [Integer] 暦の開始年(元嘉20年)
34
+ BEGIN_YEAR = 443
35
+ # @return [Integer] 西暦0年の積年
36
+ WESTERN_YEAR = 1612
37
+ # @return [Integer] 余数
38
+ YEAR_REMAINDER = 1595
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../cycle/remainder'
4
+
5
+ # :nodoc:
6
+ module Zakuro
7
+ # :nodoc:
8
+ module Genka
9
+ #
10
+ # Const 定数
11
+ #
12
+ module Const
13
+ #
14
+ # Remainder 大余小余
15
+ #
16
+ module Remainder
17
+ #
18
+ # @note 『歴代天文律暦等志彙編 六』中華書房 p.1727
19
+ # 「推弦望法..加朔大餘七,小餘二百八十七,小分三,小分満四從小餘」
20
+ #
21
+ # @return [Cycle::Remainder] 弦(1分=4秒)
22
+ QUARTER = Cycle::Remainder.new(day: 7, minute: 287, second: 3)
23
+
24
+ #
25
+ # @note 『歴代天文律暦等志彙編 六』中華書房 p.1727
26
+ # 「推二十四氣術」「求次氣,加朔大餘十五,小餘六十六,小分十一,小分満氣法從小餘,小餘満度法從大餘」
27
+ #
28
+ # @return [Cycle::Remainder] 気策(24分の1年)
29
+ SOLAR_TERM_AVERAGE = Cycle::TermRemainder.new(day: 15, minute: 66 + 11.0 / 24, second: 0)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../../calculation/cycle/abstract_remainder'
4
+
5
+ require_relative '../const/number'
6
+
7
+ # :nodoc:
8
+ module Zakuro
9
+ # :nodoc:
10
+ module Genka
11
+ # :nodoc:
12
+ module Cycle
13
+ #
14
+ # Remainder 時刻情報(大余小余)
15
+ #
16
+ class Remainder < Calculation::Cycle::AbstractRemainder
17
+ #
18
+ # @note 『歴代天文律暦等志彙編 六』中華書房 p.1727
19
+ # 「推弦望法..加朔大餘七,小餘二百八十七,小分三,小分満四從小餘」
20
+ #
21
+ # @return [Integer] 分(1分=4秒)
22
+ MINUTE = 4
23
+
24
+ #
25
+ # 初期化
26
+ #
27
+ # @param [Integer] day 大余("日"に相当)
28
+ # @param [Integer] minute 小余("分"に相当)
29
+ # @param [Integer] second 秒
30
+ # @param [Integer] total 繰り上げなしの小余
31
+ #
32
+ def initialize(day: -1, minute: -1, second: -1, total: -1)
33
+ super(base_day: Const::Number::Cycle::DAY, base_mitune: MINUTE,
34
+ day: day, minute: minute, second: second, total: total)
35
+ end
36
+
37
+ #
38
+ # 特定の文字フォーマットにして出力する
39
+ #
40
+ # @return [String] フォーマットした結果
41
+ #
42
+ def format(form: '%.4f', digit: 4)
43
+ return '' if invalid?
44
+
45
+ decimal = @day + @minute / @base_day.to_f
46
+ super(form, decimal.round(digit))
47
+ end
48
+ end
49
+
50
+ #
51
+ # TermRemainder 時刻情報(大余小余)
52
+ #
53
+ class TermRemainder < Calculation::Cycle::AbstractRemainder
54
+ #
55
+ # @note 『歴代天文律暦等志彙編 六』中華書房 p.1726
56
+ # 「氣法,二十四」
57
+ #
58
+ # @return [Integer] 分(1分=24秒)
59
+ MINUTE = 24
60
+
61
+ #
62
+ # 初期化
63
+ #
64
+ # @param [Integer] day 大余("日"に相当)
65
+ # @param [Integer] minute 小余("分"に相当)
66
+ # @param [Integer] second 秒
67
+ # @param [Integer] total 繰り上げなしの小余
68
+ #
69
+ def initialize(day: -1, minute: -1, second: -1, total: -1)
70
+ super(base_day: Const::Number::Cycle::TERM_DAY, base_mitune: MINUTE,
71
+ day: day, minute: minute, second: second, total: total)
72
+ end
73
+
74
+ #
75
+ # 特定の文字フォーマットにして出力する
76
+ #
77
+ # @return [String] フォーマットした結果
78
+ #
79
+ def format(form: '%.4f', digit: 4)
80
+ return '' if invalid?
81
+
82
+ decimal = @day + @minute / @base_day.to_f
83
+ # NOTE: roundなしで format を使用した場合は、四捨五入が正しく実行されないことが判明した
84
+ # 具体的には、468年の中気は '55.7813' だが '55.7812' になる
85
+ # これは '55.7812500' を4桁にした際に、境界値の少数点以下5桁目の '5' が切り捨てを受けたためである
86
+ # format による四捨五入は避け、roundによる四捨五入を採用する
87
+ super(form, decimal.round(digit))
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../../calculation/cycle/abstract_solar_term'
4
+
5
+ require_relative '../const/remainder'
6
+
7
+ require_relative './remainder'
8
+
9
+ # :nodoc:
10
+ module Zakuro
11
+ # :nodoc:
12
+ module Genka
13
+ # :nodoc:
14
+ module Cycle
15
+ #
16
+ # SolarTerm 二十四節気
17
+ #
18
+ class SolarTerm < Calculation::Cycle::AbstractSolarTerm
19
+ # @return [Remainder] 気策(24分の1年)
20
+ SOLAR_TERM_AVERAGE = Const::Remainder::SOLAR_TERM_AVERAGE
21
+
22
+ #
23
+ # 初期化
24
+ #
25
+ # @param [Integer] index 連番
26
+ # @param [Remainder] remainder 時刻情報(大余小余)
27
+ #
28
+ def initialize(index: -1, remainder: TermRemainder.new)
29
+ super(index: index, remainder: remainder, average: SOLAR_TERM_AVERAGE)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -12,8 +12,25 @@ module Zakuro
12
12
  # Gateway アクセサメソッド群
13
13
  #
14
14
  class Gateway < AbstractVersion
15
- # @return [False] リリースなし
16
- RELEASE = false
15
+ # @return [True] リリースあり
16
+ RELEASE = true
17
+
18
+ # @return [String] 暦クラス名
19
+ VERSION_NAME = 'Genka'
20
+
21
+ #
22
+ # 西暦日から和暦日に変換する
23
+ #
24
+ # @param [Date] western_date 西暦日
25
+ #
26
+ # @return [Result::Single] 和暦日
27
+ #
28
+ def self.to_japan_date(western_date:)
29
+ date = Western::Calendar.create(date: western_date)
30
+
31
+ context = Context.new(version_name: VERSION_NAME)
32
+ Calculation::Summary::Single.get(context: context, date: date)
33
+ end
17
34
  end
18
35
  end
19
36
  end
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../const/remainder'
4
+
5
+ require_relative '../cycle/solar_term'
6
+
7
+ require_relative '../stella/origin/first_term'
8
+
9
+ require_relative '../stella/origin/january'
10
+
11
+ # :nodoc:
12
+ module Zakuro
13
+ # :nodoc:
14
+ module Genka
15
+ # :nodoc:
16
+ module Monthly
17
+ #
18
+ # LunarPhase 月の位相
19
+ #
20
+ class LunarPhase
21
+ # @return [Cycle::Remainder] 弦
22
+ QUARTER = Const::Remainder::QUARTER
23
+
24
+ # TODO: AbstractLunarPhase でも使用している
25
+
26
+ # @return [Array<String>] 月内の弦
27
+ PHASE_INDEXES = %w[朔日 上弦 望月 下弦].freeze
28
+
29
+ # @return [Cycle::AbstractRemainder] 経
30
+ attr_reader :remainder
31
+
32
+ #
33
+ # 初期化
34
+ #
35
+ # @param [Cycle::Remainder] remainder 正月経朔
36
+ #
37
+ def initialize(remainder:)
38
+ # 経
39
+ @remainder = remainder
40
+
41
+ # 弦の位置
42
+ @index = 0
43
+ end
44
+
45
+ #
46
+ # 次の弦に進める
47
+ #
48
+ # @return [Remainder] 定朔
49
+ #
50
+ def next_phase
51
+ adjusted = remainder.clone
52
+
53
+ add_quarter_moon_size
54
+
55
+ adjusted
56
+ end
57
+
58
+ #
59
+ # 次の月に進める
60
+ # @note 進めた後の月の定朔ではなく、当月のものを返却する
61
+ #
62
+ # @return [Remainder] 当月初の定朔
63
+ #
64
+ def next_month
65
+ result = nil
66
+ PHASE_INDEXES.each_with_index do |_phase, index|
67
+ adjust = next_phase
68
+ result = adjust if index.zero?
69
+ end
70
+
71
+ result
72
+ end
73
+
74
+ private
75
+
76
+ #
77
+ # 次の弦に進める
78
+ #
79
+ # @return [Integer] 弦
80
+ #
81
+ def next_index
82
+ @index += 1
83
+ @index = 0 if @index >= PHASE_INDEXES.size
84
+ @index
85
+ end
86
+
87
+ def add_quarter_moon_size
88
+ @remainder.add!(QUARTER)
89
+
90
+ next_index
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../../calculation/range/medieval_annual_range'
4
+ require_relative '../../../output/logger'
5
+ require_relative '../monthly/lunar_phase'
6
+ require_relative '../stella/solar/average'
7
+
8
+ # :nodoc:
9
+ module Zakuro
10
+ # :nodoc:
11
+ module Genka
12
+ # :nodoc:
13
+ module Range
14
+ #
15
+ # AnnualRange 年間範囲
16
+ #
17
+ module AnnualRange
18
+ # @return [Output::Logger] ロガー
19
+ LOGGER = Output::Logger.new(location: 'annual_range')
20
+
21
+ #
22
+ # 一覧取得する
23
+ #
24
+ # * 対象年に対して、当年1月-翌年1月までを出力する
25
+ # * 対象年(西暦)と計算年(元号x年)の紐付けは行わない
26
+ #
27
+ # @param [Context] context 暦コンテキスト
28
+ # @param [Integer] western_year 西暦年
29
+ #
30
+ # @return [Array<Month>] 1年データ
31
+ #
32
+ def self.get(context:, western_year:)
33
+ # 正月中気
34
+ solar_term = Cycle::SolarTerm.new(
35
+ index: 4, remainder: Origin::FirstTerm.get(western_year: western_year)
36
+ )
37
+ # 正月に立春が含まれる可能性があるので、立春まで戻しておく
38
+ solar_term.prev_term!
39
+
40
+ # 経
41
+ remainder = Origin::January.get(western_year: western_year)
42
+
43
+ lunar_phase = Monthly::LunarPhase.new(remainder: remainder)
44
+
45
+ solar_average = Solar::Average.new(solar_term: solar_term)
46
+
47
+ annual_range = Calculation::Range::MedievalAnnualRange.get(
48
+ context: context, lunar_phase: lunar_phase, solar_average: solar_average
49
+ )
50
+
51
+ pop_months_on_next_year(annual_range: annual_range)
52
+ end
53
+
54
+ #
55
+ # 来年の月を除去する
56
+ #
57
+ # @param [Array<Month>] annual_range 1年データ
58
+ #
59
+ # @return [Array<Month>] 1年データ
60
+ #
61
+ def self.pop_months_on_next_year(annual_range:)
62
+ result = []
63
+ number = 0
64
+ annual_range.each do |month|
65
+ # 来年
66
+ break if number > month.month_label.number
67
+
68
+ number = month.month_label.number
69
+ result.push(month)
70
+ end
71
+
72
+ result
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../const/number'
4
+ require_relative '../../cycle/remainder'
5
+
6
+ # :nodoc:
7
+ module Zakuro
8
+ # :nodoc:
9
+ module Genka
10
+ # :nodoc:
11
+ module Origin
12
+ #
13
+ # FirstTerm 年初の中気(正月中雨水)
14
+ #
15
+ module FirstTerm
16
+ # @return [Integer] 二十四節気の1日
17
+ TERM_DAY = Const::Number::Cycle::TERM_DAY
18
+ # @return [Float] 余数
19
+ YEAR_REMAINDER = Const::Number::Stack::YEAR_REMAINDER.to_f
20
+ # @return [Integer] 西暦0年の積年
21
+ WESTERN_YEAR = Const::Number::Stack::WESTERN_YEAR
22
+
23
+ #
24
+ # 年初の中気(正月中雨水)を求める
25
+ #
26
+ # @note 計算は宋書(1)に従う。念のため『日本暦日原典』(2)と比較する
27
+ # 1. (1612 + 西暦年) * 餘数(1595) / 度法(304) = A' ...余りが中気の小余
28
+ # A' / 60 = B' ...余りが朔の大余
29
+ # 『歴代天文律暦等志彙編 六』中華書房 p.1728
30
+ #
31
+ # 2. (1612 + x) * 222070 / 608 = A' ...余りが中気の小余
32
+ # A' / 60 = B' ...余りが朔の大余
33
+ #
34
+ # 小余上限(度法)の違いで、宋書に従ったほうが良いと判断した。分母が変わるだけで結果に相違はない
35
+ #
36
+ # @param [Integer] western_year 西暦年
37
+ #
38
+ # @return [Remainder] 年初の中気(正月中雨水)
39
+ #
40
+ def self.get(western_year:)
41
+ total_western_year = WESTERN_YEAR + western_year
42
+ # (1612 + x) * 222070 / 608 = A' ...余りが中気の小余
43
+ stack = (total_western_year * YEAR_REMAINDER / TERM_DAY).to_i
44
+ minute = (total_western_year * YEAR_REMAINDER % TERM_DAY).to_i
45
+ # A' / 60 = B' ...余りが朔の大余
46
+ day = stack % Cycle::TermRemainder::LIMIT
47
+ # p stack
48
+ # p minute
49
+ # p day
50
+ Cycle::TermRemainder.new(day: day, minute: minute, second: 0)
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../const/number'
4
+ require_relative '../../cycle/remainder'
5
+
6
+ # :nodoc:
7
+ module Zakuro
8
+ # :nodoc:
9
+ module Genka
10
+ # :nodoc:
11
+ module Origin
12
+ #
13
+ # January 1月
14
+ #
15
+ module January
16
+ # @return [Integer] 日法
17
+ DAY = Const::Number::Cycle::DAY
18
+ # @return [Float] 朔望月
19
+ SYNODIC_MONTH = Const::Number::Cycle::SYNODIC_MONTH.to_f
20
+ # @return [Integer] 西暦0年の積年
21
+ WESTERN_YEAR = Const::Number::Stack::WESTERN_YEAR
22
+ # @return [Float] 19年=235朔望月
23
+ METONIC_CYCLE = 235 / 19.to_f
24
+
25
+ #
26
+ # 1月経朔を求める
27
+ #
28
+ # @param [Integer] western_year 西暦年
29
+ #
30
+ # @return [Remainder] 11月経朔
31
+ #
32
+ def self.get(western_year:)
33
+ # (1612 + x) * 235 / 19 = A ...余り
34
+ stack = ((WESTERN_YEAR + western_year) * METONIC_CYCLE).to_i
35
+ # A * 22207 / 752 = B ...余りが朔の小余
36
+ minute_total = (stack * SYNODIC_MONTH / DAY).to_i
37
+ minute = (stack * SYNODIC_MONTH % DAY).to_i
38
+ # B / 60 = C ...余りが朔の大余
39
+ day = minute_total % Cycle::Remainder::LIMIT
40
+ # p stack
41
+ # p minute_total
42
+ # p minute
43
+ # p day
44
+ Cycle::Remainder.new(day: day, minute: minute, second: 0)
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../../../calculation/stella/solar/abstract_average'
4
+
5
+ require_relative '../../const/remainder'
6
+
7
+ require_relative '../../cycle/solar_term'
8
+
9
+ # :nodoc:
10
+ module Zakuro
11
+ # :nodoc:
12
+ module Genka
13
+ # :nodoc:
14
+ module Solar
15
+ #
16
+ # Average 平気(太陽軌道平均)
17
+ #
18
+ class Average < Calculation::Solar::AbstractAverage
19
+ #
20
+ # 初期化
21
+ #
22
+ # @param [Integer] western_year 西暦年
23
+ #
24
+ def initialize(solar_term:)
25
+ super(solar_term: solar_term)
26
+ end
27
+
28
+ #
29
+ # 冬至から数えた1年データの月ごとに二十四節気を割り当てる
30
+ #
31
+ # @param [Array<Month>] annual_range 1年データ
32
+ #
33
+ # @return [Array<Month>] 1年データ
34
+ #
35
+ def set(annual_range:)
36
+ super(annual_range: annual_range)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -29,6 +29,19 @@ module Zakuro
29
29
  super(base_day: Const::Number::Cycle::DAY, base_mitune: MINUTE,
30
30
  day: day, minute: minute, second: second, total: total)
31
31
  end
32
+
33
+ #
34
+ # 特定の文字フォーマットにして出力する
35
+ #
36
+ # @param [String] form フォーマット(大余、小余、秒それぞれを%dで指定する)
37
+ #
38
+ # @return [String] フォーマットした結果
39
+ #
40
+ def format(form: '%d-%d')
41
+ return '' if invalid?
42
+
43
+ super(form, @day, @minute, @second)
44
+ end
32
45
  end
33
46
 
34
47
  #
@@ -50,6 +63,19 @@ module Zakuro
50
63
  super(base_day: Const::Number::Cycle::DAY, base_mitune: MINUTE,
51
64
  day: day, minute: minute, second: second, total: total)
52
65
  end
66
+
67
+ #
68
+ # 特定の文字フォーマットにして出力する
69
+ #
70
+ # @param [String] form フォーマット(大余、小余、秒それぞれを%dで指定する)
71
+ #
72
+ # @return [String] フォーマットした結果
73
+ #
74
+ def format(form: '%d-%d')
75
+ return '' if invalid?
76
+
77
+ super(form, @day, @minute, @second)
78
+ end
53
79
  end
54
80
  end
55
81
  end
@@ -55,7 +55,7 @@ module Zakuro
55
55
  # 二十四節気(冬至)
56
56
  solar_term = Cycle::SolarTerm.new(index: 0, remainder: winter_solstice)
57
57
 
58
- first_solar_term_index = Average.calc_fist_solar_term_index(western_year: western_year)
58
+ first_solar_term_index = Average.calc_first_solar_term_index(western_year: western_year)
59
59
 
60
60
  # 対象の二十四節気まで戻す
61
61
  solar_term.prev_by_index(first_solar_term_index)
@@ -77,7 +77,7 @@ module Zakuro
77
77
  #
78
78
  # @return [Integer] 二十四節気番号
79
79
  #
80
- def self.calc_fist_solar_term_index(western_year:)
80
+ def self.calc_first_solar_term_index(western_year:)
81
81
  # 天正閏余
82
82
  lunar_age = Origin::LunarAge.get(western_year: western_year)
83
83
 
@@ -29,6 +29,19 @@ module Zakuro
29
29
  super(base_day: Const::Number::Cycle::DAY, base_mitune: MINUTE,
30
30
  day: day, minute: minute, second: second, total: total)
31
31
  end
32
+
33
+ #
34
+ # 特定の文字フォーマットにして出力する
35
+ #
36
+ # @param [String] form フォーマット(大余、小余、秒それぞれを%dで指定する)
37
+ #
38
+ # @return [String] フォーマットした結果
39
+ #
40
+ def format(form: '%d-%d')
41
+ return '' if invalid?
42
+
43
+ super(form, @day, @minute, @second)
44
+ end
32
45
  end
33
46
 
34
47
  #
@@ -50,6 +63,19 @@ module Zakuro
50
63
  super(base_day: Const::Number::Cycle::DAY, base_mitune: MINUTE,
51
64
  day: day, minute: minute, second: second, total: total)
52
65
  end
66
+
67
+ #
68
+ # 特定の文字フォーマットにして出力する
69
+ #
70
+ # @param [String] form フォーマット(大余、小余、秒それぞれを%dで指定する)
71
+ #
72
+ # @return [String] フォーマットした結果
73
+ #
74
+ def format(form: '%d-%d')
75
+ return '' if invalid?
76
+
77
+ super(form, @day, @minute, @second)
78
+ end
53
79
  end
54
80
  end
55
81
  end
@@ -55,7 +55,7 @@ module Zakuro
55
55
  # 二十四節気(冬至)
56
56
  solar_term = Cycle::SolarTerm.new(index: 0, remainder: winter_solstice)
57
57
 
58
- first_solar_term_index = Average.calc_fist_solar_term_index(western_year: western_year)
58
+ first_solar_term_index = Average.calc_first_solar_term_index(western_year: western_year)
59
59
 
60
60
  # 対象の二十四節気まで戻す
61
61
  solar_term.prev_by_index(first_solar_term_index)
@@ -77,7 +77,7 @@ module Zakuro
77
77
  #
78
78
  # @return [Integer] 二十四節気番号
79
79
  #
80
- def self.calc_fist_solar_term_index(western_year:)
80
+ def self.calc_first_solar_term_index(western_year:)
81
81
  # 天正閏余
82
82
  lunar_age = Origin::LunarAge.get(western_year: western_year)
83
83
 
@@ -1,5 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative './genka/cycle/remainder'
4
+ require_relative './genka/cycle/solar_term'
5
+ require_relative './genka/range/annual_range'
6
+
3
7
  require_relative './gihou/cycle/remainder'
4
8
  require_relative './gihou/cycle/solar_term'
5
9
  require_relative './gihou/range/annual_range'
@@ -3,5 +3,5 @@
3
3
  # :nodoc:
4
4
  module Zakuro
5
5
  # @return [String] library version
6
- VERSION = '0.4.0'
6
+ VERSION = '0.5.0'
7
7
  end