rand.Seed(time.Now().UTC().UnixNano()) 中的 UTC() 调用是否多余?
Is the UTC() call redundant in rand.Seed(time.Now().UTC().UnixNano())?
网上很多例子都用rand.Seed(time.Now().UTC().UnixNano())
来初始化伪随机数生成器种子。
我发现如果我省略 UTC()
调用,它仍然可以正常工作。
Unix(或 UnixNano)时间无论如何是自纪元以来的秒数(或毫秒),即 1970-01-01 00:00:00.000000000 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())
是否安全?
您设置伪随机数生成器种子,使生成的数字难以猜测。
当您查看 UTC()
方法 documentation 时,您会发现它唯一做的就是设置位置(时区)。使用哪个时区生成随机种子是无关紧要的。
重要的是,使用 UnixNano()
,该平台实际上 return 计时如此精确。否则,可能会猜到随机种子,这可能允许:random number generator attack
请考虑一种更安全的方法来初始化随机种子生成器:
可以肯定地说在使用 UnixNano()
时可以省略 UTC()
先看time.go中UTC()
的代码:1107:
// UTC returns t with the location set to UTC.
func (t Time) UTC() Time {
t.setLoc(&utcLoc)
return t
}
它只设置当前时间的位置。
现在,根据 time.go 文件中对 In()
方法的评论,位置信息仅用于“显示目的”。参见 time.go: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: %d\n", now.UnixNano(), now.Hour(), now.Minute(), now.Second())
fmt.Printf("utc UnixNano: %d, Hour: %d, Minute: %d, Second: %d\n", 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
Time.UnixNano()
returns 源时间的 Unix 时间,自 1970 年 1 月 1 日 UTC 以来经过的纳秒数。它总是在 UTC 区域中解释,源时间的位置无关紧要。 unix 时间与区域无关。它的文档清楚地说明了这一点:
The result does not depend on the location associated with 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("%v\n\t%v\n\t%v\n", 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("%v\n\t%v\n\t%v\n", t2, t2.UnixNano(), t2.UTC().UnixNano())
我们解析 2 个输入时间,一次在非 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() 是否安全 - 是
网上很多例子都用rand.Seed(time.Now().UTC().UnixNano())
来初始化伪随机数生成器种子。
我发现如果我省略 UTC()
调用,它仍然可以正常工作。
Unix(或 UnixNano)时间无论如何是自纪元以来的秒数(或毫秒),即 1970-01-01 00:00:00.000000000 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())
是否安全?
您设置伪随机数生成器种子,使生成的数字难以猜测。
当您查看 UTC()
方法 documentation 时,您会发现它唯一做的就是设置位置(时区)。使用哪个时区生成随机种子是无关紧要的。
重要的是,使用 UnixNano()
,该平台实际上 return 计时如此精确。否则,可能会猜到随机种子,这可能允许:random number generator attack
请考虑一种更安全的方法来初始化随机种子生成器:
可以肯定地说在使用 UnixNano()
UTC()
先看time.go中UTC()
的代码:1107:
// UTC returns t with the location set to UTC.
func (t Time) UTC() Time {
t.setLoc(&utcLoc)
return t
}
它只设置当前时间的位置。
现在,根据 time.go 文件中对 In()
方法的评论,位置信息仅用于“显示目的”。参见 time.go: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: %d\n", now.UnixNano(), now.Hour(), now.Minute(), now.Second())
fmt.Printf("utc UnixNano: %d, Hour: %d, Minute: %d, Second: %d\n", 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
Time.UnixNano()
returns 源时间的 Unix 时间,自 1970 年 1 月 1 日 UTC 以来经过的纳秒数。它总是在 UTC 区域中解释,源时间的位置无关紧要。 unix 时间与区域无关。它的文档清楚地说明了这一点:
The result does not depend on the location associated with 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("%v\n\t%v\n\t%v\n", 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("%v\n\t%v\n\t%v\n", t2, t2.UnixNano(), t2.UTC().UnixNano())
我们解析 2 个输入时间,一次在非 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() 是否安全 - 是