Datetime 计算时间。Go中从1601-01-01开始的时间戳的时间
我正在尝试解析.ndx文件。它包含一个64位值,表示自1601年1月1日(UTC)以来的100纳秒间隔数。 下面是python的实现: 看起来增量变量溢出,即使按小时设置也是如此。有没有办法计算这个 编辑:在文档中找到 持续时间以int64纳秒计数表示两个瞬间之间经过的时间。该表述将可表述的最大期限限制为约290年 是否有超过290年的第三方软件包 EDIT2:最后我需要时间。给定时间戳的时间是一个Datetime 计算时间。Go中从1601-01-01开始的时间戳的时间,datetime,go,time,Datetime,Go,Time,我正在尝试解析.ndx文件。它包含一个64位值,表示自1601年1月1日(UTC)以来的100纳秒间隔数。 下面是python的实现: 看起来增量变量溢出,即使按小时设置也是如此。有没有办法计算这个 编辑:在文档中找到 持续时间以int64纳秒计数表示两个瞬间之间经过的时间。该表述将可表述的最大期限限制为约290年 是否有超过290年的第三方软件包 EDIT2:最后我需要时间。给定时间戳的时间是一个int64值,表示以纳秒为单位的持续时间。如上所述,int64的最大值约为290年,因此不能用它
int64
值,表示以纳秒为单位的持续时间。如上所述,int64
的最大值约为290年,因此不能用它来表示更长的持续时间
最简单、朴素的解决方案
一个简单的解决方案是将您的输入转换为time.Duration
,它将代表您实际持续时间的百分之一,因为输入是以100纳秒为单位的。您可以将此持续时间添加到从参考日期开始的时间:1601-01-01 UTC
100次,您完成了:
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
}
输出(在上尝试):
朴素解优化
是的,上面的解决方案有一个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
}
输出再次是相同的。试一试这个
此解决方案保证最少的迭代。例如,如果持续时间少于290年,将有一个time.Add()
调用。如果持续时间介于290年和580年之间,将有2个time.Add()
调用等
请注意,在最后的time.Add()
调用中,我们将input
乘以100
将100纳秒单位转换为纳秒。这将始终成功,因为只要它大于maxdUnits
,前面的循环就会递减它。如果还有什么东西需要添加,我们也只调用这个finaltime.Add()
,以确保最少的迭代。在实践中,这可能总是正确的,因此可以忽略这一点:即使输入为0,添加零也不会改变t
,我将其添加到“最少迭代次数”标题中。如果您不需要之前的日期,例如1900,为什么不将日期移到1900
因此,从ndx中取int64,将其从1601移到1900,除以100,然后根据新纪元进行计算。没有循环,应该非常快速和准确使用syscall找到另一个解决方案。Filetime:
对第三方软件包的请求在这里是无关紧要的。但一个简单的解决方案可能是存储一个time.Duration
,以及一个乘数。如果您需要3000年的持续时间,您可以存储30年的time.duration
,例如10倍的乘数。在其他情况下,如果您只关心年数,那么一个简单的int
就可以了。这两种方法是否适用于您取决于您对持续时间变量所做的操作。正如您所引用的,time.duration
不能表示超过290年的持续时间。那你想要什么呢?给定时间戳的1601-01-01
之后的小时、分钟、秒值;或者一个表示时间戳的time.time
值,或者什么?请澄清您的问题。顺便说一句,您的示例时间戳看起来“短”,它表示1642年。如果将0添加到它:132118740000000000
,则它将是2019-09-02
。
fmt.Println(getTime(132118740000000000))
2019-09-02 05:00:00 +0000 UTC
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
}
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
}
// 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())
}