C#:使用模数学递减时钟

试图用手模拟24小时时间的翻转(使用数学与使用时间跨度类)。 递增部分很容易弄清楚如何从23:00到0:00滚动,但从另一个方向走向结果却变得非常混乱。 这是我到目前为止所拥有的:

static void IncrementMinute(int min, int incr) { int newMin = min + incr, hourIncrement = newMin / 60; //increment or decrement the hour if((double)newMin % 60  -1) hourIncrement = -1; Console.WriteLine("Hour increment is {0}: ", hourIncrement); } 

我发现的问题是当倒退时,如果模数在数字之间,它将不会正确递减。 例如:它是12:00并且你减去61分钟,我们知道时间将是10:59,因为从12:00到11:59,小时应该回滚1小时,然后从11:00再回来到10:59 不幸的是我计算它的方式:在这种情况下newMin%60,只抓取第一个小时回滚,但由于第二次回滚在技术上是-1.0166作为余数,并且因为mod只返回一个整数,所以它四舍五入。 我确定我在这里缺少一些基本的数学,但有人可以帮助我吗?

编辑:我已经写了很多种方式。 有些比其他人更接近,但我知道这比看起来更简单。 我知道这个看起来有点“他正在做什么”,但你应该能够看到我想要做的事情。 增加时钟并使其从23:59到0:00翻转很容易。 向后看已经certificate并不那么容易。

好的,这是带翻转的incrementMinute。 简单。 但试着倒退。 不起作用。

 static void IncrementMinute(int min, int incr) { int newMin = min + incr, hourIncrement = newMin / 60; min = newMin % 60; Console.WriteLine("The new minute is {0} and the hour has incremented by {1}", min, hourIncrement); } 

我会选择一些更简单的东西

 public class Clock { public const int HourPerDay = 24; public const int MinutesPerHour = 60; public const int MinutesPerDay = MinutesPerHour * HourPerDay; private int totalMinutes; public int Minute { get { return this.totalMinutes % MinutesPerHour; } } public int Hour { get { return this.totalMinutes / MinutesPerHour; } } public void AddMinutes(int minutes) { this.totalMinutes += minutes; this.totalMinutes %= MinutesPerDay; if (this.totalMinutes < 0) this.totalMinutes += MinutesPerDay; } public void AddHours(int hours) { this.AddMinutes(hours * MinutesPerHour); } public override string ToString() { return string.Format("{0:00}:{1:00}", this.Hour, this.Minute); } } 

样品用法:

 new Clock().AddMinutes(-1); // 23:59 new Clock().AddMinutes(-61); // 22:59 new Clock().AddMinutes(-1441); // 23:59 new Clock().AddMinutes(1); // 00:01 new Clock().AddMinutes(61); // 01:01 new Clock().AddMinutes(1441); // 00:01 

您可以先尝试计算分钟和小时的增量,然后处理新分钟跨越一小时边界的情况,如下所示:

 int hourIncrement = incr / 60; int minIncrement = incr % 60; int newMin = min + minIncrement; if (newMin < 0) { newMin += 60; hourIncrement--; } else if (newMin > 60) { newMin -= 60; hourIncrement++; } 

编辑

我喜欢@Ben Voigts的回答,但想知道性能是否会有任何差异。 我在下面运行控制台应用程序来计算两者,并对结果感到有些惊讶。

  • 上面的代码为40毫秒
  • Ben的回答是2876 ms

这是在发布版本中完成的。 其他人可以运行并确认吗? 我在计算时间方面犯了什么错误吗?

 using System; using System.Diagnostics; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { Stopwatch sw = new Stopwatch(); int max = 100000000; sw.Start(); for (int i = 0; i < max; i++) IncrementMinute1(0, -61); sw.Stop(); Console.WriteLine("IncrementMinute1: {0} ms", sw.ElapsedMilliseconds); sw.Reset(); sw.Start(); for (int i = 0; i < max; i++) IncrementMinute2(0, -61); sw.Stop(); Console.WriteLine("IncrementMinute2: {0} ms", sw.ElapsedMilliseconds); Console.ReadLine(); } static void IncrementMinute1(int min, int incr) { int hourIncrement = incr / 60; int minIncrement = incr % 60; int newMin = min + minIncrement; if (newMin < 0) { newMin += 60; hourIncrement--; } else if (newMin > 60) { newMin -= 60; hourIncrement++; } } static void IncrementMinute2(int min, int incr) { min += incr; int hourIncrement = (int)Math.Floor(min / 60.0); min -= hourIncrement * 60; } } } 

模数学仅针对整数定义。 如果您尝试将模数运算与实数混合,则不会成功。 你需要找出一种不同的数学方法。

尝试

  int newMin = min + incr, hourIncrement = (int)Math.Floor(newMin / 60.0); min -= hourIncrement * 60; 

基本问题是你希望hourIncrement向下hourIncrement入,但整数除法向零hourIncrement入。 它们与正数相同,但不是负数……

编辑(摆脱无用的额外变量):

  min += incr; int hourIncrement = (int)Math.Floor(min / 60.0); min -= hourIncrement * 60; 

EDIT2(避免浮点运算):

  min += incr; int hourIncrement = min / 60; min -= hourIncrement * 60; if (min < 0) { min += 60; --hourIncrement; } 

为什么要复杂化

 public System.Timers.Timer timer = new System.Timers.Timer(1000); public DateTime d; public void init() { timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed); d = new DateTime(2011, 11, 11, 23, 59, 50); d=d.AddHours(1); Console.Writeline(d); d=d.AddHours(-2); Console.Writeline(d); timer.Enabled = true; } void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { this.Dispatcher.Invoke(DispatcherPriority.Normal, (Action)(() => { MoveClockHands(); d=d.AddSeconds(1); Console.WriteLine(d); })); } void MoveClockHands() //12 hours clock ( s=d.Second * 6; m=d.Minute * 6; h=0.5 * ((d.Hour % 12) * 60 + d.Minute) }