互联网上的许多示例使用rand.Seed(time.Now().UTC().UnixNano())
初始化伪随机数生成器种子。
我发现,如果省略UTC()
调用,它仍然可以正常工作。
Unix(或UnixNano(时间无论如何都是自epoch以来的秒数(或毫秒(,即1970-01-01 00:00:00.000000000000 UTC。Unix或UnixNano时间无论如何都与时区无关。
以以下代码为例:
package main
import (
"fmt"
"time"
)
func main() {
t := time.Now()
fmt.Println(t.UnixNano())
fmt.Println(t.UTC().UnixNano())
}
所以我的问题是:UTC()
调用有什么用途吗?或者省略UTC()
调用而只调用rand.Seed(time.Now().UnixNano())
安全吗?
可以肯定地说,使用UnixNano()
时可以省略UTC()
首先及时查看UTC()
的代码。go:1107:
// UTC returns t with the location set to UTC.
func (t Time) UTC() Time {
t.setLoc(&utcLoc)
return t
}
它只设置当前时间的位置。
现在,根据time.go文件中对In()
方法的注释,位置信息仅用于";显示目的";。查看时间。转到:1119:
// In returns a copy of t representing the same time instant, but
// with the copy's location information set to loc for display
// purposes.
//
// In panics if loc is nil.
func (t Time) In(loc *Location) Time {
if loc == nil {
panic("time: missing Location in call to Time.In")
}
t.setLoc(loc)
return t
}
只有在必须显示时间时才使用位置:
// abs returns the time t as an absolute time, adjusted by the zone offset.
// It is called when computing a presentation property like Month or Hour.
func (t Time) abs() uint64 {
l := t.loc
// Avoid function calls when possible.
if l == nil || l == &localLoc {
l = l.get()
}
sec := t.unixSec()
if l != &utcLoc {
if l.cacheZone != nil && l.cacheStart <= sec && sec < l.cacheEnd {
sec += int64(l.cacheZone.offset)
} else {
_, offset, _, _ := l.lookup(sec)
sec += int64(offset)
}
}
return uint64(sec + (unixToInternal + internalToAbsolute))
}
运行以下代码以查看差异。两者都基于相同的UnixNano,只更改时间,因为位置只在打印前应用:
var now = time.Now()
var utc = now.UTC()
fmt.Printf("now UnixNano: %d, Hour: %d, Minute: %d, Second: %dn", now.UnixNano(), now.Hour(), now.Minute(), now.Second())
fmt.Printf("utc UnixNano: %d, Hour: %d, Minute: %d, Second: %dn", utc.UnixNano(), utc.Hour(), utc.Minute(), utc.Second())
now UnixNano: 1595836999431598000, Hour: 10, Minute: 3, Second: 19
utc UnixNano: 1595836999431598000, Hour: 8, Minute: 3, Second: 19
您设置了伪随机数生成器种子,使生成的数字难以猜测。
当您查看UTC()
方法文档时,您会发现它所做的唯一事情就是设置位置(时区(。哪个时区用于随机种子生成是无关紧要的。
重要的是,使用了UnixNano()
,而且该平台实际上可以如此精确地返回时间。否则,可能会猜测随机种子,这可能允许:随机数生成器攻击
请考虑一种更安全的方法来初始化随机种子生成器:https://stackoverflow.com/a/54491783/5279383
Time.UnixNano()
返回源时间的Unix时间,即自1970年1月1日UTC以来经过的纳秒数。它总是在UTC区域进行解释,不管源时间位于什么位置。unix时间与区域无关。其文件明确指出:
结果不取决于与t相关的位置。
所以您不需要调用Time.UTC()
,您将得到相同的结果。
参见此示例:
t1, err := time.Parse("2006-01-02 15:04:05 -0700", "2020-07-27 13:50:00 +0200")
if err != nil {
panic(err)
}
fmt.Printf("%vnt%vnt%vn", t1, t1.UnixNano(), t1.UTC().UnixNano())
t2, err := time.Parse("2006-01-02 15:04:05 -0700", "2020-07-27 13:50:00 +0000")
if err != nil {
panic(err)
}
fmt.Printf("%vnt%vnt%vn", t2, t2.UnixNano(), t2.UTC().UnixNano())
我们解析两个输入时间,一个在非UTC区域,另一个在UTC区域。我们为两者打印UnixNano()
,无论是否调用UTC()
。结果完全相同。
输出(在Go Playground上尝试(:
2020-07-27 13:50:00 +0200 +0200
1595850600000000000
1595850600000000000
2020-07-27 13:50:00 +0000 UTC
1595857800000000000
1595857800000000000
- UTC((调用有任何用途吗-是
- 省略UTC((是否安全-是