# 计算时间。从时间戳开始的时间，从Go中的1601-01-01开始

I'm trying to parse .ndx file. Which contains a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (UTC). Here's implementation in python: https://github.com/mekh/jtv2xmltv/blob/master/jtv2xml.py#L31

``````package main

import (
"fmt"
"time"
)

func main() {
var timestamp int64
timestamp = 132118740000000000

delta := time.Duration(timestamp)*time.Microsecond
fmt.Println(delta)

seconds, _ := divmod(timestamp, 1000000)
hours, seconds := divmod(seconds, 3600)
delta = time.Duration(hours)*time.Hour
fmt.Println(delta)

layout := "2006-01-02"
start, _ := time.Parse(layout, "1601-01-01")

}

func divmod(numerator, denominator int64) (quotient, remainder int64) {
quotient = numerator / denominator // integer division, decimals are truncated
remainder = numerator % denominator
return
}
``````

https://play.golang.org/p/--zQUtJN5Lh

Looks like delta variable overflows, even when setting by hours. Is there any way to calculate this?

EDIT: Found in docs https://golang.org/pkg/time/#Duration

A Duration represents the elapsed time between two instants as an int64 nanosecond count. The representation limits the largest representable duration to approximately 290 years.

Is there any 3rd party packages for duration longer than 290 years?

EDIT2: in the end I need time.Time of a given timestamp

• 写回答

#### 2条回答默认 最新

• dreamfly0514 2019-09-12 09:31
关注

`time.Duration` is an `int64` value representing a duration in nanoseconds. As stated, max value of `int64` is about 290 years, so bigger durations cannot be represented by it.

## Simplest, naive solution

One simple solution is to convert your input to `time.Duration`, which will represent one hundredth of your actual duration, because the input is in 100-nanosecond units. You may add this duration to a time starting with the reference date: `1601-01-01 UTC` a hundred times, and you're done:

``````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++ {
}
return t
}
``````

Testing it:

``````fmt.Println(getTime(132118740000000000))
``````

Output (try it on the Go Playground):

``````2019-09-02 05:00:00 +0000 UTC
``````

## Naive solution optimized

Yes, the above solution has a loop with 100 iterations, which may not be optimal.

One way to speed up the above is to reduce the number of iterations. We may do so if the input is not "very" large. For example if the input multiplied by 2 also fits into `int64`, we could pre-multiply it by `2`, and then we would only need 50 iterations. Similarly, if the `input*10` would also fit into `int64`, we could pre-multiply it by `10` and then we would only need 10 iterations.

The input is 100-nanosecond units. `100` is dividable by 100, 50, 25, 20, 10, 5, 4, 2, so to not lose any nanoseconds, we could check these factors if the input multiplied by these still fits into `int64`, and if so we can divide the iterations count by it. In the best case scenario (if duration is less than 2.9 years, we can reduce the iterations to 1).

Example doing so:

``````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++ {
}
return t
}
``````

This will output the same, try it on the Go Playground. In this example the number of iterations is only 2.

## Fewest iterations

Similar to the above solution, but here in each iteration we will increment the time with the biggest duration possible. That is: `time.Duration(math.MaxInt64)`, but since the input is in 100-nanosecond units, to be exact, we'll use `time.Duration(math.MaxInt64).Truncate(100 * time.Nanosecond)`. We keep doing this until the remaining duration is less than the maximum, which will be the final addition to get the time instant we're looking for. As an extra, we also don't need the first loop which looked for the biggest divisor (to which the iterations count could be reduced).

``````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 {
input -= maxdUnits
}
if input != 0 {
}
return t
}
``````

Output again is the same. Try this one on the Go Playground.

This solution guarantees fewest iterations. E.g. if duration is less than 290 years, there will be a single `time.Add()` call. If duration is between 290 and 580 years, there will be 2 `time.Add()` calls etc.

Note that in the final `time.Add()` call we multiply `input` by `100` to convert 100-nanosecond units to nanoseconds. This will always succeed, because the loop before that decrements it as long as its bigger than `maxdUnits`. We also only call this final `time.Add()` if there is still something left to add, to ensure the fewest iterations. In practice this will likely always be true, so this `if` could be left out: even if `input` is 0, adding zero will not change `t`, I added it to be true to the "fewest iterations" title.

本回答被题主选为最佳回答 , 对您是否有帮助呢?
评论

#### 悬赏问题

• ¥15 在线手电筒追加按钮JS
• ¥15 调用函数时，无关变量的改变引起函数值的改变
• ¥15 xy坐标转化为经纬度坐标
• ¥15 一般三角模糊数的上界值和下届值取中值的多少比较合理？
• ¥15 关于#python#的问题，请各位专家解答！
• ¥20 Hbase启动失败，无法启动HMaster
• ¥20 Lumerical FDTD solutions 中模型的相对阻抗，有效介电常数和有效磁导率的实部和虚部的数据如何获得？
• ¥100 sql reporting service 远程smtp服务器配置支持
• ¥15 ppyoloe_r带角度目标检测，loss_cls没法收敛
• ¥15 淘宝交易指数如何解读，其关联的数据指标是什么