Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Round Down to nearest boundary in dateTime

In this answer of a similar question the DateTime is rounded to the closes (time) boundary, the Math.Round method does not allow round to the lower boundary by choice.
Is there a way to calculate the same way the lower boundary of some time ?
Meaning if the time is 10/2/2012 10:52:30 and the choice is an hour than the time is : 10/2/2012 10:00:00, if the choice is day than 10/2/2012 00:00:00 and so on.

like image 902
guyl Avatar asked Jan 18 '23 20:01

guyl


1 Answers

If you only need to go to a particular unit, I probably wouldn't even bother using Math.Round or Math.Floor - I'd just go with something like:

switch (unitToRoundDownTo)
{
    case Unit.Second:
        return new DateTime(old.Year, old.Month, old.Day,
                            old.Hour, old.Minute, old.Second, old.Kind);
    case Unit.Minute:
        return new DateTime(old.Year, old.Month, old.Day,
                            old.Hour, old.Minute, 0, old.Kind);
    case Unit.Hour:
        return new DateTime(old.Year, old.Month, old.Day, old.Hour, 0, 0, old.Kind);
    case Unit.Day:
        return new DateTime(old.Year, old.Month, old.Day, 0, 0, 0, old.Kind);
    case Unit.Month:
        return new DateTime(old.Year, old.Month, 1, 0, 0, 0, old.Kind);
    case Unit.Year:
        return new DateTime(old.Year, 1, 1, 0, 0, 0, old.Kind);
    default:
        throw new ArgumentOutOfRangeException();
}

That doesn't work if you need "the nearest 5 minutes" etc, but for a single time unit it's simpler to understand and debug than trying to get arithmetic to work.

Alternatively, as a different spin on the accepted answer to the question you link to, you can just do:

// tickCount is the rounding interval, e.g. TimeSpan.FromMinutes(5).Ticks
DateTime rounded = new DateTime((old.Ticks / tickCount) * tickCount);

Note that this won't help for rounding to the start of the month or year.

like image 72
Jon Skeet Avatar answered Jan 28 '23 14:01

Jon Skeet