Skip to content

Commit

Permalink
Fix parsing of fractional durations (#13832)
Browse files Browse the repository at this point in the history
The parsing of fractional durations checked for non-negativity by
testing second > 0, which reports false for not only negative integers
but also for 0.

Note that changing `if second > 0` to `if second >= 0` would fix
behaviour for "PT0,6S", but would break "PT-0,6S".
  • Loading branch information
urmastalimaa authored and josevalim committed Sep 18, 2024
1 parent c996318 commit 86ec46a
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 1 deletion.
10 changes: 9 additions & 1 deletion lib/elixir/lib/calendar/iso.ex
Original file line number Diff line number Diff line change
Expand Up @@ -715,7 +715,15 @@ defmodule Calendar.ISO do
{second, <<delimiter, _::binary>> = rest} when delimiter in [?., ?,] ->
case parse_microsecond(rest) do
{{ms, precision}, "S"} ->
ms = if second > 0, do: ms, else: -ms
ms =
case string do
"-" <> _ ->
-ms

_ ->
ms
end

{:ok, [second: second, microsecond: {ms, precision}] ++ acc}

_ ->
Expand Down
5 changes: 5 additions & 0 deletions lib/elixir/test/elixir/calendar/duration_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -237,8 +237,10 @@ defmodule DurationTest do
assert Duration.from_iso8601("P4Y2W3Y") == {:error, :invalid_date_component}
assert Duration.from_iso8601("P5HT4MT3S") == {:error, :invalid_date_component}
assert Duration.from_iso8601("P5H3HT4M") == {:error, :invalid_date_component}
assert Duration.from_iso8601("P0.5Y") == {:error, :invalid_date_component}
assert Duration.from_iso8601("PT1D") == {:error, :invalid_time_component}
assert Duration.from_iso8601("PT.6S") == {:error, :invalid_time_component}
assert Duration.from_iso8601("PT0.5H") == {:error, :invalid_time_component}
assert Duration.from_iso8601("invalid") == {:error, :invalid_duration}
end

Expand All @@ -262,6 +264,9 @@ defmodule DurationTest do
assert Duration.from_iso8601!("PT6S") == %Duration{second: 6}
assert Duration.from_iso8601!("PT1,6S") == %Duration{second: 1, microsecond: {600_000, 1}}
assert Duration.from_iso8601!("PT-1.6S") == %Duration{second: -1, microsecond: {-600_000, 1}}
assert Duration.from_iso8601!("PT0,6S") == %Duration{second: 0, microsecond: {600_000, 1}}
assert Duration.from_iso8601!("PT-0,6S") == %Duration{second: 0, microsecond: {-600_000, 1}}
assert Duration.from_iso8601!("-PT-0,6S") == %Duration{second: 0, microsecond: {600_000, 1}}
assert Duration.from_iso8601!("-P10DT4H") == %Duration{day: -10, hour: -4}
assert Duration.from_iso8601!("-P10DT-4H") == %Duration{day: -10, hour: 4}
assert Duration.from_iso8601!("P-10D") == %Duration{day: -10}
Expand Down

0 comments on commit 86ec46a

Please sign in to comment.