@@ -919,6 +919,9 @@ defmodule Calendar.ISO do
919919 end
920920 end
921921
922+ defp floor_div_positive_divisor ( int1 , int2 ) when int1 >= 0 , do: div ( int1 , int2 )
923+ defp floor_div_positive_divisor ( int1 , int2 ) , do: - div ( - int1 - 1 , int2 ) - 1
924+
922925 @ doc """
923926 Returns how many days there are in the given year-month.
924927
@@ -1854,7 +1857,7 @@ defmodule Calendar.ISO do
18541857 months_in_year = 12
18551858 total_months = year * months_in_year + month + months - 1
18561859
1857- new_year = Integer . floor_div ( total_months , months_in_year )
1860+ new_year = floor_div_positive_divisor ( total_months , months_in_year )
18581861
18591862 new_month =
18601863 case rem ( total_months , months_in_year ) + 1 do
@@ -1977,7 +1980,7 @@ defmodule Calendar.ISO do
19771980
19781981 if total in @ unix_range_microseconds do
19791982 microseconds = Integer . mod ( total , @ microseconds_per_second )
1980- seconds = @ unix_epoch + Integer . floor_div ( total , @ microseconds_per_second )
1983+ seconds = @ unix_epoch + floor_div_positive_divisor ( total , @ microseconds_per_second )
19811984 precision = precision_for_unit ( unit )
19821985 { date , time } = iso_seconds_to_datetime ( seconds )
19831986 { :ok , date , time , { microseconds , precision } }
@@ -2106,9 +2109,8 @@ defmodule Calendar.ISO do
21062109 end
21072110
21082111 defp days_to_year ( days ) when days < 0 do
2109- # floor_div(days, n) = -div(-days - 1, n) - 1 for negative days
2110- y_min = - div ( - days - 1 , @ days_per_nonleap_year ) - 1
2111- y_max = - div ( - days - 1 , @ days_per_leap_year ) - 1
2112+ y_min = floor_div_positive_divisor ( days , @ days_per_nonleap_year )
2113+ y_max = floor_div_positive_divisor ( days , @ days_per_leap_year )
21122114
21132115 { year , day_start } =
21142116 days_to_year_interpolated (
@@ -2123,8 +2125,8 @@ defmodule Calendar.ISO do
21232125 end
21242126
21252127 defp days_to_year ( days ) do
2126- y_max = div ( days , @ days_per_nonleap_year )
2127- y_min = div ( days , @ days_per_leap_year )
2128+ y_min = floor_div_positive_divisor ( days , @ days_per_leap_year )
2129+ y_max = floor_div_positive_divisor ( days , @ days_per_nonleap_year )
21282130
21292131 { year , day_start } =
21302132 days_to_year_interpolated (
@@ -2147,13 +2149,7 @@ defmodule Calendar.ISO do
21472149 d_diff = d_max - d_min
21482150
21492151 numerator = diff * ( days - d_min )
2150-
2151- offset =
2152- if numerator >= 0 do
2153- div ( numerator , d_diff )
2154- else
2155- - div ( - numerator - 1 , d_diff ) - 1
2156- end
2152+ offset = floor_div_positive_divisor ( numerator , d_diff )
21572153
21582154 mid = min + max ( 0 , min ( offset , diff ) )
21592155 d_mid = days_in_previous_years ( mid )
0 commit comments