【问题标题】:C# Time span to string issueC# 字符串问题的时间跨度
【发布时间】:2014-09-01 13:41:09
【问题描述】:

你好 stackoverflow 的人们。当我尝试将时间跨度转换为字符串时遇到问题。

代码如下:

   private void timer1_Tick(object sender, EventArgs e)
    {
        timeLeft = timeLeft - 1;
        TimeLabel.Text = TimeSpan.FromMilliseconds(timeLeft).ToString("h'h 'm'm 's's'");
    }

请注意,timeLeft 以毫秒为单位。

但是,每当我尝试通过这个时,我都会得到 2 组分钟部分。 像这样:

虽然应该是这个时间:

【问题讨论】:

  • 您应该通过减去两个DateTime 值来计算剩余时间,其中一个是DateTime.Now。您不能保证计时器每次应该正确计时,并且可能会以任何一种方式倾斜毫秒,随着时间的推移,这会导致您剩余的时间不准确。
  • 另外,我不明白这里有什么问题。你从值中减去1,然后将其转换为FromMilliseconds,显然你一次倒计时一毫秒。这将在 208 个刻度后为您提供显示的值。这不是你想要的吗?如果不是,那你为什么要那样做呢?
  • 56.792 不是 2 组分钟。它是 56 秒和 792 毫秒
  • 我不明白问题是什么?你能解释得更好吗?

标签: c# string timer visual-c#-express-2010


【解决方案1】:

我看到你在每个计时器滴答声中更新标签,虽然它没有显示在代码中,但看起来你的计时器间隔可能设置为 1 秒,对吗?

您做错的第一件事就是相信您之前在计时器中设置的 1 秒间隔,并将您的代码硬编码到该间隔。事实是您不能依靠计时器间隔来精确,因为大多数计时器的分辨率时间约为 14 - 16 毫秒,因此这不是测量时间的精确方法。

您应该改用使用 Win32 API QueryPerformanceFrequencyQueryPerformanceCounter 的时间 System.Diagnostics.Stopwatch 类。由于 Windows 不是Real Time Operation System,因此这些是测量时间的更可靠和快速的方法。

至于代码的外观,我提供了一个示例,它应该很容易适应您。此外,我还为您的 TimeSpan - 字符串翻译问题提供了一个解决方案。

class Program
{
    static void Main(string[] args)
    {
        Stopwatch sw = new Stopwatch();

        Console.WriteLine("Starting..");
        sw.Start();
        Console.ReadLine();
        sw.Stop();
        Console.WriteLine("Elapsed time {0}:{1}:{2}:{3}", sw.Elapsed.Hours.ToString("00"), sw.Elapsed.Minutes.ToString("00"), sw.Elapsed.Seconds.ToString("00"), sw.Elapsed.Milliseconds);
    }
}

使用 System.Diagnostics.Stopwatch 属性时要小心,使用 Elapsed.Ticks 属性和 ElapsedTicks 属性有很大的不同,它在here 中进行了解释。

希望对你有帮助!!

【讨论】:

  • 如果我没记错秒表计数不是吗?这应该倒计时
【解决方案2】:

由于无法保证计时器将准确地每毫秒触发一次,因此您必须保存开始时间,然后通过从当前时间中减去开始时间来计算经过的时间。

这里有一段代码sn-p来说明:

private DateTime _StartTime;

private void OnCheckBoxTimerEnabledCheckedChanged(object sender, EventArgs e)
{
    _StartTime = DateTime.UtcNow;
    timer.Enabled = checkBoxTimerEnabled.Checked;
}

private void OnTimerTick(object sender, System.EventArgs e)
{
    var now = DateTime.UtcNow;
    labelTimeElapsed.Text = (now - _StartTime).ToString("h'h 'm'm 's's'");
}

在这种情况下,您也不需要每毫秒触发一次计时器。只需每 100 毫秒触发一次,以确保用户眼睛足够准确。

还有一个提示: 如果您需要自己计算相对时间,您应该始终坚持使用DateTime.UtcNow 而不是DateTime.Now。因此,当您从正常时间切换到夏令时(反之亦然)时,当您的计时器正在运行时,您不会遇到麻烦。

【讨论】:

    【解决方案3】:

    您的代码没有任何问题。但我猜你认为有,因为上面的示例显示 2:02:56 和另一个 02:03:00 是相当 Close 缺少大约 3200 毫秒...

    timeLeft 的实际值是多少?

    Read some more in the documentation on customizing timespan strings

    【讨论】:

    • 这是一个关闭定时器,值会根据用户输入而变化,在这种情况下,它将是“3776000”,它是由这一行计算的Settime = Convert.ToInt32(numericUpDown1.Value * 3600000 + numericUpDown2.Value * 60000 + numericUpDown3.Value * 1000);
    【解决方案4】:

    正如 Lasse V. Karlsen 在对您的问题的评论中提到的那样,使用 Timer's Tick 事件来跟踪经过的时间会导致不准确。

    您要做的是在计时器开始时存储一个时间戳 (DateTime.Now),然后在每次计时器滴答时将其与新的 DateTime.Now 进行比较,如下所示:

        DateTime timestamp;
        TimeSpan timeLeft;
    
        private void begin_timer()
        {
            timestamp = DateTime.Now;
            timer1.start();
        }
    
        private void timer1_Tick(object sender, EventArgs e)
        {
            timeLeft = DateTime.Now - timestamp;
            TimeLabel.Text = timeLeft.ToString("HH:mm:ss.fff");
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多