I have some golang code that deals with time.Time dates. I'd like to write some tests that check for specific dates. How do I do that?
It appears as though the contents of time.Time struct are all private so I can't initialize one directly. And the only way to create one that I see is to time.Parse it. But since time.Parse returns two values, (one of which is error), I can't time.Parse in a global var initialization. I'm stuck with creating my containing structs globally, (which is so-so), but then filling in the time.Time elements later, in init. This trips several linters who suggest that init is a bad idea, that creating a struct without setting all fields it a bad idea, etc.
Is there a better way to create a constant time.Time? Am I missing something obvious?
You can just declare the variable, then use methods to change it:
package main
import (
"fmt"
"time"
)
func main() {
var t time.Time
fmt.Println(t.IsZero()) // true
fmt.Println(t) // 0001-01-01 00:00:00 +0000 UTC
t = t.AddDate(1969, 0, 0)
fmt.Println(t) // 1970-01-01 00:00:00 +0000 UTC
}
https://godocs.io/time#Time.AddDate
Related
I have a structure that gets rendered via template. e.g.:
type Foo struct {
Created time.Time
...
}
I pass this value to a template, and I'd like to this rendered see:
Created at 2022-11-22 9:50 (0d1h12m34s ago)
Displaying the timestamp (and formatting it) is easy enough, but I can't find a way to calculate the interval.
Created at {{.Created}} ({{???}} ago)
In go, this would be accomplished by time.Since(foo.Created) which returns a Duration, and then I can convert duration to string in various ways.
But doing the calculation in the template itself does not seem possible:
function "time" not defined
Or is it?
Can't find any information that explicitly tells me that time (or other arbitrary functions) are never ever allowed in templates. So I don't know if I'm just calling it wrong.
(I know I could create a new FooTemplateValue from a Foo add that field, so the template can render the duration as-is. I was just trying to avoid it if I can and use the actual object as-is).
You can register a custom template function using template.FuncMap, then you can invoke that function inside the template just like you would invoke a builtin function.
template.New("").Funcs(template.FuncMap{
"dur_until_now": func(t time.Time) time.Duration {
return time.Now().Sub(t)
},
}).Parse(`{{ dur_until_now .Created }}`)
https://go.dev/play/p/wM2f1oDFtDr
Or you can declare a custom time type and have that type implement a method that produces the desired value, then you can invoke that method inside the template directly on the field.
type MyTime struct{ time.Time }
func (t MyTime) DurUntilNow() time.Duration {
return time.Now().Sub(t.Time)
}
// ...
.Parse(`{{ .Created.DurUntilNow }}`)
https://go.dev/play/p/3faW4nTzK3-
Looks like you need to initialize the Created field with time.Now()
package main
import (
"fmt"
"time"
)
type Foo struct {
Created time.Time
// ...
}
func main() {
x := Foo{Created: time.Now()}
fmt.Println(time.Since(x.Created))
}
I'm a new starter in Go. Here is a problem that has been puzzling me.
In short, when I printed a struct with an anonymous field of the type time.Time, the output was similar to a time.Time variable printed alone. Neither braces nor other fields were displayed.
package main
import (
"fmt"
"time"
)
type Embedding struct {
i int
time.Time
}
type NoEmbedding struct {
i int
Present time.Time
}
func main() {
// `embedding` and `noEmbedding` shared exactly the same content
embedding := Embedding{
1,
time.Now(),
}
noEmbedding := NoEmbedding{
1,
time.Now(),
}
fmt.Println("embedding:\n", embedding)
fmt.Println("no embedding:\n", noEmbedding)
}
/* output
embedding:
2020-09-18 01:42:37.9201284 +0800 CST m=+0.011626601
no embedding:
{1 2020-09-18 01:42:37.9201284 +0800 CST m=+0.011626601}
*/
The problem is essentially a further step into "Why is time in Go printed differently in a struct?" I've gone over "Embedding in GO" but yet to find any clues.
fmt.Println will use the String method if one exists. When you embed a time value in a struct, the String method of Time is promoted to struct's String method. That's the reason why it prints differently.
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.
In my RESTFUL web service which is an online game, I'm storing starting time of every question in an global variable like this: var MyTime time.Time which I should update it after every level of the game. My application is distributed, so I want to make sure all of my apps are not updating it at the same time. That's why I've decided to make it atomic.
Actually I'm familiar with Golang sync/atomic package.
I tried to use atomic.LoadPointer() method but it needs specific argument type which isn't safe. Do you any other way for this?
Update:
Okay I solved my problem like this.
I defined time variable as atomic.Value and used atomic Load and Store methods. This is the code:
var myTime atomic.Value
myTime.Store(newTime) and load myTime.Load().(time.Time).
Consider that Load() method returns interface, so you should write (time.Time) at the end in order to convert it to time.Time type.
This can't be done, as such, because time.Time is a compound type:
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
}
However, you can do this with pointers, so *time.Time would be possible, if this suits your needs. But of course, this is discouraged, by virtue of the fact that atomic.LoadPointer and atomic.StorePointer use the unsafe package to accomplish their magic.
A much better approach, if it will work for you, is just to use a mutex to protect your value. There are many ways to do this, but one minimal example:
type MyTime struct {
t time.Time
mu sync.RWMutex
}
func (t *MyTime) Time() time.Time {
t.mu.RLock()
defer t.mu.RUnlock()
return t.t
}
func (t *MyTime) SetTime(tm time.Time) {
t.mu.Lock()
defer t.mu.Unlock()
t.t = tm
}
You can keep unix time https://golang.org/pkg/time/#example_Time_Unix as atomic which is int64. Then convert to go time after you've read atomic value.
If you are only interested in the timestamp, you could simply keep a reference to the unix time, which is int64 and atomically update that.
var ts int64
func main() {
atomic.StoreInt64(&ts, time.Now().Unix())
t := time.Unix(atomic.LoadInt64(&ts), 0)
fmt.Println(t)
}
Instead, if you need the entire Time struct, read on.
Go 1.19 (still in beta)
If you are okay with storing a pointer to a time.Time object, you can use atomic.Pointer, which is a generic struct that abstracts atomic.LoadPointer and atomic.StorePointer. As a simple example:
// instantiate generic struct with time.Time
var at = atomic.Pointer[time.Time]{}
func main() {
t := time.Now()
at.Store(&t)
t = *at.Load()
fmt.Println(t)
}
Playground: https://go.dev/play/p/KwTMgvJIenx?v=gotip
Note that in Go 1.19 you can also use atomic.Int64. The advantage of these atomic types instead of top-level functions is that it's more fool-proof; it's impossible to access the value non-atomically as it's hidden behind the struct.
I know we need to use the time.Time interface for dates in Go.
And to format, we need to use the format function.
http://golang.org/pkg/time/#Time.Format
But what are the valid and different formatters available for time.Time in Golang?
The docs for time.Format say http://golang.org/pkg/time/#Time.Format:
Predefined layouts ANSIC, UnixDate, RFC3339 and others describe standard and convenient representations of the reference time. For more information about the formats and the definition of the reference time, see the documentation for ANSIC and the other constants defined by this package.
So, in the constants http://golang.org/pkg/time/#pkg-constants:
To define your own format, write down what the reference time would look like formatted your way; see the values of constants like ANSIC, StampMicro or Kitchen for examples. The model is to demonstrate what the reference time looks like so that the Format and Parse methods can apply the same transformation to a general time value.
In short: you write the reference time Mon Jan 2 15:04:05 MST 2006 in the format you want and pass that string to Time.Format()
As #Volker said, please read the docs and read about the difference between types and interfaces.
package main
import (
"fmt"
"time"
)
func main() {
t := time.Now()
fmt.Println(t.Format(time.Kitchen))
t := time.Now()
tf := t.Format("2006-01-02 15:04:05-07:00")
fmt.Println(tf)
}
In case you need custom layout and/or struggling with build in layouts.
type Rtime struct {
Year int
Month int
Day int
Hour int
Minute int
Second int
Nanosecond int
Millisecond int
Offset int
OffsetString string
Zone string
}
func (rt *Rtime) LocalNow() {
t := time.Now()
rt.Hour,rt.Minute,rt.Second = t.Clock()
rt.Nanosecond = t.Nanosecond()
rt.Millisecond = rt.Nanosecond / 1000000
rt.Month = int(t.Month())
rt.Day = t.Day()
rt.Year = t.Year()
rt.OffsetString = ""
rt.Zone, rt.Offset = t.Local().Zone()
if rt.Offset > 0 {
rt.OffsetString = fmt.Sprintf("+%02d%02d",
rt.Offset/(60*60),
rt.Offset%(60*60)/60)
} else {
rt.OffsetString = fmt.Sprintf("%02d%02d",
rt.Offset/(60*60),
rt.Offset%(60*60)/60)
}
}
str := fmt.Sprintf("%04d-%02d-%02d %02d:%02d:%02d.%03d %s %s %d",
rt.Year,rt.Month,rt.Day,rt.Hour,rt.Minute,rt.Second,
rt.Millisecond,rt.Zone,rt.OffsetString,rt.Nanosecond)
fmt.Println(str)
output
2021-06-06 09:21:54.949 EEST +0300 949861778
Golang prescribes different standards to be followed for getting valid dates.
Available in http://golang.org/pkg/time/#Time.Format