diff --git a/csharp/src/Google.Protobuf.Test/WellKnownTypes/DurationTest.cs b/csharp/src/Google.Protobuf.Test/WellKnownTypes/DurationTest.cs index 141faf80e0..8124f0c91d 100644 --- a/csharp/src/Google.Protobuf.Test/WellKnownTypes/DurationTest.cs +++ b/csharp/src/Google.Protobuf.Test/WellKnownTypes/DurationTest.cs @@ -128,5 +128,38 @@ namespace Google.Protobuf.WellKnownTypes var duration = new Duration { Seconds = 1, Nanos = -1 }; Assert.AreEqual("{ \"@warning\": \"Invalid Duration\", \"seconds\": \"1\", \"nanos\": -1 }", duration.ToString()); } + + [Test] + public void Comparability() + { + Duration[] durationsInExpectedSortOrder = + { + null, + new Duration { Seconds = -10, Nanos = -10 }, + new Duration { Seconds = -10, Nanos = -1 }, + new Duration { Seconds = -1, Nanos = -10 }, + new Duration { Seconds = -1, Nanos = -1 }, + new Duration(), + new Duration { Seconds = 1, Nanos = 1 }, + new Duration { Seconds = 1, Nanos = 10 }, + new Duration { Seconds = 10, Nanos = 1 }, + new Duration { Seconds = 10, Nanos = 10 } + }; + + for (int i = 0; i < durationsInExpectedSortOrder.Length; i++) + { + var target = durationsInExpectedSortOrder[i]; + if (target is null) + { + continue; + } + for (int j = 0; j < durationsInExpectedSortOrder.Length; j++) + { + var expectedResult = Math.Sign(i - j); + var actualResult = target.CompareTo(durationsInExpectedSortOrder[j]); + Assert.AreEqual(expectedResult, actualResult); + } + } + } } } diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/DurationPartial.cs b/csharp/src/Google.Protobuf/WellKnownTypes/DurationPartial.cs index 9a468fc198..cdf3c31c70 100644 --- a/csharp/src/Google.Protobuf/WellKnownTypes/DurationPartial.cs +++ b/csharp/src/Google.Protobuf/WellKnownTypes/DurationPartial.cs @@ -38,7 +38,7 @@ namespace Google.Protobuf.WellKnownTypes { // Manually-written partial class for the Duration well-known type, // providing a conversion to TimeSpan and convenience operators. - public partial class Duration : ICustomDiagnosticMessage + public partial class Duration : ICustomDiagnosticMessage, IComparable { /// /// The number of nanoseconds in a second. @@ -266,5 +266,26 @@ namespace Google.Protobuf.WellKnownTypes } } } + + + /// + /// Given another duration, returns 0 if the durations are equivalent, -1 if this duration is shorter than the other, and 1 otherwise. + /// + /// + /// This method expects that both durations are normalized; that is, that the values of + /// and are within the documented bounds. + /// If either value is not normalized, the results of this method are unspecified. + /// + /// The duration to compare with this object. + /// An integer indicating whether this duration is shorter or longer than . + public int CompareTo(Duration other) + { + return other == null ? 1 + : Seconds < other.Seconds ? -1 + : Seconds > other.Seconds ? 1 + : Nanos < other.Nanos ? -1 + : Nanos > other.Nanos ? 1 + : 0; + } } }