我正在尝试解析.ndx文件。其中包含一个64位值,代表自1601年1月1日(UTC)起100纳秒间隔的数量。 这是python中的实现:https://github.com/mekh/jtv2xmltv/blob/master/jtv2xml.py#L31
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id='foo'>
<a><b>a</b></a>
<a><b>b</b></a>
<a><b>c</b></a>
</div>
https://play.golang.org/p/--zQUtJN5Lh
看起来像增量变量溢出,即使按小时设置也是如此。有什么方法可以计算出来吗?
编辑:在文档https://golang.org/pkg/time/#Duration
中找到Duration表示两个瞬间之间经过的时间,以int64纳秒计数。该表示将最大可表示持续时间限制为大约290年。
是否有第三方套餐的有效期超过290年?
EDIT2 :最后我需要时间。给定时间戳记的时间
答案 0 :(得分:4)
time.Duration
是一个int64
值,表示以纳秒为单位的持续时间。如前所述,int64
的最大值约为290年,因此无法表示更长的持续时间。
一种简单的解决方案是将输入转换为time.Duration
,这将代表实际持续时间的百分之一,因为输入以100纳秒为单位。您可以将此持续时间添加到从参考日期开始的时间:1601-01-01 UTC
一百次,您已完成:
func getTime(input int64) time.Time {
t := time.Date(1601, 1, 1, 0, 0, 0, 0, time.UTC)
d := time.Duration(input)
for i := 0; i < 100; i++ {
t = t.Add(d)
}
return t
}
测试:
fmt.Println(getTime(132118740000000000))
输出(在Go Playground上尝试):
2019-09-02 05:00:00 +0000 UTC
是的,上面的解决方案有一个包含100次迭代的循环,这可能不是最佳选择。
加快上述速度的一种方法是减少迭代次数。如果输入不是很大,我们可能会这样做。例如,如果输入乘以2也适合int64
,则可以将其乘以2
,然后只需要进行50次迭代。同样,如果input*10
也适合int64
,我们可以将其乘以10
,然后只需要10次迭代即可。
输入为100纳秒单位。 100
可以被100、50、25、20、10、5、4、2整除,因此为了不损失任何纳秒,如果输入乘以这些乘积仍然适合int64
,我们可以检查这些因素,如果可以的话,我们可以将迭代次数除以它。在最佳情况下(如果持续时间少于2.9年,我们可以将迭代次数减少为1)。
示例如下:
var divisors = []int64{100, 50, 25, 20, 10, 5, 4, 2}
func getTime(input int64) time.Time {
iterations := 100
for _, div := range divisors {
if input <= math.MaxInt64/div {
input *= div
iterations /= int(div)
break
}
}
t := time.Date(1601, 1, 1, 0, 0, 0, 0, time.UTC)
d := time.Duration(input)
for i := 0; i < iterations; i++ {
t = t.Add(d)
}
return t
}
这将输出相同的内容,请在Go Playground上进行尝试。在此示例中,迭代次数仅为2。
类似于上述解决方案,但是在这里,在每次迭代中,我们将以最大可能的持续时间增加时间。即:time.Duration(math.MaxInt64)
,但是由于输入是以100纳秒为单位的,因此,我们将使用time.Duration(math.MaxInt64).Truncate(100 * time.Nanosecond)
。我们会一直这样做,直到剩余持续时间小于最大持续时间为止,这将是获得我们正在寻找的即时时间的最后加法。另外,我们也不需要第一个循环来寻找最大的除数(可以将迭代次数减少到最大)。
func getTime(input int64) time.Time {
maxd := time.Duration(math.MaxInt64).Truncate(100 * time.Nanosecond)
maxdUnits := int64(maxd / 100) // number of 100-ns units
t := time.Date(1601, 1, 1, 0, 0, 0, 0, time.UTC)
for input > maxdUnits {
t = t.Add(maxd)
input -= maxdUnits
}
if input != 0 {
t = t.Add(time.Duration(input * 100))
}
return t
}
输出再次相同。在Go Playground上尝试这个。
此解决方案保证了最少的迭代。例如。如果持续时间少于290年,则将有一个time.Add()
通话。如果持续时间在290至580年之间,则会有2次time.Add()
通话,等等。
请注意,在最后的time.Add()
调用中,我们将input
乘以100
将100纳秒单位转换为纳秒。这将始终成功,因为在此之前的循环将其循环的时间减小到只要它大于maxdUnits
。如果还需要添加一些内容,我们也仅将其称为最终time.Add()
,以确保迭代次数最少。实际上,这可能总是正确的,因此可以if
忽略掉:即使input
为0,加零也不会改变t
,我将其添加为true。 “最小迭代”标题。
答案 1 :(得分:0)
如果您不需要以前的日期,例如1900,为什么不将日期更改为1900?
因此,您从ndx中获取int64,将其差异从1601移至1900,将其除以100,然后根据新纪元进行计算。没有循环,并且应该非常快速和准确
答案 2 :(得分:-1)
使用syscall找到了另一个解决方案。Filetime:https://parsiya.net/blog/2018-11-01-windows-filetime-timestamps-and-byte-wrangling-with-go/
// toTime converts an 8-byte Windows Filetime to time.Time.
func toTime(t [8]byte) time.Time {
ft := &syscall.Filetime{
LowDateTime: binary.LittleEndian.Uint32(t[:4]),
HighDateTime: binary.LittleEndian.Uint32(t[4:]),
}
return time.Unix(0, ft.Nanoseconds())
}