131

How can I get Unix time in Go in milliseconds?

I have the following function:

func makeTimestamp() int64 {
    return time.Now().UnixNano() % 1e6 / 1e3
}

I need less precision and only want milliseconds.

blackgreen
  • 34,072
  • 23
  • 111
  • 129
mconlin
  • 8,169
  • 5
  • 31
  • 37

7 Answers7

217

The 2021 answer:

As of go v1.17, the time package added UnixMicro() and UnixMilli(), so the correct answer would be: time.Now().UnixMilli()

For go v.1.16 and earlier:

Just divide it:

func makeTimestamp() int64 {
    return time.Now().UnixNano() / 1e6
}

1e6, i.e. 1 000 000, is the number of nanoseconds in a millisecond.

Here is an example that you can compile and run to see the output

package main

import (
    "time"
    "fmt"
)

func main() {
    a := makeTimestamp()

    fmt.Printf("%d \n", a)
}

func makeTimestamp() int64 {
    return time.Now().UnixNano() / 1e6
}
lxgr
  • 3,719
  • 7
  • 31
  • 46
OneOfOne
  • 95,033
  • 20
  • 184
  • 185
  • 52
    The above calculation doesn't really make sense. You don't divide nanoseconds by miliseconds. It happens to be the case that golang choses to represent times down to nanosecond and the constant 'Millisecond' is 1,000,000. Mathematically speaking, calculation should be: `time.Now().UnixNano() * (time.Nanosecond / time.Millisecond)`. However it's best to change the order because of integer division: `time.Nanosecond * time.Now().UnixNano() / time.Millisecond` – Jonno Nov 04 '14 at 01:00
  • Probably need some casts.. o/w should be fine. – Jonno Nov 04 '14 at 01:02
  • 2
    Thanks for that. Note I didn't say you get the wrong result. It's that the calculation doesn't make sense and you're using information about go's constants. If tomorrow go has a new version that chooses higher precision for time units, for example, `time.Nanosecond == 10 `and `time.Millisecond == 10,000,000`, your code breaks – Jonno Nov 04 '14 at 01:07
  • @Jonno all built-in constants (and library methods) are guaranteed for the 1.x release cycle. https://golang.org/doc/go1compat – OneOfOne Nov 04 '14 at 01:09
  • 5
    thanks for that. You're welcome to rely on that guarantee, but this is in effect a Y2K bug. It may break at some point in the future. Why choose the wrong mathematical representation? – Jonno Nov 04 '14 at 01:12
  • @Jonno I'm not sure what you're talking about, Nanoseconds / Milliseconds are mathematical constants. http://golang.org/src/pkg/time/time.go#L450 – OneOfOne Nov 04 '14 at 01:15
  • 2
    they are arbitrary constants. They may change in the future. The time package currently "works" in nanosecond precision, but that's an arbitrary choice leading to setting time.Millisecond = 1,000,000. Note that even in the same file you referenced, time.Milisecond is set to 1000 * Microsecond, because mathematically speaking that's what it should represent. I'm going offline - Hope my explanation helps – Jonno Nov 04 '14 at 01:24
  • 15
    -1 This is just wrong. Your units don't add up. Look up dimensional analysis from physics. Your result does not represent time. – Kugel Jan 20 '15 at 12:48
  • @OneOfOne You got the right answer and you proved it in your code. – zachdyer May 13 '15 at 19:10
  • 10
    Quick answer for busy peoples. Look at [https://gobyexample.com/epoch](https://gobyexample.com/epoch) – honzajde Aug 15 '15 at 13:17
  • 1
    should be: return time.Now().UnixNano() / 1000 / 1000 – Sathya Dec 16 '15 at 03:09
  • why not just use time.Now().Unix instead of the converting? – temple Oct 08 '17 at 21:16
  • Unix() returns seconds. – OneOfOne Oct 12 '17 at 18:20
  • 2
    This answer is completely wrong. Use `time.Now().UnixNano() / int64(1e6)` instead. – clay Jun 06 '18 at 17:18
  • 1
    @clay this answer will work for all go 1.x.x versions and there for is not wrong, – Pizza lord - on strike Jul 31 '19 at 07:31
69

Keep it simple.

func NowAsUnixMilli() int64 {
    return time.Now().UnixNano() / 1e6
}
stratovarius
  • 3,720
  • 1
  • 30
  • 26
  • 1
    UnixNano result is undefined if the Unix time in nanoseconds cannot be represented by an int64 (a date before the year 1678 or after 2262) – chaokunyang Jun 10 '22 at 13:20
68

As @Jono points out in @OneOfOne's answer, the correct answer should take into account the duration of a nanosecond. Eg:

func makeTimestamp() int64 {
    return time.Now().UnixNano() / (int64(time.Millisecond)/int64(time.Nanosecond))
}

OneOfOne's answer works because time.Nanosecond happens to be 1, and dividing by 1 has no effect. I don't know enough about go to know how likely this is to change in the future, but for the strictly correct answer I would use this function, not OneOfOne's answer. I doubt there is any performance disadvantage as the compiler should be able to optimize this perfectly well.

See https://en.wikipedia.org/wiki/Dimensional_analysis

Another way of looking at this is that both time.Now().UnixNano() and time.Millisecond use the same units (Nanoseconds). As long as that is true, OneOfOne's answer should work perfectly well.

Bjorn Roche
  • 11,279
  • 6
  • 36
  • 58
  • 5
    The value of `.UnixNano()` will *always* be the time in Nanoseconds, `time.Millisecond` will *always* be the value for well, you guessed it, a millisecond, so even if for whatever idiotic reason the constant changes value, dividing UnixNano by Millisecond will *always* return the value in millisecond. – OneOfOne Feb 02 '16 at 05:36
  • 9
    The units of Unix.Nano is not in question; nor is the value of time.Millisecond. What *is* in question is the unit of time.Millisecond. It happens to be defined in nanoseconds, which is why your answer works. If time.Milliseconds were measured in other units (say, microseconds), the answer you gave would not work. – Bjorn Roche Feb 02 '16 at 15:54
  • 2
    @BjornRoche I'm a little late to this party, but wouldn't the correct answer be `(int64(time.Now().UnixNano() / int64(time.Nanosecond))/int64(time.Millisecond)`? The dimensional analysis `ns/(ms/ns)` returns `ns^2/ms`. Your answer also works because `time.Nanosecond=1`, but the units are off... – The Puma Jan 07 '18 at 16:35
  • 1
    @thepuma It's been a while so I might be looking at this wrong or misunderstanding you, but ns/(ms/ns) is equivalent to ns^2/ms, so both answers should work. – Bjorn Roche Jan 26 '18 at 21:55
  • This answer is correct because running this will display the same result as when converting using the online converter https://www.unitconverters.net/prefixes/nano-to-milli.htm – user666 Aug 16 '18 at 06:43
  • If you need best performance, turn the denominator into a constant. There's no reason to recalculate each time you want the current time: var millisConversion = (int64(time.Millisecond)/int64(time.Nanosecond)) – thebiggestlebowski Apr 15 '19 at 11:14
12

How can I get Unix time in Go in milliseconds?

Go 1.17 and above

No more divisions from nanoseconds. Starting from Go 1.17 you can just use Time.UnixMilli method directly:

// a deterministic date value
t := time.Date(2021, 7, 16, 0, 0, 0, 0, time.UTC)

m := t.UnixMilli()
fmt.Println(m) // 1626393600000

Playground: https://play.golang.org/p/JSExv5jw2ZW

blackgreen
  • 34,072
  • 23
  • 111
  • 129
5

At https://github.com/golang/go/issues/44196 randall77 suggested

time.Now().Sub(time.Unix(0,0)).Milliseconds()

which exploits the fact that Go's time.Duration already have Milliseconds method.

andig
  • 13,378
  • 13
  • 61
  • 98
3

I think it's better to round the time to milliseconds before the division.

func makeTimestamp() int64 {
    return time.Now().Round(time.Millisecond).UnixNano() / (int64(time.Millisecond)/int64(time.Nanosecond))
}

Here is an example program:

package main

import (
        "fmt"
        "time"
)

func main() {
        fmt.Println(unixMilli(time.Unix(0, 123400000)))
        fmt.Println(unixMilli(time.Unix(0, 123500000)))
        m := makeTimestampMilli()
        fmt.Println(m)
        fmt.Println(time.Unix(m/1e3, (m%1e3)*int64(time.Millisecond)/int64(time.Nanosecond)))
}

func unixMilli(t time.Time) int64 {
        return t.Round(time.Millisecond).UnixNano() / (int64(time.Millisecond) / int64(time.Nanosecond))
}

func makeTimestampMilli() int64 {
        return unixMilli(time.Now())
}

The above program printed the result below on my machine:

123
124
1472313624305
2016-08-28 01:00:24.305 +0900 JST
hnakamur
  • 521
  • 4
  • 17
2

Simple-read but precise solution would be:

func nowAsUnixMilliseconds(){
    return time.Now().Round(time.Millisecond).UnixNano() / 1e6
}

This function:

  1. Correctly rounds the value to the nearest millisecond (compare with integer division: it just discards decimal part of the resulting value);
  2. Does not dive into Go-specifics of time.Duration coercion — since it uses a numerical constant that represents absolute millisecond/nanosecond divider.

P.S. I've run benchmarks with constant and composite dividers, they showed almost no difference, so feel free to use more readable or more language-strict solution.

Liubov
  • 182
  • 5
  • 1
    If you want to know the correct Unix time in milliseconds (milliseconds since the Epoch), you should not use Round(), as that will round up half the time, and your result will then contain a millisecond which has not fully elapsed yet. – torbenl Apr 07 '20 at 05:07
  • Thanks for a note, @torbenl - this may be important for most of systems (mine is an exclusion, this time is stored for history only). – Liubov Apr 20 '20 at 19:28