Late to the party but I've always used "Ticks" arithmetic to do these kinds of things. A straightforward way to "truncate" seconds (and any milliseconds) is:
var d1 = DateTime.Now;
var noSeconds = new DateTime(d1.Ticks / TimeSpan.TicksPerMinute * TimeSpan.TicksPerMinute);
Of course I've encapsulated all of it in neat functions:
public static long Round(this long dateTicks, TimeSpan span) {
long ticks = (dateTicks + (span.Ticks / 2)) / span.Ticks;
return ticks * span.Ticks;
}
public static long Floor(this long dateTicks, TimeSpan span) {
long ticks = (dateTicks / span.Ticks);
return ticks * span.Ticks;
}
You can see there's a Round
method which will round upward if the "span" is halfway to the next interval (31 seconds will round up for example, while 30 will round down). To strip a period, just use the Floor
method. The following console script will show how to use these:
using System;
public static long Round(this long dateTicks, TimeSpan span) {
long ticks = (dateTicks + (span.Ticks / 2)) / span.Ticks;
return ticks * span.Ticks;
}
public static long Floor(this long dateTicks, TimeSpan span) {
long ticks = (dateTicks / span.Ticks);
return ticks * span.Ticks;
}
DateTime d1 = new DateTime(2022, 03, 31, 08, 30, 31, 235);
DateTime d2 = new DateTime(Floor(d1.Ticks, TimeSpan.FromMinutes(1)));
DateTime d3 = new DateTime(Round(d1.Ticks, TimeSpan.FromMinutes(1)));
Console.WriteLine(d1);
Console.WriteLine(d2);
Console.WriteLine(d3);
Which will result int:
3/31/2022 8:30:31 AM
3/31/2022 8:30:00 AM
3/31/2022 8:31:00 AM
You could also have rounded or floored in any time span: 5 seconds, 30 seconds, half an hour, etc.
With these Tick-based methods I've created a bunch of overloaded extension methods for many "data and time" types. Feel free to use however you wish:
using System;
public static class DateAndTimeExtensions
{
public static long Round(this long dateTicks, TimeSpan span) {
long ticks = (dateTicks + (span.Ticks / 2)) / span.Ticks;
return ticks * span.Ticks;
}
public static long Round(this long dateTicks, TimeSpan span, TimeSpan grace) {
long ticks = (dateTicks + (span.Ticks - grace.Ticks)) / span.Ticks;
return ticks * span.Ticks;
}
public static long Floor(this long dateTicks, TimeSpan span) {
long ticks = (dateTicks / span.Ticks);
return ticks * span.Ticks;
}
public static long Ceil(this long dateTicks, TimeSpan span) {
long ticks = (dateTicks + span.Ticks - 1) / span.Ticks;
return ticks * span.Ticks;
}
public static DateTime Round(this DateTime date, TimeSpan span)
=> new DateTime(date.Ticks.Round(span));
public static DateTime Round(this DateTime date, TimeSpan span, TimeSpan grace)
=> new DateTime(date.Ticks.Round(span, grace));
public static DateTime Floor(this DateTime date, TimeSpan span)
=> new DateTime(date.Ticks.Floor(span));
public static DateTime Ceil(this DateTime date, TimeSpan span)
=> new DateTime(date.Ticks.Ceil(span));
public static DateTimeOffset Round(this DateTimeOffset date, TimeSpan span)
=> new DateTimeOffset(date.Ticks.Round(span), date.Offset);
public static DateTimeOffset Round(this DateTimeOffset date, TimeSpan span, TimeSpan grace)
=> new DateTimeOffset(date.Ticks.Round(span, grace), date.Offset);
public static DateTimeOffset Floor(this DateTimeOffset date, TimeSpan span)
=> new DateTimeOffset(date.Ticks.Floor(span), date.Offset);
public static DateTimeOffset Ceil(this DateTimeOffset date, TimeSpan span)
=> new DateTimeOffset(date.Ticks.Ceil(span), date.Offset);
public static TimeSpan Round(this TimeSpan time, TimeSpan span)
=> new TimeSpan(time.Ticks.Round(span));
public static TimeSpan Round(this TimeSpan time, TimeSpan span, TimeSpan grace)
=> new TimeSpan(time.Ticks.Round(span, grace));
public static TimeSpan Floor(this TimeSpan time, TimeSpan span)
=> new TimeSpan(time.Ticks.Floor(span));
public static TimeSpan Ceil(this TimeSpan time, TimeSpan span)
=> new TimeSpan(time.Ticks.Ceil(span));
public static TimeSpan Abs(this TimeSpan time)
=> new TimeSpan(Math.Abs(time.Ticks));
}
Using the above extension methods you can easily truncate or round in any time span you require. Just look at the following examples:
var d = new TimeSpan(3, 20, 31); // 3h20min31s
var roundedAt5Seconds = d.Round(TimeSpan.FromSeconds(5)); // 03:20:30
var roundedAt1Minute = d.Round(TimeSpan.FromMinutes(1)); // 03:21:00
var flooredAt1Minute = d.Floor(TimeSpan.FromMinutes(1)); // 03:20:00
var roundedAtHalfHour = d.Round(TimeSpan.FromMinutes(30)); // 03:30:00
var flooredAtHalfHour = d.Floor(TimeSpan.FromMinutes(30)); // 03:00:00