Skip to content

Commit c71580f

Browse files
author
Rick Hull
committed
provide ordinal_day to constructor if known
1 parent ef1b61b commit c71580f

File tree

1 file changed

+17
-16
lines changed

1 file changed

+17
-16
lines changed

lib/compsci/date.rb

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ def self.leap_days(year)
4141
MONTH_DAYS =
4242
[MON31, MON28, MON31, MON30, MON31, MON30,
4343
MON31, MON31, MON30, MON31, MON30, MON31].freeze
44-
NUM_MONTHS = 12 # MONTH_DAYS.size
4544

4645
# derive CUMULATIVE_DAYS from MONTH_DAYS, zero-indexed
4746
CUMULATIVE_DAYS = MONTH_DAYS.reduce([0]) { |acc, days|
@@ -53,7 +52,7 @@ def self.leap_days(year)
5352

5453
# implementation considerations
5554
MIN_Y, MIN_M, MIN_D = 1, 1, 1
56-
MAX_Y, MAX_M, MAX_D = 9999, NUM_MONTHS, MON31
55+
MAX_Y, MAX_M, MAX_D = 9999, MONTH_DAYS.size, MON31
5756

5857
DAYS_400 = 146097 # self.year_days(400)
5958
DAYS_100 = 36524 # self.year_days(100)
@@ -76,8 +75,8 @@ def self.year_days(years)
7675

7776
# given a day count, what is the current year?
7877
# despite leap years, never guess too low, only too high
79-
def self.guess_year(days)
80-
((days - 1) / MEAN_ANNUAL_DAYS).round + 1
78+
def self.guess_year(day_count)
79+
((day_count - 1) / MEAN_ANNUAL_DAYS).round + 1
8180
end
8281

8382
# perform lookup by month number and year, one-indexed, with leap days
@@ -107,7 +106,7 @@ def self.month_and_day(day_of_year, year)
107106
month_days = self.cumulative_days(month, year)
108107

109108
# rewind the guess by one month if needed
110-
if month > 1 and month_days >= day_of_year
109+
if month > MIN_M and month_days >= day_of_year
111110
month -= 1
112111
month_days = self.cumulative_days(month, year)
113112
end
@@ -121,17 +120,17 @@ def self.annual_days(year)
121120
end
122121

123122
# convert days to current year with days remaining
124-
def self.year_and_day(days)
125-
year = self.guess_year(days)
123+
def self.year_and_day(day_count)
124+
year = self.guess_year(day_count)
126125
year_days = self.year_days(year - 1)
127126

128127
# rewind the guess as needed
129-
while year > 1 and year_days >= days
128+
while year > MIN_Y and year_days >= day_count
130129
year -= 1
131130
year_days -= self.annual_days(year)
132131
end
133132

134-
[year, days - year_days]
133+
[year, day_count - year_days]
135134
end
136135

137136
#
@@ -146,11 +145,13 @@ def self.to_ordinal(year, month, day)
146145
end
147146

148147
# convert days since epoch back to Date
149-
def self.from_ordinal(days)
150-
raise(RuntimeError, "days should be positive: #{days}") unless days > 0
151-
year, days = self.year_and_day(days)
152-
month, day = self.month_and_day(days, year)
153-
Date.new(year, month, day)
148+
def self.from_ordinal(day_count)
149+
unless day_count > 0
150+
raise(RuntimeError, "day_count should be positive: #{day_count}")
151+
end
152+
year, annual_days = self.year_and_day(day_count)
153+
month, day = self.month_and_day(annual_days, year)
154+
Date.new(year:, month:, day:, ordinal_day: day_count)
154155
end
155156

156157
#
@@ -184,7 +185,7 @@ def self.month_name(number)
184185

185186
attr_reader :ordinal_day
186187

187-
def initialize(year:, month:, day:)
188+
def initialize(year:, month:, day:, ordinal_day: nil)
188189
# validate year
189190
raise(InvalidYear, year) unless (MIN_Y..MAX_Y).cover?(year)
190191

@@ -205,7 +206,7 @@ def initialize(year:, month:, day:)
205206
raise(InvalidDay, day) unless (MIN_D..max_days).cover?(day)
206207

207208
@leap_year = Date.leap_year?(year)
208-
@ordinal_day = Date.to_ordinal(year, month, day)
209+
@ordinal_day = ordinal_day || Date.to_ordinal(year, month, day)
209210

210211
super(year:, month:, day:)
211212
end

0 commit comments

Comments
 (0)