Repository: nodatime/nodatime (csharp)

Issue:
Non-allocative way of having TotalSeconds between two LocalTime inputs
Hello!
For some reason the project I work on have called something 

```
public double GetTotalSeconds(LocalTime time1, LocalTime time2)
{
    return (time1 - time2).ToDuration().TotalSeconds;
}
```
which results in 80B allocation per call.
We call this on 3 different time fields and this has to be repeated for a large number of times which results in large amount of allocation.

Im not sure how useful it is for others but if possible I would like to see if we can have something like https://github.com/nodatime/nodatime/issues/1450 and implement this without having a Period object created. ie. Get the same thing done by Period.Between return directly:
`(double)(EndTime.NanosecondOfDay - StartTime.NanosecondOfDay) / 1_000_000_000` 

This should yield a benchmark like below (shortrun job):
| Method                 | Mean       | Error      | StdDev    | Median     | Gen0   | Allocated |
|----------------------- |-----------:|-----------:|----------:|-----------:|-------:|----------:|
| TotalSecondsLocalTimePeriod  | 23.1932 ns | 12.0196 ns | 0.6588 ns | 22.8489 ns | 0.0064 |      80 B |
| TotalSecondsLocalTime |  0.0349 ns |  0.8089 ns | 0.0443 ns |  0.0200 ns |      - |         - |

If you are happy on this proposal, I can help to create a PR for it (first time :)).
Thanks in advance.
(...and question I have in mind..:
- I saw there is an uncheck on Period.Between()'s implementation - but curious under what case that would be required since it is always doing a subtraction?
- Why not implement #1450 as extension on LocalTime itself but in the Period class?)

Pull request:
Fixes #1835

Patch:
diff --git a/src/NodaTime/Period.cs b/src/NodaTime/Period.cs
index 9748c2219..b59b5a26a 100644
--- a/src/NodaTime/Period.cs
+++ b/src/NodaTime/Period.cs
@@ -423,6 +423,20 @@ public static int DaysBetween(LocalDate start, LocalDate end)
             return InternalDaysBetween(start, end);
         }
 
+        /// <summary>
+        /// Returns the number of nanoseconds between two <see cref="LocalTime"/> values.
+        /// </summary>
+        /// <remarks>
+        /// If <paramref name="end"/> is before <paramref name="start" />, the returned value will be negative.
+        /// </remarks>
+        /// <param name="start">Start time</param>
+        /// <param name="end">End time</param>
+        /// <returns>The number of nanoseconds between the given times.</returns>
+        public static long NanosecondsBetween(LocalTime start, LocalTime end)
+        {
+            return unchecked(end.NanosecondOfDay - start.NanosecondOfDay);
+        }
+
         /// <summary>
         /// Returns the period between a start and an end date/time, using only the given units.
         /// </summary>
@@ -698,7 +712,7 @@ public static Period Between(LocalTime start, LocalTime end, PeriodUnits units)
             // number of nanoseconds. All the operations can be done with simple long division/remainder ops,
             // so we don't need to delegate to TimePeriodField.
 
-            long remaining = unchecked(end.NanosecondOfDay - start.NanosecondOfDay);
+            long remaining = NanosecondsBetween(start, end);
 
             // Optimization for a single unit
             switch (units)


Test patch:
diff --git a/src/NodaTime.Test/PeriodTest.cs b/src/NodaTime.Test/PeriodTest.cs
index c66ead03f..386e35fa5 100644
--- a/src/NodaTime.Test/PeriodTest.cs
+++ b/src/NodaTime.Test/PeriodTest.cs
@@ -315,6 +315,25 @@ public void BetweenLocalDateTimes_InvalidUnits()
             Assert.Throws<ArgumentException>(() => Period.Between(TestDateTime1, TestDateTime2, (PeriodUnits)(-1)));
         }
 
+        private static TestCaseData[] NanosecondsBetweenLocalTimesTestCaseData =>
+        [
+            new TestCaseData(LocalTime.MinValue, LocalTime.MaxValue, LocalTime.MaxValue.NanosecondOfDay)
+                .SetName($"Nanoseconds between {nameof(LocalTime.MinValue)} and {nameof(LocalTime.MaxValue)} should be maximum {nameof(LocalTime.MaxValue.NanosecondOfDay)}"),
+            new TestCaseData(LocalTime.MaxValue, LocalTime.MinValue, -LocalTime.MaxValue.NanosecondOfDay)
+                .SetName($"Nanoseconds between {nameof(LocalTime.MaxValue)} and {nameof(LocalTime.MinValue)} should be negative maximum {nameof(LocalTime.MaxValue.NanosecondOfDay)}"),
+            new TestCaseData(LocalTime.MinValue, LocalTime.MinValue.PlusNanoseconds(1), 1L)
+                .SetName($"Nanoseconds between {nameof(LocalTime.MinValue)} and {nameof(LocalTime.MinValue)}_Plus_One should be 1"),
+            new TestCaseData(LocalTime.MinValue.PlusNanoseconds(1), LocalTime.MinValue, -1L).
+                SetName($"Nanoseconds between {nameof(LocalTime.MinValue)}_Plus_One and {nameof(LocalTime.MinValue)} should be negative 1"),
+        ];
+
+        [TestCaseSource(nameof(NanosecondsBetweenLocalTimesTestCaseData))]
+        public void NanosecondsBetweenLocalTimes(LocalTime start, LocalTime end, long expected)
+        {
+            var actual = Period.NanosecondsBetween(start, end);
+            Assert.AreEqual(expected, actual);
+        }
+
         [Test]
         public void BetweenLocalTimes_InvalidUnits()
         {