在rand中,UTC()调用是多余的吗.种子(time.Now().UTC().UnixNano())



互联网上的许多示例使用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((是否安全-是

最新更新