Q1. How do I create a golang time struct from a nanosecond timestamp?
Q2. How do I then compute the number of hours since this timestamp?
In Go a "time" object is represented by a value of the struct type time.Time.
You can create a Time from a nanosecond timestamp using the time.Unix(sec int64, nsec int64) function where it is valid to pass nsec outside the range [0, 999999999].
And you can use the time.Since(t Time) function which returns the elapsed time since the specified time as a time.Duration (which is basically the time difference in nanoseconds).
t := time.Unix(0, yourTimestamp)
elapsed := time.Since(t)
To get the elapsed time in hours, simply use the Duration.Hours() method which returns the duration in hours as a floating point number:
fmt.Printf("Elapsed time: %.2f hours", elapsed.Hours())
Try it on the Go Playground.
Note:
Duration can format itself intelligently in a format like "72h3m0.5s", implemented in its String() method:
fmt.Printf("Elapsed time: %s", elapsed)
You pass the nanoseconds to time.Unix(0, ts), example:
func main() {
now := time.Now()
ts := int64(1257856852039812612)
timeFromTS := time.Unix(0, ts)
diff := now.Sub(timeFromTS)
fmt.Printf("now: %v\ntime from ts: %v\ndiff: %v\ndiff int:", now, timeFromTS, diff, int64(diff))
}
playground
Related
Go has methods to extract almost every component of a timestamp, eg time.Second(), time.Nano(), but none to extract the millisecond portion of a timestamp.
How does one extract the millisecond value of a timestamp.
eg, in the case of a timestamp like:
2021-01-07 10:33:06.511
i want to extract 511
To access the fraction seconds, you may use time.Nanosecond(). And if we convert it to time.Duration (time.Duration is exactly the nanoseconds count), we can take advantage of its Duration.Milliseconds() method (which of course does no magic but code will be clearer and easier to read):
func extractMs(t time.Time) int64 {
return time.Duration(t.Nanosecond()).Milliseconds()
}
Try it on the Go Playground.
there is an answer in the comments, but i want to post here to be cannonical:
func extractMillisecond(t time.Time) int {
ms := time.Duration(t.Nanosecond()) / time.Millisecond
return int(ms)
}
I am trying to understand how to use/call libraries & functions of Golang by reading the official documentation but couldn't fully comprehend.
Below are some examples that I hope to get advise from the experts here in SO
Example 1: time
From the documentation:
type Time
func Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location) Time
func Now() Time
I interpret the above as type Time has method Now which does not take in any input and returns a Time type.
thus,
var t time.Time
fmt.Println(t)
yields 0001-01-01 00:00:00 +0000 UTC So. t is a valid time.Time type variable.
Question 1:
But why is t.Now() throwing an error t.Now undefined (type time.Time has no field or method Now)?
Question 2:
Interestingly, time.Now() returns the value desired. Does that mean Now() is not a method of type Time?
var t time.Time declares a variable of type time.Time with the zero value for the type.
func Now() Time: Now() is a function with no parameters which returns type time.Time
func (t Time) Month() Month: Month() is a method on the receiver t type time.Time with no parameters which returns type time.Month.
For example,
package main
import (
"fmt"
"time"
)
func main() {
var t time.Time
fmt.Println(t)
t = time.Now()
fmt.Println(t)
m := t.Month()
fmt.Println(m)
}
Playground: https://play.golang.org/p/Ume5kxDAe05
Output:
0001-01-01 00:00:00 +0000 UTC
2009-11-10 23:00:00 +0000 UTC m=+0.000000001
November
Note: In the playground the time begins at 2009-11-10 23:00:00 UTC. This makes it easier to cache programs by giving them deterministic output.
Take A Tour of Go.
See The Go Programming Language Specification
I think what you are really asking here is: why is the package documentation laid out the way it is? That is, for this specific case, in this specific package documentation, we see:
type Time
func Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location) Time
func Now() Time
where the type Time line appears by itself, then immediately underneath it, several func declarations appear that return a value of type Time.
The reason these are indented two characters is to indicate that these functions return a value of type Time. The reason that they appear under the type Time line is that these functions return a value of type Time.
In this case, both reasons add up to the same thing—they're redundant. That's OK though! It's just a function of the fact that the Go documentation generator is a program that obeys these sort and indent rules. Nothing here implies that the two functions are receiver functions.
Consider another example from the same package documentation. Somewhat earlier, we see:
type Duration
func ParseDuration(s string) (Duration, error)
func Since(t Time) Duration
func Until(t Time) Duration
Here, this tells us that all three of these functions return a Duration—though the first one returns both a Duration and an error. The ParseDuration function is an ordinary function. It is the functions Since and Until that are receiver functions.1 They take a receiver argument of type Time (and no other arguments) and return a value of type Duration.
In some other design, it might make sense to sort the Since and Until functions underneath the type name Time, since these are receiver functions of type Time. But the package documentation sorts (and groups) by return type, not receiver or argument type. That's all there really is to it here.
1You can—and the spec does—call these methods if you like.
I'm trying to write protobuf *Timestamp.timestamp to binary, and the error I got is invalid type *Timestamp.timestamp and I've tried to no avail, can anyone point me to some direction? thanks!
package main
import (
"bytes"
"encoding/binary"
"fmt"
google_protobuf "github.com/golang/protobuf/ptypes/timestamp"
"time"
)
func main() {
buff := new(bytes.Buffer)
ts := &google_protobuf.Timestamp{
Seconds: time.Now().Unix(),
Nanos: 0,
}
err := binary.Write(buff, binary.LittleEndian, ts)
if err != nil {
panic(err)
}
fmt.Println("done")
}
can anyone point me to some direction?
Read the error message.
binary.Write: invalid type *timestamp.Timestamp
Read the documentation for binary.Write and timestamp.Timestamp.
Package binary
import "encoding/binary"
func Write
func Write(w io.Writer, order ByteOrder, data interface{}) error
Write writes the binary representation of data into w. Data must be a
fixed-size value or a slice of fixed-size values, or a pointer to such
data. Boolean values encode as one byte: 1 for true, and 0 for false.
Bytes written to w are encoded using the specified byte order and read
from successive fields of the data. When writing structs, zero values
are written for fields with blank (_) field names.
package
timestamp
import "github.com/golang/protobuf/ptypes/timestamp"
type
Timestamp
type Timestamp struct {
// Represents seconds of UTC time since Unix epoch
// 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to
// 9999-12-31T23:59:59Z inclusive.
Seconds int64 `protobuf:"varint,1,opt,name=seconds,proto3" json:"seconds,omitempty"`
// Non-negative fractions of a second at nanosecond resolution. Negative
// second values with fractions must still have non-negative nanos values
// that count forward in time. Must be from 0 to 999,999,999
// inclusive.
Nanos int32 `protobuf:"varint,2,opt,name=nanos,proto3" json:"nanos,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
A Timestamp represents a point in time independent of any time zone or
calendar, represented as seconds and fractions of seconds at
nanosecond resolution in UTC Epoch time. It is encoded using the
Proleptic Gregorian Calendar which extends the Gregorian calendar
backwards to year one. It is encoded assuming all minutes are 60
seconds long, i.e. leap seconds are "smeared" so that no leap second
table is needed for interpretation. Range is from 0001-01-01T00:00:00Z
to 9999-12-31T23:59:59.999999999Z. By restricting to that range, we
ensure that we can convert to and from RFC 3339 date strings. See
https://www.ietf.org/rfc/rfc3339.txt.
As the error message says: *timestamp.Timestamp is not a fixed-size value or a slice of fixed-size values, or a pointer to such data.
To confirm that, comment out the XXX_unrecognized variable-sized field; there is no error.
package main
import (
"bytes"
"encoding/binary"
"fmt"
"time"
)
// https://github.com/golang/protobuf/blob/master/ptypes/timestamp/timestamp.pb.go
type Timestamp struct {
// Represents seconds of UTC time since Unix epoch
// 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to
// 9999-12-31T23:59:59Z inclusive.
Seconds int64 `protobuf:"varint,1,opt,name=seconds,proto3" json:"seconds,omitempty"`
// Non-negative fractions of a second at nanosecond resolution. Negative
// second values with fractions must still have non-negative nanos values
// that count forward in time. Must be from 0 to 999,999,999
// inclusive.
Nanos int32 `protobuf:"varint,2,opt,name=nanos,proto3" json:"nanos,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
// XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func main() {
buff := new(bytes.Buffer)
ts := &Timestamp{
Seconds: time.Now().Unix(),
Nanos: 0,
}
err := binary.Write(buff, binary.LittleEndian, ts)
if err != nil {
panic(err)
}
fmt.Println("done")
}
Playground: https://play.golang.org/p/Q5NGnO49Dsc
Output:
done
I have been trying to work with some go, and have found some weird behavior on windows. If I construct a time object from parsing a time string in a particular format, and then use functions like time.Since(), I get negative durations.
Code sample:
package main
import (
"fmt"
"time"
"strconv"
)
func convertToTimeObject(dateStr string) time.Time {
layout := "2006-01-02T15:04:05.000Z"
t, _:= time.Parse(layout, dateStr)
return t
}
func main() {
timeOlder := convertToTimeObject(time.Now().Add(-30*time.Second).Format("2006-01-02T15:04:05.000Z"))
duration := time.Since(timeOlder)
fmt.Println("Duration in seconds: " + strconv.Itoa(int(duration.Seconds())))
}
If you run it on Linux or the Go Playground link, you get the result as Duration in seconds: 30 which is expected.
However, on Windows, running the same piece of code with Go 1.10.3 gives Duration in seconds: -19769.
I've banged my head on this for hours. Any help on what I might be missing?
The only leads I've had since now are that when go's time package goes to calculate the seconds for both time objects (time.Now() and my parsed time object), one of them has the property hasMonotonic and one doesn't, which results in go calculating vastly different seconds for both.
I'm not the expert in time, so would appreciate some help. I was going to file a bug for Go, but thought to ask here from the experts if there's something obvious I might be missing.
I think I figured out what the reason for the weird behavior of your code snippet is and can provide a solution. The relevant docs read as follows:
since returns the time elapsed since t. It is shorthand for time.Now().Sub(t).
But:
now returns the current local time.
That means you are formatting timeOlder and subtract it from an unformatted local time. That of course causes unexpected behavior. A simple solution is to parse the local time according to your format before subtracting timeOlder from it.
A solution that works on my machine (it probably does not make a lot of sense to give a playground example, though):
func convertToTimeObject(dateStr string) time.Time {
layout := "2006-01-02T15:04:05.000Z"
t, err := time.Parse(layout, dateStr)
// check the error!
if err != nil {
log.Fatalf("error while parsing time: %s\n", err)
}
return t
}
func main() {
timeOlder := convertToTimeObject(time.Now().Add(-30 * time.Second).Format("2006-01-02T15:04:05.000Z"))
duration := time.Since(timeOlder)
// replace time.Since() with a correctly parsed time.Now(), because
// time.Since() returns the time elapsed since the current LOCAL time.
t := time.Now().Format("2006-01-02T15:04:05.000Z")
timeNow := convertToTimeObject(t)
// print the different results
fmt.Println("duration in seconds:", strconv.Itoa(int(duration.Seconds())))
fmt.Printf("duration: %v\n", timeNow.Sub(timeOlder))
}
Outputs:
duration in seconds: 14430
duration: 30s
I have a following function which calculated time since startTime, uptime: time.Since(startTime).String().
This returns time as follows:
"uptime": "3m54.26744075s"
How do I convert time to be in seconds, as follows:
"uptime": "123456789"
time.Since() returns you a value of type time.Duration which has a Duration.Seconds() method, just use that:
secs := time.Since(startTime).Seconds()
This will be of type float64. If you don't need the fraction part, just convert it to int, e.g. int(secs). Alternatively you may divide the time.Duration value with time.Second (which is the number of nanoseconds in a second), and you'll get to an integer seconds value right away:
secs := int(time.Since(startTime) / time.Second)
(Note that the int conversion in this last example is not to drop the fraction part because this is already an integer division, but it's rather to have the result as a value of type int instead of time.Duration.)
Also see related question: Conversion of time.Duration type microseconds value to milliseconds