From 86ec46a5c4ca5556dccde127b55b0e2e2eca18a8 Mon Sep 17 00:00:00 2001 From: Urmas Talimaa Date: Wed, 18 Sep 2024 10:03:36 +0300 Subject: [PATCH] Fix parsing of fractional durations (#13832) 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". --- lib/elixir/lib/calendar/iso.ex | 10 +++++++++- lib/elixir/test/elixir/calendar/duration_test.exs | 5 +++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/lib/elixir/lib/calendar/iso.ex b/lib/elixir/lib/calendar/iso.ex index dca389bc2a4..d016bf8113b 100644 --- a/lib/elixir/lib/calendar/iso.ex +++ b/lib/elixir/lib/calendar/iso.ex @@ -715,7 +715,15 @@ defmodule Calendar.ISO do {second, <> = 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} _ -> diff --git a/lib/elixir/test/elixir/calendar/duration_test.exs b/lib/elixir/test/elixir/calendar/duration_test.exs index f3dccf34477..1240d176aab 100644 --- a/lib/elixir/test/elixir/calendar/duration_test.exs +++ b/lib/elixir/test/elixir/calendar/duration_test.exs @@ -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 @@ -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}