@@ -41,7 +41,6 @@ def self.leap_days(year)
41
41
MONTH_DAYS =
42
42
[ MON31 , MON28 , MON31 , MON30 , MON31 , MON30 ,
43
43
MON31 , MON31 , MON30 , MON31 , MON30 , MON31 ] . freeze
44
- NUM_MONTHS = 12 # MONTH_DAYS.size
45
44
46
45
# derive CUMULATIVE_DAYS from MONTH_DAYS, zero-indexed
47
46
CUMULATIVE_DAYS = MONTH_DAYS . reduce ( [ 0 ] ) { |acc , days |
@@ -53,7 +52,7 @@ def self.leap_days(year)
53
52
54
53
# implementation considerations
55
54
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
57
56
58
57
DAYS_400 = 146097 # self.year_days(400)
59
58
DAYS_100 = 36524 # self.year_days(100)
@@ -76,8 +75,8 @@ def self.year_days(years)
76
75
77
76
# given a day count, what is the current year?
78
77
# 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
81
80
end
82
81
83
82
# 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)
107
106
month_days = self . cumulative_days ( month , year )
108
107
109
108
# 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
111
110
month -= 1
112
111
month_days = self . cumulative_days ( month , year )
113
112
end
@@ -121,17 +120,17 @@ def self.annual_days(year)
121
120
end
122
121
123
122
# 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 )
126
125
year_days = self . year_days ( year - 1 )
127
126
128
127
# rewind the guess as needed
129
- while year > 1 and year_days >= days
128
+ while year > MIN_Y and year_days >= day_count
130
129
year -= 1
131
130
year_days -= self . annual_days ( year )
132
131
end
133
132
134
- [ year , days - year_days ]
133
+ [ year , day_count - year_days ]
135
134
end
136
135
137
136
#
@@ -146,11 +145,13 @@ def self.to_ordinal(year, month, day)
146
145
end
147
146
148
147
# 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 )
154
155
end
155
156
156
157
#
@@ -184,7 +185,7 @@ def self.month_name(number)
184
185
185
186
attr_reader :ordinal_day
186
187
187
- def initialize ( year :, month :, day :)
188
+ def initialize ( year :, month :, day :, ordinal_day : nil )
188
189
# validate year
189
190
raise ( InvalidYear , year ) unless ( MIN_Y ..MAX_Y ) . cover? ( year )
190
191
@@ -205,7 +206,7 @@ def initialize(year:, month:, day:)
205
206
raise ( InvalidDay , day ) unless ( MIN_D ..max_days ) . cover? ( day )
206
207
207
208
@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 )
209
210
210
211
super ( year :, month :, day :)
211
212
end
0 commit comments