Lucas Hendren
Lucas Hendren

Reputation: 2826

How many bytes are in a golang time object

I am having to store a time object in an array of bytes in a go project I am working on and have to declare the size of the array up front. I can not find the length in bytes referenced anywhere. At this point, I am planning on using the time.MarshalBinary() from the time library to convert it to bytes and manually figuring it out. But I wanted to know if anyone has any reference to the number of bytes this is and if time.MarshalBinary() is the best method to use for converting to bytes.

Upvotes: 2

Views: 5865

Answers (2)

Jonathan Hall
Jonathan Hall

Reputation: 79546

The answer to this question is not as straight forward as it might seem. It depends a lot on how much detail you need to preserve in your marshaling.

As pointed out in another answer, you can simply use unsafe.Sizeof() to determine the in-memory size of a time object, but this has little resemblance to the actual marshaled size, for the simple reason that it contains a pointer. If we look at the definition of time.Time we see:

type Time struct {
    // wall and ext encode the wall time seconds, wall time nanoseconds,
    // and optional monotonic clock reading in nanoseconds.
    //
    // From high to low bit position, wall encodes a 1-bit flag (hasMonotonic),
    // a 33-bit seconds field, and a 30-bit wall time nanoseconds field.
    // The nanoseconds field is in the range [0, 999999999].
    // If the hasMonotonic bit is 0, then the 33-bit field must be zero
    // and the full signed 64-bit wall seconds since Jan 1 year 1 is stored in ext.
    // If the hasMonotonic bit is 1, then the 33-bit field holds a 33-bit
    // unsigned wall seconds since Jan 1 year 1885, and ext holds a
    // signed 64-bit monotonic clock reading, nanoseconds since process start.
    wall uint64
    ext  int64

    // loc specifies the Location that should be used to
    // determine the minute, hour, month, day, and year
    // that correspond to this Time.
    // The nil location means UTC.
    // All UTC times are represented with loc==nil, never loc==&utcLoc.
    loc *Location
}

Whether you care about the timezone info stored in loc, is application dependent. If you always store UTC times (usually the best approach), then you can ignore this bit entirely, which means you can get by storing just the two uint64s.

But even these two fields depend on whether or not you're using a monotonic clock. When marshaling data, you almost certainly do not care about the monotonic clock, whether or not it's encoded in those bits.

What this means is that, in most cases, you should be able to store a full time object in 64 bits (8 bytes), plus a timezone indicator, if necessary.

Further, depending on the precision you need, you may be able to store only the seconds field (discarding sub-second precision), which needs only 33 bits. If you only care about minutes or days, you could use even less space.

Upvotes: 5

Diericx
Diericx

Reputation: 438

You can use usafe.Sizeof to get the size in bytes of a variable. I did this

package main

import (
    "fmt"
    "time"
    "unsafe"
)

func main() {
    t := time.Now()
    fmt.Printf("a: %T, %d\n", t, unsafe.Sizeof(t))
}

Looks like its 24 bytes! :)

Also MarshalBinary looks like it works, although it depends on where you are sending it and how you want to unmarshal it. It may be easier to simply convert it to a string then use that if you are using it in Javascript or something.

Upvotes: 0

Related Questions