@@ -208,23 +208,13 @@ defmodule Calendar.ISO do
208208
209209 # Converts count of days since 0000-01-01 to {year, month, day} tuple.
210210 @ doc false
211- @ doc since: "1.5.0"
212- def date_from_iso_days ( days ) when days in 0 .. 3_652_424 do
211+ def date_from_iso_days ( days ) when days in - 3_652_059 .. 3_652_424 do
213212 { year , day_of_year } = days_to_year ( days )
214213 extra_day = if leap_year? ( year ) , do: 1 , else: 0
215214 { month , day_in_month } = year_day_to_year_date ( extra_day , day_of_year )
216215 { year , month , day_in_month + 1 }
217216 end
218217
219- def date_from_iso_days ( days ) when days in - 3_652_059 .. - 1 do
220- { year , day_of_year } = days_to_year ( - days )
221- previous_extra_day = if leap_year? ( year ) , do: 1 , else: 0
222- extra_day = if leap_year? ( year + 1 ) , do: 1 , else: 0
223- day_of_year = @ days_per_nonleap_year + extra_day - day_of_year
224- { month , day_in_month } = year_day_to_year_date ( extra_day , day_of_year )
225- { - year - 1 , month , day_in_month + previous_extra_day }
226- end
227-
228218 defp div_mod ( int1 , int2 ) do
229219 div = div ( int1 , int2 )
230220 rem = int1 - div * int2
@@ -761,20 +751,44 @@ defmodule Calendar.ISO do
761751 if leap_year? ( year ) , do: 1 , else: 0
762752 end
763753
754+ defp days_to_year ( days ) when days < 0 do
755+ year_estimate = - div ( - days , @ days_per_nonleap_year ) - 1
756+
757+ { year , days_before_year } =
758+ days_to_year ( year_estimate , days , days_to_end_of_epoch ( year_estimate ) )
759+
760+ leap_year_pad = if leap_year? ( year ) , do: 1 , else: 0
761+ { year , leap_year_pad + @ days_per_nonleap_year + days - days_before_year }
762+ end
763+
764764 defp days_to_year ( days ) do
765- year = Integer . floor_div ( days , @ days_per_nonleap_year )
766- { year , days_before_year } = days_to_year ( year , days , days_in_previous_years ( year ) )
765+ year_estimate = div ( days , @ days_per_nonleap_year )
766+
767+ { year , days_before_year } =
768+ days_to_year ( year_estimate , days , days_in_previous_years ( year_estimate ) )
769+
767770 { year , days - days_before_year }
768771 end
769772
770- defp days_to_year ( year , days1 , days2 ) when days1 < days2 do
773+ defp days_to_year ( year , days1 , days2 ) when year < 0 and days1 >= days2 do
774+ days_to_year ( year + 1 , days1 , days_to_end_of_epoch ( year + 1 ) )
775+ end
776+
777+ defp days_to_year ( year , days1 , days2 ) when year >= 0 and days1 < days2 do
771778 days_to_year ( year - 1 , days1 , days_in_previous_years ( year - 1 ) )
772779 end
773780
774781 defp days_to_year ( year , _days1 , days2 ) do
775782 { year , days2 }
776783 end
777784
785+ defp days_to_end_of_epoch ( year ) when year < 0 do
786+ previous_year = year + 1
787+
788+ div ( previous_year , 4 ) - div ( previous_year , 100 ) + div ( previous_year , 400 ) +
789+ previous_year * @ days_per_nonleap_year
790+ end
791+
778792 defp days_in_previous_years ( 0 ) , do: 0
779793
780794 defp days_in_previous_years ( year ) do
0 commit comments