代码之家  ›  专栏  ›  技术社区  ›  Rookie Programmer Aravind

如何以分钟为单位舍入小时数(如果最小值小于30,则为小时数+0,否则为小时数+1)?

  •  13
  • Rookie Programmer Aravind  · 技术社区  · 14 年前

    我需要根据日期时间变量中的分钟对小时进行四舍五入。条件是:如果分钟数小于30,则分钟数必须设置为零,小时数不得更改;否则,如果分钟数大于等于30,则小时数必须设置为小时数+1,分钟数再次设置为零。秒被忽略。

    例子:
    11/08/2008 04:30:49 应该变成 11/08/2008 05:00:00
    11/08/2008 04:29:49 应该变成 11/08/2008 04:00:00

    我已经编写了非常好的代码,但我只想知道一个更好的方法,如果可以写的话,也会喜欢其他方法。

    string date1 = "11/08/2008 04:30:49";
    DateTime startTime;
    DateTime.TryParseExact(date1, "MM/dd/yyyy HH:mm:ss", null,     
        System.Globalization.DateTimeStyles.None, out startTime);
    
    if (Convert.ToInt32((startTime.Minute.ToString())) > 29)
    {
        startTime = DateTime.Parse(string.Format("{0}/{1}/{2} {3}:{4}:{5}",
            startTime.Month.ToString(), startTime.Day.ToString(), 
            startTime.Year.ToString(), startTime.Hour.ToString(), "00", "00"));
        startTime = startTime.Add(TimeSpan.Parse("01:00:00"));
        Console.WriteLine("startTime is :: {0}", 
            startTime.ToString("MM/dd/yyyy HH:mm:ss"));
    }
    else
    {
        startTime = DateTime.Parse(string.Format("{0}/{1}/{2} {3}:{4}:{5}", 
            startTime.Month.ToString(), 
            startTime.Day.ToString(), startTime.Year.ToString(), 
            startTime.Hour.ToString(), "00", "00"));
    
            Console.WriteLine("startTime is :: {0}", 
            startTime.ToString("MM/dd/yyyy HH:mm:ss"));
    }
    
    9 回复  |  直到 7 年前
        1
  •  28
  •   tvanfosson    14 年前

    作为替代方案:

    public static DateTime Round( DateTime dateTime )
    {
        var updated = dateTime.AddMinutes( 30 );
        return new DateTime( updated.Year, updated.Month, updated.Day,
                             updated.Hour,  0, 0, dateTime.Kind );
    }
    
        2
  •  22
  •   Ramin Bateni    7 年前

    如果速度是一个问题,以下应该是最快的方法:

    static DateTime RoundToHour(DateTime dt){
        long ticks = dt.Ticks + 18000000000;
        return new DateTime(ticks - ticks % 36000000000, dt.Kind);
    }
    

    这也是一种非常直接和简单的方法。

    解释一下,日期时间结构实际上没有存储年、月、日、小时、分钟等的字段。它只存储一个 long 值,自某个时期(公元1月1日)以来的“滴答”数。一个刻度是100纳秒,或者说是10000000秒。

    无论何时使用任何日期/时间属性,它都会除以适当的常量。

    在这里,我们加上一个等于30分钟的常数(30*60*1e7=18000000000滴答),然后减去一个等于1小时的常数(60*60*1e7=3600000000滴答)后的余数。

        3
  •  6
  •   Hans Kesting    14 年前

    怎么办:

    public static DateTime RoundToHours(DateTime input)
    {
    DateTime dt = new DateTime(input.Year, input.Month, input.Day, input.Hour, 0, 0);
    
        if (input.Minute > 29)
          return dt.AddHours(1);
        else
          return dt;
    }
    

    不需要转换成字符串再转换回来!

    编辑:
    使用 input.Hour+1 如果小时为23,则构造函数中的将失败。这个 .AddHours(1) 将在第二天正确生成“0:00”。

        4
  •  4
  •   mcintyre321    9 年前

    给你!

    var rounded = date.AddMinutes(30).Date.AddHours(date.AddMinutes(30).Hour);
    

    对于那些想把它铺在地上的人来说

    var floored = date.Date.AddHours(date.Hours)
    
        5
  •  3
  •   Russell Steen    14 年前
      DateTime s = DateTime.Now;
      if (s.Minute > 30) s = s.AddHours(1); //only add hours if > 30
      if (s.Minute == 30 && s.Second > 0) s = s.AddHours(1); //add precision as needed
      s = new DateTime(s.Year, s.Month, s.Day, s.Hour, 0, 0);
    
        6
  •  3
  •   Morfildur    14 年前

    扩展汉斯·凯斯汀的好答案:

    public DateTime RoundToHours(DateTime input)
    {
          DateTime dt = new DateTime(input.Year, input.Month, input.Day, input.Hour, 0, 0);
          return dt.AddHours((int)(input.Minutes / 30));
    }
    

    可能不需要(int)强制转换。

    编辑:改编了汉斯·凯斯汀在回答中所做的更正。

        7
  •  3
  •   CrimsonX    14 年前

    为了改进其他一些方法,这里有一个方法还将保留日期时间类型:

    /// <summary>
    /// Rounds a DateTime to the nearest hour.
    /// </summary>
    /// <param name="dateTime">DateTime to Round</param>
    /// <returns>DateTime rounded to nearest hour</returns>
    public static DateTime RoundToNearestHour(this DateTime dateTime)
    {
      dateTime += TimeSpan.FromMinutes(30);
    
      return new DateTime(dateTime.Year, dateTime.Month, dateTime.Day, dateTime.Hour, 0, 0, dateTime.Kind);
    }
    
        8
  •  1
  •   Roland    7 年前

    基于P爸爸的解决方案,我建议不要在一小时内硬编码那么多的代码。硬编码是邪恶的,不是吗?使用此修改后的解决方案,您现在可以将任何给定时间舍入为任意分钟数:

        public DateTime RoundToMinutes(DateTime dt, int NrMinutes)
        {
            long TicksInNrMinutes = (long)NrMinutes * 60 * 10000000;//1 tick per 100 nanosecond
            long ticks = dt.Ticks + TicksInNrMinutes / 2;
            return new DateTime(ticks - ticks % TicksInNrMinutes, dt.Kind);
        }
    

    我用这个四舍五入到最接近的5分钟,例如22:23变为22:25。

    几年前,我用同样的方法把钱四舍五入到最接近的25美分,例如22.23美元变成22.25美元。但项目经理有时会改变主意,但将四舍五入改为最接近的10%或5%是微不足道的。所以现在,当我的项目经理希望把时间四舍五入到另一轮的分钟数时,我也不必紧张。

    所以这种舍入方法既快速又灵活。


    我的方法已在中找到并发布 this 2008 SO solution

        9
  •  1
  •   Roland    7 年前
    DateTime dtm = DateTime.Now;
    if (dtm.Minute < 30)
    {
         dtm = dtm.AddMinutes(dtm.Minute * -1);
    }
    else
    {    
         dtm = dtm.AddMinutes(60 - dtm.Minute);
    }
    dtm = dtm.AddSeconds(dtm.Second * -1);