DateTime.Round extension method

Posted on March 12, 2008. Filed under: 3.5, ASP.NET, Extensions, LINQ | Tags: , , , , |

I recently needed to group by minutes (or seconds, or hours, or days) in a LINQ expression, and I found that there isn’t a round function built into the C# DateTime object. The following will round to the nearest second, minute, hour, or day. I stopped there because different months have different numbers of days (and I don’t need to group by months…) but it is easy enough to add months and years to the code.

Keep in mind that this doesn’t give you the current minute (or whatever) rather it gives you the closest minute (or whatever).


using System;

namespace MikeInMadison
{
    public static class Extensions
    {
        public static DateTime Round(this DateTime d, RoundTo rt)
        {
            DateTime dtRounded = new DateTime();

            switch (rt)
            {
                case RoundTo.Second:
                    dtRounded = new DateTime(d.Year, d.Month, d.Day, d.Hour, d.Minute, d.Second);
                    if (d.Millisecond >= 500) dtRounded = dtRounded.AddSeconds(1);
                    break;
                case RoundTo.Minute:
                    dtRounded = new DateTime(d.Year, d.Month, d.Day, d.Hour, d.Minute, 0);
                    if (d.Second >= 30) dtRounded = dtRounded.AddMinutes(1);
                    break;
                case RoundTo.Hour:
                    dtRounded = new DateTime(d.Year, d.Month, d.Day, d.Hour, 0, 0);
                    if (d.Minute >= 30) dtRounded = dtRounded.AddHours(1);
                    break;
                case RoundTo.Day:
                    dtRounded = new DateTime(d.Year, d.Month, d.Day, 0, 0, 0);
                    if (d.Hour >= 12) dtRounded = dtRounded.AddDays(1);
                    break;
            }

            return dtRounded;
        }

        public enum RoundTo
        {
            Second, Minute, Hour, Day
        }
    }
}

I’m using this extension method within LINQ to group RateItems by minutes. I’m getting the high, low, open, close, and begin time in a list of stock prices.

            var rates = from ri in RateItems
                        group ri by ri.Time.Round(Extensions.RoundTo.Hour) into g
                        select new
                        {
                            Time = g.First().Time.Round(Extensions.RoundTo.Hour),
                            High = g.Max(g2 => g2.Bid),
                            Low = g.Min(g2 => g2.Bid),
                            Open = g.First().Bid,
                            Close = g.Last().Bid
                        };
About these ads

5 Responses to “DateTime.Round extension method”

RSS Feed for Mike In Madison Comments RSS Feed

Thank you for sharing this, this DateTime round functionality was exactly what I needed for something I’m working on.

Evan

Here’s the code in VB.net:

Public Class Extensions
Public Function Round(ByVal d As DateTime, _
ByVal rt As RoundTo) As Date
Dim dtRounded As Date

Select (rt)
Case RoundTo.Second
dtRounded = New DateTime(d.Year, _
d.Month, d.Day, d.Hour, _
d.Minute, d.Second)
If (d.Millisecond >= 500) Then _
dtRounded = dtRounded.AddSeconds(1)

Case RoundTo.Minute
dtRounded = New DateTime(d.Year, _
d.Month, d.Day, d.Hour, _
d.Minute, 0)
If (d.Second >= 30) Then _
dtRounded = dtRounded.AddMinutes(1)

Case RoundTo.Hour
dtRounded = New DateTime(d.Year, _
d.Month, d.Day, d.Hour, 0, 0)
If (d.Minute >= 30) Then _
dtRounded = dtRounded.AddHours(1)

Case RoundTo.Day
dtRounded = New DateTime(d.Year, _
d.Month, d.Day, 0, 0, 0)
If (d.Hour >= 12) Then _
dtRounded = dtRounded.AddDays(1)
End Select
Return dtRounded
End Function

Enum RoundTo
Second
Minute
Hour
Day
End Enum
End Class

I made a small mistake. Change the function declaration to:

Shared Function Round(ByVal d As DateTime, _
ByVal rt As RoundTo) As Date

thanks alot

I’ve added one more thing when copying your code. When creating a new DateTime, you’re not copying the DateKind, which is pretty important in our solution, as DateTime values are otherwise transferred as Localtime over WCF, causing all kinds of mayhem when you’re talking to systems in other timezones.

The change is pretty simple. At the end of each Datetime constructor call, add d.Kind:

tRounded = new DateTime(d.Year, d.Month, d.Day, d.Hour, d.Minute, d.Second, d.Kind);


Comments are closed.

Liked it here?
Why not try sites on the blogroll...

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: