This seems like a non-answer answer, but I don't know how you could improve upon what you already have. It works, it's concise, it's flexible (not hard-coded to a specific interval), it truncates fractions of a minute, and it maintains the Kind
property. What more do you need?
Test code:
static void Main(string[] args)
{
TestRoundingForHourAfter(DateTime.Parse("10 AM"));
TestRoundingForHourAfter(DateTime.Parse("10 AM").AddTicks(123456789));
}
static void TestRoundingForHourAfter(DateTime baseTime)
{
foreach (DateTime input in Enumerable.Range(0, 60).Select(minutes => baseTime + TimeSpan.FromMinutes(minutes)))
{
DateTime output = RoundDown(input, TimeSpan.FromMinutes(10));
Console.WriteLine($"{input:hh:mm:ss.fffffff} rounds to {output:hh:mm:ss.fffffff}");
}
}
public static DateTime RoundDown(DateTime dt, TimeSpan d)
{
var delta = dt.Ticks % d.Ticks;
return new DateTime(dt.Ticks - delta, dt.Kind);
}
Test output:
10:00:00.0000000 rounds to 10:00:00.0000000
10:01:00.0000000 rounds to 10:00:00.0000000
10:02:00.0000000 rounds to 10:00:00.0000000
10:03:00.0000000 rounds to 10:00:00.0000000
10:04:00.0000000 rounds to 10:00:00.0000000
10:05:00.0000000 rounds to 10:00:00.0000000
10:06:00.0000000 rounds to 10:00:00.0000000
10:07:00.0000000 rounds to 10:00:00.0000000
10:08:00.0000000 rounds to 10:00:00.0000000
10:09:00.0000000 rounds to 10:00:00.0000000
10:10:00.0000000 rounds to 10:10:00.0000000
...
10:00:12.3456789 rounds to 10:00:00.0000000
10:01:12.3456789 rounds to 10:00:00.0000000
10:02:12.3456789 rounds to 10:00:00.0000000
10:03:12.3456789 rounds to 10:00:00.0000000
10:04:12.3456789 rounds to 10:00:00.0000000
10:05:12.3456789 rounds to 10:00:00.0000000
10:06:12.3456789 rounds to 10:00:00.0000000
10:07:12.3456789 rounds to 10:00:00.0000000
10:08:12.3456789 rounds to 10:00:00.0000000
10:09:12.3456789 rounds to 10:00:00.0000000
10:10:12.3456789 rounds to 10:10:00.0000000
...