Skip to content

Commit c4b42dd

Browse files
authored
Add unit fast paths to Calendar.ISO.iso_days_to_unit/2 (#15771)
Assisted-by: Claude Code:claude-fable-5 Signed-off-by: Thomas Cioppettini <544875+tomciopp@users.noreply.github.com>
1 parent 15572f5 commit c4b42dd

2 files changed

Lines changed: 33 additions & 4 deletions

File tree

lib/elixir/lib/calendar/iso.ex

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2115,10 +2115,24 @@ defmodule Calendar.ISO do
21152115
end
21162116

21172117
@doc false
2118-
def iso_days_to_unit({days, {parts, ppd}}, unit) do
2119-
day_microseconds = days * @parts_per_day
2120-
microseconds = divide_by_parts_per_day(parts, ppd)
2121-
System.convert_time_unit(day_microseconds + microseconds, :microsecond, unit)
2118+
def iso_days_to_unit(iso_days, :second) do
2119+
floor_div_positive_divisor(iso_days_to_microseconds(iso_days), @microseconds_per_second)
2120+
end
2121+
2122+
def iso_days_to_unit(iso_days, :millisecond) do
2123+
floor_div_positive_divisor(iso_days_to_microseconds(iso_days), 1_000)
2124+
end
2125+
2126+
def iso_days_to_unit(iso_days, :microsecond) do
2127+
iso_days_to_microseconds(iso_days)
2128+
end
2129+
2130+
def iso_days_to_unit(iso_days, unit) do
2131+
System.convert_time_unit(iso_days_to_microseconds(iso_days), :microsecond, unit)
2132+
end
2133+
2134+
defp iso_days_to_microseconds({days, {parts, ppd}}) do
2135+
days * @parts_per_day + divide_by_parts_per_day(parts, ppd)
21222136
end
21232137

21242138
@doc false

lib/elixir/test/elixir/calendar/datetime_test.exs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,21 @@ defmodule DateTimeTest do
491491
assert DateTime.to_unix(min_datetime) == -377_705_116_800
492492
end
493493

494+
test "to_unix/2 with non-default units floors pre-epoch datetimes" do
495+
datetime = ~U[1969-12-31 23:59:59.999999Z]
496+
497+
assert DateTime.to_unix(datetime, :second) == -1
498+
assert DateTime.to_unix(datetime, :millisecond) == -1
499+
assert DateTime.to_unix(datetime, :microsecond) == -1
500+
assert DateTime.to_unix(datetime, :nanosecond) == -1_000
501+
502+
assert DateTime.from_unix!(-17_412_508_654_473, :millisecond)
503+
|> DateTime.to_unix(:millisecond) == -17_412_508_654_473
504+
505+
assert DateTime.from_unix!(1_000_000_123, :millisecond)
506+
|> DateTime.to_unix(:millisecond) == 1_000_000_123
507+
end
508+
494509
test "compare/2" do
495510
datetime1 = %DateTime{
496511
year: 2000,

0 commit comments

Comments
 (0)