【问题标题】:My time calculation gives me a minus figure我的时间计算给了我一个负数
【发布时间】:2020-08-16 12:11:17
【问题描述】:

以下工作相当不错:

using System;
using System.Threading;

namespace cursor_position
{
    class Program
    {
        static void Main(string[] args)
        {
            DateTime startTime = DateTime.Now;;
            TimeSpan timeRemaining;
            int intCount = 119;
            
            for (int i = 0; i <= intCount; i++)
            {
                Thread.Sleep(2000);
                
                Console.Clear();

                timeRemaining = TimeSpan.FromTicks(DateTime.Now.Subtract(startTime).Ticks * (intCount - (i+1)) / (i+1));

                Console.SetCursorPosition(0, 0);
                Console.Write("ETA: ");
                Console.Write(String.Format("{0} Minutes, {1} Seconds", timeRemaining.Minutes, timeRemaining.Seconds));

                Console.WriteLine();
            }
        }
    }
}

但是,就在最后,我得到了 ETA 计算的负数。代码运行的时间越长(如果我增加sleep 或intCount),ETA 的负数就越大。

有人知道为什么吗?

【问题讨论】:

  • 这是因为时间延迟越大,Ticks 乘以 -1 越大(考虑 i=59 的情况,您的剩余时间由 Ticks*(59-60)/60 计算)。
  • 你为什么不按秒倒数呢?
  • 我会考虑使用 Microsoft 的反应式框架 (NuGet "System.Reactive") - 然后你可以这样做:DateTime startTime = DateTime.Now; DateTime targetTime = startTime.AddMinutes(1.0); var query = Observable.Interval(TimeSpan.FromSeconds(1.0)).Select(x =&gt; targetTime.Subtract(DateTime.Now)); query.Subscribe(x =&gt; Console.WriteLine($"ETA: {x.Minutes} Minutes, {x.Seconds} Seconds"));。

标签: c# .net datetime .net-core


【解决方案1】:

当您尝试使用这样的数学计算时差时,总是会出现问题。最好完全不使用计数器来强化你的代码。

试试这个代码:

DateTime startTime = DateTime.Now;
DateTime targetTime = startTime.AddMinutes(1.0);

while (true)
{
    DateTime now = DateTime.Now;
    if (now > targetTime)
    {
        break;
    }
    else
    {
        TimeSpan timeRemaining = targetTime.Subtract(now);

        Console.Write("ETA: ");
        Console.Write(String.Format("{0} Minutes, {1} Seconds", timeRemaining.Minutes, timeRemaining.Seconds));

        Console.WriteLine();

        Thread.Sleep(1000);
    }
}

我认为在您当前的问题中使用Thread.Sleep(1000)(在您的原始问题中)和Thread.Sleep(2000) 使我不清楚您想要计算不确定过程的剩余时间,例如复制文件。在我看来,您只是在进行“计时器倒计时”。

让我们编写一个通用函数来估计不确定过程的剩余时间。

public TimeSpan ComputeRemaining((int count, DateTime time) start, (int count, DateTime time) current, int end) =>
    current.count - start.count == 0
        ? TimeSpan.MaxValue
        : TimeSpan.FromSeconds((end - current.count) * current.time.Subtract(start.time).TotalSeconds / (current.count - start.count));

给定一个起始计数和DateTime、一个给定的current 计数和DateTime,以及所需的end 计数,这个函数产生剩余时间。

它可以随着计数的增加或减少而工作。

让我们看看它的实际效果。

var now = DateTime.Now;
var start = (count: 0, time: now.Subtract(TimeSpan.FromSeconds(5.0)));
var current = (count: 50, time: now);
var end = 100;
Console.WriteLine(ComputeRemaining(start, current, end).TotalSeconds);

所以这个例子是一个在5.0 秒前开始的进程,现在已经完成了 50% - 需要多长时间? 5.0 秒。此代码正确写出5。

让我们用你的示例应用试试吧:

static void Main(string[] args)
{
    var random = new Random();
    
    DateTime startTime = DateTime.Now;
    int intCount = 30;

    for (int i = 0; i <= intCount; i++)
    {
        Thread.Sleep(random.Next(100, 2000));

        TimeSpan timeRemaining = ComputeRemaining((0, startTime), (i, DateTime.Now), intCount);

        Console.Write("ETA: ");
        Console.Write(String.Format("{0} Minutes, {1} Seconds", timeRemaining.Minutes, timeRemaining.Seconds));

        Console.WriteLine();
    }
}

当我运行它时,我得到:

预计到达时间:48 分 5 秒 预计到达时间:0 分 54 秒 预计到达时间:0 分 39 秒 预计到达时间:0 分 42 秒 预计到达时间:0 分 41 秒 预计到达时间:0 分 33 秒 预计到达时间:0 分 32 秒 预计到达时间:0 分 32 秒 预计到达时间:0 分 31 秒 预计到达时间:0 分 29 秒 预计到达时间:0 分 29 秒 预计到达时间:0 分 28 秒 预计到达时间:0 分 27 秒 预计到达时间:0 分 25 秒 预计到达时间:0 分 22 秒 预计到达时间:0 分 20 秒 预计到达时间:0 分 18 秒 预计到达时间:0 分 17 秒 预计到达时间:0 分 16 秒 预计到达时间:0 分 14 秒 预计到达时间:0 分 12 秒 预计到达时间:0 分 11 秒 预计到达时间:0 分 10 秒 预计到达时间:0 分 8 秒 预计到达时间:0 分 7 秒 预计到达时间:0 分 6 秒 预计到达时间:0 分 4 秒 预计到达时间:0 分 3 秒 预计到达时间:0 分 2 秒 预计到达时间:0 分 1 秒 预计到达时间:0 分 0 秒

请注意,在我的示例的早期阶段,估算值实际上增加了,因为它是根据随机输入的时间计算得出的。

我相信这就是您要找的。​​p>

【讨论】:

  • 不确定如何将其应用到我的代码中,因为我不知道提前完成需要多长时间。
  • @oshirowanen - 是的,你知道。你正在设置 intCount 并且你有 Thread.Sleep(X) 你知道你正在计算 intCount * X 毫秒数。
  • @oshirowanen - 哦,这是一个移动的估计吗?这是否就像您移动文件时显示移动完成的估计时间一样?那么Thread.Sleep(2000);的使用只是为了模拟工作?
  • @oshirowanen - 这是您要计算的类型吗?你到底需要什么?
【解决方案2】:

看来你的括号有问题。

假设我们设置了intCount = 1,那么根据你的代码,for循环会被执行两次。一次用于i=0,一次用于i=1。

当i = 0 我们有:1234 * (intCount - (i + 1)) / (i + 1) ==&gt; 1234*(1 - (0 + 1)) / (0 + 1)

上面的代码等于1234 * A / B,其中A是(intCount - (i + 1)),B是(i + 1)。所以首先会计算1234 * A,然后将结果除以B!

所以我们有等于 0 的 1234 * (1-(0+1)) 和等于 0 的 0 / 1。

当i = 1 我们有`1234 * (intCount - (i + 1)) / (i + 1) ==> 1234*(1 - (1 + 1)) / (1 + 1) = -617

我们有1234 * (1-(1+1)) 等于-1234,然后-1234 / 1 等于-1234。

要解决此问题,您需要将for 循环更改为:

for (int i = 0; i < intCount; i++)

在这种情况下,循环将执行一次(i=0),您将不再获得负值。并且也做这个修改来解决括号问题:

timeRemaining = TimeSpan.FromTicks(DateTime.Now.Subtract(startTime).Ticks * ((intCount - (i + 1)) / (i + 1)));

【讨论】:

  • 你算错了。 -1 / 2 == 0。如果是-1.0 / 2.0,则等于-0.5,但不是整数。
  • @Enigmativity 你是对的,我已经更新了答案
  • 数学仍然是错误的。当您有ticks = 1234、intCount = 1 和i = 1 时,则为(ticks * (intCount - (i + 1)) / (i + 1)) == -617。你在正确的轨道上,但你显示了一些令人困惑的数字。你仍然表现出双重困惑-0.5。
  • 我真是个粗心大意的人:-|
猜你喜欢
  • 2014-12-03
  • 1970-01-01
  • 2021-04-01
  • 2021-07-23
  • 1970-01-01
  • 2022-01-23
  • 2022-01-17
  • 2023-01-18
  • 2020-09-11
相关资源
最近更新 更多