Module: Sekki24::Lunisolar::Calendar

Defined in:
lib/sekki24/lunisolar/calendar.rb

Constant Summary collapse

LEAP_MONTH_RULE =
:winter_solstice_priority
MIN_LUNISOLAR_YEAR =
MIN_YEAR - 1
MAX_LUNISOLAR_YEAR =
MAX_YEAR

Class Method Summary collapse

Class Method Details

.clear_cache!Object



71
72
73
74
75
76
77
# File 'lib/sekki24/lunisolar/calendar.rb', line 71

def clear_cache!
  @cache_mutex.synchronize do
    @range_cache.clear
    @year_cache.clear
  end
  MonthBuilder.clear_cache!
end

.convert(value, tz:) ⇒ Object

Raises:



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/sekki24/lunisolar/calendar.rb', line 18

def convert(value, tz:)
  local_date = local_date(value, tz)
  validate_gregorian_year(local_date.year)
  month = generated_range(local_date.year, tz).find { |entry| entry.include?(local_date) }
  raise Error, "could not assign lunisolar month for #{local_date}" unless month

  Date.new(
    year: month.year,
    month: month.month,
    day: (local_date - month.start_date).to_i + 1,
    leap: month.leap?,
    gregorian_date: local_date,
    month_length: month.length
  )
end

.to_gregorian(year, month, day, leap:, tz:) ⇒ Object



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/sekki24/lunisolar/calendar.rb', line 47

def to_gregorian(year, month, day, leap:, tz:)
  lunar_year = validate_lunar_year(year)
  month_number = Integer(month)
  day_number = Integer(day)
  raise ArgumentError, "leap must be true or false" unless [true, false].include?(leap)
  unless (1..12).cover?(month_number)
    raise ArgumentError, "lunar month must be between 1 and 12"
  end

  target = self.year(lunar_year, tz: tz).find do |entry|
    entry.month == month_number && entry.leap? == leap
  end
  raise ArgumentError, "lunisolar month does not exist" unless target
  unless (1..target.length).cover?(day_number)
    raise ArgumentError, "lunar day must be between 1 and #{target.length}"
  end

  result = target.start_date + day_number - 1
  validate_gregorian_year(result.year)
  result
rescue TypeError
  raise ArgumentError, "lunar month and day must be Integers"
end

.year(year, tz:) ⇒ Object



34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/sekki24/lunisolar/calendar.rb', line 34

def year(year, tz:)
  lunar_year = validate_lunar_year(year)
  cache_key = [lunar_year, TimeScale.timezone_key(tz)].freeze
  cached = @cache_mutex.synchronize { @year_cache[cache_key] }
  return cached if cached

  months = generated_range(lunar_year, tz).select { |month| month.year == lunar_year }.freeze
  unless [12, 13].include?(months.length)
    raise Error, "expected 12 or 13 lunisolar months for #{lunar_year}, got #{months.length}"
  end
  @cache_mutex.synchronize { @year_cache[cache_key] ||= months }
end