这是关于格式()功能及其行为
不关于MILLISECONDS输出!
时间格式的示例仅为示例,但不是更多!
我们有两个由Timer()返回的顺序值。格式化后,我们得到的是时间测量而不是时间戳:
? Format(36411.44921875 / 86400, "hh:nn:ss")
10:06:51
? Format(36410.984375 / 86400, "hh:nn:ss")
10:06:51 ' I'm waiting for 10:06:50 here
Add_1:
我没有被问及如何绕过这个问题(比如格式分离整数和小数部分等)。我很有意思 - 这是Format()的原生行为吗?是否有特定的格式字符串,例如,以避免舍入?
Add_2:
两个顺序值
顺序在这里并不重要。我刚刚在日志中发现了这个序列中提到的行为:
222 16-10-06 10:06:51.449 36411.44921875 0.421428810402199
221 16-10-06 10:06:51.984 36410.984375 0.421423430266204
抱歉我的英文......
ADD_3:
在我的例子中,我仍然分别处理整数和小数部分。所以我这样做了:
Format$(Int(dDate * 86400) / 86400, "hh:nn:ss")
'543 16-10-06 12:03:21.214 43401.21484375 0.502328875506366
'542 16-10-06 12:03:20.667 43400.66796875 0.502322545934606
然而,这只是一个技巧而不是所有情况都很方便......
Add_4:
显然,我的英语不够好:(
问题是使用Format()会破坏时间戳! 在采用时间戳时,仅使用向下舍入。
例如,我们现在有23:49:59.981765
什么是时间精度的时间戳? 23.不是00.
分钟准确度?是的,23:49,但不是23:50!
秒 - 23:49:59
毫秒? 23:49:59.981
不要与时间戳和时间间隔测量相混淆......在第二种情况下,你可以将任何东西弄圆...
Add_4.1:
从上面的Add_4玩 23:49:59.981765 :
? Format(CDate((TimeValue("23:49:59") * 86400 + .981765) / 86400), "hh")
23 ' *** !!! NOT ROUNDED !!! ***
? Format(CDate((TimeValue("23:49:59") * 86400 + .981765) / 86400), "hh:nn")
23:50
? Format(CDate((TimeValue("23:49:59") * 86400 + .981765) / 86400), "hh:nn:ss")
23:50:00
结论
Format()表现得像他喜欢的那样。
有些价值观,有些 - 不是。通过哪些规则?这是绝密 出于什么原因,它使用标准舍入而不是VB(A)中的银行舍入?这是一个绝密的第2号。
。
++++++++++++++++++++++++++++++++++++++++++++++++ <无线电通信/>
P.S。
首先 - 非常感谢共产国际(RotFront!)和古斯塔夫有用地澄清了触及的问题。
然而,我的问题(陈述) - 格式()表现得像他喜欢 - 仍然是开放的。
当我说出&#34; Timer()&#34;这句话时,这是我最大的错误。和&#34;毫秒&#34;。甚至当标题澄清时都忽略了它。我问第二次 - 请忘记&#34;定时器()&#34;,&#34;毫秒&#34;和点后的数字catterpillars。
真的有共产国际(RotFront!)的唯一评论,我在等待披露:
日期类型本身以第二精度指定,此上下文中的格式适用于日期类型。
换句话说,不是Format(),而是内部(im-或显式)转换为Date数据类型是around的原因。我已经准备好对此感到满意,但是:
:一种。如上所述 https://msdn.microsoft.com/en-us/library/ms221646.aspx
变体时间解析为一秒。 忽略输入日期中的任何毫秒。
我们看到毫秒不仅不会被忽略,而是舍入而不是!
B中。 How_1他们四舍五入?
共产国际(RotFront!)绝对正确地说:
如果没有在全职的情况下查看它,就不可能考虑将其缩小一秒。
在我的情况下,圆形链在几小时内断开。但它假设,所有时间成分,即秒,分,小时,天,月,年都是公平的......
℃。 How_2他们四舍五入?
Comintern(RotFront!)写道:
Windows使用距离零方法1的一半。
哪个&#34; Windows&#34;?谁是&#34; Windows&#34;? 我知道,VB(A)有一个舍入函数 - Round() - 它使用&#34; Round half to even&#34;。数据类型转换的所有内部舍入也使用它。但不是&#34;一半远离零&#34;。
只有Format(),upstart,white crow,使用&#34;一半远离零&#34; ...为什么?
d。 Resolution_1 ...
什么意思&#34;解决方案&#34;适用于数据类型? 500毫秒,1秒 - 只有两到三个来源,这个&#34;分辨率&#34;数字听起来......我手上有Date == Double数据类型。我无法理解 - 如何从连续数字线中删除它们 - 这0.5-1秒......
电子。 Resolution_2 ...
也许所有这些误解是因为只有内部计时器 - Date(),Now(),Time(),Timer() - 被认为是唯一可能的时间戳来源?在我的情况下,我获得具有可靠的真实时间戳的外部csv日志,并且Format()为我扭曲了这些优秀的数据。
即使在直接使用Timer()的情况下也是如此。我从QueryPerformanceCounter和GetSystemTimeAsFileTime中显示了两个计数。为了在视觉上评估它们的有效性,我将其格式化为&#34; hh:nn:ss.000&#34;并靠近它们的Timer()数据被Format()扭曲...
答案 0 :(得分:2)
我只想知道 - 有没有办法控制舍入,由...产生 格式()internaly?
没有
但是通过自定义方法,您可以根据需要处理毫秒。
您可以在主题和下载所有常见任务的代码上学习本文,包括显示小数秒或毫秒的方法:
MS Access Can Handle Millisecond Time Values
如果您对此有任何疑问,请回来。
<强>附录强>
我在这里看到很多混乱,这些混淆了你的问题。所以,为了回到这个,如果你想摆脱你的值的毫秒部分(分别是449和984)来获得只有“完整”秒的显示,你可以使用这个功能(取自上面的链接)杀死毫秒:
Public Function DateTimeRound( _
ByVal datTime As Date) _
As Date
' Returns datTime rounded off to the second by
' removing a millisecond portion.
Call RoundSecondOff(datTime)
DateTimeRound = datTime
End Function
Private Sub RoundSecondOff( _
ByRef datDate As Date)
' Rounds off datDate to the second by
' removing a millisecond portion.
Const clngSecondsPerDay As Long = 24& * 60& * 60&
Dim lngDate As Long
Dim lngTime As Long
Dim dblTime As Double
' Get date part.
lngDate = Fix(datDate)
' Get time part.
dblTime = datDate - lngDate
' Round time part to the second.
lngTime = Fix(dblTime * clngSecondsPerDay)
' Return date part and rounded time part.
datDate = CDate(lngDate + lngTime / clngSecondsPerDay)
End Sub
现在您可以将格式应用于结果值。
附录2
对PS的更正:
日期类型本身以第二精度指定,格式为 此上下文适用于日期类型。
换句话说,不是Format(),而是内部(im-或显式)转换 to Date数据类型是回合的原因。
虽然数据类型仅指定为秒数,但这并未阻止以毫秒精度运行的能力。因此,你的“其他词语”应恰恰相反:
Format(),而不是内部(明确或明确)转换,是回合的原因。
您指向 LPSYSTEMTIME 的链接会增加很多混淆,因为这与Windows时间有关,而这与Windows的数据类型Date(A)无关。你应该忘记这一切,因为它是Windows内部的,在VBA中没有用,除了你可以通过Windows API访问它的特殊情况(正如你将在我的毫秒文章中演示的那样)。
在我的情况下,圆形链在几小时内断开。
是的,如果值的毫秒部分超过500,就会发生这种情况。您可以使用上面的函数来避免这种情况。
我知道,VB(A)有一个舍入函数 - Round() - 和它 使用“圆一半甚至”。数据类型的所有内部舍入 转换也使用它。但不是“一半远离零”。
你在这里错过了许多细节。 Round 和所有Cxxx函数(如CLng)执行 Banker's Rounding 或“round to even”。相反,作为VBA的唯一功能, Format 执行正常的4/5舍入,就像您在学校学到的那样。因此,它将始终将十进制秒舍入到最接近的整数。
你问为什么,除了“按设计”之外,没有其他答案。
如果您真的对舍入主题感兴趣,请注意本机 Round 非常错误。您可以阅读所有相关内容,包括文档和函数,其中涵盖了Github中任何值的任何数值数据类型的舍入的所有方面:
什么意思是“解决方案”适用于数据类型?
这意味着两个值之间的最小差异。对于数据类型Date:100-01-01 00:00:00.000
和9999-12-31 23:59:59.999
的极值,这恰好是1 ms,因此对于整个Date范围有效。在1899-12-30
左右的小范围内,您可以达到微秒,并且在几个小时的范围内,甚至到纳秒。
我无法理解 - 如何从连续数字中删除它们 线 - 这0.5-1秒...
好吧,幸运的是情况并非如此,所以没有什么可以理解的。
在我的情况下,我获得具有可靠的真实时间戳的外部csv日志
这就是生活,这就是我当时写这篇文章的原因之一。如何处理这类案件。
Format()为我扭曲了这个优秀的数据。
是的,因为格式不适合它。但是,再一次,使用我的函数来切断分秒,你可以按原样使用格式。
对于 Timer ,我无法看到它的情况。它实际上不是用于其名称所暗示的任何其他内容 - 它返回一个分辨率为1/64秒的 Single ,对于快速计时函数或运行查询非常方便。就是这样。
答案 1 :(得分:2)
tl; dr - 没有舍入规则秒。这取决于整个时间。
日期类型在内部存储为Double,而后者又是带有52位尾数的IEEE 754浮点数。基数必须适应足够高的值,以表示VT_DATE(12999年12月31日)有效的最大日期。自纪元以来的几天表达,即2,958,465。这意味着必须在小数点左侧容纳至少7位数字。
假设数据类型占支持的最大基数,则在十进制右边给出13位数而不会丢失精度(请参阅this answer以获取该数字的来源,以及{{上的维基百科文章) 3}}以获得更详细的解释)。假设基数基于存储的实际数字(示例中为5位数),则得到14位精度。 实际上在IEEE规范中定义了几种舍入方法,但Windows使用Machine Epsilon方法 1 。
请记住,这会发生所有级别的Double格式化,因为它被定义为小数天,每个组件都会产生重复的分数:
1 / 24 / 60 / 60
,或.0000115740740740741。请注意,VBA在19位数后对该值进行舍入。1 / 24 / 60
,或.0006944444444444444。请注意,VBA在18位数后对此进行舍入。1 / 24
,或.0416666666666667。请注意,VBA也会对此进行舍入,但精度为16位。这些计算都不需要考虑基数,但更重要的是它们都是相互混合的。这意味着任何小时,分钟或秒组件的任何精度损失都会影响所有这些。 如果不在全日制的背景下查看它,就不可能考虑将其缩小一秒。
现在,让我们来看看你的代码:
Format$(Int(dDate * 86400) / 86400, "hh:nn:ss")
你提到你正在评估Timer()
函数的结果,所以让我们假设为dDate = Timer()
的论证。首先要指出的是Timer
会返回Single
,不会返回Double
。这意味着返回值的精度只能假设精确到大约7位小数(基数固定为1)。为了将其强制转换为Date,您必须对其进行缩放,并在此过程中将其隐式转换为Double。但是,不能假设整个计算比7位小数更精确。您执行的每个额外计算都可能导致基于精度的舍入误差。
因此,唯一具体的解决方案是不依赖于超过1秒的精度等级的格式,并且如果您需要更高的精度,请滚动您自己的格式化功能或使用备用存储机制(@Gustav指向一个方向)。