TimeSpan calculation is different between TimeOnly and DateTime
Asked Answered
W

0

1

I'm having a hard time understanding why this is happening or even if this should be happening. If I calculate the TimeSpan between two DateTime objects (same date, different times) and compare it to the same calculation using two TimeOnly objects I get different results.

var start = new DateTime(1, 1, 1, 14, 0, 0);
var end = new DateTime(1, 1, 1, 10, 0, 0);
Console.WriteLine(end - start); // Prints -4 hours

However...

var start = new TimeOnly(14, 0, 0);
var end = new TimeOnly(10, 0, 0);
Console.WriteLine(end - start); // Prints 20 hours???

Isn't the span between starting at 2pm and ending at 10am always a span of -4 hours? Interestingly enough if I take the second one and do Console.WriteLine(end.ToTimeSpan() - start.ToTimeSpan()); I end up with -4 hours.

This feels like an error on TimeOnly's part but I don't know. Here is a fiddle I did comparing results between NodaTime, System.DateTime, converting System.TimeOnly to TimeSpan, and System.TimeOnly.

Wellesz answered 19/7, 2022 at 15:27 Comment(10)
Docs: "Gives the elapsed time between two points on a circular clock, which will always be a positive value."Rack
TimeOnly will wrap around at the 24 hour mark because it has no concept of dates. For your use case, you should just use TimeSpan itself.Parodic
TimeOnly doesn't take the date into account, so it just calculates it to the next daySabu
Check out the documentation this behaviour is intendedAcrobatic
Formulating this as "points on a circular clock" is a very friendly if operational description. I guess it's intended to not scare away people with the horrors of... MODULAR ARITHMETIC. (Dun dun dunnn.)Higgs
That makes sense. I could see why +20 was happening but seeing NodaTime, TimeSpan, and System.DateTime all provide -4 threw me off. Maybe I should change the question to "why does TimeOnly calculate its TimeSpan differently?" Just want to make sure this post is as useful as possible.Wellesz
"points on a circular clock" - well, my clock has only 12 hours, so that's a bad term IMHO.Gymkhana
If your clock only has 12 hours, then a time like 14:00:00 isn't going to work that well. The difference between the two calculations is that in the DateTime case, you are specifying the date as well as the time when you are doing the subtraction. In the TimeOnly case, you are specifying the start at 2:00pm and the end at 10:00am. Ends are always after starts (in my concept of time - i.e., backwards time doesn't exist), so 20 hours elapseSelle
@Selle Do you think that is the case with TimeSpan as well? It must keep reference of the day (since you can do TimeSpan.FromDays(int)). So when I do TimeSpan.FromHours(14) - TimeSpan.FromHours(10) I end up with -4.Wellesz
@LoganK: Something I picked up reading the Noda Time docs is how many semantically different date and time concepts there are. The main problem with the original native (DateTime, DateTimeOffset & TimeSpan) implementation is that it squishes them all together. Semantically, TimeSpan & TimeOnly represent two different things. TimeSpan is the span of time between two times. TimeOnly is a time of day. If you say that something ends at 10am and starts at 2pm, then it's pretty obvious that it's going to run overnight - clocks never run backwards. Saying 10am is 4 hours before 2pm does make senseSelle

© 2022 - 2024 — McMap. All rights reserved.