在 C# 中舍入 FILETIME 以适应 FAT 舍入
Rounding FILETIME in C# to accommodate FAT rounding
我有一个 Windows FILETIME :
A 64-bit value representing the number of 100-nanosecond intervals
since January 1, 1601 (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。
数学不是我最强的科目...我可以安全地将最后四位数字归零吗?或者我应该忘记上面的代码并将最后八位数字完全归零吗?或者……换个方式?
与其纠结于 DateTime
对象,不如只做原始数学运算更容易:
如果input
是100纳秒的个数,那么:
/10
为微秒数;
/10,000
为毫秒数;
/10,000,000
为秒数;
/20,000,000
为 'two-seconds' 个数;
所以:
input = input / 20000000 * 20000000;
除法会将数字向下舍入到最后一个偶数秒,然后乘法会将其再次恢复到正确的大小。
但是你说你希望它四舍五入:
input = (input / 20000000 + 1) * 20000000;
在再次分解之前将小数加一 'two-second'。
迂腐地说,如果 input
恰好 两秒标记,那么这将增加两秒。要解决这个问题:
if (input % 20000000!=0) {
input = (input / 20000000 + 1) * 20000000;
} // if
在决定提高它之前检查是否有小数 'two-second'。我会留给你是否添加这个额外的支票...
@Matthew Watson 指出,程序员解决上述问题的常用技巧是预先添加 不完全 足以滚动 input
到下一个 'two-second',然后继续进行先除后乘。如果 input
超过了最小值,那么它会滚动:
const long twoSeconds = 20000000;
...
input = (input + twoSeconds - 1) / twoSeconds * twoSeconds;
使用原始报价,然后将其四舍五入为两秒的间隔。这比尝试在逗号后添加或删除内容更简单。
const long twoSecondsInTicks = 20000000; // 20 million
long twoSecondIntervals = originalDt.Ticks / twoSecondsInTicks;
if (originalDt.Ticks % twoSecondsInTicks != 0) ++twoSecondIntervals;
var newDt = new DateTime(twoSecondIntervals * twoSecondsInTicks);
您的问题出在四舍五入到最接近的秒数行:
// round it UP to the nearest Second
var newDt = originalDt.AddMilliseconds(1000 - originalDt.Millisecond);
你保持完整毫秒的分数(因为originalDt.Millisecond
是一个整数值),微- 和 nano- 秒;应该是
// round it UP to the nearest Second
var newDt = originalDt.AddTicks( - (originalDt.Ticks % TimeSpan.TicksPerSecond));
当使用 ticks 时,最小的 可能的日期时间单位,你会得到预期的 130790247820000000
而没有 纳秒 (...8763
)
我有一个 Windows FILETIME :
A 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (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。
数学不是我最强的科目...我可以安全地将最后四位数字归零吗?或者我应该忘记上面的代码并将最后八位数字完全归零吗?或者……换个方式?
与其纠结于 DateTime
对象,不如只做原始数学运算更容易:
如果input
是100纳秒的个数,那么:
/10
为微秒数;
/10,000
为毫秒数;
/10,000,000
为秒数;
/20,000,000
为 'two-seconds' 个数;
所以:
input = input / 20000000 * 20000000;
除法会将数字向下舍入到最后一个偶数秒,然后乘法会将其再次恢复到正确的大小。
但是你说你希望它四舍五入:
input = (input / 20000000 + 1) * 20000000;
在再次分解之前将小数加一 'two-second'。
迂腐地说,如果 input
恰好 两秒标记,那么这将增加两秒。要解决这个问题:
if (input % 20000000!=0) {
input = (input / 20000000 + 1) * 20000000;
} // if
在决定提高它之前检查是否有小数 'two-second'。我会留给你是否添加这个额外的支票...
@Matthew Watson 指出,程序员解决上述问题的常用技巧是预先添加 不完全 足以滚动 input
到下一个 'two-second',然后继续进行先除后乘。如果 input
超过了最小值,那么它会滚动:
const long twoSeconds = 20000000;
...
input = (input + twoSeconds - 1) / twoSeconds * twoSeconds;
使用原始报价,然后将其四舍五入为两秒的间隔。这比尝试在逗号后添加或删除内容更简单。
const long twoSecondsInTicks = 20000000; // 20 million
long twoSecondIntervals = originalDt.Ticks / twoSecondsInTicks;
if (originalDt.Ticks % twoSecondsInTicks != 0) ++twoSecondIntervals;
var newDt = new DateTime(twoSecondIntervals * twoSecondsInTicks);
您的问题出在四舍五入到最接近的秒数行:
// round it UP to the nearest Second
var newDt = originalDt.AddMilliseconds(1000 - originalDt.Millisecond);
你保持完整毫秒的分数(因为originalDt.Millisecond
是一个整数值),微- 和 nano- 秒;应该是
// round it UP to the nearest Second
var newDt = originalDt.AddTicks( - (originalDt.Ticks % TimeSpan.TicksPerSecond));
当使用 ticks 时,最小的 可能的日期时间单位,你会得到预期的 130790247820000000
而没有 纳秒 (...8763
)