From 6701f223550f86a0cebef6023d6665ad1b835668 Mon Sep 17 00:00:00 2001 From: urmastalimaa Date: Wed, 18 Sep 2024 09:20:18 +0300 Subject: [PATCH 1/3] Add tests for rejecting fractional non-second components Existing behaviour is to accept fractions only in the second components --- lib/elixir/test/elixir/calendar/duration_test.exs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/elixir/test/elixir/calendar/duration_test.exs b/lib/elixir/test/elixir/calendar/duration_test.exs index f3dccf34477..d6b662225ad 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 From 49b5f710213f437580c1ef00281d21981585ada1 Mon Sep 17 00:00:00 2001 From: urmastalimaa Date: Wed, 18 Sep 2024 09:10:44 +0300 Subject: [PATCH 2/3] Add tests for parsing fractional durations between -1 and +1 seconds Extend tests for existing fractional durations parsing behaviour. Parsing "PT0,6S" should result in a positive microsecond, which will be fixed in the next commit. The parser currently accepts both a negative prefix "-PT" and a negative value in the components "-0,6S". Combining both into "-PT-0,6S" is also accepted by the parser, resulting in an overall positive duration. Although the practical value of double negative durations is dubious, the accepting nature of the parser is tested. The JavaScript libraries that I tested disagree whether "-PT-0,6S" represents a positive or negative duration, "moment" and "tinyduration" reported positive, "luxon" (the successor to moment) reported negative. If the parser accepts double negatives at all, resulting in anything but a positive duration would be unintuitive. --- lib/elixir/test/elixir/calendar/duration_test.exs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/elixir/test/elixir/calendar/duration_test.exs b/lib/elixir/test/elixir/calendar/duration_test.exs index d6b662225ad..70ea395e799 100644 --- a/lib/elixir/test/elixir/calendar/duration_test.exs +++ b/lib/elixir/test/elixir/calendar/duration_test.exs @@ -264,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 _faulty = 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} From 5678a3332e320a8d8deda02cb775b2ce8361ff2b Mon Sep 17 00:00:00 2001 From: urmastalimaa Date: Wed, 18 Sep 2024 09:22:48 +0300 Subject: [PATCH 3/3] Fix parsing of fractional durations with 0 in the integer component 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 | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) 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 70ea395e799..1240d176aab 100644 --- a/lib/elixir/test/elixir/calendar/duration_test.exs +++ b/lib/elixir/test/elixir/calendar/duration_test.exs @@ -264,7 +264,7 @@ 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 _faulty = Duration.from_iso8601!("PT0,6S") == %Duration{second: 0, 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}