0

What's the best way to round minutes on C# on DateTime object? This is the case:

  • When I am at 10h:11mn I need to transform it to 10h:10mn
  • When I am at 10h:19mn I need to transform it to 10h:10mn
  • When I am at 10h:10mn I need to transform it to 10h:10mn
  • When I am at 10h:25mn I need to transform it to 10h:20mn

I started to test a round down like this:

public static DateTime RoundDown(this DateTime dt, TimeSpan d)
{
    var delta = dt.Ticks % d.Ticks;

    return new DateTime(dt.Ticks - delta, dt.Kind);
}
Lance U. Matthews
  • 15,725
  • 6
  • 48
  • 68
user1428798
  • 1,534
  • 3
  • 24
  • 50
  • 1
    Possible duplicate of [Is there a simple function for rounding a DateTime down to the nearest 30 minutes, in C#?](https://stackoverflow.com/questions/10100088/is-there-a-simple-function-for-rounding-a-datetime-down-to-the-nearest-30-minute) or [Rounding DateTime objects](https://stackoverflow.com/questions/1393696/rounding-datetime-objects) – Lance U. Matthews Mar 17 '19 at 16:50

3 Answers3

0

This will do the work, but only for the nearest 10-minute-interval. In order for this to be more generic it needs to be implemented with a Timespan included as a parameter, to define the level of rounding on the datetime.

    public DateTime RoundDateTimeMinutes(DateTime date, bool roundUp = true)
    {
        var minutesDiff = date.Minute % 10;

        if (minutesDiff == 5)
        {
            if (roundUp)
            {
                date = date.AddMinutes(minutesDiff);
            }
            else
            {
                date = date.AddMinutes(-minutesDiff);
            }
        }            
        else if (minutesDiff > 5)
        {
            date = date.AddMinutes(10 - minutesDiff);
        }
        else
        {
            date = date.AddMinutes(-minutesDiff);
        }

        return date;
    }

Edit: Actually the result above rounds up the nearest 10-minute-interval. This is the actual method that always rounds down minutes.

    public DateTime RoundDateTimeMinutes(DateTime date)
    {
        var minutesDiff = date.Minute % 10;
        return date.AddMinutes(-minutesDiff);            
    }
kyriakosio
  • 106
  • 6
  • I'm not sure how this is the answer when it doesn't do what the question specifies. When given `10:19` this returns `10:20`, not `10:10`. Also, given, say, `10:11:30` this returns `10:10:30`, not `10:10:00` (though the question doesn't specify how fractions of a minute should be handled). – Lance U. Matthews Mar 17 '19 at 17:33
0

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
...
Lance U. Matthews
  • 15,725
  • 6
  • 48
  • 68
-1

Simply construct a new DateTime, passing the year, month, day, and hour of the unrounded DateTime. For minutes, pass the original minutes modulo 10, and for seconds pass 0.

var rounded = new DateTime
(
    original.Year,
    original.Month,
    original.Day,
    original.Hour,
    Math.Floor(original.Minute / 10) * 10
    0
);
John Wu
  • 50,556
  • 8
  • 44
  • 80
  • 1
    With `Minute % 10` you end up with a time where `Minute` ranges from `0` to `9` (e.g. `10:59` becomes `10:09`). Did you mean `dt.Minute - dt.Minute % 10`? Also, you can't use object initializer syntax since those properties are read-only (though the idea is still clear). – Lance U. Matthews Mar 17 '19 at 18:36
  • Oops. Should have been constructor arguments. Corrected that and the math. – John Wu Mar 17 '19 at 19:02