Merge pull request #39538.

Closes #39538.
This commit is contained in:
Rafael Mendonça França 2020-11-02 20:42:40 +00:00
commit 81ee5dcdf4
No known key found for this signature in database
GPG Key ID: FC23B6D0F1EEE948
3 changed files with 27 additions and 11 deletions

View File

@ -1,3 +1,24 @@
* Calling `iso8601` on negative durations retains the negative sign on individual
digits instead of prepending it.
This change is required so we can interoperate with PostgreSQL, which prefers
negative signs for each component.
Compatibility with other iso8601 parsers which support leading negatives as well
as negatives per component is still retained.
Before:
(-1.year - 1.day).iso8601
# => "-P1Y1D"
After:
(-1.year - 1.day).iso8601
# => "P-1Y-1D"
*Vipul A M*
* Remove deprecated `ActiveSupport::Notifications::Instrumenter#end=`.
*Rafael Mendonça França*

View File

@ -15,7 +15,7 @@ module ActiveSupport
# Builds and returns output string.
def serialize
parts, sign = normalize
parts = normalize
return "PT0S" if parts.empty?
output = +"P"
@ -30,7 +30,7 @@ module ActiveSupport
time << "#{sprintf(@precision ? "%0.0#{@precision}f" : '%g', parts[:seconds])}S"
end
output << "T#{time}" unless time.empty?
"#{sign}#{output}"
output
end
private
@ -48,13 +48,7 @@ module ActiveSupport
parts[:days] += parts.delete(:weeks) * SECONDS_PER_WEEK / SECONDS_PER_DAY
end
# If all parts are negative - let's make a negative duration
sign = ""
if parts.values.all? { |v| v < 0 }
sign = "-"
parts.transform_values!(&:-@)
end
[parts, sign]
parts
end
def week_mixed_with_date?(parts)

View File

@ -618,12 +618,13 @@ class DurationTest < ActiveSupport::TestCase
["P1Y1M21D", 1.year + 1.month + 3.week ],
["P1Y1M", 1.year + 1.month ],
["P1Y1M1D", 1.year + 1.month + 1.day ],
["-P1Y1D", -1.year - 1.day ],
["P-1Y-1D", -1.year - 1.day ],
["P1Y-1DT-1S", 1.year - 1.day - 1.second ], # Parts with different signs are exists in PostgreSQL interval datatype.
["PT1S", 1.second ],
["PT1.4S", (1.4).seconds ],
["P1Y1M1DT1H", 1.year + 1.month + 1.day + 1.hour],
["PT0S", 0.minutes ],
["PT-0.2S", (-0.2).seconds ],
]
expectations.each do |expected_output, duration|
assert_equal expected_output, duration.iso8601, expected_output.inspect
@ -651,7 +652,7 @@ class DurationTest < ActiveSupport::TestCase
def test_iso8601_output_and_reparsing
patterns = %w[
P1Y P0.5Y P0,5Y P1Y1M P1Y0.5M P1Y0,5M P1Y1M1D P1Y1M0.5D P1Y1M0,5D P1Y1M1DT1H P1Y1M1DT0.5H P1Y1M1DT0,5H P1W +P1Y -P1Y
P1Y P0.5Y P0,5Y P1Y1M P1Y0.5M P1Y0,5M P1Y1M1D P1Y1M0.5D P1Y1M0,5D P1Y1M1DT1H P1Y1M1DT0.5H P1Y1M1DT0,5H P1W +P1Y -P1Y P-1Y
P1Y1M1DT1H1M P1Y1M1DT1H0.5M P1Y1M1DT1H0,5M P1Y1M1DT1H1M1S P1Y1M1DT1H1M1.0S P1Y1M1DT1H1M1,0S P-1Y-2M3DT-4H-5M-6S
]
# That could be weird, but if we parse P1Y1M0.5D and output it to ISO 8601, we'll get P1Y1MT12.0H.