Is there a simple function for rounding a DateTime down to the nearest 30 minutes, in C#?

后端 未结 7 1049
佛祖请我去吃肉
佛祖请我去吃肉 2020-12-02 01:35

For example:

2011-08-11 16:59 becomes 2011-08-11 16:30

相关标签:
7条回答
  • 2020-12-02 02:15

    Here's how I handled it. Below is the base method and an overload to round to the nearest 30 minutes:

    public static DateTime RoundMinutes(this DateTime value)
    {
        return RoundMinutes(value, 30);
    }
    
    public static DateTime RoundMinutes(this DateTime value, int roundMinutes)
    {
        DateTime result = new DateTime(value.Ticks);
    
        int minutes = value.Minute;
        int hour = value.Hour;
        int minuteMod = minutes % roundMinutes;
    
        if (minuteMod <= (roundMinutes / 2))
        {
            result = result.AddMinutes(-minuteMod);
        }
        else
        {
            result = result.AddMinutes(roundMinutes - minuteMod);
        }
    
        return result;
    }
    
    0 讨论(0)
  • 2020-12-02 02:17

    Exploiting some math

    var input = DateTime.Now; // or however you get DateTime
    var rounded = input.AddMinutes(-input.TimeOfDay.TotalMinutes % 30d);
    

    Note that TimeOfDay is a TimeSpan and its TotalMinutes property is a double and that the modulus operator functions on doubles like follows:

    47.51 % 30d == 17.51

    16.2 % 30d == 16.2

    768.7 % 30d == 18.7

    You could change the 30d to any value you like other than zero. Changing to 15 rounds down to 15 minute intervals for instance. Changing from 30d to -30d, didn't change the results from the tests that I ran.

    You could create a rounding extension method (providing this rounding method for all DateTime values):

    public static class DateTimeExtensions
    {
        public static DateTime Round(this DateTime self, double minutesInInterval)
        {
            if (minutesInInterval == 0d) throw new ArgumentOutOfRangeException("minutesInInterval");
            return self.AddMinutes(-self.TimeOfDay.TotalMinutes % minutesInInterval);
        }
    }
    
    0 讨论(0)
  • 2020-12-02 02:24
    DateTime RoundDown(DateTime dt, TimeSpan d)
    {
        return new DateTime((dt.Ticks / d.Ticks) * d.Ticks);
    }
    

    Example:

    var dt1 = RoundDown(DateTime.Parse("2011-08-11 16:59"), TimeSpan.FromMinutes(30));
    // dt1 == {11/08/2011 16:30:00}
    
    var dt2 = RoundDown(DateTime.Parse("2011-08-11 17:00"), TimeSpan.FromMinutes(30));
    // dt2 == {11/08/2011 17:00:00}
    
    var dt3 = RoundDown(DateTime.Parse("2011-08-11 17:01"), TimeSpan.FromMinutes(30));
    // dt3 == {11/08/2011 17:00:00}
    
    0 讨论(0)
  • 2020-12-02 02:26

    A more generic solution rounding to the nearest time span:

    
    public static DateTime RoundUp(this DateTime dt, TimeSpan d)
    {
        var delta = (d.Ticks - (dt.Ticks % d.Ticks)) % d.Ticks;
        return new DateTime(dt.Ticks + delta);
    }
    
    public static DateTime RoundDown(this DateTime dt, TimeSpan d)
    {
        var delta = dt.Ticks % d.Ticks;
        return new DateTime(dt.Ticks - delta);
    }
    
    public static DateTime RoundToNearest(this DateTime dt, TimeSpan d)
    {
        var delta = dt.Ticks % d.Ticks;
        bool roundUp = delta > d.Ticks / 2;
    
        return roundUp ? dt.RoundUp(d) : dt.RoundDown(d);
    }

    It would be used this way:

    var date = new DateTime(2010, 02, 05, 10, 35, 25, 450); // 2010/02/05 10:35:25
    var rounded = date.RoundToNearest(TimeSpan.FromMinutes(30)); // 2010/02/05 10:30:00

    More in this response.

    0 讨论(0)
  • 2020-12-02 02:27
    DateTime newDateTime = new DateTime(oldDateTime.Year, oldDateTime.Month, oldDateTime.Day
      ,oldDateTime.Hour, (oldDateTime.Minute / 30) * 30, 0);
    
    0 讨论(0)
  • 2020-12-02 02:30

    I would say something like that

    var time = DateTime.Now;
    var rounded = time.AddMinutes(
            time.Minute>30 ? -(time.Minute-30) : -time.Minute) 
    

    And you could even do your own extension

    public static class TimeHelper {
       public static DateTime RoundDown (this DateTime time)
       {
           return time.AddMinutes(
             time.Minute>30 ? -(time.Minute-30) : -time.Minute);
       }
    }
    

    EDIT

    This function cut's also the seconds / milliseconds if necessary. Thanks for the hint.

    public static DateTime RoundDown(this DateTime time)
    {
        return time.Subtract(
            new TimeSpan(0, 0, time.Minute > 30 ? (time.Minute - 30) : time.Minute, 
                time.Second, time.Millisecond));
    }
    
    0 讨论(0)
提交回复
热议问题