2
\$\begingroup\$

I'm trying to generate a random time between now and 3 years ago. To my knowledge, Go doesn't have a random(min,max) feature in either math/rand or crypto/rand where min > 0. To naively combat that, I generate a slice containing every time stamp within the relative now and 3 years ago, and then select the index at random with rand.Intn(len(timeRange)), because I am guaranteed to get a random index between 0 and len(timeRange). It works just fine, and I get a Unix time stamp sometime between now and 3 years ago. However, I want to generate just one timestamp, not ~94m of them and then randomly picking one...it's egregiously slow.

Here is the code:

package main

import (
    "time"
    "math/rand"
    "fmt"
)

func randomTimestamp() time.Time {
    now := time.Now().Unix()
    threeYearsAgo := int64(now - 94608000)
    timeRange := make([]int64,1)
    for i := threeYearsAgo; i < now; i++ {
        timeRange = append(timeRange, i)
    }
    randomTime := rand.Intn(len(timeRange))

    randomNow := time.Unix(timeRange[randomTime], 0)

    return randomNow
}

func main() {
    for i := 0; i < 25; i++ {
        fmt.Println(randomTimestamp().Format(time.RFC3339))
    }
}

How can I optimise randomTimestamp() so it doesn't have to calculate every second over the last 3 years, but it randomly picks one between now and 3 years ago?

\$\endgroup\$
  • 3
    \$\begingroup\$ I don't know the in's and out's of your language, but from an abstract logic point of view, surely you can just select a random integer between 0 and 94608000, then subtract your integer from now \$\endgroup\$ – Darren H Dec 3 '16 at 11:16
2
\$\begingroup\$

As Darren H has said in the comments, just generate a random number between 0 and nanoseconds in three years, and subtract from time.Now():

const threeYears = 3 * 365 * 24 * time.Hour

func main() {
    rand.Seed(time.Now().UnixNano())
    d := time.Duration(rand.Int63n(int64(threeYears)))
    fmt.Println(time.Now().Add(-d))
}
\$\endgroup\$
  • \$\begingroup\$ This is a good answer (bonus points for seeding the rand package properly). Small nit: the int64 conversion is unnecessary due to the way numerical constants work in Go. \$\endgroup\$ – Ted Dec 11 '16 at 0:58
  • 2
    \$\begingroup\$ @Ted I'm afraid that's wrong. time.Hour is typed, so threeYears has the type time.Duration. You can try and remove the conversion yourself and get cannot use threeYears (type time.Duration) as type int64 in argument to rand.Int63. \$\endgroup\$ – Ainar-G Dec 11 '16 at 9:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.