【问题标题】:Rounding FILETIME in C# to accommodate FAT rounding在 C# 中舍入 FILETIME 以适应 FAT 舍入
【发布时间】:2016-10-16 16:48:14
【问题描述】:

我有一个 Windows FILETIME

一个 64 位值,表示 100 纳秒间隔的数量 自 1601 年 1 月 1 日 (UTC))

我需要将它向上舍入到最接近的偶数秒,如 here 所述。

我目前的代码:

        var originalDt = DateTime.FromFileTimeUtc(input);

        // round it UP to the nearest Second
        var newDt = originalDt.AddMilliseconds(1000 - originalDt.Millisecond);

        // then if our new Second isn't even
        if (newDt.Second % 2 != 0)
        {
            // add one second to it, then it'll be even
            newDt = newDt.AddSeconds(1);
        }

        return newDt.ToFileTimeUtc();

不太好用...它将 130790247821478763 变成 130790247820008763,我在 130790247800000000 之后。

数学不是我最擅长的科目...我可以安全地将最后四位数字归零吗?还是我应该忘记上面的代码,只将最后八位数字完全归零?或者……另一种方式?

【问题讨论】:

  • 你用value = N * (value / N + N-1)四舍五入到N的倍数

标签: c# datetime math filetime


【解决方案1】:

与其在DateTime 对象上苦苦挣扎,不如只做简单的数学运算:

如果input是100纳秒的数量,那么:

/10为微秒数;
/10,000为毫秒数;
/10,000,000为秒数;
/20,000,000为'两秒数';

所以:

input = input / 20000000 * 20000000;

除法会将数字向下舍入到最后一个偶数秒,然后乘法将再次将其恢复为正确的大小。

但你说你希望它向上取整:

input = (input / 20000000 + 1) * 20000000;

在再次分解之前,这会在小数字上增加一个“两秒”。

迂腐地,如果input 正好在两秒标记处,那么这将增加两秒。要解决这个问题:

if (input % 20000000!=0) {
    input = (input / 20000000 + 1) * 20000000;
} // if

在决定增加它之前检查是否有任何小数“两秒”。至于你是否添加这个额外的检查,我会留给你...

@Matthew Watson 指出,解决上述问题的程序员常用技巧是预先添加 不太 足以将 input 滚动到下一个“两秒”,然后继续并做除法然后乘法。如果input 超过最小值,则将其翻转:

    const long twoSeconds = 20000000;
    ...
    input = (input + twoSeconds - 1) / twoSeconds * twoSeconds;

【讨论】:

  • 正是我想要的。
  • 其实我觉得你可以做input = ((input + 20000000 - 1) / 20000000) * 20000000;来避免做模数计算
  • @Matthew 是的!现在向一个自称是非数学家的人解释一下
  • @JohnBurger 谢谢,这正是我要找的答案!
【解决方案2】:

使用原始刻度,然后将它们四舍五入到两秒的间隔。这比尝试在逗号后添加或删除内容更简单。

const long twoSecondsInTicks = 20000000;    // 20 million
long twoSecondIntervals = originalDt.Ticks / twoSecondsInTicks;
if (originalDt.Ticks % twoSecondsInTicks != 0) ++twoSecondIntervals;
var newDt = new DateTime(twoSecondIntervals * twoSecondsInTicks);

【讨论】:

    【解决方案3】:

    您的问题在于四舍五入到最近的秒行:

    // round it UP to the nearest Second
    var newDt = originalDt.AddMilliseconds(1000 - originalDt.Millisecond);
    

    你留下完整的毫秒的分数(因为originalDt.Millisecond是一个整数值),micro-和nano em>- 秒;应该是

    // round it UP to the nearest Second
    var newDt = originalDt.AddTicks( - (originalDt.Ticks % TimeSpan.TicksPerSecond));
    

    当使用 ticks 时,最小 可能的日期时间单位,你会得到预期的 130790247820000000 而没有 纳秒 (...8763)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-11-05
      • 2012-06-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多